Pérdida o sin pérdida?

18

Dado un archivo de audio, determine si está codificado en un formato con pérdida o sin pérdida. Para los propósitos de este desafío, solo se deben clasificar los siguientes formatos:

Reglas

  • Si la entrada se toma en forma de un nombre de archivo, no se deben hacer suposiciones sobre el nombre de archivo (por ejemplo, no se garantiza que la extensión sea correcta para el formato, ni siquiera presente).
  • No habrá metadatos ID3 o APEv2 presentes en los archivos de entrada.
  • Se pueden utilizar dos salidas únicas y distinguibles, como 0y 1, lossyy lossless, fooy bar, etc.

Casos de prueba

Los casos de prueba para este desafío consisten en un archivo zip ubicado aquí que contiene dos directorios: lossyy lossless. Cada directorio contiene varios archivos de audio que son todas ondas sinusoidales de 440 Hz de 0,5 segundos, codificadas en varios formatos. Todos los archivos de audio tienen extensiones que coinciden con los formatos anteriores, con la excepción de A440.m4a(que es audio AAC en un contenedor MPEG Layer 4).

Mego
fuente
El " audio AAC en un contenedor MPEG Layer 4 " plantea la pregunta: ¿qué otros formatos de contenedor deben manejar las respuestas?
Peter Taylor
@PeterTaylor Solo AAC recibió una mención especial porque no pude encontrar una manera de proporcionar audio AAC sin incrustarlo en un contenedor MPEG Layer 4 a través de FFMPEG. El audio Vorbis está incrustado en un contenedor Ogg (como es la norma para el audio Vorbis). Todos los demás son formatos independientes.
Mego
¿Estás seguro del archivo TTA? Según las especificaciones , los archivos TTA deben comenzar con el número mágico TTA1 o TTA2. FFM2 (el número mágico de su archivo) parece corresponder a la secuencia de FFmpeg. El archivo Linux reconoce el encabezado TTA1, pero no el FFM2.
Dennis
Además, ¿podemos suponer que AAC siempre estará en un encabezado MPEG Layer 4? Si no, ¿qué podemos suponemos?
Dennis
¿Podemos tomar el contenido del archivo como entrada o nuestro código tiene que recuperarlos?
Shaggy

Respuestas:

18

Jalea , 7 5 bytes

ƈƈeØA

Los formatos con pérdida devuelven 0 , los formatos sin pérdida devuelven 1 .

Pruébalo en línea! (enlaces permanentes en Gist)

Antecedentes

Los formatos que tenemos que admitir tienen los siguientes números mágicos, es decir, comienzan con estos bytes.

Format    Header (text)       Header (hex)
-----------------------------------------------------------------------------------
AC3       .w                  0B 77
AMR       #!AMR               23 21 41 4D 52
AAC       ÿñP@..ü             FF F1 50 40 00 1F FC
  M4A     ... ftypM4A         00 00 00 20 66 74 79 70 4D 34 41 20
MP2       ÿû                  FF FB
MP3       ÿû                  FF FB
OGG       OggS                4F 67 67 53
WMA       0&²u.fÏ.¦Ù.ª.bÎl    30 26 B2 75 8E 66 CF 11 A6 D9 00 AA 00 62 CE 6C

AIFF      FORM????AIFF        46 4F 52 4D ?? ?? ?? ?? 41 49 46 46
FLAC      fLaC                66 4C 61 43
TTA       TTA1                54 54 41 31
  FFM2    FFM2                46 46 4D 32
WAV       RIFF????WAVE        52 49 46 46 ?? ?? ?? ?? 57 41 56 45

Las entradas sangradas son contenedores para el formato anterior que aparecen en los casos de prueba. ?denota un byte variable. .denota un byte no imprimible. Todos los demás bytes se muestran como su carácter ISO 8859-1.

Al observar solo el segundo byte, podemos determinar el formato de una manera fácil:

Los formatos sin pérdida tienen una letra mayúscula como segundo byte, mientras que los formatos con pérdida no.

Cómo funciona

ƈƈeØA  Main link. No arguments.

ƈ      Read a char from STDIN and set the left argument to this character.
 ƈ     Read another char from STDIN and set the return value to this character.
   ØA  Yield the uppercase alphabet, i.e., "ABCDEFGHIJKLMNOPQRSTUVWXYZ".
  e    Exists; return 1 if the return value (second char on STDIN) belongs to the
       uppercase alphabet, 0 if not.
Dennis
fuente
2
Esta es una solución muy inteligente.
Mego
10

C, 82 80 32 bytes

Inspirado por la respuesta de @Dennis , esto se puede reducir mucho más:

main(){return getchar()&200^64;}

Canalice los datos del archivo a stdin. Devuelve 0 para sin pérdida, o distinto de cero para con pérdida.

O el cheque original más largo:

char v[5];main(){scanf("%4c",v);return*v&&strstr("fLaC FORM RIFF TTA1 FFM2",v);}

Canalice los datos del archivo a stdin. Devuelve distinto de cero (1) para sin pérdida, o 0 para con pérdida.

Por lo que puedo decir, todos los formatos que enumeró tienen números mágicos separados (excepto AIFF / WAV, pero ambos son sin pérdida de todos modos), por lo que esto solo verifica ese número mágico para un valor sin pérdida conocido. Esto *v&&es solo para proteger contra archivos coincidentes que comienzan con un byte nulo (M4A).

He incluido los valores que encontré en las hojas de especificaciones ( fLaC= FLAC, RIFF= WAV / AIFF, TTA1= TTA), y FORM= AIFF y FFM2= TTA son de los archivos de muestra proporcionados (solo puedo adivinar que estos son formatos de envoltura o versiones posteriores).


O una alternativa más corta para hacer trampa:

Bash + archivo, 61 bytes

N="$(file "$1")";[[ $N = *": d"* || $N = *IF* || $N = *FL* ]]

Toma el nombre de archivo como argumento. Devuelve 0 para sin pérdida, o distinto de cero para con pérdida.

Hace exactamente lo que esperarías; pregunta filecuál es el tipo de archivo, luego busca patrones conocidos. TTA coincide : d( : data), coincide con AIFF / WAV IFy coincide con FLAC FL. Ninguno de los resultados sin pérdida coincide con ninguno de estos, y he probado que aún funciona si se eliminan los nombres de archivo.


Pruebas:

for f in "$@"; do
    echo "Checking $f:";
    ./identify2 "$f" && echo "shorter C says LOSSLESS" || echo "shorter C says LOSSY";
    ./identify < "$f" && echo "longer C says LOSSY" || echo "longer C says LOSSLESS";
    ./identify.sh "$f" && echo "file says LOSSLESS" || echo "file says LOSSY";
done;

# This can be invoked to test all files at once with:
./identify_all.sh */*
Dave
fuente
¿Su solución Bash también funciona si la extensión del archivo es incorrecta? "no se garantiza que la extensión sea correcta para el formato", por lo que debería poder darle a un archivo una extensión incorrecta y aún así hacerlo funcionar.
mbomb007
@ mbomb007 Acabo de probar con las extensiones mezcladas y todavía las identifica bien. Creo fileque no confía en las extensiones de todos modos (¡muchos usuarios consideran que cambiar el nombre de un png a jpeg es lo mismo que convertirlo!)
Dave
7

GS2 , 3 bytes

◄5ì

Los formatos con pérdida devuelven 0 , los formatos sin pérdida devuelven 1 .

Pruébalo en línea! (enlaces permanentes en Gist)

Antecedentes

Los formatos que tenemos que admitir tienen los siguientes números mágicos, es decir, comienzan con estos bytes.

Format    Header (text)       Header (hex)
-----------------------------------------------------------------------------------
AC3       .w                  0B 77
AMR       #!AMR               23 21 41 4D 52
AAC       ÿñP@..ü             FF F1 50 40 00 1F FC
  M4A     ... ftypM4A         00 00 00 20 66 74 79 70 4D 34 41 20
MP2       ÿû                  FF FB
MP3       ÿû                  FF FB
OGG       OggS                4F 67 67 53
WMA       0&²u.fÏ.¦Ù.ª.bÎl    30 26 B2 75 8E 66 CF 11 A6 D9 00 AA 00 62 CE 6C

AIFF      FORM????AIFF        46 4F 52 4D ?? ?? ?? ?? 41 49 46 46
FLAC      fLaC                66 4C 61 43
TTA       TTA1                54 54 41 31
  FFM2    FFM2                46 46 4D 32
WAV       RIFF????WAVE        52 49 46 46 ?? ?? ?? ?? 57 41 56 45

Las entradas sangradas son contenedores para el formato anterior que aparecen en los casos de prueba. ?denota un byte variable. .denota un byte no imprimible. Todos los demás bytes se muestran como su carácter ISO 8859-1.

Al observar solo el segundo byte, podemos determinar el formato de una manera fácil:

Los formatos sin pérdida tienen una letra mayúscula como segundo byte, mientras que los formatos con pérdida no.

Cómo funciona

     (implcit) Push the entire input from STDIN as a string on the stack.
◄    Push 1.
 5   Get the strings character at index 1, i.e., its second character.
  ì  Test if the character is an uppercase letter.
Dennis
fuente
2

JavaScript (ES6), 20 bytes

c=>/^[fFRT]/.test(c)

Explicación

Toma el contenido del archivo como entrada y devuelve truesi el archivo es sin pérdidas, o falsesi se trata de pérdidas probando el primer carácter de esa entrada para ver si se trata de un f, F, Ro T.


Intentalo

Pegue el contenido de un archivo en el textarea.

f=
c=>/^[fFRT]/.test(c)
i.addEventListener("input",_=>console.log(f(i.value)))
<textarea id=i></textarea>


Segundo esfuerzo, 81 63 bytes

Obtiene el contenido de un archivo de una URL proporcionada, que resultó ser exagerado.

u=>fetch(u).then(r=>r.text()).then(t=>alert(/^[fFRT]/.test(t)))

En primer esfuerzo, 146 116 89 bytes

No es válido ya que los tipos mime están vinculados a extensiones y, aparentemente, los encabezados de respuesta califican como entrada adicional.

u=>fetch(u).then(r=>alert(/aiff|flac|tta|wave|wav$/.test(r.headers.get("Content-Type"))))
Lanudo
fuente
Los servidores web generalmente generan el MIME en función de la extensión del archivo, lo que va en contra de las reglas aquí. ¿Ha verificado si funciona en los archivos que se sirven sin una extensión? (si lo hace, entonces probablemente debería incluir el nombre del servidor que está utilizando como parte del "idioma")
Dave
1
@Dave Estoy seguro de que no. MIME y la extensión no dependen entre sí en absoluto. Si cambia la extensión de un archivo y lo carga, el tipo MIME es el MIME del contenido real del archivo, no la extensión. Sin embargo, tal como están las cosas, probablemente no esté permitido ingresar datos como URL. No estoy seguro.
mbomb007
@ mbomb007 No estoy seguro de por qué dices eso; los tipos mime son una cosa de Internet, no una cosa de sistema de archivos / archivo, y los servidores que conozco lo determinarán en función de la extensión usando una búsqueda configurada (para la velocidad de publicación de encabezados; no quieren inspeccionar cada archivo antes de servir eso). Tomemos, por ejemplo, Apache AddType <mime> <extension>o IIS <MimeMap>. Por supuesto, una configuración específica o una herramienta de alojamiento de archivos podría hacer una inspección adecuada, y eso merecería hacer que la elección del servidor sea parte de la respuesta (¡ya que es el servidor el que determina el tipo de archivo!)
Dave
1
He realizado la validación de archivos con .NET, y el tipo MIME coincidía con el contenido incluso cuando se cambió la extensión antes de cargarla.
mbomb007
@ mbomb007, cualquiera que sea el componente .NET que haya utilizado debe haber realizado una inspección de archivos durante la carga o al entregar los archivos (supongo que durante la carga para el rendimiento, pero nunca se sabe). Volviendo a mi comentario original, eso haría que esta respuesta sea algo así como "JavaScript + .NET SeverLibraryXYZ". En cuanto a la entrada de una URL, puedo ver por qué dudas, pero personalmente lo consideraría válido siempre que se mencione la opción del servidor. Tal vez hay un meta existente, pero finalmente, por supuesto, depende de Mego.
Dave
1

Chip , 11 bytes

~Z~S
t'G~aF

Replicó descaradamente la respuesta de Dennis 'Jelly en Chip.

Devoluciones sin 0x0pérdidas, devoluciones con pérdidas 0x1.

Pruébelo en línea , enlaces en esencia (gracias Dennis por la estrategia TIO aquí)

¡Explique!

~Z~S
t'

Esta porción es limpieza: Selimina el primer byte y termina después del segundo.

G~aF

Esta es la carne de la decisión. A cada byte de entrada se accede por los bits HGFEDCBA. Si Gestá establecido, y Fno lo está, eso significa que el byte está dentro del rango 0x40de 0x5f(que es más o menos equivalente a 'mayúscula' y lo suficientemente bueno para la tarea en cuestión).

Sin embargo, para el ahorro de bytes, invierto esta decisión de G and (not F)a (not G) or F, ya que o puede estar implícito en Chip.

Este valor verdadero / falso resultante se coloca en a, que es el bit más bajo de la salida. (Todos los demás bits serán cero). En el TIO, ejecuto la salida a través de hexdump para que los valores sean visibles.

De manera equivalente, en C-ish, uno diría algo como:

out_byte = !(in_byte & 0x40) && (in_byte & 0x20)
Phlarx
fuente
1

Cubix, 16 bytes

$-!u'HIa'@/1@O<

Forma neta:

    $ -
    ! u
' H I a ' @ / 1
@ O < . . . . .
    . .
    . .

Inténtalo tú mismo

Debe ingresar los valores de bytes decimales del archivo en una lista separada. El separador no importa, cualquier cosa que no sea un dígito o un signo menos es suficiente. El código realmente solo se preocupa por el primer byte, por lo que puede omitir el resto del archivo si lo desea. El programa genera salidas 0sin pérdidas y 1con pérdidas. Pruébalo aquí ! La entrada predeterminada usa un encabezado FLAC.

Explicación

Lo bueno de los archivos es que (casi) todos ellos tienen la llamada magia. Esos son los primeros bytes del archivo. Un buen software no verifica la extensión del archivo, sino la magia del archivo para ver si puede manejar un determinado archivo.

Dennis ha encontrado una manera de usar esta magia para encontrar el tipo de compresión, pero el hecho de que descartó el primer byte me hizo querer intentar encontrar un método que usara el primer byte, en lugar del segundo. Después de todo, esta comunidad se trata de guardar bytes.

Aquí hay una lista de los primeros bytes de los diferentes tipos de archivos. Los ordené en dos grupos: con pérdida y sin pérdida. Aquí están los valores de su primer byte en decimal, hexadecimal y binario. Es posible que ya veas un patrón ...

Lossy:                  Lossless:
255:0xFF:0b11111111     102:0x66:0b01100110
 79:0x4F:0b01001111      84:0x54:0b01010100
 35:0x23:0b00100011      82:0x52:0b01010010
 11:0x0B:0b00001011      70:0x46:0b01000110
  0:0x00:0b00000000

El patrón que vi fue que el segundo bit (contado de izquierda a derecha) siempre estaba activado en los bytes "sin pérdidas" y el quinto bit siempre estaba desactivado. Esta combinación no aparece en ninguno de los formatos con pérdida. Para "extraer" esto, simplemente haríamos un AND binario (by 0b01001000 (=72)) y luego lo compararíamos con 0b01000000 (=64). Si ambos son iguales, el formato de entrada no tiene pérdida, de lo contrario es con pérdida.

Lamentablemente, Cubix no tiene ese operador de comparación, por lo que utilicé la resta (si el resultado es 64, esto produce 0, y de lo contrario resulta en 8, -56 o -64. Volveré a esto más adelante.

Primero, comencemos al comienzo del programa. El AND binario se realiza utilizando el acomando:

'HIa
'H   # Push 0b01001000 (72)
  I  # Push input
   a # Push input&72

Luego, comparamos con 64 usando la resta (tenga en cuenta que golpeamos un espejo que refleja la IP en la cara superior [primera línea, segundo carácter, apuntando al sur] en el medio de esta parte).

'@-
'@  # Push 0b01000000 (64)
  - # Subtract from (input&72)
    # Yields 0 for lossy, non-zero otherwise

Después de que el IP cambia u, usamos un poco de flujo de control para empujar a 1a la pila si (y solo si) la parte superior de la pila no es cero:

!$1
!   # if top = 0:
 $1 #   do nothing
    # else:
  1 #   push 1

Después de envolver el cubo, tocamos la <instrucción, que apunta la IP hacia el oeste en la cuarta línea. Todo lo que queda por hacer es generar y finalizar.

O@
O  # Output top of the stack as number
 @ # End program

Por lo tanto, el programa genera 0pérdidas y 1pérdidas.

Luke
fuente