Cómo cambiar la velocidad de fotogramas de un video sin volver a codificar

14

Estoy tratando de cambiar la velocidad de fotogramas de un video MP4 (es un video GoPro de 120 fps, quiero reproducirlo a 30 fps para un efecto de cámara lenta).

Estoy usando avconv para esto:

avconv -i SourceMovie.mp4 -vf setpts=4.0*PTS -r 30 DestMovie.mp4

Eso técnicamente funciona, pero vuelve a codificar la película. Además de ser lento, obviamente es un problema de calidad. Técnicamente debería haber una manera de configurar los fps en el encabezado del video, ¿cómo puedo cambiar eso? (Cualquier herramienta que no sea avconv también funcionaría).

EboMike
fuente

Respuestas:

15

MP4Box puede hacerlo.

El comando

MP4Box -add SourceMovie.mp4#video -raw 1 -new test

crea los archivos testy test_track1.h264. Ahora puede crear un archivo mp4 con la velocidad de fotogramas admitida que desee (30 en este ejemplo):

MP4Box -add test_track1.h264:fps=30 -new DestMovie.mp4

MP4Box es parte del gpacpaquete, así que asegúrese de que esté instalado.

Mitch
fuente
66
Realmente no es sencillo, pero lo entendí: debes hacerlo en dos pasos. Primero extraiga la transmisión de video por separado como raw ( MP4Box -add source.mp4#video -raw 1 -new test) y luego guárdela como MP4 nuevamente ( MP4Box -add test_track1.h264:fps=30 -new dest.mp4). También puede agregar una pista de audio allí (a través de #audio).
EboMike
Es mejor usar la -singleopción para el primer comando. MP4Box -single 1 -raw 1 SourceMovie.mp4crea solo un archivo en SourceMovie_track1.h264lugar de dos.
diversenok
6

Cambiar la velocidad de fotogramas en el encabezado del video (contenedor) no tiene ningún efecto en la videostream (o audiostream) en sí. La recodificación es la única opción.

Videostreams tiene marcas de tiempo y en la mayoría de los videos los cuadros son interdependientes entre sí debido a la compresión entre cuadros. Algunos jugadores pueden acelerar y ralentizar el video, pero no mediante comandos integrados o algo así. Ningún jugador puede cambiar la velocidad de fotogramas sobre la marcha cuando un comando de contenedor lo solicita. El archivo de video terminará fuera de las especificaciones (es decir, no seguirá los estándares) y el 99.9% de los jugadores se negarán a cumplirlo. Es imposible hacer lo que quiere sin recodificar. Por supuesto, puede esperar con la recodificación hasta el último paso en su edición.

thom
fuente
1
Gracias Thom! Pregunta estúpida, ¿por qué? ¿Cada cuadro tiene una marca de tiempo que obliga al jugador a imponer una determinada velocidad de reproducción? Quiero exactamente los mismos cuadros, solo quiero que se reproduzcan a una velocidad diferente.
EboMike
2
Hola Mike, no, tu pregunta no es estúpida, francamente, la forma en que crees que es bastante inteligente. Me gusta tu forma de pensar. Agregué más información a mi respuesta porque era demasiado largo para poner esto en el cuadro de comentarios.
Tom
¡Gracias! Eso es bastante informativo. Ahora, en cuanto a la recodificación, ¿cuál es la mejor manera de hacerlo con algo como avconv? Utilicé la línea de comando anterior, pero eso resultó en una calidad horrible: casi podía ver cada macrobloque.
EboMike
1
Las marcas de tiempo en las secuencias de video se almacenan en el contenedor, no en la secuencia de bits h.264 en sí, creo. Siempre que solo desee cambiar el tiempo, pero no el orden, de qué cuadro se muestra cuando, no debería necesitar transcodificar, solo remux. (Y si hace xcode, con un hardware más rápido, usaría -preset slower o veryslow para obtener más calidad a la MISMA tasa de bits, en lugar de simplemente arrojar más bits al problema. Y use -crf 18 o algo así, no ABR)
Peter Cordes
1
Sin embargo, no puedo entender cómo hacer que ffmpeg produzca una velocidad de fotogramas diferente. Parece que mkvmerge / mp4box son necesarios, a menos que pueda obtener ffmpeg para generar un flujo de bits sin formato de .264, y luego usar la opción fps para el demuxer h.264 (que -h documentos completos que tiene, ya que el flujo de bits no tiene tiempo info, solo ordenando.)
Peter Cordes
3

En el caso de que su intención principal sea reproducirlo en cámara lenta, y no mantener el archivo como MP4, puede usar la herramienta GUI MKVmerge para remuxarlo a un contenedor Matroska que puede cambiar fácilmente la velocidad de fotogramas. Remuxing es mucho mejor que volver a codificar, porque solo cambia los metadatos, y no la secuencia en sí.

Primero instalas el paquete

sudo apt-get install mkvtoolnix-gui

Luego inicia MKVmerge GUI. Te enfrentarás a una ventana como esta

mkvmerge gui 1

Simplemente presione el botón Agregar y seleccione su archivo o simplemente arrastre y suelte el archivo en el área "Archivos de entrada". En este punto, debería poder seleccionar la transmisión de video en su video. También puede eliminar otras transmisiones, ya que de todos modos se interpondrán en el camino.

Una vez que lo haya seleccionado, debería ver que las pestañas inferiores se activan:

ingrese la descripción de la imagen aquí

Cambiar a "Formatear acciones específicas"

ingrese la descripción de la imagen aquí

Puede ver que hay un campo "FPS", donde puede ingresar el valor de fotogramas por segundo. Parecía que planeabas ralentizar las cosas cuatro veces, por lo que tu objetivo sería aproximadamente 7 fotogramas por segundo. También puede usar la opción "Estirar por".

Después de eso, puede cambiar el nombre del archivo de salida (si lo desea) y presionar "Iniciar muxing".

El programa se ejecutará y deberías tener tu archivo.

v010dya
fuente
2

También quería ralentizar sin pérdidas mis películas de 120 FPS a 30 FPS. Hice un script que lo hace cambiando el tempo del sonido y modificando FPS directamente en el contenedor MP4. Se requieren las siguientes herramientas:

  1. avconv para convertir transmisiones de audio
  2. sondstretch para ralentizar el tempo de audio
  3. gpac para hacer que MP4Box cambie FPS

La secuencia de comandos utilizada para la conversión está aquí:

#!/bin/bash
#########################################
# Lossless slow down from 120 to 30 FPS #
#                                       #
# Use:                                  #
#                                       #
#   slow.bash <mp4_file>                #
#                                       #
#                           #-= OSi =-# #
#########################################


# Prepare basic variables
IN_FILE="$1"
NAME=$(echo "${IN_FILE}" | sed 's/\.[^.]*//')


# Clean up before start
rm -f "${NAME}.ac3" "${NAME}.wav" "${NAME}_.wav" "${NAME}" "${NAME}_track1.h264" "${NAME}_slow.mp4"


# Slow down sound
avconv -i "${IN_FILE}" -vn -acodec pcm_s16le "${NAME}_.wav"
soundstretch "${NAME}_.wav" "${NAME}.wav" -tempo=-75
avconv -i "${NAME}.wav" -vn -codec:a ac3_fixed -b:a 448k "${NAME}.ac3"


# Change video frame rate and multiplex with slowed sound
MP4Box -add "${IN_FILE}#video" -raw 1 -new "${NAME}"
MP4Box -add "${NAME}_track1.h264:fps=30" -add "${NAME}.ac3" -new "${NAME}_slow.mp4"


# Clean up when we are done
rm -f "${NAME}.ac3" "${NAME}.wav" "${NAME}_.wav" "${NAME}" "${NAME}_track1.h264"

Este script crea una copia de MP4 con _slow postfix.

OSi
fuente