Как без потерь кодировать последовательность изображений jpg в видео в ffmpeg?

У меня есть большой набор jpg, которые я хочу преобразовать в видео без потерь (или, по крайней мере, очень близко к без потерь, если время кодирования не намного выше, чем в противном случае).

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

Есть ли какой-нибудь кодек и подходящие настройки для ffmpeg, которые могут это сделать?

sequence-of-jpegs долгое время был кодеком. Цифровые камеры, которые не используют h.264, неизменно записывают MJPEG, и, я думаю, карты видеозахвата использовали его.

Ответы (4)

Просто мультиплексируйте изображения

Вы можете просто мультиплексировать изображения JPG, чтобы сделать видео:

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

Обратите внимание, что если вы опустите , то к вводу будет применено -framerateзначение по умолчанию .-framerate 25

Оптимизация без потерь

Вы можете использовать jpegtranоптимизацию без потерь для каждого кадра, что может обеспечить значительную экономию размера файла:

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

Теперь мультиплексируйте ffmpeg, как показано выше.

Проверяем, что это действительно без потерь

Мультиплексор framehash можно использовать для сравнения уникального хэша каждого кадра, чтобы убедиться, что результат действительно без потерь:

$ 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
...

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

Также см

не могли бы вы уточнить, чего framemd5должны достичь две команды, помимо простого перечисления хэшей? как мне получить дополнительное сжатие, когда таким образом идентифицируются идентичные кадры?
Хэши были включены только для того, чтобы показать вам, что кадры такие же, как и отдельные изображения, поэтому выполняется ваше требование хранить «каждый отдельный кадр jpg как есть (без повторного сжатия)».
Опубликовал свой собственный ответ с непроверенной идеей удаления повторяющихся кадров, чтобы получить VFR MJPEG.mkv. VFR — единственный способ, который я могу придумать, чтобы воспользоваться преимуществами временной избыточности с MJPEG. :П
SSIM может быть более быстрым способом сравнения точности.

Это приведет к выводу видео H.264 без потерь, в котором кадры будут использовать информацию из других кадров.

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

Объяснение вариантов:

  • -f image2- указывает ffmpeg выбрать группу изображений
  • -r 30- говорит ffmpeg кодировать со скоростью 30 кадров (или изображений) в секунду (измените это на желаемую частоту кадров)
  • -i %09d.jpg- говорит ffmpeg использовать изображения от 000000000.jpg до 999999999.jpg в качестве входных данных. Измените 9in %09d.jpgна количество нулей в именах вашей последовательности изображений. Если ваши имена файлов, например, img0001.jpg, то это будет выражено как img%04d.jpg
  • -vcodec libx264- сообщает ffmpeg о необходимости вывода в файл, совместимый с H.264.
  • -profile:v high444- указывает libx264 использовать профиль High 4:4:4 Predictive Lossless, что позволяет кодировать без потерь
  • -refs 16- указывает libx264 хранить 16 изображений в буфере, чтобы на них могли ссылаться другие изображения в видео.
  • -crf 0- говорит libx264 выполнять кодирование без потерь
  • -preset ultrafast- сообщает libx264, что скорость кодирования важнее размера выходного файла.
  • a.mp4- указывает ffmpeg сохранять вывод в файле MP4 с именем a.mp4. Измените это на имя файла и формат, который вы хотите использовать.
Несколько замечаний: -f image2здесь лишнее. Демультиплексор файла изображения должен использовать -framerateвместо -r. libx264 автоматически выберет подходящий -profileдля без потерь, и -presetбудет работать с файлами -refs.
-refs 5в MOST, если вы не знаете, что в вашем контенте есть идентичные изображения, разделенные несколькими другими, это может привести к тому, что x264 потеряет ссылку до того, как доберется до дубликата. Выше ultrafast, чем в режиме без потерь, мало что отличается, за исключением ~ 10% -ного прироста CABAC по сравнению с CAVLC (из-за высокой стоимости процессора при битрейтах, необходимых для без потерь). Серьезно, на каком-то лайв-экшене 720x480p60 (вывод с деинтерлейсом) superfastбыло 28 ГБ, slowerбыло 27 ГБ. Если время кодирования не имеет значения, а время декодирования имеет значение, избегайте CABAC. Может даже -tune fastdecode. Умеренное количество ссылок не помешает.
И если вам нужно сжечь процессор, вы даже можете попробовать -preset placeboдобавить несколько дополнительных долей процента.
Также для полноты картины у h265 тоже есть свой режим без потерь. -vcodec libx265 -x265-params lossless=1является эквивалентным вариантом. (Но по моему опыту (= запись презентаций слайд-шоу в Powerpoint), это не обязательно лучше, и это намного медленнее, чем h264). Оставайтесь с нами для AOMedia в следующем году AV1 / IETF NETVC1 / Xiph's Daala / что бы это ни было переименовано к тому времени ... в режиме без потерь
Будьте здоровы !

Вы можете создать aviанимацию в виде серии pngизображений ( png без потерь, поэтому jpeg => pngпреобразование не должно ухудшать ваши изображения):

если ваши изображения названыimg_0001.jpg

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

где «25» — частота кадров, которую вы хотите получить в результирующем видео. -start_numberне нужен, если он равен 1, но полезен, если ваш первый номер видео не равен 1.

Если вы хотите кодировать в mjpegкомандной строке высочайшего качества:

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

И прелесть в том, что вы можете преобразовать видео обратно в серию изображений:

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

и т.д...

Это не совсем соответствует потребностям спрашивающих. Он ищет способ, чтобы кадр мог обновляться без потерь только при изменении изображения. Это означает, что одно и то же изображение может быть использовано более одного раза. Также jpeg по своей природе не без потерь, поскольку я считаю, что он использует сжатие jpeg даже при максимальном качестве.
На самом деле я предполагаю, что он был готов к некоторому сжатию, хотя я не уверен, как оно будет работать с длинными последовательностями одного и того же кадра. Я все еще думаю, что нужен формат представления с переменной частотой кадров, хотя я не уверен, что ffmpeg его поддерживает.
CorePNG также может создавать P-кадры. Обычно jpeg не является сжатием без потерь, и я сомневаюсь, что mjpeg может создавать P-кадры. Я согласен, что не отвечаю на вопрос, как он задан, но я даю решение, чтобы иметь видео без потерь с ffmpeg.

Чтобы расширить ответ LordNeckbeard, да, просто мультиплексируйте данные JPEG в видеопоток MJPEG. Это будет наименьшее представление точной последовательности выходных изображений, даже несмотря на то, что MJPEG — ужасно неэффективный кодек по сегодняшним меркам. (без временной избыточности и даже без внутреннего предсказания.

Вы можете сделать MJPEG-видео с переменной частотой кадров, чтобы использовать дубликаты изображений во входных данных.

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

Хм, это не сработает, так как mpdecimate не будет работать со сжатыми данными, и мы не можем позволить ffmpeg декодировать, а затем повторно преобразовать данные изображения в jpeg без потерь и затрат ЦП.

Может быть, если вы заменили дубликаты исходных файлов jpg пустыми файлами с этим порядковым номером или что-то в этом роде?

Поскольку этот вопрос даже не новый, я не собираюсь тратить время на то, чтобы выяснить, как это сделать, если кто-то не ответит, чтобы спросить, как это сделать. Но поскольку MJPEG может помещаться в контейнер mkv, я уверен, что можно иметь файл, который не дублирует данные jpeg для повторяющихся кадров, а вместо этого просто не имеет выходного кадра для декодирования, пока последовательность дубликатов не будет над.

О, вот идея:

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

Затем удалите (или отодвиньте в сторону) все jpeg для кадров, которые mpdecimate хочет удалить (возможно, у него есть какие-то параметры ведения журнала? Или -vf showinfo, и проанализируйте его, и переместите или жестко свяжите только те кадры, которые отображаются в его выводе, оставив позади упавшие JPEG-файлы?). мультиплексируйте это в MJPEG.mkv, затем сделайте что-нибудь с mkvmerge, чтобы заменить временные метки кадров в нем временными метками из mpdecimate.timestamps.

Если бы вы использовали xcoding, а не просто мультиплексировали данные jpeg в MJPEG, это было бы НАМНОГО проще, поскольку вы просто использовали бы мою первую команду с mpdecimate и любым кодеком, кроме copy, и это просто сработало бы (tm).

Я ничего из этого не пробовал, так как это был старый вопрос. Также причина, по которой я не заполнил пробелы в том, как на самом деле фильтровать ваш каталог jpeg на основе вывода mpdecimate или как на самом деле использовать поток меток времени.