Aprendi a transcodificar vídeo MKV para MP4 com codificação de vídeo HEVC (x265) para tornar os arquivos menores de uma forma que torne tudo compatível com iOS. Mas, embora o processo seja ótimo - e a compactação seja ótima com tamanho de arquivo baixo - quando tento mesclar legendas em um vídeo específico, o vídeo MP4 resultante recebo uma pilha de erros do FFmpeg como este:
[mp4 @ 0x7facb9002000] pts has no value
[mp4 @ 0x7facb9002000] Application provided duration: 3152805999 / timestamp: 3154741000 is out of range for mov/mp4 format
Estou usando o macOS Mojave (10.15.2) com o FFmpeg 4.2.1 instalado via Homebrew, mas o problema persiste mesmo se eu baixar a compilação noturna (ffmpeg-4.2.1-macos64-static, 20191215-9fe0790) e usar esse binário em vez disso da versão instalada do Homebrew.
O problema é que tenho este vídeo que converti com sucesso em um MP4 com vídeo x264 e áudio AAC no passado e consegui mesclar legendas SRT também no arquivo resultante sem problemas. Mas quando eu crio um MP4 usando vídeo HEVC (x265) hoje da mesma fonte exata, a mesclagem de legendas SRT falha com os erros “pts não tem valor” e “está fora do intervalo para o formato mov/mp4”.
Este é o comando que uso para criar o vídeo MP4 HEVC (x265) a partir de uma fonte MKV:
ffmpeg -i input.mkv \
-map_metadata -1 \
-vf scale=-1:720 \
-c:v libx265 -crf 20 -c:a aac -b:a 128k \
-threads 4 \
-tag:v hvc1 -sn \
-map 0:0 -map 0:1 output_hevc.mp4 \
;
E este é o comando usado com sucesso no passado para mesclar legendas SRT em um MP4 existente sem recodificar:
ffmpeg -i output_hevc.mp4 \
-i input.srt \
-c:v copy -c:a copy \
-c:s mov_text -metadata:s:s:0 language=eng \
output_final.mp4 \
;
Acho que o problema pode ser que em cerca de 50% do vídeo não há legendas; apenas nos segundos 50% do vídeo são necessárias legendas.
O vídeo em questão tem cerca de 2 horas de duração. E nos primeiros 50 minutos, não há necessidade de legendas em inglês. Mas cerca de 50 minutos depois, é quando as legendas começam.
Então as legendas no SRT começam assim:
1
00:52:33,123 --> 00:52:50,123
It was a dark and stormy night…
Mas quando executo o comando FFmpeg acima, a saída é algo como isto; vezes um pouco falsificado para o propósito do exemplo:
Stream mapping:
Stream #0:0 -> #0:0 (copy)
Stream #0:1 -> #0:1 (copy)
Stream #1:0 -> #0:2 (subrip (srt) -> mov_text (native))
Press [q] to stop, [?] for help
frame=25560 fps=0.0 q=-1.0 size= 304640kB time=00:52:00.00 bitrate= 791.7kbits/frame=50730 fps=50726 q=-1.0 size= 681984kB time=time=00:52:00.00 bitrate=1772.4kbit[mp4 @ 0x7facb9002000] Application provided duration: 3152137000 / timestamp: 3152137000 is out of range for mov/mp4 format
[mp4 @ 0x7facb9002000] pts has no value
[mp4 @ 0x7facb9002000] Application provided duration: 3152805999 / timestamp: 3154741000 is out of range for mov/mp4 format
[mp4 @ 0x7facb9002000] pts has no value
[mp4 @ 0x7facb9002000] Application provided duration: 3153246998 / timestamp: 3156809000 is out of range for mov/mp4 format
[mp4 @ 0x7facb9002000] pts has no value
[mp4 @ 0x7facb9002000] Application provided duration: 3154051997 / timestamp: 3159013000 is out of range for mov/mp4 format
[mp4 @ 0x7facb9002000] pts has no value
[mp4 @ 0x7facb9002000] Application provided duration: 3155556996 / timestamp: 3163817000 is out of range for mov/mp4 format
E toneladas de mensagens semelhantes até, et voila! A mesclagem termina, nenhuma legenda é visível e pronto.
Isso está me deixando louco! Quero dizer, se eu usar o mesmo comando, mas especificar um tempo de busca que comece por volta do ponto em que as legendas entram, eu realmente vejo as legendas em 50% do vídeo que precisa delas:
ffmpeg -I output_hevc.mp4 \
-i input.srt \
-c:v copy -c:a copy \
-c:s mov_text -metadata:s:s:0 language=eng \
-ss 3120 \
output_final.mp4 \
;
Mas eu preciso de mais de 50% do vídeo, é claro. Caramba, acabei de tentar este comando; Posso obter as legendas para mesclar com o MP4 se eu definir a busca para qualquer valor igual ou superior a 1005 segundos:
ffmpeg -i output_hevc.mp4 \
-i input.srt \
-c:v copy -c:a copy \
-c:s mov_text -metadata:s:s:0 language=eng \
-ss 1005 \
output_final.mp4 \
;
Mas o que há de tão mágico em 16,75 minutos (1005 segundos) no contexto disso?
Por que consigo mesclar as legendas se seleciono apenas as vezes em que as legendas aparecem nos segundos 50% do vídeo, mas não se executo o comando para mesclar o vídeo completo?
FWIW, se eu executar um comando semelhante para criar um MKV do vídeo, tudo bem!
ffmpeg -i output_hevc.mp4 \
-i input.srt \
-c:v copy -c:a copy -c:s copy \
output.mkv \
;
De alguma forma, essa fusão mov_text
faz com que o processo falhe, ao que parece.
E se eu adicionar uma legenda falsa no início do arquivo assim:
0
00:00:00,000 --> 00:16:75,000
Foo!
1
00:52:33,123 --> 00:52:50,123
It was a dark and stormy night…
Tudo funciona como desejado! Exceto por ter a palavra “Foo!” aparecendo em 50% do vídeo. Obviamente não é o ideal.
Existe alguma maneira de contornar isso? Isso é um bug do FFmpeg ou talvez um problema com o vídeo HEVC (x265) com legendas sendo mescladas?
Parece que adicionar uma legenda falsa no início do arquivo SRT que se estende desde o início do vídeo até onde as legendas começam corrigiu esse problema.
Esta solução é claramente um “hack”, mas funciona.
Partindo da minha ideia de adicionar uma legenda falsa no início do arquivo SRT, percebi que as legendas SRT - de acordo com as especificações SRT - permitem tags HTML. Sabendo que adicionei a seguinte legenda falsa e tudo funciona!
É isso! Apenas adicionar uma tag em negrito vazia permite que tudo funcione e que as legendas sejam mescladas…
Mas - como declarado no início - isso é claramente um hack e estou aberto para ouvir mais de outras pessoas que sabem mais sobre o FFmpeg. Só posso supor que nenhum desses problemas reflete o comportamento desejado e deve haver uma maneira mais elegante de lidar com casos como esse. Ou isso é um bug (não um recurso) e deve ser relatado?