56 votes

Suppression des images dupliquées séquentiellement lors de l'utilisation de FFmpeg

Existe-t-il un moyen de détecter les images dupliquées dans la vidéo à l'aide de la fonction ffmpeg ?

J'ai essayé -vf drapeau avec select=gt(scene\,0.xxx) pour le changement de scène. Mais, cela n'a pas fonctionné dans mon cas.

81voto

Gyan Points 28168

Utilisez le mpdecimate dont le but est de "supprimer les images qui ne diffèrent pas beaucoup de l'image précédente afin de réduire la fréquence d'images".

  • Cela va générer un affichage sur la console montrant les images que le filtre considère comme des doublons.

    ffmpeg -i input.mp4 -vf mpdecimate -loglevel debug -f null -
  • Pour générer une vidéo avec les doublons supprimés

    ffmpeg -i input.mp4 -vf mpdecimate,setpts=N/FRAME_RATE/TB out.mp4

El setpts L'expression du filtre génère des timestamps lisses pour une vidéo à FRAME_RATE FPS. Pour une explication de l'horodatage, voir Qu'est-ce que l'échelle de temps vidéo, la base de temps ou le timestamp dans ffmpeg ?

0 votes

C'est ce que je cherche. merci !

0 votes

Moi aussi ! Merci beaucoup !

1 votes

C'est ce que j'ai fait, et ça a très bien marché, merci. En prime, le fichier mp4 contenait beaucoup moins de mégaoctets, même s'il ne contenait que quelques images.

37voto

J'ai également eu ce problème et l'excellente réponse de Gyan ci-dessus m'a permis de démarrer, mais le résultat était un son désynchronisé et j'ai dû explorer d'autres options :

mpdecimate vs décimer filtres

  • mpdecimate est la recommandation standard que j'ai trouvée partout dans SO et sur internet, mais je ne pense pas qu'il devrait être le premier choix.
    • il utilise l'heuristique, donc il peut et va sauter certaines images en double.
    • vous pouvez ajuster la détection avec frac mais c'est un travail supplémentaire que vous voudrez peut-être éviter si vous pouvez
    • il n'est pas vraiment censé fonctionner avec mp4 conteneur ( source ), mais j'utilisais mkv Cette limitation ne s'applique donc pas à mon cas, mais il est bon d'en être conscient.
  • decimate supprime les cadres avec précision, mais n'est utile que pour les doublons qui se produisent périodiquement.

Taux d'images détecté et réel

  • si vous avez un fichier multimédia avec des images en double, il est bon de s'assurer que la fréquence d'images détectée correspond à la fréquence réelle.

  • ffprobe in.mkv affichera le nombre d'images par seconde détectées ; cela peut ressembler à ceci

    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)

  • le taux de trame réel peut être trouvé si vous ouvrez le média in.mkv dans un lecteur multimédia qui vous permet d'avancer d'une image à la fois, puis de compter les étapes nécessaires pour avancer la lecture d'une seconde, dans mon cas c'était 30 fps

  • pas une grande surprise pour moi, parce que chaque 6ème image était un double (5 bonnes images et 1 double), donc après 25 bonnes images il y avait aussi 5 doubles

ce qui est N/FRAME_RATE/TB

  • sauf l'utilisation de FRAME_RATE variable le N/FRAME_RATE/TB est égal à l'exemple ci-dessous tiré de la documentation de ffmpeg ( source )

    Définir une fréquence fixe de 25 images par seconde :
    setpts=N/(25*TB)

  • les mathématiques derrière tout cela parfaitement expliquées dans Qu'est-ce que l'échelle de temps vidéo, la base de temps ou le timestamp dans ffmpeg ?

    • il calcule essentiellement l'horodatage pour chaque image et le multiplie avec la base de temps. TB pour améliorer la précision

FRAME_RATE valeur FPS variable ou littérale (par exemple 25)

  • C'est pourquoi il est important de connaître votre FPS détecté et réel.
  • si le FPS détecté correspond à votre FPS réel (par ex. les deux sont 30 fps ), vous pouvez sans problème utiliser FRAME_RATE variable dans N/FRAME_RATE/TB
  • mais si les FPS détectés diffèrent, vous devez calculer la valeur de la FRAME_RATE sur votre propre
    • dans mon cas, mon FPS réel était 30 images par seconde et j'ai enlevé toutes les 6 images, donc le FPS cible est 25 ce qui conduit à N/25/TB
      • si j'ai utilisé FRAME_RATE (et j'ai vraiment essayé) il prendrait les mauvaises fps détectées de 25 cadres, c'est-à-dire FRAME_RATE=25 et le faire passer par mpdecimate qui supprimerait toutes les 6 images et mettrait à jour FRAME_RATE=20.833 donc N/FRAME_RATE/TB serait en fait N/20.833/TB ce qui est complètement faux

à utiliser ou à ne pas utiliser setpts

  • donc le setpts Le filtre est déjà assez compliqué, surtout à cause des problèmes de FPS que les images dupliquées peuvent créer.

  • la bonne nouvelle est que vous n'avez peut-être pas besoin de la setpts filtre du tout

  • Voici ce que j'ai utilisé avec bons résultats

    [ffmpeg](https://linux.die.net/man/1/ffmpeg) -i in.mkv -vf [mpdecimate](https://ffmpeg.org/ffmpeg-filters.html#mpdecimate) out.mkv

    [ffmpeg](https://linux.die.net/man/1/ffmpeg) -i in.mkv -vf [decimate](https://ffmpeg.org/ffmpeg-filters.html#decimate-1)=cycle=6,[setpts](https://ffmpeg.org/ffmpeg-filters.html#setpts)=N/25/TB out.mkv

  • mais ce qui suit m'a donné audio désynchronisé

    [ffmpeg](https://linux.die.net/man/1/ffmpeg) -i in.mkv -vf [mpdecimate](https://ffmpeg.org/ffmpeg-filters.html#mpdecimate),[setpts](https://ffmpeg.org/ffmpeg-filters.html#setpts)=N/FRAME_RATE/TB out.mkv

    [ffmpeg](https://linux.die.net/man/1/ffmpeg) -i in.mkv -vf [mpdecimate](https://ffmpeg.org/ffmpeg-filters.html#mpdecimate),[setpts](https://ffmpeg.org/ffmpeg-filters.html#setpts)=N/25/TB out.mkv

    [ffmpeg](https://linux.die.net/man/1/ffmpeg) -i in.mkv -vf [decimate](https://ffmpeg.org/ffmpeg-filters.html#decimate-1)=cycle=6 out.mkv

  • comme vous le voyez

    • mpdecimate y décimer ne fonctionne pas de la même manière
    • mpdecimate a mieux fonctionné pour moi sans setpts filtre
    • tandis que décimer nécessaire setpts et de plus, je dois éviter FRAME_RATE et utiliser la variable N/25/TB au lieu de cela, parce que le FPS réel n'a pas été détecté correctement.

note sur asetpts

  • il fait le même travail que setpts mais pour l'audio
  • cela n'a pas vraiment corrigé la désynchronisation audio pour moi mais vous voulez l'utiliser comme ceci -af [asetpts](https://ffmpeg.org/ffmpeg-filters.html#setpts_002c-asetpts)=N/SAMPLE_RATE/TB
  • peut-être que vous êtes censé ajuster le SAMPLE_RATE en fonction du ratio d'images dupliquées supprimées, mais cela me semble être un travail supplémentaire inutile, en particulier lorsque ma vidéo avait l'audio synchronisé au début, il est donc préférable d'utiliser des commandes qui maintiendront cette situation au lieu de la corriger plus tard.

en résumé

Si la commande habituellement recommandée [ffmpeg](https://linux.die.net/man/1/ffmpeg) -i in.mkv -vf [mpdecimate](https://ffmpeg.org/ffmpeg-filters.html#mpdecimate),[setpts](https://ffmpeg.org/ffmpeg-filters.html#setpts)=N/FRAME_RATE/TB out.mkv ne fonctionne pas pour vous, essayez ceci :

[ffmpeg](https://linux.die.net/man/1/ffmpeg) -i in.mkv -vf [mpdecimate](https://ffmpeg.org/ffmpeg-filters.html#mpdecimate) out.mkv

o

[ffmpeg](https://linux.die.net/man/1/ffmpeg) -i in.mkv -vf [decimate](https://ffmpeg.org/ffmpeg-filters.html#decimate-1)=cycle=6,[setpts](https://ffmpeg.org/ffmpeg-filters.html#setpts)=N/25/TB out.mkv

_( cycle=6 parce qu'une image sur six est dupliquée et N/25/TB parce qu'après avoir supprimé les doublons, la vidéo aura 25 fps (éviter les FRAME_RATE variable) ; adaptez à votre cas d'utilisation)_

1 votes

Le setpts est nécessaire avec le mp4 parce que c'est un muxer à frame rate constant. Ajouter -vsync vfr et supprimer setpts dans ma commande pour garder les images dédupliquées avec le même timestamp lors de la sauvegarde en mp4

0 votes

Add -vsync vfr and remove setpts in my command @Gyan --- C'est exactement ce que j'ai fait pour le cas d'utilisation avec mpdecimate En particulier, j'ai retiré le setpts et je n'ai même pas eu besoin du -vsync vfr . Tout est dans tl;dr section.

0 votes

The setpts is needed with mp4 because it is a constant frame rate muxer @Gyan --- c'est intéressant, mais remarquez aussi que si j'ai pu supprimer setpts du filtre de la mpdecimate cas d'utilisation du filtre (comme vous le suggérez), je a dû utiliser setpts pour le decimate usecase. Les deux sont mkv . Allez comprendre !

0voto

Hooman Points 321

J'ai essayé les solutions proposées ici et aucune d'entre elles ne semble fonctionner lorsqu'il s'agit de découper la vidéo et de conserver l'audio. Il existe une mpdecimate_trim qui fait un bon travail. Il liste essentiellement toutes les trames à abandonner (en utilisant mpdecimate ) et crée ensuite un filtre complexe pour couper toutes ces images (et l'audio correspondant) de la vidéo en divisant la vidéo et en n'incluant que la partie sans images dupliquées.

J'ai cependant dû modifier quelques options dans le code. Par exemple, dans mpdecimate_trim.py j'ai dû modifier cette ligne :

dframes2 = get_dframes(ffmpeg(True, "-vf", "mpdecimate=hi=576", "-loglevel", "debug", "-f", "null", "-").stderr)

Je devais détecter les doublons de manière un peu plus agressive, j'ai donc modifié le mpdecimate option pour mpdecimate=hi=64*32:lo=64*24:frac=0.05

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X