ffmpeg实现对视频流的截图
使用 ffmpeg 进行截图
首先在 ZLMediaKit 这流媒体服务中看到对应截图的命令如下:
1 | |
可以看出命令有 3 个字符串类型的占位符,根据实际情况 3 个占位符分别是:
- ffmpeg 的绝对执行路径
- 视频地址或者远端主机视频流地址
- 截图后的图片生成文件名
然后对实际占位符进行填充,我执行了以下命令:
1 | |
命令执行后在当前目录就生成了一张名称为 1.jpeg 的图片,成功截图。
结合命令和 ffmpeg 的 help 选项,也得知了这些选项中的一些意思
-i 选项
该选项是 input 的意思,表示要输入的视频源或者视频文件
-y 选项
该选项表示是否覆盖要生成的文件,在要生成的截图文件如果存在时是否要覆盖,带上了就覆盖。
-f 选项
该选项表示将生成的图片进行强制格式化,这里将要输出的图片类型选择 mjpeg,也就是 jpeg 类型
后续改进
在后续的改进下可以使用以下命令去截图,按需选择命令:
1ffmpeg -f rtsp -rtsp_transport tcp -i rtsp://admin:yz20100415@192.168.99.64 -vframes 1 -s 370'*'210 -y output.jpg以上命令将传输模式转成tcp,避免udp模式下可能会出现的花屏
-s 选项表示截出来的照片大小,例子中是370x210分辨率
弊端
使用上述方式进行截图有一些弊端,就是每次执行命令只会截图一帧。
我在后面有一个需求,就是收到一个请求只会需要对目标视频流就行截图,这个截图不仅仅要截一张图,还需要连续截图,支持每隔一段时间就截图,支持截取多长视频流的图片等等需求。
在遇到上面的需求时,第一种截图方式就不适用了。
在经过翻找其他程序员的解决方案和结合 ffmpeg 本身官网之后,我找到了上述需求的解决方案。
每隔一段时间截图
这里的一段时间支持秒级别,使用 -vf 选项进行时间控制,完整命令如下:
1 | |
-vf 选项表示 video filter,在该选项后面跟的是要过滤的子选项,这里使用 fps,值等于 1,代表每一秒。然后后面生成的图片使用了%d 占位符,代表了生成图片的数量,这个数字会递增。
不过需要注意的是,该命令是不会自动结束的,只要你的视频流还一直在播放,那么就会一直截图。
fps 的值也不一定都得写一个绝对值,也可以使用以下格式:
每一分钟截一张图, 图片命名为 img001.jpg, img002.jpg,img003.jpg 依次书序输出:
1 | |
每十分钟输出一张图片:
1 | |
以上方法都存在了一个弊端,那就是我这个视频流没有停止的话,那么这个程序就会一直截图下去,那有没有办法去控制这个截图的数量呢?
比如我有一个一直推流的视频流地址,我只需要在接入视频流的 15 秒内去截图,这个可以用 -to 选项进行控制读取视频的时长,完整命令如下:
1 | |
上面 -to 选项代表记录或转码停止时间,也就是读取视频流多长时间,时间单位是秒;上面命令跟的值是 5,所以就读取视频流 5 秒钟,并且每秒截一张图,以 out 序号.png 的方式生成图片。
-to 选项控制读取视频流多长时间,其实也可以换成 -t 选项,该选项代表 duration,也就是持续时长;只不过该选项是以时间格式来书写的,完整命令如下:
1 | |
这个命令与上一个命令都能达到一样的效果。