美文网首页
通过ffmpeg实现视频流截图

通过ffmpeg实现视频流截图

作者: questionuncle | 来源:发表于2017-10-12 16:23 被阅读0次

    最近忙于新产品技术点突破,针对架构摸索暂时停住。目前需要解决的问题是如何从视频流中截取一张图。

    概况

    在安防领域有各种视频监控产品,它们遵循的通讯协议也不尽相同,归纳起来主要遵循GB/T 28181、ONVIF、PSIA等协议。

    GB/T 28181协议

    其通信协议如下所示

    通信协议结构图.png
    其视频编码格式主要有:MPEG-4、H.264、SVAC等,目前主流的视频编码格式是H.264。
    其实时传输协议为RTP,在此传输协议基础上对视音频数据进行封装,其又分为PS封装和非PS封装:
    基于RTP的PS封装,是将视音频流封装成PS包,再将PS包以负载的方式封装成RTP包。
    基于RTP的非PS封装,是直接将视音频流以负载的方式封装成RTP包。
    如果对RTP协议感兴趣可以参考:
    RTP协议分析
    RTSP/RTP/RTCP详解整理
    RTP协议全解析(H264码流和PS流)
    RTP/RTSP/RTCP有什么区别?
    Wireshark 抓包分析 RTSP/RTP/RTCP 基本工作过程
    公司装有一台宇视的电警卡口抓拍机HC161智能交通600万摄像单元,可以看出该电警搭载的网络摄像头支持ONVIF、GB/T28181等协议,同时查看其视频配置
    视频配置.png
    可以尝试通过VLC连接RTSP视频流 vlc.png

    安装ffmpeg

    在CentOS7上安装ffmpeg

    yum -y install epel-release
    rpm --import http://li.nux.ro/download/nux/RPM-GPG-KEY-nux.ro
    rpm -Uvh http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-1.el7.nux.noarch.rpm
    yum search ffmpeg
    yum -y install ffmpeg ffmpeg-devel
    ffmpeg -version
    
    version.png
    ffmpeg -y -i rtsp://user:password@ip:port-ss 00:00:01 -vframes 1 -f image2 -vcodec png image.png
    
    image.png

    Java调用脚本

    脚本正确调用,接下来就通过Java调用远程服务器上脚本实现视频流截图,在此借助Ganymed SSH-2 for Java,实现SSH远程执行脚本。

    package com.dhl.runshell;
    
    import ch.ethz.ssh2.Connection;
    import ch.ethz.ssh2.Session;
    import ch.ethz.ssh2.StreamGobbler;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    
    /**
     * Created by daihl on 2017/10/10.
     */
    public class CommandRunner {
        public static Connection getOpenedConnection(String host, String username, String password) throws IOException {
            Connection conn = new Connection(host);
            conn.connect(); // make sure the connection is opened
            boolean isAuthenticated = conn.authenticateWithPassword(username, password);
            if (isAuthenticated == false)
                throw new IOException("Authentication failed.");
            return conn;
        }
    
        public static String execShellScript(String host, String username,
                                             String password,
                                             String cmd, int port) throws IOException {
            Connection conn = null;
            Session sess = null;
            InputStream stdout = null;
            BufferedReader br = null;
            StringBuffer buffer = new StringBuffer("exec result:");
            buffer.append(System.getProperty("line.separator"));// 换行
            try {
                conn = getOpenedConnection(host, username, password);
                sess = conn.openSession();
                sess.execCommand(cmd);
                stdout = new StreamGobbler(sess.getStdout());
                br = new BufferedReader(new InputStreamReader(stdout));
                while (true) {
                    // attention: do not comment this block, or you will hit
                    // NullPointerException
                    // when you are trying to read exit status
                    String line = br.readLine();
                    if (line == null)
                        break;
                    buffer.append(line);
                    buffer.append(System.getProperty("line.separator"));// 换行
                }
            } finally {
                sess.close();
                conn.close();
            }
            return buffer.toString();
        }
    
        public static void main(String[] args) {
            String cmd = "ffmpeg -y -i rtsp://user:password@ip:port -ss 00:00:01 -vframes 1 -f image2 -vcodec png image.png;echo end";
            try {
                String info = CommandRunner.execShellScript("ip", "user",
                        "password",cmd,22);
    
                System.out.println("info is:"+info);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    后继工作

    通过SSH远程执行脚本有点简单粗暴,何不将这截图功能做成服务,向外发布,更加灵活方便。故后期工作如下:
    准备一台图片服务器,其主要职责有
    1.图片文件存储
    2.响应终端的抓图请求,并将图片保存到指定文件夹目录下
    3.响应终端的合图请求,以上两者做成服务的形式,终端通过分布式调用服务,完成操作并返回结果状态
    4.接收终端上传的图片
    硬件需求:
    1.因图片服务器上安装ffmpeg工具,其需要对视频流进行解码,并按照png格式组织编码,对计算性能要求高,所以CPU性能要好
    2.作为图片文件存储服务器,存储容量要大
    3.接受多终端设备连接,网口带宽要大

    后记

    因为要接收反馈结果,cmd命令可以这样写

    rtsp://user:password@ip:port -ss 00:00:01 -vframes 1 -f image2 -vcodec png image.png && echo succeeded ||echo failed
    

    当ffmpeg执行正确时,会输出succeeded,当ffmpeg不能正确执行时,会输出failed

    新建目录文件夹,将截图文件放入指定文件夹中

    if [ ! -d /home/daihl/$(date +%Y%m%d) ]; then mkdir -p /home/daihl/$(date +%Y%m%d)&&echo "mkdir"; fi
    

    相关文章

      网友评论

          本文标题:通过ffmpeg实现视频流截图

          本文链接:https://www.haomeiwen.com/subject/ctlvyxtx.html