web-dev-qa-db-fra.com

Comment diviser une vidéo en utilisant FFMPEG pour que chaque morceau commence par une image clé?

Nous devons diviser un grand flux vidéo WMV en direct en petits morceaux de même taille. Nous avons fait un script qui fonctionne très bien en faisant cela, sauf pour une chose: les morceaux vidéo ne commencent pas par une image clé, donc lors de la lecture de la plupart des morceaux vidéo, ils n'affiche aucune image jusqu'à ce qu'une image clé de la vidéo originale soit finalement atteint.

N'y a-t-il pas un moyen de dire à ffmpeg de faire démarrer la vidéo de sortie avec une image clé?

Voici à quoi ressemblent nos lignes de commande en ce moment:

ffmpeg.exe -i "C:\test.wmv" -ss 00:00:00 -t 00:00:05 -acodec copy -vcodec copy -async 1 -y  "0000.wmv"
ffmpeg.exe -i "C:\test.wmv" -ss 00:00:05 -t 00:00:05 -acodec copy -vcodec copy -async 1 -y  "0001.wmv"

etc...

32
sboisse

Les dernières versions de FFMPEG incluent une nouvelle option "segment" qui fait exactement ce dont je pense que vous avez besoin.

ffmpeg -i INPUT.mp4 -acodec copy -f segment -vcodec copy -reset_timestamps 1 -map 0 OUTPUT%d.mp4

Cela produit une série de fichiers de sortie numérotés qui sont divisés en segments en fonction des images clés. Dans mes propres tests, cela a bien fonctionné, même si je ne l'ai utilisé sur rien de plus que quelques minutes et uniquement au format MP4.

29
Tim Bull

Comme indiqué sur le site officiel FFMPEG Docs , cela a mieux fonctionné pour moi de spécifier -ss timestart avant -i input_file.ext, car il définit (ou je comprends) le début de la vidéo générée sur l'image clé la plus proche trouvée avant l'horodatage spécifié.

Changez votre exemple en:

ffmpeg.exe -ss 00:00:00 -i "C:\test.wmv" -t 00:00:05 -acodec copy -vcodec copy -async 1 -y  "0000.wmv"

J'ai testé cette méthode en travaillant sur .flv et .mp4 des dossiers.

29

L'utilisation d'une version plus récente de ffmpeg peut y parvenir en utilisant ffprobe et le multiplexeur de segments ffmpeg.

1.Utilisez ffprobe et awk pour identifier les images clés aussi près que possible de la longueur de bloc souhaitée.

ffprobe -show_frames -select_streams v:0 -print_format csv **[SOURCE_VIDEO]** 2>&1 | grep -n frame,video,1 | awk 'BEGIN { FS="," } { print $1 " " $5 }' | sed 's/:frame//g' | awk 'BEGIN { previous=0; frameIdx=0; size=0; } { split($2,time,"."); current=time[1]; if (current-previous >= **[DURATION_IN_SECONDS]**){ a[frameIdx]=$1; frameIdx++; size++; previous=current;} } END { str=a[0]; for(i=1;i<size;i++) { str = str "," a[i]; } print str;}'

  • [SOURCE_VIDEO] = chemin vers la vidéo que vous souhaitez segmenter
  • [DURATION_IN_SECONDS] = longueur de segment souhaitée en secondes

La sortie est une chaîne d'images clés séparée par des virgules.

2.Utilisez la sortie des images clés ci-dessus comme entrée pour ffmpeg.

ffmpeg -i [SOURCE_VIDEO] -codec copy -map 0 -f segment -segment_frames [OUTPUT_OF_STEP_1] ​​[SEGMENT_PREFIX] _% 03d .([SOURCE_VIDEO_EXTENSION] = =

  • [SOURCE_VIDEO] = chemin vers la vidéo que vous souhaitez segmenter
  • [OUTPUT_OF_STEP_1] = chaîne d'images clés séparée par des virgules
  • [SEGMENT_PREFIX] = nom de la sortie du segment
  • [SOURCE_VIDEO_EXTENSION] = extension de la vidéo source (par exemple, mp4, mkv)
12
Steek

Utilisation ffprobe -show_frames -pretty <stream> pour identifier les images clés.

6
d33pika

Si vous êtes prêt à faire des scripts et que vous voulez des images I à un intervalle particulier, la seule façon de le faire est

  1. Exécutez ffprobe et collectez les emplacements des trames I à partir de la sortie

    ffprobe -show_streams

  2. Exécutez une série de commandes -ss -t en utilisant le même script pour obtenir les morceaux que vous désirez.

Vous pouvez ensuite faire en sorte que votre script décide du nombre minimum d'images [disons qu'il y a deux images I à 10 images l'une de l'autre, vous ne voulez vraiment pas les découper ici].

L'autre façon de le faire est d'utiliser le multisfilesink de gstreamer et de définir le mode sur l'image clé [cependant, cela se fragmentera à chaque image clé afin que ce ne soit pas idéal]

3
av501