Cambiar la velocidad de fotogramas en ffmpeg sin volver a codificar

14

Tengo un video mkv (h264) que es 23.976 fps (24000/1001) pero quiero convertirlo a 25 fps sin volver a codificar 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 De acuerdo con los documentos, esto debería funcionar:

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

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

phate89
fuente
1
Creo que eso no es posible con FFmpeg en este momento. -rno es compatible con la copia de flujo y no hay filtros de flujo de bits para cambiar la velocidad de fotogramas.
Ely
1
demasiado. Tendré que usar mkvmerge cada vez. gracias
phate89
1
Hay una forma complicada de hacer esto con ffmpeg regular y una forma directa de hacerlo con una versión modificada antigua de ffmpeg. Si está interesado, lo escribiré como respuesta.
Gyan
1
Sí, gracias ... Me gustaría hacerlo sin herramientas adicionales (ya necesito ffmpeg)
phate89
1
@Mulvya estás hablando de esto ¿verdad? Dudé en vincularlo, pero ahora es viejo. Sin embargo, estoy interesado en la forma complicada de hacerlo con FFmpeg regular.
Ely

Respuestas:

15

Este es el método que usa 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.

Esencialmente, 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 origen, 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 integral 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 debe tener el mismo valor que el nuevo tbn. Si realizó el paso 2a, esto es muy fácil y es simplemente la nueva velocidad de fotogramas. Entonces, para fps objetivo 45, tbndebería ser nuevo 45.


3 . Generar video 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.


4 Concat los videos.

Primero haz 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, corta el preroll falso

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!

Gyan
fuente
1
Muy inteligente, buena respuesta.
Rowe Morehouse