Cambiar la velocidad de fotogramas en ffmpeg sin volver a codificar

Cambiar la velocidad de fotogramas en ffmpeg sin volver a codificar

Tengo un video mkv (h264) que es de 23.976 fps (24000/1001) pero quiero convertirlo a 25 fps sin volver a codificarlo y perder calidad. Sé que mkvmerge puede hacerlo (con la opción --default-duration '0:25fps') pero me gustaría hacerlo directamente desde ffmpeg si es posible. Según los documentos, esto debería funcionar:

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

pero cuando lo ejecuto solo obtengo los mismos fps de video. ¿Cuál es el método correcto para hacerlo (si existe) en ffmpeg?

Respuesta1

Este es el método que utiliza las versiones actuales de FFmpeg. Se basa en que el demuxer concat no reescala el PTS de las entradas después del primer archivo, sino que simplemente aplica un desplazamiento fijo. Digamos que tiene una transmisión de 30 fps con una escala de tiempo de 15360(típica de salida FFmpeg). Eso significa que el marco 0tiene PTS 0y el marco 30tiene PTS 15360. Esto se convertiría en una transmisión de 45 fps si pudiéramos cambiar la escala de tiempo 23040sin afectar los valores de PTS.

Básicamente, eso es lo que hace el siguiente método.

1. Identificar las propiedades de origen.

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

Desea tener en cuenta las propiedades de la fuente, especialmente la resolución y tbn.


2a. (Opcional) Cambie la escala de tiempo a algo conveniente para simplificar los cálculos.

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

esto nos atrapa

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

Si realiza este paso, la nueva escala de tiempo debe ser igual o un múltiplo entero de la velocidad de fotogramas original.

2b. Calcule la escala de tiempo necesaria, de modo que para la velocidad de fotogramas objetivo x, el PTS del número de fotograma xen la fuente tenga el mismo valor que el nuevo tbn. Si realizaste el paso 2a, esto es muy fácil y es simplemente el nuevo framerate. Entonces, para los fps objetivo 45, new tbndebería ser 45.


3. Generar vídeo ficticio.

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

Todas las propiedades deben ser iguales, como resolución, perfil H.264, formato de píxeles, recuento de referencias, etc. para obtener mejores resultados.


4Concat los videos.

Primero crea un archivo de texto.

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

Entonces, el concat

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

El archivo de salida tendrá el segundo video reproduciéndose a 45 fps.

5. Ahora, corte el preroll ficticio.

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

y tu tienes

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

¡Dije que esto era complicado!

Respuesta2

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

Esto ralentiza correctamente un mp4 de 25 fps creado por Handbrake desde una fuente de DVD PAL a 23,974 fps. El programa original es NTSC. El audio permanece sincronizado durante todo el tiempo de ejecución de 47 minutos. Es muy rápido ya que no se realiza ninguna decodificación/codificación. Sin embargo, hay fallos de audio (interrupciones) en intervalos de aproximadamente 3 segundos. El mismo resultado con vcodecel códec sustituido, excepto que, aunque el vídeo no se vuelve a codificar, el audio se vuelve a codificar a la mitad de la tasa de bits original y aún tiene fallos de abandono.

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

Esto elimina las interrupciones de audio, pero vuelve a codificar el audio. Eso es mucho más rápido que volver a codificar el video. El inconveniente restante es que el valor predeterminado es la mitad de la velocidad de bits de audio original. Necesito descubrir cómo configurar la velocidad de bits de audio para la recodificación.

Respuesta3

Usar-itsscaleen el vídeo de entrada para lograr un cambio efectivo en la velocidad de fotogramas. Funciona bien con -vcodec copy.

Respuesta4

Puedes hacer esto usando el filtro de flujo de bits setts. Esto también evita la molestia de escribir una secuencia sin formato en un archivo y luego remuxificarla. Esto funciona porque, si bien no puedes usar filtros normales con copia de códec ( -c:v copy), ya que funcionan en la secuencia de video decodificada, puedes usar filtros de secuencia de bits que funcionan en la secuencia codificada.

Por ejemplo, para cambiar la velocidad de fotogramas a 60 fps, inserte

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

Esto debería configurar ambos ptsy dtssin decodificar la transmisión. Si tienes un vídeo con velocidad de fotogramas variable, es posible que necesites algo como esto en su lugar

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

Esto modifica las duraciones del cuadro en lugar de asumir que cada cuadro tiene una duración constante. La expresión de aspecto extraño ifes para garantizar que el primer fotograma esté desplazado correctamente, ya que PREV_OUTPTSestá establecido en -9223372036854775808(valor mínimo de int de 64 bits) durante el primer fotograma, y ​​debemos reemplazarlo con cero.

Si tiene fotogramas B, esto puede estropear la decodificación, ya que dtses posible que deba ser más pequeño que pts, pero de todos modos parece funcionar bien para mí. Puedes intentar reemplazar setts=tscon setts=ptssi tienes problemas. Verhttps://ffmpeg.org/ffmpeg-bitstream-filters.html#settspara detalles

información relacionada