
Из-за ошибки в старых версиях x264 видеопотоки h.264 имеют следующие три свойства:
- закодировано с помощью x264 build 150 или более ранней версии
- с использованием цветовой субдискретизации 4:4:4
- битовый поток не содержит информации о версии 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.