ffmpeg-elimina cuadros secuencialmente duplicados
duplicates (2)
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 decimate 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ísticas por lo que puede y saltará algunos marcos duplicados
- puede ajustar la detección con el parámetro
frac
, pero es un trabajo adicional que puede evitar si puede - en realidad no se supone que funcione con el contenedor
mp4
( source ), pero estaba usandomkv
por lo que esta limitación no se aplicó a mi caso, pero es bueno saberlo
-
decimate
elimina cuadros con precisión, pero es útil solo para duplicados que ocurren periódicamente
velocidad de fotogramas detectada vs real
- para que tenga un archivo multimedia con cuadros duplicados, es una buena idea asegurarse de que la velocidad de cuadros detectada coincida con la real
ffprobe in.mkv
emitirá 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 contenido multimedia
in.mkv
en un reproductor multimedia que le permite pasar un fotograma a la vez; luego cuente los pasos necesarios para avanzar el tiempo de reproducción durante 1 segundo, en mi caso fue de 30 fps- No fue una gran sorpresa para mí, porque cada sexto fotograma era duplicado (5 buenos fotogramas y 1 duplicado), así que después de 25 buenos fotogramas también había 5 duplicados.
¿Qué es N/FRAME_RATE/TB
excepto el uso de la variable
FRAME_RATE
, laN/FRAME_RATE/TB
es igual al siguiente ejemplo de la documentación de ffmpeg ( source )Establecer tasa fija de 25 cuadros por segundo:
setpts=N/(25*TB)
la matemática subyacente se explica 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
TB
base de tiempo para mejorar la precisión
- básicamente calcula la marca de tiempo para cada fotograma y la multiplica por
Variable FRAME_RATE
vs valor FPS literal (por ejemplo, 25)
- Por eso es importante conocer su FPS detectado y real
- Si el FPS detectado coincide con su FPS real (p. ej., ambos son 30 fps ), puede usar la variable
FRAME_RATE
enN/FRAME_RATE/TB
- pero si el FPS detectado difiere del que tiene que calcular el
FRAME_RATE
por su cuenta- en mi caso, mi FPS real fue de 30 cuadros por segundo y eliminé cada 6º cuadro, por lo que el FPS objetivo es de 25, lo que lleva a
N/25/TB
- si usé
FRAME_RATE
(y en realidad lo intenté) tomaría los fps detectados incorrectamente de 25 cuadros, es decir,FRAME_RATE=25
, ejecutarlo a través del filtrompdecimate
que eliminaría cada 6 cuadros y se actualizaría aFRAME_RATE=20.833
por lo queN/FRAME_RATE/TB
sería en realidadN/20.833/TB
cual es completamente incorrecto
- si usé
- en mi caso, mi FPS real fue de 30 cuadros por segundo y eliminé cada 6º cuadro, por lo que el FPS objetivo es de 25, lo que lleva a
usar o no usar setpts
- así que el filtro setpts ya se hizo bastante complicado, especialmente debido al desorden de FPS que pueden crear los cuadros duplicados
- la buena noticia es que puede que no necesite el filtro setpts 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
como ves
- mpdecimate y decimate no funciona de la misma manera
- mpdecimate funcionó mejor para mí sin filtros setpts
- Mientras setpts filtro de setpts necesario, setpts evitar la variable
FRAME_RATE
y usarN/25/TB
lugar porque el FPS real no se detectó correctamente
nota sobre asetpts
- hace el mismo trabajo que setpts pero para audio
- realmente no corrigió el audio desync para mí, pero quieres usarlo así:
-af asetpts =N/SAMPLE_RATE/TB
- tal vez
SAMPLE_RATE
ajustarSAMPLE_RATE
acuerdo con la proporción de fotogramas duplicados eliminados, pero me parece un trabajo adicional innecesario, especialmente cuando mi video tenía el audio sincronizado al principio, por lo que es mejor usar comandos que lo mantengan de esa manera en lugar de arreglarlo luego
tl; dr
Si el comando generalmente recomendado ffmpeg -i in.mkv -vf mpdecimate , setpts =N/FRAME_RATE/TB out.mkv
no funciona, intente 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 es duplicado y N/25/TB
porque después de eliminar los duplicados, el video tendrá 25 fps (evite la variable FRAME_RATE
); ajústelo a su caso de uso)
¿Hay alguna forma de detectar fotogramas duplicados dentro del video usando ffmpeg
?
-vf
indicador -vf
con select=gt(scene/,0.xxx)
para el cambio de escena. Pero, no funcionó para mi caso.
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 consola que muestra los cuadros que 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
setpts expresión de filtro de setpts genera marcas de tiempo suaves para un video a FRAME_RATE fps. Vea una explicación de las marcas de tiempo en ¿Qué es la escala de tiempo, la base de tiempo o la marca de tiempo de video en ffmpeg?