我的目标;使用 ffmpeg 从视频文件中导出一系列图像。我猜我的问题与每秒帧数和比特率有关。
我尝试了以下命令:
ffmpeg -i myVideo.mp4 -r 1 images_%04d.jpg
但不知何故,在 45 秒的视频中,我最终得到了 47 张图片。准确获取这些信息非常重要。我无法提前知道适当的 FPS 或比特率是多少,如果我在运行命令时需要这些值,我需要能够以某种方式从 ffmpeg 中提取它们。
我还考虑过导出视频中的所有图像ffmpeg -i myVideo images_%04d.jpg
,然后将图像数量除以视频的总秒数。这样我会得到 24.97 左右的结果,然后我会四舍五入到 25 并删除每 25 帧中的 24 帧。我担心的是,如果文件是 VBR,并且高比特率部分位于视频的开头,那么我完成的帧数将不会精确匹配每秒 1 帧。例如,第 30 张图像实际上可能出现在视频中更接近第 31 秒的位置。
运行 ffmpeg -> ffmpeg -i "/videos/11.mp4" -s "352x264" "/images/image%06d.jpg" FFmpeg 版本 0.6-4:0.6-2ubuntu6.1,版权所有 (c) 2000-2010 FFmpeg 开发人员 于 2011 年 3 月 31 日 18:43:47 使用 gcc 4.4.5 构建 配置:--extra-version=4:0.6-2ubuntu6.1 --prefix=/usr --enable-avfilter --enable-avfilter-lavf --启用-vdpau --启用-bzlib --启用-libgsm --启用-libschroedinger --启用-libspeex --启用-libtheora --启用-libvorbis --启用-vaapi --启用-pthreads --启用-zlib --启用-libvpx --disable-stripping--enable-runtime-cpudetect--enable-gpl--enable-postproc--enable-x11grab --启用-libdc1394 --启用共享--禁用静态 libavutil 50.15。 1 / 50.15。 1 libavcodec 52.72.2 / 52.72.2 libavformat 52.64. 2 / 52.64. 2 libavdevice 52.2.0 / 52.2.0 libavfilter 1.19.0 / 1.19.0 libswscale 0.11. 0 / 0.11. 0 libpostproc 51. 2. 0 / 51. 2. 0 似乎流 1 编解码器帧速率与容器帧速率不同:49938.00 (49938/1) -> 24.97 (24969/1000) 输入 #0,mov,mp4,m4a,3gp,3g2,mj2,来自'/videos/11.mp4': 元数据: 主要品牌:mp42 次要版本:0 兼容品牌: isomavc1mp42 时长:00:00:32.60,开始:0.000000,比特率:433 kb/s 流 #0.0(und):音频:aac,44100 Hz,立体声,s16,127 kb/s 流 #0.1(und):视频:h264、yuv420p、352x264 [PAR 1:1 DAR 4:3]、303 kb/s、24.97 fps、24.97 tbr、24969 tbn、49938 tbc 输出 #0,图像 2,至‘/images/image%06d.jpg’: 元数据: 编码器:Lavf52.64.2 流 #0.0(und):视频:mjpeg、yuvj420p、352x264 [PAR 1:1 DAR 4:3]、q=2-31、200 kb/s、90k tbn、24.97 tbc 流映射: 流 #0.1 -> #0.0 按 [q] 停止编码帧= 176 fps= 0 q=24.8 大小= -0kB 时间=7.05 比特率= -0.0kbits/s ^Mframe= 312 fps=236 q=24.8 大小= -0kB 时间=12.50 比特率= -0.0kbits/s ^Mframe= 316 fps=112 q=24.8 大小= -0kB 时间=12.66 比特率= -0.0kbits/s ^Mframe= 322 fps= 55 q=24.8 大小= -0kB 时间=12.90 比特率= -0.0kbits/s ^Mframe= 327 fps= 39 q=24.8 大小= -0kB 时间=13.10 比特率= -0.0kbits/s ^Mframe= 331 fps= 33 q=24.8 大小= -0kB 时间=13.26 比特率= -0.0kbits/s ^Mframe= 336 fps= 31 q=24.8 大小= -0kB 时间=13.46 比特率= -0.0kbits/s ^M帧= 339 fps= 27 q=24.8 大小= -0kB 时间=13.58 比特率= -0.0kbits/s ^M帧= 344 fps= 22 q=24.8 大小= -0kB 时间=13.78 比特率= -0.0kbits/s
有人知道如何使用 ffmpeg 从视频中导出图像并获得时间准确的结果吗?谢谢!
答案1
您需要手动指定一个-vsync
值。差异很可能是由于可变/恒定帧速率和帧时间戳的差异造成的。如果您有 VFR 源,ffmpeg 默认会尝试以估计速率(值tbr
)为目标,并会丢弃或复制帧以“平滑”运动。将帧导出为图像也遵循此行为。文档中的一些信息:
-垂直同步范围
视频同步方法。出于兼容性原因,旧值可以指定为数字。新添加的值必须始终指定为字符串。
0,直通
每个帧都带有其时间戳,从解复用器传递到复用器。
1、到岸价
将复制并删除帧以准确实现所要求的恒定帧速率。
2、vfr
帧连同其时间戳一起传递或者被丢弃,以防止两帧具有相同的时间戳。
降低
作为直通但销毁所有时间戳,使得多路复用器根据帧速率生成新的时间戳。
-1,自动
根据多路复用器功能在 1 和 2 之间进行选择。这是默认方法。
正如这里所说,ffmpeg 将-vsync -1
默认选择(用于视频编码和图像导出)。您想要的是直接通过而没有任何变化。-vsync 0
如果您想保持每一帧原样,没有丢失或重复,请使用。您可能会收到有关非单调 DTS 的消息,但这可以基本忽略。以下是用于从视频中准确输出所有帧的示例命令:
ffmpeg -i video.nut -f image2 -vsync 0 frame-%03d.tiff
答案2
你确定你丢失了帧吗?你的输入视频是 h264,支持可变帧速率。要获取有关每个帧的详细信息,我建议使用以下命令:
ffmpeg -i inputvideo -vf showinfo -acodec copy -vcodec mpeg2video temp.mp4
这样你就会知道你的电影有多少帧。
您可以通过将电影转换为非可变帧速率视频、使用参数-r float
,然后导出照片(就像在命令中所做的那样)来避免可变帧速率。
答案3
我观察到使用 -r 参数提取图像时也出现了类似的不稳定行为。
我找到了一个对我有用的解决方案,即改用 -vf fps=X 选项(下面有一些重要说明)。信不信由你,这里的行为似乎比使用 -r 的行为更可预测。
- 要从输入视频每 X 秒生成一张图像,请计算 1/X 的浮点值并运行:
ffmpeg -i input.mp4 -vf fps=1.0/x image-%04d.jpg
例如每秒获取 2 张图像:
ffmpeg -i input.mp4 fps=0.5 image-%04d.jpg
这几乎可以完成正确的事,请注意:
- 生成了额外的第一帧,应将其忽略。
- 每 X 秒生成一帧,其中 X 是 的参数
-vf fps=X
,从 X/2 秒开始。
因此,运行:
ffmpeg -i input.mp4 fps=1 image-%04d.jpg
5 秒的视频将产生 6 个文件,第一个文件应该被忽略,第 2 到第 6 个文件将对应时间戳:0.5、1.5、2.5、3.5 和 4.5。
这是一个对于调试此类事情有用的测试视频:
https://drive.google.com/file/d/0B56RokrDs3xabS1TS19wRjlBaVk/view?usp=sharing