Obrigado por postar esta pergunta, isso me ajudou a entender a natureza do problema que eu estava tendo também. Eu tenho uma solução que parece funcionar.
No meu caso, estou usando o ffmpeg dos repositórios do Ubuntu. A última versão que conseguiu decodificar meus arquivos libx264 foi 2.8.6. Após atualizar para 2.8.14 ou 2.8.15, tive os problemas de decodificação que você descreve. Eu não quero recodificar meus vídeos antigos, só quero corrigir o cabeçalho para que o ffmpeg possa identificar corretamente o erro que foi introduzido durante a codificação original e reproduzi-los corretamente.
Então, primeiro eu baixei o binário estático que inclui a versão mais recente do ffmpeg, v4 . Eu vinculei esse binário a ffmpeg4
em meu sistema para que eu possa controlar qual versão estou usando. Precisamos de alguns dos novos recursos que foram introduzidos após o 2.8 (não sei exatamente quando). Se você já tem uma versão mais nova do ffmpeg instalada, use-a e substitua ffmpeg4
por ffmpeg
nos comandos abaixo.
Agora, extraia o bitstream bruto do seu vídeo quebrado (chame-o BROKEN.mkv).
ffmpeg4 -i BROKEN.mkv -vcodec copy -an -bsf:v h264_mp4toannexb raw.h264
Não tenho certeza se o sinalizador h264_mp4toannexb é necessário, ele pode ser inserido automaticamente formato.
Agora, coloque o fluxo de bits em um novo contêiner mp4, e corrija as informações sobre a antiga compilação x264 com bugs no cabeçalho do 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
O fluxo de bits não contém informações de registro de data e hora, portanto, você receberá muitos avisos aqui. Eu também achei que tinha que definir manualmente a taxa de quadros para 30fps ( -r 30
) porque caso contrário, adivinhava alguma taxa de quadros variável entre 25 e 30fps. Eu não sei como extrair corretamente os timestamps ou mux-los corretamente no novo contêiner. Por favor, deixe-me saber se você tem uma correção! Muitas pessoas recomendam -fflags +genpts
, mas isso não parecem fazer qualquer coisa para mim. Por fim, adicionei -avoid_negative_ts 1
para que o timestamp do primeiro quadro não seja negativo.
Finalmente, e isso é opcional, se você quiser colocar os resultados em um contêiner MKV, você pode fazer isso
ffmpeg4 -i FIXED.mp4 -c copy FIXED.mkv
Por que converte primeiro para MP4 e depois para MKV ? Parece que o contêiner MKV simplesmente se recusará a prosseguir sem timestamps, mas o MP4 fará isso e apenas emitirá avisos. Então você pode converter para MKV sem avisos.
Então, depois de tudo isso, eu tenho arquivos MP4 e MKV funcionando. No entanto, inspecionei alguns quadros e houve pequenas alterações (mudanças de luminância na ordem de ~ 2 níveis). Eu não entendo porque isso aconteceu porque isso deveria ter sido sem perdas. Por favor, deixe-me saber se você tem sugestões sobre como isso pode ser feito melhor.
Editar: notei que alguns dos meus timestamps eram negativos no contêiner MP4, começando em -0,066667s. Depois de se mudar para um contêiner MKV, todos os timestamps negativos se tornaram zeros. A adição de -output_ts_offset 0.066667
ao comando corrigiu isso e os iniciou em zero. Eu não entendo porque começou em -0,066667 embora.
Editar 2: Uma maneira melhor de remover carimbos de hora negativos é usar "-avoid_negative_ts 1" ao codificar o mp4.