перезапустить задание ffmpeg после сбоя

Существует ли общий метод или какая-то стратегия для перезапуска неудачного задания перекодирования с того места, на котором оно было остановлено в момент сбоя (или остановки по какой-либо причине)?

Например, если у меня есть 2-часовое задание по перекодированию, и оно терпит неудачу/вылетает через 1 час и 59 минут, есть ли способ, которым я могу просто выполнить эту работу в последние минуты и использовать прогресс, который у меня уже был, предполагая, что частично перекодированный файл до сих пор доступен?

Ответы (2)

Прямой вариант возобновления кодирования недоступен.

А что касается ручного перезапуска кодирования, то это тоже невозможно. Две причины:

1) при перекодировании в типичный контейнер, такой как MP4, индекс записывается после завершения кодирования. В частичном файле такого индекса не будет, если процесс неожиданно завершился, и поэтому существующий файл не может быть проанализирован.

2) Если вы не можете точно определить последний неповрежденный кадр, закодированный в частичном файле, ваше соединение не будет бесшовным.


Тем не менее, есть утомительный способ сделать это. Метод основан на использовании segmentмультиплексора. Вы кодируете в формат MPEG-TS, но сегментируете вывод по мере его создания. В случае сбоя задания вы проверяете несколько атрибутов и возобновляете кодирование на основе этих данных. Наконец, вы соединяете все сегменты вместе.

Шаг 1 : Кодировать и сегментировать

Для достижения наилучших результатов аудио и видео должны быть сделаны отдельно. На самом деле звук можно сделать без сегментации, так как он кодируется намного быстрее.

ffmpeg -i in.mp4 -c:a aac -vn job-audio.mp4

И для видео

ffmpeg -copyts -start_at_zero -ss 0 -i in.mp4 -c:v libx264 -an
       -f segment -segment_time 0.01 -segment_time_delta 1
       -muxpreload 0 -muxdelay 0 -mpegts_copyts 1
       -segment_start_number 0 -segment_list files.ffcat
job-video%d.ts

Каждый вышеприведенный сегмент будет содержать одну GOP, поэтому никакие кадры в сегменте не зависят от кадров в других сегментах для воспроизведения.

Шаг 2 Определите точку возобновления

Предположим, задание завершается ошибкой при создании сегмента №5.

Во-первых, вы бежите

ffprobe "in.mp4" -show_entries stream=codec_type,start_time,duration -of compact

Это произведет показание, подобное этому

stream|codec_type=audio|start_time=0.000000|duration=356.309333
stream|codec_type=video|start_time=0.040000|duration=356.360000

Обратите внимание на время начала видеопотока.

Теперь запустите его для первого и последнего (неполного) сегмента.

ffprobe "job-video0.ts" -show_entries stream=codec_type,start_time,duration -of compact

stream|codec_type=video|start_time=0.080000|duration=10.000000

Вы видите положительное смещение 0,04 относительно видеопотока MP4. Назовем это начальным значением смещения

Теперь, для последнего потока

ffprobe "job-video5.ts" -show_entries stream=codec_type,start_time,duration -of compact

stream|codec_type=video|start_time=20.080000|duration=4.320000

Шаг 3. Возобновление кодирования

Итак, теперь вы бежите

ffmpeg -copyts -start_at_zero -ss {start_time of last segment - initial offset} -i in.mp4 -c:v libx264 -an
       -f segment -segment_time 0.01 -segment_time_delta 1
       -muxpreload 0 -muxdelay 0 -mpegts_copyts 1 -initial_offset {initial offset}
       -segment_start_number {index number of last segment} -segment_list files-resume.ffcat
job-video%d.ts

Шаг 4. Соедините сегменты

У вас будет несколько .ffcatфайлов - от первого запуска и всех возобновленных запусков. Скопируйте записи из всех вторичных прогонов и добавьте их в первый файл. Избегайте дублирования.

Бег

ffmpeg -f concat -i files.ffcat -i job-audio.mp4 -c copy full.mp4
чтобы уточнить, знаете ли вы, что для каждого сегмента будет одна GOP, потому что, как говорится в документах, когда segment_time_delta "... указан, ключевой кадр начнет новый сегмент, если его PTS удовлетворяет отношению..."?
Да, очень низкое значение segment_time гарантирует, что дельта редко вступает в игру. Первоначально я добавил эту опцию, потому что мои первоначальные команды также включали звук. И формат start_time в этих случаях не всегда совпадает с форматом start_time видео. Теперь это спорно.

Если вы знаете конкретную часть файла, которую блокирует задание кодирования, вы можете использовать параметры и ffmpegдля обхода точки блокировки. Подробнее об этих параметрах можно прочитать в документации к инструменту .--ss-t

предположим, что отказ непредсказуем, т. е. нет известной точки отказа.