例子:某文件夹中全部是mp4视频,对每个视频提取最后一个关键帧,并保存为同名jpg,一行代码实现
方法1:
for i in /path/to/folder/*.mp4; do ffmpeg -i "$i" -vf "select='eq(pict_type,I)'" -skip_frame nokey -frame_pts 1 -f image2 -vframes 1 "${i%.*}.jpg"; done
说明:采用for do done的方式,比较好理解,其中ffmpeg中命令的意思是:找到视频中的关键帧,-vf "select='eq(pict_type,I)'"
选项指定了只选择关键帧,-skip_frame nokey
选项指定跳过非关键帧,-frame_pts 1
选项指定根据时间戳获取最后一个关键帧,-f image2
选项指定输出图像格式为 JPEG,-vframes 1
选项指定仅提取一帧,"${i%.*}.jpg"
则指定输出文件名为输入文件名去掉扩展名后加上 .jpg
方法2:
for i in /path/to/folder/*.mp4; do ffmpeg -i "$i" -vf "select='eq(pict_type,I)',showinfo" -f null - 2>&1 | grep "pict_type:I" | tail -n 1 | sed "s/.*pos:\([0-9]\+\).*/\1/" | xargs -I{} ffmpeg -i "$i" -vf "select='eq(pict_type,I)',setpts=N/TB" -ss {} -vframes 1 "${i%.*}.jpg" ; done
说明:这个方法是找到关键帧,然后提取每个帧的起始时间,然后取最后一个帧的时间,然后提取
setpts
是 FFmpeg 中用于设置视频帧时间戳的滤镜。在命令中使用 setpts=N/TB
参数,其中 N
表示帧时间戳(PTS)的新值,TB
表示时间基准(timebase),即单位时间所包含的时间长度。这里的 N/TB
就是新的时间戳的值,其单位是秒。
使用 setpts=N/TB
参数可以改变视频帧的播放速度,因为它可以改变视频帧的时间戳,从而影响视频帧的播放顺序和速度。
对于本题中的命令,使用 setpts=N/TB
参数可以让 FFmpeg 从视频中提取关键帧并设置时间戳,将时间戳设置为关键帧出现的时间点,保证提取的关键帧是视频中真实存在的帧,而不是重新编码后的帧。这样,在提取关键帧的同时,可以保证提取出来的帧不会因为时间戳的问题出现问题。
方法3:
ls /path/to/folder/*.mp4 | xargs -I{} sh -c 'ffmpeg -i "{}" -vf "select=eq(pict_type\,I),setpts=N/TB" -ss $(ffmpeg -i "{}" -vf "select=eq(pict_type\,I),showinfo" -f null - 2>&1 | grep "pict_type:I" | tail -n 1 | sed "s/.*pos:\([0-9]\+\).*/\1/") -vframes 1 "${1%.*}.jpg"' sh {} \;
说明:该方法采用ls的方式,所以xargs中需要采用sh -c
标签:关键帧,提取,ffmpeg,pict,type,TB From: https://www.cnblogs.com/chentiao/p/17137115.html