
Devido a um bug nas versões antigas do x264, o vídeo h.264 transmite com as três propriedades a seguir:
- codificado com x264 build 150 ou anterior
- usando subamostragem de croma 4:4:4
- bitstream não contém informações de versão x264
não será reproduzido corretamente por muitos reprodutores de vídeo. Novas versões do player de vídeo mpv
têm uma opção dedicada
--vd-lavc-assume-old-x264
abordando especificamente esta questão (ver:https://mpv.io/manual/master/).
NoRastreador de bugs FFmpegsugere-se adicionar o SEI.h264 adequado ao stream de vídeo (contendo as informações da versão x264, eu acho). Prefiro não confiar nesses hacks, então minha pergunta é:Existe uma maneira "correta" (de preferência usando ffmpeg) de reparar os arquivos como se eles tivessem sido codificados com uma nova versão (corrigida) do x264 em primeiro lugar?
Obviamente eu gostaria de continuar (mais ou menos) em vídeoqualidadeetamanho do arquivo. Se a recodificação for necessária, ela não deverá mudar nada, apenas corrigir o comportamento de bugs da antiga implementação x264. (Mais informações:O relatório de errosdá um exemplo de arquivo corrompido. Conjectura-se que o bug no antigo x264 provavelmente foiintroduzido aqui.)
Responder1
Obrigado por postar esta pergunta, ela também me ajudou a entender a natureza do problema que eu estava tendo. 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 a 2.8.6. Após atualizar para 2.8.14 ou 2.8.15, tive os problemas de decodificação que você descreve. Não quero recodificar meus vídeos antigos, só quero consertar 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 eubaixou o binário estático que inclui a versão mais recente do ffmpeg, v4. Vinculei esse binário ffmpeg4
em meu sistema para poder controlar qual versão estou usando. Precisamos de alguns dos novos recursos que foram introduzidos após o 2.8 (não tenho certeza de quando). Se você já possui uma versão mais recente do ffmpeg instalada, basta usá-la e substituí-la ffmpeg4
nos ffmpeg
comandos abaixo.
Agora, extraia o fluxo de bits bruto do seu vídeo quebrado (chame-o de 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,pode ser inserido automaticamentepara este formato.
Agora, coloque o bitstream em um novo contêiner mp4,e corrija as informações sobre a antiga compilação x264 com bugs no cabeçalho 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 carimbo de data/hora, então você receberá muitos avisos aqui. Também descobri que precisava definir manualmente a taxa de quadros para 30fps ( -r 30
) porque, caso contrário, ele adivinhava alguma taxa de quadros variável entre 25 e 30fps. Não sei como extrair corretamente os carimbos de data/hora ou misturá-los corretamente no novo contêiner. Por favor, deixe-me saber se você tiver uma solução! Muita gente recomenda -fflags +genpts
, mas isso nãoparece fazer qualquer coisapara mim. Por fim, adicionei -avoid_negative_ts 1
para que o carimbo de data/hora do primeiro quadro não fosse 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 queconverta primeiro para MP4 e depois para MKV? Parece que o contêiner MKV simplesmente se recusará a prosseguir sem carimbos de data e hora, mas o MP4 fará isso e apenas emitirá avisos. Então você pode converter para MKV sem avisos.
Depois de tudo isso, tenho arquivos MP4 e MKV funcionando. No entanto, inspecionei alguns quadros e há pequenas alterações (alterações de luminância da ordem de ~2 níveis). Não entendo por que isso aconteceu porque 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 carimbos de data/hora eram negativos no contêiner MP4, começando em -0,066667s. Depois de mudar para um contêiner MKV, todos os carimbos de data/hora negativos tornaram-se zeros. Adicionar -output_ts_offset 0.066667
ao comando corrigiu isso e fez com que eles começassem do zero. Não entendo por que começou em -0,066667.
Edição 2: A melhor maneira de remover carimbos de data/hora negativos é usar "-avoid_negative_ts 1" ao codificar o mp4.