Métodos de compresión / almacenamiento de medios en WAVE y JPEG, parte 1

Hola Mi primera serie de artículos tendrá como objetivo estudiar métodos de compresión y almacenamiento de imágenes / sonido, como JPEG (imagen) y WAVE (sonido), y también incluirán ejemplos de programas que utilizan estos formatos (.jpg, .wav) en la práctica. En esta parte consideraremos WAVE.


La historia


WAVE (Waveform Audio File Format) es un formato de archivo contenedor para almacenar grabaciones de flujo de audio. Este contenedor se usa típicamente para almacenar sonido sin comprimir en modulación de código de pulso. (Adaptado de Wikipedia)

Fue inventado y publicado en 1991 junto con RIFF por Microsoft e IBM (las principales compañías de TI de la época).


Estructura de archivo


El archivo tiene una parte de encabezado, los datos en sí, pero no hay pie de página. El encabezado pesa un total de 44 bytes.
El encabezado contiene configuraciones para el número de bits en la muestra, la frecuencia de la descripción, la profundidad del sonido, etc. información necesaria para una tarjeta de sonido. (Todos los valores numéricos de la tabla deben escribirse en orden Little-Endian)


Nombre del bloqueTamaño de bloque (B)Descripción / PropósitoValor (para algunos es fijo
trozo4 4Definir un archivo como contenedor de medios0x52494646 en Big-Endian ("RIFF")
trozo4 4El tamaño de todo el archivo sin chunkId y chunkSizeARCHIVO_TAMAÑO - 8
formatear4 4Definición de tipo de RIFF0x57415645 en Big-Endian ("WAVE")
subchunk1Id4 4Para ocupar más espacio de archivo formato continuo0x666d7420 en Big-Endian ("fmt")
subchunk1Size4 4Encabezado restante (en bytes)16 por defecto (para el caso sin compresión de transmisión de audio)
audioFormat2Formato de audio (depende del método de compresión y la estructura de datos de audio)1 (para PCM, que estamos considerando)
numChannels2Numero de canales1/2, tomamos 1 canal (3/4/5/6/7 ... - una pista de audio específica, por ejemplo 4 para un sonido cuádruple, etc.)
sampleRate4 4Frecuencia de muestreo de sonido (en hercios)Cuanto más, mejor será el sonido, pero se necesitará más memoria para crear una pista de audio de la misma longitud, el valor recomendado es 48000 (la calidad de sonido más aceptable)
byteRate4 4Número de bytes en 1 segundosampleRate numChannels bitsPerSample (en adelante)
blockAlign2Número de bytes para 1 muestranumChannels * bitsPerSample: 8
bitsPerSample2El número de bits por 1 muestra (profundidad)Cualquier número que sea múltiplo de 8. Cuanto más grande, mejor y más difícil será el audio, a partir de 32 bits no hay diferencia para una persona
subchunk2Id4 4La marca de referencia del comienzo de los datos (ya que puede haber otros elementos de encabezado dependiendo del formato de audio)0x64617461 en Big-Endian ("datos")
subchunk2Size4 4Tamaño del área de datostamaño de los datos en int
datosbyteRate * duración de audioDatos de audio?

Ejemplo de WAVE


La tabla anterior se puede traducir fácilmente a una estructura C, pero hoy nuestro lenguaje es Python. Lo más fácil de hacer con la onda es un generador de ruido. Para esta tarea, no necesitamos un alto byteRate y compresión.
Para comenzar, importamos los módulos necesarios:


# WAV.py from struct import pack #  py-     C from os import urandom #    /dev/urandom,  windows: # from random import randint # urandom = lambda sz: bytes([randint(0, 255) for _ in range(sz)]) #   windows, .. urandom'    from sys import argv, exit #      if len(argv) != 3: # +1   (-1,   ) print('Usage: python3 WAV.py [num of samples] [output]') exit(1) 

Luego, necesitamos crear todas las variables necesarias de la tabla de acuerdo con sus tamaños. Los valores variables en él dependen aquí solo de numSamples (el número de muestras). Cuanto más haya, más tiempo durará nuestro ruido.


 numSamples = int(argv[1]) output_path = argv[2] chunkId = b'RIFF' Format = b'WAVE' subchunk1ID = b'fmt ' subchunk1Size = b'\x10\x00\x00\x00' # 0d16 audioFormat = b'\x01\x00' numChannels = b'\x02\x00' # 2-    () sampleRate = pack('<L', 1000) # 1000 ,    ,     .  1000-  ,   bitsPerSample = b'\x20\x00' # 0d32 byteRate = pack('<L', 1000 * 2 * 4) # sampleRate * numChannels * bitsPerSample / 8 (32 bit sound) blockAlign = b'\x08\x00' # numChannels * BPS / 8 subchunk2ID = b'data' subchunk2Size = pack('<L', numSamples * 2 * 4) # * numChannels * BPS / 8 chunkSize = pack('<L', 36 + numSamples * 2 * 4) # 36 + subchunk2Size data = urandom(1000 * 2 * 4 * numSamples) #   

Solo queda escribirlos en la secuencia necesaria (como en la tabla):


 with open(output_path, 'wb') as fh: fh.write(chunkId + chunkSize + Format + subchunk1ID + subchunk1Size + audioFormat + numChannels + sampleRate + byteRate + blockAlign + bitsPerSample + subchunk2ID + subchunk2Size + data) #  

Y así, hecho. Para usar el script, necesitamos agregar los argumentos de línea de comando necesarios:
python3 WAV.py [num of samples] [output]
cantidad de muestras - cuenta muestras
salida - ruta al archivo de salida


Aquí hay un enlace a un archivo de audio de prueba con ruido, pero para ahorrar memoria, bajé BPS a 1b / sy bajé el número de canales a 1 (con una transmisión de audio estéreo sin comprimir de 32 bits a 64kbs obtuvimos 80M de un archivo .wav limpio, y solo 10): https: / /instaud.io/3Dcy


El código completo (WAV.py) (el código tiene muchos valores duplicados de variables, esto es solo un boceto):


 from struct import pack #  py-     C from os import urandom #    /dev/urandom,  windows: # from random import randint # urandom = lambda sz: bytes([randint(0, 255) for _ in range(sz)]) #   windows, .. urandom'    from sys import argv, exit #      if len(argv) != 3: # +1   (-1,   ) print('Usage: python3 WAV.py [num of samples] [output]') exit(1) numSamples = int(argv[1]) output_path = argv[2] chunkId = b'RIFF' Format = b'WAVE' subchunk1ID = b'fmt ' subchunk1Size = b'\x10\x00\x00\x00' # 0d16 audioFormat = b'\x01\x00' numChannels = b'\x02\x00' # 2-    () sampleRate = pack('<L', 1000) # 1000 ,    . bitsPerSample = b'\x20\x00' # 0d32 byteRate = pack('<L', 1000 * 2 * 4) # sampleRate * numChannels * bitsPerSample / 8 (32 bit sound) blockAlign = b'\x08\x00' # numChannels * BPS / 8 subchunk2ID = b'data' subchunk2Size = pack('<L', numSamples * 2 * 4) # * numChannels * BPS / 8 chunkSize = pack('<L', 36 + numSamples * 2 * 4) # 36 + subchunk2Size data = urandom(1000 * 2 * 4 * numSamples) #   with open(output_path, 'wb') as fh: fh.write(chunkId + chunkSize + Format + subchunk1ID + subchunk1Size + audioFormat + numChannels + sampleRate + byteRate + blockAlign + bitsPerSample + subchunk2ID + subchunk2Size + data) #     

Resumen


Entonces aprendiste un poco más sobre el sonido digital y cómo se almacena. En esta publicación no utilizamos la compresión (audioFormat), pero para revisar cada uno de los artículos populares necesitará los artículos 10. Espero que haya aprendido algo nuevo para usted y esto lo ayudará en futuros desarrollos.
Gracias


Fuentes

Estructura de archivos WAV
WAV - Wikipedia

Source: https://habr.com/ru/post/450774/


All Articles