Правильно исправить видео, которые были закодированы старой версией x264.

Правильно исправить видео, которые были закодированы старой версией x264.

Из-за ошибки в старых версиях x264 видеопотоки h.264 имеют следующие три свойства:

  1. закодировано с помощью x264 build 150 или более ранней версии
  2. с использованием цветовой субдискретизации 4:4:4
  3. битовый поток не содержит информации о версии x264

не будет правильно воспроизводиться многими видеоплеерами. Новые версии видеоплеера mpvимеют специальную опцию

--vd-lavc-assume-old-x264

специально посвященные этому вопросу (см.:https://mpv.io/manual/master/).

НаFFmpeg баг-трекерпредлагается добавить правильный SEI.h264 в видеопоток (содержащий информацию о версии x264, я полагаю). Я предпочитаю не полагаться на такие хаки, поэтому мой вопрос:Есть ли «правильный» способ (в идеале с использованием ffmpeg) восстановить файлы, как будто они изначально были закодированы с помощью новой (исправленной) версии x264??

Очевидно, я хотел бы остаться (более или менее) видеокачествоиразмер файла. Если необходимо перекодирование, то оно не должно ничего изменить, кроме исправления ошибочного поведения старой реализации x264. (Дополнительная информация:Отчет об ошибкедает пример поврежденного файла. Предполагается, что ошибка в старом x264, вероятно, былапредставлено здесь.)

решение1

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

В моем случае я использую ffmpeg из репозиториев Ubuntu. Последняя версия, которая смогла декодировать мои файлы libx264, была 2.8.6. После обновления до 2.8.14 или 2.8.15 у меня возникли проблемы с декодированием, которые вы описываете. Я не хочу перекодировать свои старые видео, я просто хочу исправить заголовок, чтобы ffmpeg мог правильно определить ошибку, которая была внесена во время исходного кодирования, и правильно их воспроизвести.

Итак, во-первых, яскачал статический двоичный файл, включающий последнюю версию ffmpeg, v4. Я связал этот двоичный файл с ffmpeg4в своей системе, чтобы я мог контролировать, какую версию я использую. Нам нужны некоторые новые функции, которые были введены после 2.8 (точно не уверен, когда). Если у вас уже установлена ​​более новая версия ffmpeg, просто используйте ее и замените ffmpeg4на ffmpegв командах ниже.

Теперь извлеките необработанный битовый поток из вашего испорченного видео (назовите его BROKEN.mkv).

ffmpeg4 -i BROKEN.mkv -vcodec copy -an -bsf:v h264_mp4toannexb raw.h264

Я не уверен, что флаг h264_mp4toannexb необходим,он может быть автоматически вставлендля этого формата.

Теперь поместите битовый поток в новый контейнер mp4,и исправить информацию о старой глючной сборке x264 в заголовке SEI.

ffmpeg4 -r 30 -i raw.h264 -avoid_negative_ts 1 -bsf:v h264_metadata='sei_user_data=dc45e9bde6d948b7962cd820d923eeef+x264 - core 150' -c copy FIXED.mp4

Битовый поток не содержит информации о временных метках, поэтому вы получите здесь кучу предупреждений. Я также обнаружил, что мне пришлось вручную установить частоту кадров 30 кадров в секунду ( -r 30), потому что в противном случае он предполагал некоторую переменную частоту кадров между 25 и 30 кадрами в секунду. Я не знаю, как правильно извлечь временные метки или правильно объединить их в новый контейнер. Пожалуйста, дайте мне знать, если у вас есть решение! Многие рекомендуют, -fflags +genptsно это некажется, что-то делаютдля меня. Наконец, я добавил, -avoid_negative_ts 1чтобы временная метка первого кадра была неотрицательной.

Наконец, и это необязательно, если вы хотите поместить результаты в контейнер MKV, вы можете сделать это

ffmpeg4 -i FIXED.mp4 -c copy FIXED.mkv

Почемуконвертировать сначала в MP4, а затем в MKV? Похоже, что контейнер MKV просто откажется продолжать работу без временных меток, но MP4 сделает это и просто выдаст предупреждения. Затем вы можете конвертировать в MKV без предупреждений.

Итак, после всего этого у меня есть рабочие файлы MP4 и MKV. Однако я проверил некоторые кадры и обнаружил незначительные изменения (изменения яркости порядка ~2 уровней). Я не понимаю, почему это произошло, ведь это должно было быть без потерь. Пожалуйста, дайте мне знать, если у вас есть предложения, как это можно сделать лучше.

Редактировать: Я заметил, что некоторые из моих временных меток были отрицательными в контейнере MP4, начиная с -0.066667s. После перехода в контейнер MKV все отрицательные временные метки стали нулями. Добавление -output_ts_offset 0.066667к команде исправило это и заставило их начинаться с нуля. Я не понимаю, почему это началось с -0.066667.

Редактирование 2: Лучший способ удалить отрицательные временные метки — использовать «-avoid_negative_ts 1» при кодировании mp4.

Связанный контент