Altere a taxa de quadros no ffmpeg sem reencodificar

Altere a taxa de quadros no ffmpeg sem reencodificar

Tenho um vídeo mkv (h264) de 23.976 fps (24000/1001), mas quero convertê-lo para 25fps sem recodificar e perder qualidade. Eu sei que mkvmerge pode fazer isso (com a opção --default-duration '0:25fps'), mas gostaria de fazer isso diretamente do ffmpeg, se possível. De acordo com a documentação, isso deve funcionar:

ffmpeg -i input.mkv -r 25 -vcodec copy output.mkv

mas quando executo só obtenho o mesmo fps de vídeo. Qual é o método correto para fazer isso (se existir) no ffmpeg?

Responder1

Aqui está o método usando as versões atuais do FFmpeg. Ele depende do demuxer concat não redimensionar o PTS das entradas após o primeiro arquivo, mas simplesmente aplicar um deslocamento fixo. Digamos que você tenha um fluxo de 30 fps com uma escala de tempo de 15360(típico de saída FFmpeg). Isso significa que o frame 0possui PTS 0e o frame 30possui PTS 15360. Isso se tornaria um fluxo de 45 fps se pudéssemos alterar a escala de tempo 23040sem afetar os valores de PTS.

Essencialmente, é isso que o método abaixo faz.

1. Identifique as propriedades de origem.

Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 1171 kb/s,
       30 fps, 30 tbr, 15360 tbn (default)

Você deseja observar as propriedades de origem, especialmente a resolução e os arquivos tbn.


2a. (Opcional) Altere a escala de tempo para algo conveniente, para simplificar os cálculos.

ffmpeg -i in.mp4 -c copy -an -video_track_timescale 30 in-v30.mp4

Isso nos leva

Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 1171 kb/s, \
       30 fps, 30 tbr, 30 tbn (default

Se você seguir esta etapa, a nova escala de tempo deverá ser igual ou um múltiplo integral da taxa de quadros original.

2b. Calcule a escala de tempo necessária para que, para o framerate alvo x, o PTS do quadro # xna origem tenha o mesmo valor que o novo tbn. Se você executou o passo 2a, isso é muito fácil e é simplesmente a nova taxa de quadros. Portanto, para fps alvo 45, new tbndeveria ser 45.


3. Gere vídeo fictício.

ffmpeg -f lavfi -i color=s=1280x720:r=45:d=1 -profile:v main -video_track_timescale 45 0.mp4

Todas as propriedades devem ser iguais, como resolução, perfil H.264, formato de pixel, contagem de referências..etc para melhores resultados.


4Concatene os vídeos.

Primeiro crie um arquivo de texto

file '0.mp4'
file 'in-v30.mp4'

Então, o concat

ffmpeg -f concat -i list.txt -c copy -video_track_timescale 45 45fps.mp4

O arquivo de saída terá o segundo vídeo sendo reproduzido a 45 fps.

5. Agora, corte o preroll fictício

ffmpeg -ss 1.1 -i 45fps.mp4 -c copy -avoid_negative_ts make_zero in45.mp4

e você tem

Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 1757 kb/s, \
       45 fps, 45 tbr, 11520 tbn (default)

Eu disse que isso era complicado!

Responder2

ffmpeg -itsscale 1.0427083 -i input.mp4 -codec copy output.mp4

Isso desacelera corretamente um mp4 de 25 fps criado pelo Handbrake a partir de uma fonte de DVD PAL para 23,974 fps. O programa original é NTSC. O áudio permanece sincronizado durante todo o tempo de execução de 47 minutos. É muito rápido porque nenhuma decodificação/codificação está sendo feita. No entanto, existem falhas de áudio (quedas) em intervalos de aproximadamente 3 segundos. O mesmo resultado com vcodeca substituição do codec, exceto que, embora o vídeo não seja recodificado, o áudio é recodificado na metade da taxa de bits original e ainda apresenta falhas de dropout.

ffmpeg -itsscale 1.0427083 -i input.mp4 -vcodec copy -filter:a "atempo=0.959041" output.mp4

Isso elimina as interrupções de áudio, mas recodifica o áudio. Isso é muito mais rápido do que recodificar vídeo. A desvantagem restante é que o padrão é metade da taxa de bits de áudio original. Precisa descobrir como definir a taxa de bits de áudio para a recodificação.

Responder3

Usar-itsscaleno vídeo de entrada para obter uma mudança efetiva na taxa de quadros. Funciona bem com -vcodec copy.

Responder4

Você pode fazer isso usando o filtro bitstream setts. Isso também evita o incômodo de gravar um fluxo bruto em um arquivo e, em seguida, remixá-lo. Isso funciona porque embora você não possa usar filtros normais com cópia de codec ( -c:v copy), já que eles funcionam no fluxo de vídeo decodificado, você pode usar filtros de fluxo de bits que funcionam no fluxo codificado.

Por exemplo, para alterar a taxa de quadros para 60 fps, insira

-bsf:v setts=ts=STARTPTS+N/TB_OUT/60

Isso deve definir ambos ptse dtssem decodificar o fluxo. Se você tiver um vídeo com taxa de quadros variável, talvez precise de algo assim

-bsf:v setts=ts='if(PREV_OUTPTS+9223372036854775808\,PREV_OUTPTS\,STARTPTS)+PREV_OUTDURATION*2'

Isto modifica as durações do quadro em vez de assumir que cada quadro tem uma duração constante. A expressão estranha ifé garantir que o primeiro quadro seja deslocado corretamente, uma vez que PREV_OUTPTSestá definido como -9223372036854775808(valor mínimo de int de 64 bits) durante o primeiro quadro, e precisamos substituí-lo por zero.

Se você tiver quadros B, isso pode atrapalhar a decodificação, pois dtspode precisar ser menor que pts, mas parece funcionar bem para mim de qualquer maneira. Você pode tentar substituir setts=tspor setts=ptsse tiver problemas. Verhttps://ffmpeg.org/ffmpeg-bitstream-filters.html#settspara detalhes

informação relacionada