Спасибо за размещение этого вопроса, это помогло мне понять природу проблемы, с которой я столкнулся. У меня есть решение, которое, кажется, работает.
В моем случае я использую 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,066667 с. После перемещения в контейнер MKV все отрицательные метки времени стали нулями. Добавление -output_ts_offset 0.066667
к команде исправило это и заставило их начинаться с нуля. Я не понимаю, почему это началось в -0.066667 все же.
Редактировать 2: Лучший способ удалить отрицательные метки времени - использовать «-avoid_negative_ts 1» при кодировании mp4.