我已经非常密切地浏览了互联网,但我找不到我需要的东西,只是它的变化并不是我想要使用的东西。
我有几个不同长度的视频,我想从开始到结束从每个视频中提取20张图片,以展示最广泛的视频印象。
所以一个视频是16米47s长=>总计1007s =>我必须每隔50秒制作一个视频快照。
所以我想使用ffmpeg的-r开关,其值为0.019860973(eq 20/1007),但是ffmpeg告诉我帧速率太小了......
我想出去做的唯一方法就是编写一个脚本,用一个被操纵的-ss开关调用ffmpeg并使用-vframes 1但这对我很慢而且有点偏离,因为ffmpegs会对图像本身进行计算...
有任何建议或指示吗?
谢谢, Vapire
答案 0 :(得分:16)
我知道我参加派对有点晚了,但我认为这可能会有所帮助:
对于每个人都有问题,ffmpeg为每一帧生成一个图像,这里是我如何解决它(使用blahdiblah的答案):
首先,我抓住了视频中的总帧数:
ffprobe -show_streams <input_file> | grep "^nb_frames" | cut -d '=' -f 2
然后我尝试使用select来抓取帧:
ffmpeg -i <input_file> -vf "select='not(mod(n,100))'" <output_file>
但是,无论mod(n,100)被设置为什么,ffmpeg都会吐出太多帧。我不得不添加-vsync 0来纠正它,所以我的最终命令看起来像这样:
ffmpeg -i <input_file> -vsync 0 -vf "select='not(mod(n,100))'" <output_file>
(其中100是你想要使用的帧频,例如,每100帧一次)
希望能帮助别人省点麻烦!
答案 1 :(得分:14)
我也试图找到这个问题的答案。我利用了拉德里的答案,但发现它有一个错误。
ffmpeg -i video.avi -r 0.5 -f image2 output_%05d.jpg
每2秒产生一帧,因为-r表示帧速率。在这种情况下,每秒0.5帧,或每2秒1帧。
使用相同的逻辑,如果您的视频长度为1007秒,并且您只需要20帧,则每50.53秒需要一帧。转换为帧速率,每秒0.01979帧。
所以你的代码应该是
ffmpeg -i video.avi -r 0.01979 -f image2 output_%05d.jpg
我希望帮助某人,就像它帮助了我一样。
答案 2 :(得分:5)
您可以尝试将视频转换为N个图像吗?
ffmpeg -i video.avi image%d.jpg
更新
或者每2秒抽取一次帧:
ffmepg -i video.avi -r 0.5 -f image2 output_%05d.jpg
更新
获取视频时长:
ffmpeg -i video.avi 2>&1 | grep 'Duration' | cut -d ' ' -f 4 | sed s/,//
然后,取决于您的编程语言,您将其转换为秒。例如,在PHP中,您可以这样做:
$duration = explode(":",$time);
$duration_in_seconds = $duration[0]*3600 + $duration[1]*60+ round($duration[2]);
其中$ time是视频时长。您可以执行$ duration_in_seconds / 20
ffmepg -i video.avi -r $duration_in_seconds/20 -f image2 output_%05d.jpg
答案 3 :(得分:5)
通常,ffmpeg会在帧到来时处理帧,因此基于总持续时间/总帧数的任何内容都需要进行一些预处理。
我建议编写一个简短的shell脚本来使用类似
的内容来获取帧总数ffprobe -show_streams <input_file> | grep "^nb_frames" | cut -d '=' -f 2
然后使用select
video filter挑选出您需要的帧。所以ffmpeg命令看起来像
ffmpeg -i <input_file> -vf "select='not(mod(n,100))'" <output_file>
除了代替每百帧,100
将替换为shell脚本中计算的数字,总共为20帧。
答案 4 :(得分:3)
我遇到了同样的问题并提出了这个似乎可以解决问题的脚本:
#/bin/sh
total_frames=`ffmpeg -i ./resources/iceageH264.avi -vcodec copy -acodec copy -f null dev/null 2>&1 | grep 'frame=' | cut -f 3 -d ' '`
numframes=$3
rate=`echo "scale=0; $total_frames/$numframes" | bc`
ffmpeg -i $1 -f image2 -vf "select='not(mod(n,$rate))'" -vframes $numframes -vsync vfr $2/%05d.png
要使用它,请将其另存为.sh文件并使用以下参数运行它以导出20帧:
./getFrames.sh ~/video.avi /outputpath 20
这将为您提供在整个视频中平均分配的指定帧数。
答案 5 :(得分:1)
<?php
header( 'Access-Control-Allow-Origin: *' );
header( 'Content-type: image/png' );
// this script returns a png image (with dimensions given by the 'size' parameter as wxh)
// extracted from the movie file specified by the 'source' parameter
// at the time defined by the 'time' parameter which is normalized against the
// duration of the movie i.e. 'time=0.5' gives the image halfway the movie.
// note that this can also be done using php-ffmpeg..
$time = floatval( $_GET[ 'time' ] );
$srcFile = $_GET[ 'source' ];
$size = $_GET[ 'size' ];
$tmpFile = tempnam( '/tmp', 'WTS.txt' );
$destFile = tempnam( '/tmp', 'WTS.png' );
$timecode = '00:00:00.000';
// we have to calculate the new timecode only if the user
// requests a timepoint after the first frame
if( $time > 0.0 ){
// extract the duration via a system call to ffmpeg
$command = "/usr/bin/ffmpeg -i ".$srcFile." 2>&1 | grep 'Duration' | cut -d ' ' -f 4 | sed s/,// >> ".$tmpFile;
exec( $command );
// read it back in from tmpfile (8 chars needed for 00:00:00), skip framecount
$fh = fopen( $tmpFile, 'r' );
$timecode = fread( $fh, 8 );
fclose( $fh );
// retieve the duration in seconds
$duration = explode( ":", $timecode );
$seconds = $duration[ 0 ] * 3600 + $duration[ 1 ] * 60 + round( $duration[ 2 ] );
$timepoint = floor( $seconds * $time );
$seconds = $timepoint % 60;
$minutes = floor( $timepoint / 60 ) % 60;
$hours = floor( $timepoint / 3600 ) % 60;
if( $seconds < 10 ){ $seconds = '0'.$seconds; };
if( $minutes < 10 ){ $minutes = '0'.$minutes; };
if( $hours < 10 ){ $hours = '0'.$hours; };
$timecode = $hours.':'.$minutes.':'.$seconds.'.000';
}
// extract an image from the movie..
exec( '/usr/bin/ffmpeg -i '.$srcFile.' -s '.$size.' -ss '.$timecode.' -f image2 -vframes 1 '.$destFile );
// finally return the content of the file containing the extracted frame
readfile( $destFile );
?>
答案 6 :(得分:0)
我遇到了同样的问题,使用选择过滤器对我不起作用,大型视频的使用率非常慢,所以我在python中附带了此脚本
它要做的是获取持续时间(以秒为单位),根据屏幕截图数量计算时间间隔,最后使用输入文件之前的查找功能在每个时间间隔拍摄屏幕截图
0.5+0.9+0.2=1.6
答案 7 :(得分:0)
我确实如此,并且100%成功。
$time = exec("ffmpeg -i input.mp4 2>&1 | grep 'Duration' | cut -d ' ' -f 4 | sed s/,//");
$duration = explode(":",$time);
$duration_in_seconds = $duration[0]*3600 + $duration[1]*60+ round($duration[2]);
$duration_in_seconds = $duration_in_seconds/20;
exec("ffmpeg -i input.mp4 -r 1/$duration_in_seconds thumb_%d.jpg");