Reanudar una codificación parcialmente completa con FFmpeg

Resumen

Dada una codificación parcialmente completada que:

  • Fue codificado usando h264 en el contenedor Matroska
  • Se interrumpió al detener manualmente FFmpeg escribiendo 'q' en la consola

...¿cuáles son las formas de reanudar la codificación de este archivo, preferiblemente agregando el archivo existente?

Detalles

Tengo algunos proyectos de codificación grandes que hago que pueden tomar hasta una semana de codificación en algunos casos. En circunstancias ideales, la computadora que realiza la codificación puede permanecer encendida, sin interrupciones y dejar que haga el trabajo. Sin embargo, en situaciones realistas, a veces esa computadora necesita dejar de codificar y apagarse o reiniciarse por una multitud de razones. Debido a esto, estoy buscando una manera de hacer que la codificación usando FFmpeg en esa computadora sea más "a prueba de balas" al anticipar posibles interrupciones y tener una forma de usar FFmpeg por sí mismo para continuar donde lo dejó más tarde.

lo que estoy haciendo ahora

Cuando esto sucede, recupero lo que puedo del archivo codificado, lo examino en el software de edición de video, encuentro un buen punto de empalme y luego uso AviSynth para crear un script que comenzará a codificar un nuevo segmento donde lo dejó el anterior. Luego uso otro software para recortar la codificación existente para que el empalme sea perfecto, luego uso el demuxer de FFmpeg para combinar los segmentos h264 individuales más tarde en un archivo completo.

Todo esto es mucho trabajo manual que puede ser muy lento y que me gustaría evitar si existe una solución más automatizada.

Ideas

Segmentación: esta parece ser la solución más prometedora, pero hay lagunas que no estoy seguro de cómo llenar. Esta respuesta parece cubrir mucho. Puede decirle a FFmpeg que genere segmentos, divididos en I-Frames a intervalos aproximados, que se pueden remuxar más tarde. Lo que no sé al mirar esa respuesta y la documentación de FFmpeg es cómo comenzaría a codificar nuevamente en un segmento específico. Parece que podría haber una manera de darle a FFmpeg un archivo que le diga dónde debe comenzar cada segmento a través del marco o el código de tiempo, pero ¿cómo hago para que comience en algún lugar en el medio de esa lista?

Sin embargo, esta opción no es ideal, ya que necesitaré tener efectivamente el doble del espacio de la codificación resultante (que con frecuencia tendrá un tamaño de 100 gigabytes) disponible, ya que necesitaré mezclar los segmentos en un solo archivo. Sería bueno si de alguna manera pudiera cortar limpiamente una codificación en curso y hacer que FFmpeg reabriera ese archivo y continuara donde lo dejó.

Máquinas virtuales: esto tiene el potencial de funcionar, ya que podría congelar el estado de la máquina antes de reiniciar, pero todo mi espacio de codificación existe en el almacenamiento conectado a la red, que no estoy seguro de que funcione en el contexto de una máquina virtual. suspendido y reanudado, ya que la VM en realidad no controla las unidades.

Convierta los archivos fuente segmentados utilizando un archivo por lotes/script de shell que acepta un índice como argumento. Siendo el índice el segmento no. en el que debe reanudarse la codificación. Puede obtener ese índice mediante la inspección manual del último segmento de salida codificado o alguna rutina de observación de carpetas.
@Gyan, lo siento, no entiendo la solución que está describiendo, ¿podría ampliarla? ¿Cómo indicaría este script a FFmpeg que continúe codificando desde donde lo dejó?

Respuestas (1)

Se me ocurrió una solución "suficientemente buena" para este problema, ya que no parece posible en el momento de escribir este artículo captar una codificación parcial que se cortó de forma arbitraria y concatenar con precisión el resto del video. .

Una solución utilizando la segmentación

Primero, use la funcionalidad de segmentación de FFmpeg para generar segmentos en algún intervalo para el cual perder dicho intervalo es una pérdida aceptable. También genere un archivo .csv con las horas de inicio y finalización del segmento. Un comando de ejemplo que logra esto es:

ffmpeg.exe -i .\source.avi -c:v libx264 -crf 20 -c:a aac -pix_fmt yuv420p -f segment -segment_time 30 -segment_list segments.csv -reset_timestamps 1 seg%03d.mkv

Suponga que durante la codificación del cuarto segmento (seg003.mkv), es necesario detener el codificador y reiniciar la máquina. Enviar una qpulsación de tecla a FFMpeg durante la codificación de un segmento lo detiene arbitrariamente en algún punto y deja ese segmento incompleto.

El segmento que fue interrumpido se pierde efectivamente y se puede eliminar. Al abrir el archivo segments.csv se revela

seg000.mkv,0.000000,33.390000
seg001.mkv,33.390000,62.586000
seg002.mkv,62.586000,91.782000
seg003.mkv,91.782000,98.655000

Usando esta información, sabemos que seg003.mkv comenzó a los 91.782 segundos en la fuente. Para continuar donde lo dejamos, usamos el mismo comando anterior para codificar la salida segmentada, pero también buscamos ( -ss) hasta el comienzo de nuestro cuarto segmento y cambiamos la numeración ( -segment_start_number):

ffmpeg.exe -ss 91.782000 -i source.avi -c:v libx264 -crf 20 -c:a aac -pix_fmt yuv420p -f segment -segment_time 30 -segment_list segments2.csv -segment_start_number 3 -reset_timestamps 1 seg%03d.mkv

FFmpeg se recuperará al comienzo del cuarto segmento y lo nombrará correctamente seg003.mkv. Tenga en cuenta que el nombre del archivo .csv de salida se ha cambiado para que el original no se sobrescriba. Este nuevo archivo .csv comenzará en 0.00, por lo que más interrupciones requerirán agregar tiempos en este archivo al archivo anterior para encontrar un punto de partida.

Finalmente, cuando todos los segmentos están listos para ser concatenados, construimos un archivo .ffcat como se describe en los ejemplos de la página wiki :

file seg000.mkv
file seg001.mkv
file seg002.mkv
file seg003.mkv
file seg004.mkv
file seg005.mkv

y ejecuta este comando:

ffmpeg.exe -f concat -i .\segments.ffcat -c copy output.mkv

Esto genera la codificación concatenada completa. La opción -fflags +genptsse menciona en la respuesta vinculada de la pregunta, y puede ser necesaria para lograr un resultado perfecto, pero no he encontrado que haga ninguna diferencia en mis pruebas.