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...
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.
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.
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;}'
Où
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] = =
Où
Utilisation ffprobe -show_frames -pretty <stream>
pour identifier les images clés.
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
Exécutez ffprobe et collectez les emplacements des trames I à partir de la sortie
ffprobe -show_streams
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]