Vamos a programar #102 - Leyendo metadatos de archivos FLAC (pt.1)

 Hola de nuevo a todos. El día de hoy vamos a continuar con más de los archivos FLAC.


En los post mas recientes hemos visto las cualidades de los archivos FLAC, pero además cómo crear los nuestros. Al igual que en MP3, existen metadatos embebidos en ellos, y sirven para describir algunos datos importantes tales cómo: el nombre de la canción, el artista, el nombre del álbum, el genero, etc.


Estructura de un archivo FLAC

La estructura de los archivos FLAC es totalmente diferente a la de un MP3 por lo que vale la pena revisarla por separado. Cada archivo FLAC consiste de cuatro partes principales:

  • Una cadena de cuatro bytes con la secuencia "fLaC" (así tal cual se ve).
  • Un bloque de metadatos con la información del "stream"
  • Cero o mas bloques de metadatos.
  • Uno o mas "frames" de audio.

Para mas detalles se puede revisar la página de xiph.org, donde esta la descripción completa para los archivos FLAC.

De las cuatro partes que se mencionan anteriormente, nos concentraremos en la segunda y tercera (Técnicamente las dos entran en el mismo conjunto, solo que la segunda es obligatoria, mientras que las subsecuentes son opcionales, hablando solamente de los bloques de metadatos), por lo que revisaremos cómo es que está compuesta cada una.

Pero antes una representación de cómo está estructurado el archivo:


Si observamos bien la imagen, veremos que hay dos partes centrales: "STREAM" y "FRAME", por ahora revisaremos la parte de "STREAM" que contiene los datos que nos interesan. 

Metadatos

A partir de ahora nos referiremos a cada parte cómo "bloque". Del lado de METADATA, cada bloque estará constituido por un encabezado (HEADER) y el bloque de datos en si, el encabezado se encarga de describir cómo es que cada parte esta formada. Para poder leer cada bloque, deberemos de seguir los datos de este. Salvo que se indique lo contrario, cada valor N representará un solo bit (OJO: bit, no byte al menos que se indique lo contrario), al igual que en la documentación (que recomiendo encarecidamente leer dos veces), usaremos un número entre los corchetes cuadrados "<" y ">" El valor que se encuentre en medio dirá cuantos bits conforman esa parte. Habiendo aclarado lo anterior, veamos cómo se forma el encabezado de cada bloque:
  • STREAM
  • METADATA_BLOCK
  • METADATA_BLOCK_HEADER (Encabezado)
    • <1>   Indicador de último bloque
    • <7>   Descriptor del tipo de bloque
    • <24> Tamaño del bloque en bytes (BYTES!!!)
Para el indicador del último bloque se usa un solo bit, si es 0 indica que hay mas bloques a continuación, pero si es 1, indica que el bloque es el último y empiezan los "FRAMES" por lo que si solo estamos leyendo los metadatos, deberíamos de dejar de buscar.

La secuencia de los siguientes 7 bits, indican que tipo de bloque es el que sigue a continuación, para ello hay una serie ya predefinida y dependiendo del valor que este nos diga, el bloque del tipo será. Actualmente solo hay siete tipos de bloque ya predefinidos y son los que siguen:
  • 0: STREAMINFO
    • Contiene información acerca de todo el archivo, este bloque es mandatorio y siempre será e primero de la secuencia después de la secuencia 0x66, 0x4c, 0x61, 0x43 (o de manera simple después de  "fLaC" ).
  • 1: PADDING
    • Este tipo de bloque sirve cómo reserva y el contenido no representará nada, normalmente se llena con 0x00. Cuando se crea el archivo sin los metadatos completos, en lugar des escribir un archivo nuevo con los bloques nuevos, simplemente se reemplaza este bloque conservando el archivo original y agilizando la escritura del mismo.
  • 2: APPLICATION
    • Nombre de la aplicación que se uso para codificar el archivo, puede ser cualquiera que el usuario elija, aunque se recomienda el registro de la aplicación para obtener un ID único para cada quien.
  • 3: SEEKTABLE
    • Sirve cómo marcador para desplazarse en el archivo a la hora de la reproducción, aunque se puede omitir, se recomienda incluirlo para agilizar la lectura.
  • 4: VORBIS_COMMENT
    • Este bloque contiene la información relevante a los creadores del contenido multimedia y la descripción del mismo, se usa la especificación de "Vorbis comment"
  • 5: CUESHEET
    • Contiene información que se puede usar en un CD
  • 6: PICTURE
    • Imagen representativa del archivo, similar a la imagen embebida en un archivo MP3.
  • 7-126: Reservado
    • Reservado por ahora, por lo que se podría decir que si un bloque tiene descriptor en este rango, no es valido. Se planea su uso futuro.
  • 127: No válido
    • Bloque no valido, ya que la misma secuencia se usa cómo marcador para sincronización.
Por lo que por ahora solo nos serian relevantes los bloques con descriptores: 0, 4, 6, 7-126 y 127. Especialmente el que tenga descriptor 0, porque es mandatorio; 4, porque seria el equivalente a los TAGS en mp3; y 6, porque es la imagen del álbum (por lo general). Sabiendo los tipos de bloques que vamos a leer, vamos a concéntranos solo en ellos, por lo que primero revisaremos cómo es que está armado el bloque "STREAMINFO".

Bloque "STREAMINFO"

El bloque STREAMINFO, consta de la siguiente secuencia:
  • <16> Tamaño mínimo del bloque.
  • <16> Tamaño máximo del bloque.
  • <24> Tamaño mínimo del "FRAME" en bytes.
  • <24> Tamaño máximo del "FRAME" en bytes.
  • <20> Frecuencia de sampleo.
  • <3> Número de canales.
  • <36> Total de muestras por segundo.
  • <128> MD5 del audio.
Ya que cada una de las secciones tiene un tamaño ya predefinido, podemos asegurar que toda la secuencia siempre tendrá el mismo tamaño y cómo no es necesario que sepamos el contenido de esta, bastará con desplazarnos al siguiente bloque. Antes de continuar, haremos el calculo a mano de la posición en la que empieza y en la que acaba, para eso usaremos XVI32 para ver el contenido de forma hexadecimal, y el archivo de muestra será el que usamos para comparar en el post de "FLAC vs WAV"

Si leemos las cosas en orden, debemos de empezar por buscar la secuencia "fLaC" que serán los primeros 4 bytes.

Ahora que sabemos que el primer bloque debe de ser el bloque STREAMINFO, nos vamos a concentrar en eso, si hacemos memoria, lo primero que debemos de buscar de cada bloque, es su encabezado que serán 32 bits (4 bytes) por lo que inmediatamente después de la secuencia "fLaC" los siguientes bytes corresponden al encabezado de nuestro bloque.

En este caso, el encabezado está representado por la secuencia hexadecimal: 0x00, 0x00, 0x00 y 0x22. ¿Pero cómo la interpretamos? simple, la referencia dice que el primer bit es el indicador del último bloque, solo si es 1, para entender mejor, veamos el número en binario.

Cómo iremos leyendo "de byte en bytes", el mínimo de bits a leer es 8, pero sim problema podemos aislar el primer bit de cada byte y determinar si es o no el último bloque, en este caso, cómo encontramos un 0, indica que hay mas bloques después de este.

Los siguientes 7 bits indicaran el tipo de bloque y para el tipo de bloque debe de ser 0, antes veamos cómo son los números del uno al seis en binario (recuerda que en el blog tenemos DecToAny que sirve para convertir un número decimal a cualquier base hasta 25, puedes descargar la aplicación para Windows, android o usar la versión web).


Pero si no quieres molestarte en revisar, aquí la numeración binaria del cero al seis, que son los valores validos para esta parte de la secuencia.



Cuando leemos la información del bloque encontramos con 0x00 lo que es igual cero decimal o 0 en binario, lo que confirma que el bloque es el bloque STREAMINFO. Los restantes 24 bits indican cual es el tamaño del bloque. Al igual que los hicimos con el primer byte, los siguiente 3, se irán leyendo de uno por uno, pero juntos representan un solo número.

Toda la secuencia anterior representa 34

Si en XVI32 marcamos esos 34 bytes, tendríamos seleccionado todo el bloque.

Y bien, por ahora es todo. para no hacer muy extenso el post, terminaremos por hoy, sirve que da tiempo para leer toda la documentación del los archivos FLAC.
Si bien este post se podría tomar cómo una mala copia de la documentación, no lo es y estoy seguro que a mas de uno le será de ayuda, pero además así es nuestro estilo de trabajo, primero nos ensuciamos las manos descuartizando el archivo con el lector hexadecimal y luego hacemos código que hace lo mismo pero más rápido. Ahora y diferente al caso de ArtView, trataré de hacer versiones para los distintos lenguajes de programación.

Ya es diciembre por lo que publicaré un par de post antes de que acabe el año. Es cierto que la actividad del blog vino en picada, pero para todos aquellos que se quedaron o que regresaron, los post iran saliendo de manera regular.

Los leo luego.

No hay comentarios.