web-dev-qa-db-fra.com

ffmpeg - supprime les trames en double séquentiellement

Existe-t-il un moyen de détecter les images en double dans la vidéo à l'aide de ffmpeg.

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

33
metlira

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

  • Cela générera une lecture de la console indiquant les images que le filtre pense être 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


Th setpts l'expression de filtre génère des horodatages fluides pour une vidéo à FRAME_RATE fps. Voir une explication des horodatages sur Qu'est-ce que l'échelle de temps vidéo, la base de temps ou l'horodatage dans ffmpeg?

48
Gyan

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 une audio désynchronisée, j'ai donc dû explorer plus d'options:

mpdecimate vs decimate filtres

  • mpdecimate est la recommandation standard que j'ai trouvée partout SO et Internet, mais je ne pense pas que ce devrait être le premier choix
    • il utilise l'heuristique donc il peut et va sauter des images en double
    • vous pouvez modifier la détection avec le paramètre frac, mais c'est un travail supplémentaire que vous voudrez peut-être éviter si vous le pouvez
    • il n'est pas vraiment censé fonctionner avec le conteneur mp4 ( source ), mais j'utilisais mkv donc cette limitation ne s'appliquait pas sur mon cas, mais bon d'en être conscient
  • decimate supprime les cadres avec précision, mais il n'est utile que pour les doublons périodiques

taux de trame détecté vs réel

  • vous avez donc un fichier multimédia avec des images en double, c'est une bonne idée de vous assurer que la fréquence d'images détectée correspond à la fréquence réelle
  • ffprobe in.mkv Affichera le FPS détecté; ça peut ressembler à ça

    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 fréquence d'images réelle peut être déterminée si vous ouvrez le média in.mkv dans un lecteur multimédia qui vous permet de passer d'une image à la fois; puis comptez les étapes nécessaires pour faire avancer le temps de lecture pendant 1 seconde, dans mon cas c'était 30 fps

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

qu'est-ce que N/FRAME_RATE/TB

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

    Réglez un taux fixe de 25 images par seconde:
    setpts=N/(25*TB)

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

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

Variable FRAME_RATE Vs valeur FPS 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 exemple, les deux sont 30 fps ), vous pouvez utiliser la variable FRAME_RATE dans N/FRAME_RATE/TB
  • mais si le FPS détecté diffère, vous devez calculer le FRAME_RATE par vous-même
    • dans mon cas, mon FPS réel était de 30 images par seconde et j'ai supprimé toutes les 6 images, donc le FPS cible est 25 ce qui conduit à N/25/TB
      • si j'utilisais FRAME_RATE (et j'ai vraiment essayé) cela prendrait les mauvais fps détectés de 25 trames ie FRAME_RATE=25, exécutez-le via le filtre mpdecimate qui supprimerait toutes les 6 trames et il serait mis à jour vers FRAME_RATE=20.833 afin que N/FRAME_RATE/TB soit en fait N/20.833/TB qui est complètement faux

utiliser ou ne pas utiliser setpts

  • donc le filtre setpts est déjà devenu assez compliqué, en particulier à cause du désordre FPS que les images en double peuvent créer
  • la bonne nouvelle est que vous n'avez peut-être pas du tout besoin du filtre setpts
  • voici ce que j'ai utilisé avec de bons résultats

    ffmpeg -i in.mkv -vf mpdecimate out.mkv

    ffmpeg -i in.mkv -vf decimate=cycle=6,setpts=N/25/TB out.mkv

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

    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

  • comme tu vois

    • mpdecimate et decimate 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 filtre et en outre, je dois éviter la variable FRAME_RATE et utiliser N/25/TB à la place 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 résolu le problème de désynchronisation audio pour moi, mais vous voulez l'utiliser quelque chose comme ça -af 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 inutile supplémentaire, surtout lorsque ma vidéo avait l'audio synchronisé au début, il est donc préférable d'utiliser des commandes qui le garderont ainsi au lieu de le réparer plus tard

tl; dr

Si la commande habituellement recommandée ffmpeg -i in.mkv -vf mpdecimate,setpts=N/FRAME_RATE/TB out.mkv Ne fonctionne pas pour vous, essayez ceci:

ffmpeg -i in.mkv -vf mpdecimate out.mkv

ou

ffmpeg -i in.mkv -vf decimate=cycle=6,setpts=N/25/TB out.mkv

(cycle=6 Car chaque 6ème image est en double et N/25/TB Car après avoir supprimé les doublons, la vidéo aura 25 ips (évitez la variable FRAME_RATE); Ajustez en fonction de votre cas d'utilisation)

13