¿Cómo codificar sin pérdidas una secuencia de imágenes jpg en un video en ffmpeg?

Tengo un gran conjunto de archivos jpg que quiero convertir en un video sin pérdida (o, al menos, muy cerca de sin pérdida, siempre que el tiempo de codificación no sea mucho más alto).

Ingenuamente, pensaría que debería haber algún códec que pueda almacenar cada fotograma jpg individual tal cual (sin recompresión), y tal vez lograr una buena compresión reemplazando algunos de los fotogramas solo con la información en el delta del fotograma anterior. En mi caso hay muchas secuencias de fotogramas que son idénticos entre sí, o que tienen una pequeña diferencia entre ellos.

¿Hay algún códec y configuración adecuada para ffmpeg que pueda lograr esto?

Sequence-of-jpegs ha sido un códec durante MUCHO tiempo. Las cámaras digitales que no usan h.264 invariablemente graban MJPEG, y creo que las tarjetas de captura de video solían usarlo.

Respuestas (4)

Solo mux las imágenes

Simplemente puede mezclar las imágenes JPG para hacer un video:

ffmpeg -framerate 30 -i input%03d.jpg -codec copy output.mkv

Tenga en cuenta que si omite , se aplicará -framerateun valor predeterminado de a la entrada.-framerate 25

Optimización sin pérdidas

Puede usar jpegtranpara realizar una optimización sin pérdidas en cada cuadro, lo que puede proporcionar ahorros significativos en el tamaño del archivo:

mkdir outputdir
for f in *.jpg; do jpegtran -optimize -copy none -perfect -v "$f" > "outputdir/$f"; done

Ahora mux con ffmpegcomo se muestra arriba.

Comprobando que en realidad no tiene pérdidas

El framehash muxer se puede usar para comparar el hash único de cada cuadro para garantizar que el resultado sea realmente sin pérdidas:

$ ffmpeg -i input%03d.jpg -f framehash -
stream_index, packet_dts, packet_pts, packet_duration, packet_size, hash
0,          0,          0,        1,   460800, 29bcc2db3726c7dfec1826c5740f603f
0,          1,          1,        1,   460800, b5fdc23d93cbd043dc2b9290dc8378f0
0,          2,          2,        1,   460800, ee0709942f24b458fd2380d134dcb59d
...

$ ffmpeg -i output.mkv -map 0:v -f framehash -
stream_index, packet_dts, packet_pts, packet_duration, packet_size, hash
0,          0,          0,        1,   460800, 29bcc2db3726c7dfec1826c5740f603f
0,          1,          1,        1,   460800, b5fdc23d93cbd043dc2b9290dc8378f0
0,          2,          2,        1,   460800, ee0709942f24b458fd2380d134dcb59d
...

En los ejemplos anteriores, cada marco asociado para la entrada y la salida comparten el mismo hash, lo que garantiza que los marcos sean idénticos y que la salida no tenga pérdidas.

Ver también

¿Podría aclarar qué framemd5se supone que deben lograr los dos comandos más allá de simplemente enumerar los hash? ¿Cómo obtendría compresión adicional cuando se identifican fotogramas idénticos?
Los valores hash se incluyeron solo para mostrarle que los cuadros son los mismos que las imágenes individuales, por lo que cumple con su requisito de almacenar "cada cuadro jpg individual tal como está (sin recompresión)".
Publiqué una respuesta propia con una idea no probada para eliminar los cuadros duplicados, para terminar con un VFR MJPEG.mkv. VFR es la única forma que se me ocurre de aprovechar la redundancia temporal con MJPEG. :PAG
SSIM puede ser una forma más rápida de comparar la fidelidad.

Esto generará un video H.264 sin pérdidas donde los cuadros usarán información de otros cuadros

ffmpeg -f image2 -r 30 -i %09d.jpg -vcodec libx264 -profile:v high444 -refs 16 -crf 0 -preset ultrafast a.mp4

Explicación de opciones:

  • -f image2- le dice a ffmpeg que seleccione un grupo de imágenes
  • -r 30- le dice a ffmpeg que codifique a 30 fotogramas (o imágenes) por segundo (cámbielo a la velocidad de fotogramas deseada)
  • -i %09d.jpg- le dice a ffmpeg que use las imágenes 000000000.jpg a 999999999.jpg como entrada. Cambie la cantidad 9de %09d.jpgceros que tienen los nombres de su secuencia de imágenes. Si los nombres de sus archivos son, por ejemplo, img0001.jpg, esto se expresaría como img%04d.jpg
  • -vcodec libx264- le dice a ffmpeg que genere un archivo compatible con H.264
  • -profile:v high444- le dice a libx264 que use el perfil High 4:4:4 Predictive Lossless, lo que permite la codificación sin pérdidas
  • -refs 16- le dice a libx264 que tenga 16 imágenes almacenadas en un búfer, para que puedan ser referenciadas por otras imágenes en el video
  • -crf 0- le dice a libx264 que realice una codificación sin pérdidas
  • -preset ultrafast- le dice a libx264 que priorice la velocidad de codificación sobre el tamaño del archivo de salida
  • a.mp4- le dice a ffmpeg que guarde la salida en un archivo MP4 llamado a.mp4. Cambie esto al nombre de archivo y formato que desea usar
Algunas notas: -f image2es superfluo aquí. El demuxer del archivo de imagen debe usarse -framerateen lugar de -r. libx264 elegirá automáticamente el apropiado -profilepara sin pérdidas, y -presetse encargará de -refs.
-refs 5como MAYOR, a menos que sepa que su contenido tiene imágenes idénticas separadas por varias otras, eso podría causar que x264 pierda la referencia antes de que llegue al duplicado. Más alto que ultrafasthace poca diferencia en el modo sin pérdidas, aparte de la ganancia de ~10% de CABAC sobre CAVLC (por un alto costo de CPU a las tasas de bits requeridas para sin pérdidas). En serio, en algunos 720x480p60 de acción en vivo (salida desentrelazada), superfasteran 28 GB, slowereran 27 GB. Si el tiempo de codificación no importa, pero el tiempo de decodificación sí, asegúrese de evitar CABAC. Tal vez incluso -tune fastdecode. El conteo moderado de referencias no debería doler.
Y si tiene CPU para quemar, incluso puede intentar -preset placeboobtener algunas fracciones de porcentaje adicionales.
También para completar, h265 también tiene su propio modo sin pérdidas. -vcodec libx265 -x265-params lossless=1es la opción equivalente. (Pero en mi experiencia (= grabación de presentaciones de diapositivas de Powerpoint), no es necesariamente mejor, y es mucho más lento que h264) Estén atentos para el próximo año AV1 de AOMedia/NETVC1 de IETF/Daala de Xiph/cualquiera que sea su nombre para entonces ... el modo sin pérdidas
Dios te bendiga !

Puede crear una avianimación como una serie de pngimágenes ( no png tiene pérdidas, por lo que la jpeg => pngconversión no debería degradar sus imágenes):

si tus imágenes tienen un nombreimg_0001.jpg

ffmpeg -r 25 -start_number 1 -f image2 -i "img_%04d.jpg" -vcodec png video.avi

donde "25" es la velocidad de fotogramas que desea en el video resultante. -start_numberno es necesario si es 1, pero es útil si su primer número de video no es 1.

Si desea codificar mjpegcon la línea de comando de la más alta calidad es:

ffmpeg -r 25 -start_number 1 -f image2 -i "img_%04d.jpg" -vcodec mjpeg -qscale 1 video.avi

Y lo bueno de esto es que puedes volver a convertir el video en una serie de imágenes:

ffmpeg -i video.avi "img_series_%04d.png"
ffmpeg -i video.avi "img_series_%04d.jpg"

etc...

Esto realmente no satisface las necesidades de los solicitantes. Él está buscando una manera de que el marco se pueda actualizar sin pérdidas solo cuando la imagen cambia. Esto significa que la misma imagen puede usarse más de una vez. Además, jpeg, por naturaleza, no tiene pérdidas, ya que creo que usa compresión jpeg incluso con la máxima calidad.
En realidad, supongo que estaba dispuesto a tener algo de compresión, aunque no estoy seguro de cómo funcionará en secuencias largas del mismo cuadro. Sigo pensando que lo que se necesita es un formato de presentación de velocidad de fotogramas variable, aunque no estoy seguro de si ffmpeg es compatible con alguno.
CorePNG también puede crear marcos P. Por lo general, jpeg no es una compresión sin pérdidas, y dudo que mjpeg pueda crear cuadros P. Estoy de acuerdo, no respondo la pregunta como se hace, pero doy una solución para tener un video sin pérdidas con ffmpeg.

Para ampliar la respuesta de LordNeckbeard, sí, simplemente mux los datos JPEG en una transmisión de video MJPEG. Esa será la representación más pequeña de la secuencia exacta de imágenes de salida, aunque MJPEG es un códec terriblemente ineficiente según los estándares actuales. (sin redundancia temporal, ni siquiera intrapredicción.

Puede hacer un video MJPEG de velocidad de fotogramas variable para aprovechar las imágenes duplicadas en su entrada.

ffmpeg -framerate 30 -i input%03d.jpg -vf mpdecimate -codec copy output.mkv  # doesn't work.

Hrm, esto no va a funcionar, ya que mpdecimate no funcionará en datos comprimidos, y no podemos dejar que ffmpeg decodifique y luego vuelva a jpeg los datos de imagen sin pérdida y costo de CPU.

¿Tal vez si reemplazara los archivos de origen jpg duplicados con archivos vacíos con ese número de secuencia, o algo así?

Dado que esta pregunta ni siquiera es reciente, no me tomaré el tiempo para averiguar cómo hacerlo a menos que alguien responda para preguntar cómo. Pero dado que MJPEG puede ir a un contenedor mkv, estoy seguro de que es posible tener un archivo que no duplique los datos jpeg para cuadros repetidos, sino que simplemente no tenga un cuadro de salida para decodificar hasta que la secuencia de duplicados sea sobre.

Ah, aquí hay una idea:

ffmpeg -framerate blah -input blah -vf mpdecimate -f mkvtimestamp_v2 mpdecimate.timestamps

Luego elimine (o mueva a un lado) todos los jpegs para los marcos que mpdecimate quiere eliminar (¿probablemente tiene algunas opciones de registro? O -vf showinfo, y analice eso, y mueva o enlace fijo solo los marcos que aparecen en su salida, dejando atrás los JPEG caídos?). mux eso a un MJPEG.mkv, luego haga algo con mkvmerge para reemplazar las marcas de tiempo del marco en eso con las marcas de tiempo de mpdecimate.timestamps.

Si estuviera codificando, en lugar de simplemente convertir datos jpeg en MJPEG, esto sería MUCHO más fácil, ya que solo usaría mi primer comando con mpdecimate y cualquier códec que no sea copy, y simplemente funcionaría (tm).

No he probado nada de esto, ya que esta era una vieja pregunta. También la razón por la que no he llenado los vacíos de cómo filtrar realmente su directorio de jpegs en función de la salida de mpdecimate, o cómo usar realmente el flujo de marca de tiempo.