Comment extraire des segments vidéo précis dans le temps avec ffmpeg?
ce n'est pas une question particulièrement Nouvelle ici, mais j'ai essayé ce qui a été suggéré là-bas sans beaucoup de chance. Donc, mon histoire:
j'ai un morceau de 15 secondes de droite de la caméra.vidéo mov à partir de laquelle je veux extraire un morceau spécifique, que je peux identifier par l'Heure de début et l'heure d'arrêt, en quelques secondes. J'ai commencé par essayer de faire ce que j'appellerai une "extraction de copie": pour obtenir les secondes 9 à 12,
ffmpeg -i test.mov -vcodec copy -acodec copy -ss 9 -to 12 test-copy.mov
C'était un pas mal comme début, mais il y a des cadres noirs au début et à la fin du clip, ce que je ne peux pas avoir -- ça doit être un montage propre à l'original. J'ai donc essayé de recoder l'original en un nouveau clip:
ffmpeg -i test.mov -ss 00:00:09 -t 00:00:03 test-out.mov
C'est mieux, mais pas tout à fait: Il n'existe plus de cadres noirs au début du clip, mais ils sont toujours là à la fin.
après un peu plus de navigation et de lecture, j'ai alors suspecté que le problème est que ffmpeg a du mal à trouver les bons points à cause d'un manque d'images clés dans la vidéo originale. J'ai donc recodé la vidéo originale pour (sans doute) ajouter des images clés, de plusieurs façons. Puisque je veux être en mesure de choisir la vidéo aux limites d'une seconde ("de 9 secondes à 12 secondes"), j'ai essayé, en copiant diverses suggestions autour du web,
ffmpeg -i test.mov -force_key_frames "expr:gte(t, n_forced)" test-forced.mp4
et
ffmpeg -i test.mov -g 1 test-g-inserted.mp4
(j'ai construit ces comme mp4's basé sur quelques commentaires au sujet d'un MP4 conteneur étant nécessaire pour soutenir la recherche d'image clé, mais je suis honnêtement juste le piratage ici. J'ai ensuite essayé l'extraction comme avant, mais sur ces nouvelles vidéos qui ont probablement maintenant des images clés. Aucune chance -- les deux semblent être à peu près les mêmes; le départ est correct mais il y a toujours des cadres noirs à la fin. (FWIW, deux tests forcés.mp4 et test-g-insérés.mp4 ont également des cadres noirs traînants.)
Donc: je suis toujours bloqué, et voudrais ne pas l'être. Des idées comme pour ce que je fais mal? J'ai l'impression d'être proche, mais j'ai vraiment besoin de me débarrasser de ces cadres noirs....
4 réponses
Ok, tout d'abord en supposant que vous connaissez la durée de démarrage et d'arrêt; nous allons ajouter des images-clés à cette durée.
ffmpeg -i a.mp4 -force_key_frames 00:00:09,00:00:12 out.mp4
la plupart du temps, vous pouvez directement couper la vidéo avec perfection, mais dans votre cas, il ne vous aide pas; donc, nous avons pris soin de lui par commande ci-dessus. Ici soyez prudent de ne pas ajouter trop de cadres de clés car il peut être un problème tout en encodant selon Ffmpeg Docs .
Maintenant, vous pouvez à nouveau essayer de couper la vidéo de temps spécifique.
ffmpeg -ss 00:00:09 -i out.mp4 -t 00:00:03 -vcodec copy -acodec copy -y final.mp4
cela résoudra le problème puisque nous avons ajouté manuellement les images clés aux points de début et de fin de la Coupe . Il a travaillé pour moi.
santé.:)
je pense que le problème que la question et les autres réponses ont est qu'ils utilisent -ss
comme une option sur le fichier de sortie, pas sur le fichier d'entrée. La plupart des options ffmpeg ne sont pas globales, mais s'appliquent seulement au fichier qu'elles précèdent. Il n'est souvent pas évident où une option doit aller, donc parfois des essais et des erreurs sont nécessaires.
utilisé correctement, avant le fichier d'entrée, ils sont censés s'appliquer à -ss
et -t
a bien fonctionné pour moi. En incluant l'audio dans la sortie, j'ai dû utiliser -shortest
comme une option pour le fichier de sortie, ou je recevais 2 minutes d'audio avec 2 secondes de vidéo.
ffmpeg version N-67413-g2a88c74 (essentiellement git source du 14 décembre 2014)
Voici une ligne de commande que j'ai utilisée pour faire un clip récemment. (en fait tweaked pour être un meilleur exemple, depuis que je suis parti en audio pour ceci, et n'a pas slo-mo it.)
ffmpeg -ss 120.2 -t 0.75 -i ../mcdeint.60p.lossless264.slow.mkv -c:a libopus -shortest -aspect 16:9 -preset veryslow -x264-params nr=250:ref=6 -crf 22 -movflags +faststart clip2.mkv
avec -c:a copy
(la source a AC3 audio), la lecture démarre avec mplayer. Il saisit probablement l'audio dès le début du cadre audio contenant le départ, puis doit utiliser un offset A/v dans le conteneur. Au démarrage, il faut une fraction de seconde pour que l'audio devance la vidéo par ce décalage, et d'ici là la vidéo passe à des FPS très bas. J'ai donc xcoded l'audio. Ni opus ni pcm_s16le ne peuvent aller dans mp4, donc j'ai utilisé un conteneur mkv pour cet exemple.
la source est un encodage sans perte x264 ( -qp 0
) de la sortie d'un yadif très lent=3:1,mcdeint=3:1:10 (sur une vidéo entrelacée BFF d'un DVD NTSC, probablement d'une caméra DV). Ce n'est pas tous les cadres I
, c'est les cadres P
avec un intervalle d'image-clé normal.
Réglage -ss de 0,2 secondes a fait exactement ce que j'espérais, donc ffmpeg doit assurer le décodage à point. Était pas juste une coïncidence d'un Je cadre où je le voulait. Peut-être que -accurate_seek
est la valeur par défaut? J'obtiens également le même résultat (byte-for-byte identique gif output) que lorsque j'utilise une source sans perte ffvhuff comme entrée. (mais il court plus vite, puisqu'il n'a pas à décoder jusqu'au point demandé.)
une autre option peut-être pertinente est -seek2any
, mais elle dit" chercher à non-keyframe au niveau de demuxer", ce qui sonne comme si cela vous permettrait de chercher de manière à produire une sortie brouillée. (c'est à dire de commencer le décodage sans en fait, générer les références que le cadre actuel nécessite, Il suffit d'utiliser tout-gris?)
Je n'ai pas essayé d'utiliser -c:v copy
, car je découpe un clip très court à Boucler, donc je sais qu'il n'y aura pas de cadres I
là où j'en ai besoin.
c'est la ligne de commande que j'ai utilisée, pour faire un court clip slo-mo sans son.
ffmpeg -ss 120.2 -t 0.75 -i ../vid.yadif3.1,mcdeint3.1.10.ffvhuff.mkv -an -shortest -aspect 16:9 -c:v libx264 -preset veryslow -x264-params nr=250:ref=6 -crf 22 -filter:v "setpts=3.0*PTS" -movflags +faststart -r 20 clip.mp4
notez que le -r 20
était important, parce que contrairement à mkv, la sortie MP4 de ffmpeg est constante-frame-rate-only (edit: parce que -vsync vfr
n'est pas la valeur par défaut avec le muxer mp4). Sans le dire autrement, il définirait la sortie FPS = entry FPS, et dupliquerait les cadres quand c'est nécessaire pour que cela se produise. x264 et GIF animé (avec transparence) peuvent tous les deux encoder des images dupliquées très efficacement, mais c'est quand même idiot.
Avant la cuisson cela comme un exemple, je l'avais fait en 2 étapes, une sortie à mkv, puis ffmpeg -i clip.mkv -c:v copy -movflags +faststart -r 20 clip.mp4
à remux. BTW, il est possible de changer les fps d'une vidéo en remuxing, sans xcoding, mais pas avec ffmpeg. https://superuser.com/questions/740196/reducing-video-size-with-avconv-why-does-the-size-increase . Mais de toute façon, ffmpeg n'a envoyé que 45 images à libx264 lors de la réalisation du mkv, même s'il pensait faire une vidéo de 2,2 secondes à 60fps. N'utilisez pas ffmpeg avec mp4 pour travailler avec des FPS variables.
edit: s'avère ffmpeg par défaut à -vsync vfr
pour la sortie mkv, mais pas pour mp4. Avec -vsync vfr
, ffmpeg peut écrire VFR en sortie mp4 très bien.
et de nouveau pour la sortie gif, dans le cas où je décide de ne pas le mettre en place avec HTML5 vidéo ( <video controls autoplay loop> <source src="clip.mp4" type="video/mp4"> </video>
)
ffmpeg -ss 120.2 -t 0.75 -i ../vid.yadif3.1,mcdeint3.1.10.ffvhuff.mkv -an -shortest -aspect 16:9 -filter:v "setpts=3.0*PTS,scale=854x480" -r 20 clip.gif
j'ai dû utiliser scale=
parce que le conteneur gif ne stocke pas un format d'image, donc il ne peut pas être auto-redimensionné sur la lecture. (mon 720 x 480 pixels 16:9 la vidéo est réduite à 854x480 en lecture. En fait devrait être 853.333, mais qui obtient arrondi, et puis les magasins ffmpeg 853x480 dans le conteneur mkv, donc en utilisant-aspect 16:9 tout le temps, de sorte que mon mp4 stockera le rapport d'aspect approprié [SAR 32:27 DAR 16:9]
, au lieu de [SAR 186:157 DAR 279:157]
)
il n'est pas nécessaire d'ajouter des images clés; comme le dit Peter, il s'agit simplement d'obtenir les options dans le bon ordre. Voir https://trac.ffmpeg.org/wiki/Seeking pour le guide officiel et définitif sur la façon de le faire correctement.
j'aimerais savoir aussi. Jusqu'à présent, j'ai converti mes vidéos sans perte, extrait un segment et les ré-encodé après avoir édité:
ffmpeg -i input -ss 9.48 -t 3.52 -c:v libx264 -crf 0 -g 1 -c:a copy TempIframe.mp4
mais c'est un processus qui prend du temps et de la perte...
j'ai essayé le suivant sans succès:
ffmpeg -i source.mp4 -ss 1 -c:v copy -seek2any 1 -avoid_negative_ts 1 -safe 1 -c:a copy segment.mp4