zoukankan      html  css  js  c++  java
  • 针对监控摄像机(海康、大华等)录像 .h264 文件的流媒体播放设计

    监控摄像机(海康、大华等)内部带的录像功能一般录制的是h264文件,这种文件格式简单的把每一帧h264字节数据保存到文件里。

    实际使用中,可能需要对特定录像进行反复检测,以训练、改进视频检测算法的准确性。

    这里介绍两种方法。

    1.使用RTSP流

    服务端1:live555 使用C++代码开发容易些,网上代码较多

    服务端2:vlc播放器,参考 使用vlc播放器做rtsp服务器

    客户端:使用vlc播放器播放rtsp视频

                使用vlc进行二次开发做自己的播放器

                web网页中使用vlc插件播放相机rtsp流视频

                Emgu.CV 播放视频-本地文件/RTSP流

    2.自定义格式

    使用UDP数据包

    服务端针对.h264视频一帧帧发送给客户端,使用UDP协议

    h264帧,尤其是I帧大小可能超过64K,即udp数据包的上限,需要考虑分包

    分包:可以在第一字节=0表示不分包,=1表示分包这是第一包,=2这是第二包

    视频清晰度暂定为480P,此时P帧一般小于64k,而I帧部分大于64k。这样可以不考虑数据包会先发后到导致乱序

    客户端:

    示例代码如下

    IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 6000);
                udpsockVideo = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                udpsockVideo.ReceiveBufferSize = 1000000;
                try
                {
                    //绑定网络地址
                    udpsockVideo.Bind(ipep);
    
                    IPAddress ip = IPAddress.Any;
    
                    //得到客户机IP
                    IPEndPoint sender = new IPEndPoint(ip, 0);
                    EndPoint Remote = (EndPoint)(sender);
    
                    log.ErrorFormat("udp开始接收视频帧");
    
                    bool bIframe = false;
                    unAvailableCnt = 0;
                    while (!bAbortvehicleEventThread)
                    {
                        if (udpsockVideo == null)
                        {
                            log.ErrorFormat("udp接收视频帧 Socket 为空!");
                            return;
                        }
    
                        if (udpsockVideo.Available <= 0)
                        {
                            unAvailableCnt++;
                            if (unAvailableCnt > 10000)
                            {
                                log.ErrorFormat("udp接收视频帧:连续未接收到视频"); //实际比10秒多
                                unAvailableCnt = 0;
                            }
                            //TimeSpan ts = new TimeSpan(100000);//0.1毫秒 1 ticks =十亿分之一秒 百万分之一毫秒 千分之一微秒,1纳秒
                            Thread.Sleep(1); //sleep 1时,由于精度问题,经常耗时10-16毫秒
                            continue;
                        }
    
                        byte[] data = new byte[100000];
                        int recv = udpsockVideo.Receive(data);
                        if (recv < 4)
                        {
                            continue;
                        }
    
                        if (ip != IPAddress.Any && (Remote as IPEndPoint).Address.ToString().Trim() != ip.ToString().Trim())
                        {
                            continue;
                        }
    
                        unAvailableCnt = 0;
    
                        try
                        {
                            if (data[0] != 0x00)
                            {
                                bIframe = true;
    
                                byte b = data[0];
                                if (b == 0x01) 
                                {
                                    iframe1 = new byte[recv - 2];
                                    Array.Copy(data, 2, iframe1, 0, recv - 2);
                                }
                                log.ErrorFormat(b.ToString());
                                if (b == 0x02)
                                {
                                    iframe2 = new byte[recv - 1];
                                    Array.Copy(data, 1, iframe2, 0, recv - 1);
                                    log.ErrorFormat(iframe2.Length.ToString());
                                }
    
                                if (iframe1.Length < 100000 && iframe2.Length < 100000)
                                {
                                    int iframeLen = iframe1.Length + iframe2.Length;
    
                                    byte[] Iframe = new byte[iframeLen];
                                    Array.Copy(iframe1, 0, Iframe, 0, iframe1.Length);
                                    Array.Copy(iframe2, 0, Iframe, iframe1.Length, iframe2.Length);
    
                                    DecH264Frame(Iframe);
    
                                    iframe1 = new byte[100000];
                                    iframe2 = new byte[100000];
                                    bIframe = false;
                                }
                            }
                            else
                            {
                                if (bIframe)
                                {
                                    bIframe = false;
                                    iframe1 = new byte[100000];
                                    iframe2 = new byte[100000];
                                }
    
                                byte[] frame = new byte[recv - 1];
                                Array.Copy(data, 1, frame, 0, recv - 1);
                                DecH264Frame(frame);
                            }
                        }
                        catch (System.Exception ex)
                        {
                            log.ErrorFormat("udp接收视频帧 解码/录像出错:" + ex.Message);
                        }
    
                    }
                }
                catch (Exception e)
                {
                    log.ErrorFormat("udp接收视频帧出错。端口:{0},出错信息:{1}", 6000, e.Message);
                }
                finally
                {
                    if (udpsockVideo != null)
                    {
                        udpsockVideo.Close();
                    }
                }
  • 相关阅读:
    [转] jquery作者John Resig编写的微模板引擎:JavaScript Micro-Templating
    【转】一种解决h5页面背景音乐不能自动播放的方案
    [转]JavaScript快速检测浏览器对CSS3特性的支持
    [转]用CSS给SVG <use>的内容添加样式
    【转】【翻译】对响应式SVG的再思考
    用 highlight.js 为文章中的代码添加语法高亮
    转载:[AngularJS系列] 那伤不起的provider们啊~ (Provider, Value, Constant, Service, Factory, Decorator)
    vue项目中遇到的过滤去重
    css 弹性盒
    vue axios用法
  • 原文地址:https://www.cnblogs.com/jhlong/p/6513612.html
Copyright © 2011-2022 走看看