Solución:
Utilice el filtro mpdecimate, cuyo propósito es “Eliminar fotogramas que no difieran mucho del fotograma anterior para reducir la velocidad de fotogramas”.
-
Esto generará una lectura de la consola que muestra qué fotogramas el filtro cree que son duplicados.
ffmpeg -i input.mp4 -vf mpdecimate -loglevel debug -f null -
-
Para generar un video con los duplicados eliminados
ffmpeg -i input.mp4 -vf mpdecimate,setpts=N/FRAME_RATE/TB out.mp4
La expresión del filtro setpts genera marcas de tiempo suaves para un video en FRAME_RATE
FPS. Consulte una explicación de las marcas de tiempo en ¿Qué es la escala de tiempo, la base de tiempo o la marca de tiempo del video en ffmpeg?
También tuve este problema y la excelente respuesta de Gyan anterior me ayudó a comenzar, pero el resultado fue un audio desincronizado, así que tuve que explorar más opciones:
mpdecimate vs diezmar filtros
mpdecimate
es la recomendación estándar que encontré en todo SO e Internet, pero no creo que deba ser la primera opción- utiliza heurística, por lo que puede omitir algunos fotogramas duplicados
- puedes modificar la detección con
frac
parámetro, pero es un trabajo adicional que quizás desee evitar si puede - realmente no se supone que funcione con
mp4
contenedor (fuente), pero estaba usandomkv
así que esta limitación no se aplicó en mi caso, pero es bueno estar al tanto
decimate
Elimina marcos con precisión, pero es útil solo para duplicados que ocurren periódicamente.
velocidad de fotogramas detectada frente a real
- para que tenga un archivo multimedia con fotogramas duplicados, es una buena idea asegurarse de que la velocidad de fotogramas detectada coincida con la real
-
ffprobe in.mkv
generará el FPS detectado; puede verse asíStream #0:0: Video: h264 (Main), yuvj420p(pc, bt709, progressive), 1920x1080, SAR 1:1 DAR 16:9, 25 fps, 25 tbr, 1k tbn, 50 tbc (default)
-
la velocidad de fotogramas real se puede averiguar si abre el medio
in.mkv
en un reproductor multimedia que le permite avanzar un fotograma a la vez; luego cuente los pasos necesarios para avanzar el tiempo de reproducción durante 1 segundo, en mi caso fue 30 fps - no es una gran sorpresa para mí, porque cada sexto fotograma estaba duplicado (5 fotogramas buenos y 1 duplicado), así que después de 25 fotogramas buenos también había 5 duplicados
que es N/FRAME_RATE/TB
-
excepto el uso de
FRAME_RATE
variable laN/FRAME_RATE/TB
es igual al siguiente ejemplo de la documentación de ffmpeg (fuente)Establezca una velocidad fija de 25 fotogramas por segundo:
setpts=N/(25*TB)
-
las matemáticas detrás de esto se explican perfectamente en ¿Qué es la escala de tiempo, la base de tiempo o la marca de tiempo del video en ffmpeg?
- Básicamente, calcula la marca de tiempo para cada fotograma y la multiplica por la base de tiempo.
TB
para mejorar la precisión
- Básicamente, calcula la marca de tiempo para cada fotograma y la multiplica por la base de tiempo.
FRAME_RATE
variable vs valor literal de FPS (por ejemplo, 25)
- por eso es importante conocer su FPS detectado y real
- si el FPS detectado coincide con su FPS real (por ejemplo, ambos son 30 fps) puedes usar felizmente
FRAME_RATE
variable enN/FRAME_RATE/TB
- pero si el FPS detectado difiere de lo que tiene que calcular el
FRAME_RATE
por tu cuenta- en mi caso, mi FPS real fue 30 fotogramas por segundo y eliminé cada sexto fotograma, por lo que el FPS objetivo es 25 lo que lleva a
N/25/TB
- si yo usara
FRAME_RATE
(y de hecho lo intenté) tomaría los fps detectados incorrectamente de 25 marcos es decirFRAME_RATE=25
, ejecutarlompdecimate
filtro que eliminaría cada sexto fotograma y se actualizaría aFRAME_RATE=20.833
asi queN/FRAME_RATE/TB
realmente seríaN/20.833/TB
que esta completamente mal
- si yo usara
- en mi caso, mi FPS real fue 30 fotogramas por segundo y eliminé cada sexto fotograma, por lo que el FPS objetivo es 25 lo que lleva a
usar o no usar setpts
- por lo que el filtro de setpts ya se volvió bastante complicado, especialmente debido al desorden de FPS que pueden crear los fotogramas duplicados
- la buena noticia es que es posible que no necesite el filtro de configuración en absoluto
-
esto es lo que usé con Buenos resultados
ffmpeg -i in.mkv -vf mpdecimate out.mkv
ffmpeg -i in.mkv -vf decimate=cycle=6,setpts=N/25/TB out.mkv
-
pero lo siguiente me dio audio desincronizado
ffmpeg -i in.mkv -vf mpdecimate,setpts=N/FRAME_RATE/TB out.mkv
ffmpeg -i in.mkv -vf mpdecimate,setpts=N/25/TB out.mkv
ffmpeg -i in.mkv -vf decimate=cycle=6 out.mkv
-
como ves
- mpdecimate y diezmar no funciona de la misma manera
- mpdecimate funcionó mejor para mí sin el filtro de setpts
- mientras diezma el filtro de setpts necesarios y, además, necesito evitar
FRAME_RATE
variable y usoN/25/TB
en cambio, porque el FPS real no se detectó correctamente
nota sobre asetpts
- hace el mismo trabajo que setpts pero para audio
- Realmente no solucionó la desincronización del audio para mí, pero quieres usarlo de esta manera
-af asetpts=N/SAMPLE_RATE/TB
- tal vez se supone que debes ajustar el
SAMPLE_RATE
de acuerdo con la proporción de fotogramas duplicados eliminados, pero me parece un trabajo extra innecesario, especialmente cuando mi video tenía el audio sincronizado al principio, por lo que es mejor usar comandos que lo mantengan así en lugar de arreglarlo más tarde
tl; dr
Si el comando generalmente recomendado ffmpeg -i in.mkv -vf mpdecimate,setpts=N/FRAME_RATE/TB out.mkv
no funciona para ti, prueba esto:
ffmpeg -i in.mkv -vf mpdecimate out.mkv
o
ffmpeg -i in.mkv -vf decimate=cycle=6,setpts=N/25/TB out.mkv
(cycle=6
porque cada sexto fotograma está duplicado y N/25/TB
porque después de eliminar los duplicados el video tendrá 25 fps (evite el FRAME_RATE
variable); ajustar para su caso de uso)
Aquí tienes las reseñas y calificaciones
Ten en cuenta mostrar este ensayo si te fue útil.