Uso de un códec de video sin pérdidas para archivar datos de video científicos (monocromáticos)

9

Pregunta básica: ¿cuál es un códec adecuado para almacenar / archivar datos de video científicos sin pérdidas ?

Estoy tratando de ayudar a mi grupo de investigación a almacenar / archivar algunos videos grabados con un microscopio. Estos videos (en escala de grises) están en formato BGR24 sin comprimir (rawvideo), 660x492 a 61 fps, y generalmente de aproximadamente 1 minuto de duración. Mis compañeros de laboratorio se están volviendo locos con el gran tamaño de estos archivos (gigabytes cada uno). Sugerí comprimirlos usando un códec sin pérdidas. (La necesidad de pérdida sin pérdida aquí se debe a que los videos son datos científicos; por lo tanto, existe cierto peligro de que un códec con pérdida pueda alterar el contenido de manera incorrecta / inesperada).

Esto es lo que probé. Primero, tomé los primeros 10 segundos de uno de estos videos y los convertí a un formato monocromo (sin formato) usando FFMpeg.

ffmpeg -t 10 -i RecordedData.avi -c:v rawvideo -pix_fmt gray raw_gray.mkv

Luego, intenté usar el modo sin pérdida de libx264 (configurando -crf 0) para comprimir el archivo resultante

ffmpeg -i raw-gray.mkv -c:v libx264 -crf 0 -pix_fmt yuv420p -color_range pc x264-yuv420p.mkv

Finalmente, extraje los datos YUV sin procesar de los archivos MKV sin procesar y h264 y los comparé.

ffmpeg -i raw-gray.mkv -c:v rawvideo -pix_fmt gray raw-gray.yuv
ffmpeg -i x264-yuv420p.mkv -c:v rawvideo -pix_fmt gray x264-decompressed.yuv
diff -sq raw-gray.yuv x264-decompressed.yuv

Aquí, el diffcomando informa que los archivos difieren cuando esperaba que fueran iguales. ¿Por qué es esto? ¿Es esto solo un pequeño error de redondeo, o posiblemente estoy perdiendo algo después de hacer la compresión H264 (supuestamente sin pérdida)? Se está produciendo alguna conversión de formatos de píxeles ( gray (YUV400) <-> YUV420), pero los canales de color (UV) deberían estar vacíos porque la entrada es monocroma.

Si realmente estoy perdiendo algo, ¿hay algo que pueda hacer para arreglar esto? ¿Existe otro códec (sin pérdida) que podría ser más apropiado para mis datos?


Actualización 1 : utilicé hexdump para comparar el contenido de los datos YUV sin comprimir de raw-gray.yuv(nunca comprimido) y x264-decompressed.yuv(comprimido y luego descomprimido) con más detalle. Aquí están los primeros bytes.

[raw-gray.yuv]

00000000  4e 50 51 53 53 52 51 50  51 51 50 4f 50 50 50 50
00000010  51 51 50 51 52 53 51 51  52 52 53 53 52 51 51 53
00000020  51 53 54 55 53 51 52 54  53 53 52 50 51 50 52 52
00000030  51 52 51 51 51 52 54 52  52 52 51 51 51 53 57 58
00000040  57 57 55 54 54 52 53 51  51 52 53 55 55 54 53 53
00000050  51 51 52 52 53 52 51 50  50 50 50 51 51 4f 4f 4e
00000060  4c 4d 4e 4d 4f 50 4f 50  51 51 51 52 52 52 52 50
00000070  50 50 52 52 53 55 55 55  57 52 53 53 53 54 56 56

[x264-decompressed.yuv]

00000000  53 55 56 57 57 56 56 55  56 56 55 54 55 55 55 55
00000010  56 56 55 56 56 57 56 56  56 56 57 57 56 56 56 57
00000020  56 57 58 59 57 56 56 58  57 57 56 55 56 55 56 56
00000030  56 56 56 56 56 56 58 56  56 56 56 56 56 57 5b 5c
00000040  5b 5b 59 58 58 56 57 56  56 56 57 59 59 58 57 57
00000050  56 56 56 56 57 56 56 55  55 55 55 56 56 54 54 53
00000060  51 52 53 52 54 55 54 55  56 56 56 56 56 56 56 55
00000070  55 55 56 56 57 59 59 59  5b 56 57 57 57 58 5a 5a

Los valores del archivo anterior son de 4 a 5 menos que los valores del último. Lo mismo se encuentra cavando un poco más en el archivo.


Actualización 2 : si uso libx264 en modo RGB, puedo obtener una coincidencia exacta con el original haciendo lo mismo que antes además de lo siguiente.

ffmpeg -i raw-gray.mkv -c:v libx264rgb -crf 0 -pix_fmt bgr24 x264-bgr24.mkv
ffmpeg -i x264-bgr24.mkv -c:v rawvideo -pix_fmt gray x264-bgr24-decomp.yuv
diff -sq raw-gray.yuv x264-bgr24-decomp.yuv

El último comando informa que los dos archivos son idénticos . Desafortunadamente, x264-bgr24.mkves aproximadamente 3 veces mayor que x264-yuv420.mkv, por lo que la compresión en modo RGB no es tan buena.

Leí en alguna parte que libx264 comprime eficientemente el video en escala de grises en modo YUV porque se da cuenta del hecho de que solo el canal Y contiene información real (los canales U y V son cero para video monocromo). En el modo RGB, creo que todos los canales contendrían información idéntica para la entrada monocromática. Quizás libx264rgb no se aprovecha de eso.

Entonces, ¿hay alguna manera de usar el modo YUV sin alterar el video, ya que la compresión es mucho más eficiente de esta manera?


Actualización 3 : pude resolver el problema con libx264 usando en -pix_fmt yuvj420plugar de -pix_fmt yuv420p -color_range pc. Luego, reproduzco el archivo original exactamente después de la compresión / descompresión. De la documentación de FFmpeg, tuve la impresión de que estos dos conjuntos de banderas eran equivalentes, pero evidentemente este no es el caso. El único problema es que recibo una advertencia con este último conjunto de indicadores: [swscaler @ 0x55b56347fe20] deprecated pixel format used, make sure you set the range correctly. Además, encontré este informe de error que podría estar relacionado con mi problema. No estoy seguro de la forma "adecuada" de hacer las cosas sin usar el formato de píxel yuvj420p aparentemente obsoleto.

Nick C.
fuente
1
Dado que los datos se descomprimen, sería mejor transformarlos a ambos a un formato de texto (por ejemplo, usar hexdump) y ejecutar el diff en eso. diffsimplemente dirá que los archivos están en algún lugar diferente. Un bit, un megabyte, todo es lo mismo. Al inspeccionar la diferencia hexadecimal, puede estimar mejor lo que sucedió y si hay algo de qué preocuparse. También verifique que la operación no redondea el ancho o la altura del video (eso me sucedió a mí).
LSerni
1
Una posible fuente de interrupción podría ser una sujeción del canal Y diferente (según CCIR-601). Compruebe si por casualidad parece perder los valores Y por debajo de 16 y por encima de 240. Vea también video.stackexchange.com/questions/16840/…
LSerni el
1
También puede usar ffmpeg para volver a descomponer sus dos videos en imágenes individuales y usar imagemagick'scompare para compararlos.
xenoid
1
Una buena manera de comparar la pérdida sin pérdida es usar el hash muxer. Mostrar la salida completa de ffmpeg -i RecordedData.avi. libx264rgb admite bgr24, por lo que puede considerar ese codificador como una opción.
llogan
1
Simplemente codifíquelos sin pérdidas utilizando el modo RGB de x264 (omita la conversión de formato de píxeles).
Gyan

Respuestas:

6

Esta no es una respuesta directa a su problema real, pero consideraría usar el FFV1códec interno FFmpeg :

$ ffmpeg -i raw-gray.mkv -c:v ffv1 ffv1.mkv

Alternativamente, la versión 3 de la misma:

$ ffmpeg -i raw-gray.mkv -c:v ffv1 -level 3 ffv1.mkv

Entonces:

$ ffmpeg -i ffv1.mkv -c:v rawvideo -pix_fmt gray raw-gray.yuv
$ diff -sq raw-ffv1.yuv raw-gray.yuv
Files raw-ffv1.yuv and raw-gray.yuv are identical

No es tan eficiente como libx264 en modo sin pérdida cuando se usa yuv420p, pero es más eficiente que usar libx264 con bgr24(en mis pruebas, la velocidad de datos estaba en algún punto intermedio). Algunas instituciones como la Biblioteca del Congreso también reconocen FFV1 como un formato de preservación adecuado .

slhck
fuente
Sin embargo, esta es una respuesta a mi pregunta básica original, que he editado para aclarar más. No encontré ningún problema con FFV1. De hecho, FFV1 logró aproximadamente la misma relación de compresión que libx264 (w / -crf 0 -preset medium) para mi video en particular, y fue más rápido. Aún mejor, es compatible directamente con el grayformato de píxeles. De hecho, esto parece ser una excelente solución.
Nick C.