C# 海康摄像头视频播放的两种方式

       目前市面上海康的摄像头占有率还是很高的,经常会用到海康的摄像头。如果要用海康的摄像头进行视频播放,可以去海康官网下载SDK,里面包含的有demo,可以很快完成

简单开发工作。

       海康的demo只写清楚了自带的预览视频播放方式(不用自己解码,直接给显示控件的句柄就可以显示,性能很好,可以多路高清视频显示),而对于进行自解码播放却没有真实的例子,只是给出了获取到YUV数据的示例。我们有很多时候还是需要进行图像处理,所以还是需要自己去解码图像,YUV数据的处理是个考验性能的地方,一般如果采用软件算法将YUV转为RGB然后送给PictureBox显示,将会很慢,高清视频还会卡。我这里就简单给出一份采用D3D解码的方案,也是参考别人的博客“WPF下YUV播放的D3D解决方案”。

       下面的代码有点乱,因为写了两种视频播放的方式,一路播放的主码流,采用的是不自己解码的方式,另一路播放的次码流,采用自己解码的方式。为了方便调用D3D,使用了SlimDX库。

 /// 
    /// 海康摄像头,双路视频,主码流用于抓取人脸,次码流用于自解码添加人脸框显示
    /// 
    public class CHCCameraForTwoVideo:ICamera
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(CHCCameraForTwoVideo));
        private readonly int showVideoWidth = 704;//子码流1大小704*576 子码流2大小640*480
        private readonly int showVideoHeight = 576;
        #region 变量定义
        private uint iLastErr = 0;
        private Int32 m_lUserID = -1;
        private bool m_bInitSDK = false;
        private Int32 m_lRealHandle_snap = -1;
        private Int32 m_lRealHandle_show = -1;
        private int lPort = -1;//全局的播放库port号
        private D3DImageSource d3dSource = null;
        CHCNetSDK.REALDATACALLBACK RealData = null;

        private PictureBox snapPicBox;
        private PictureBox showPicBox;

        public string Direction
        {
            get;set;
        }

        public int Id
        {
            get;set;
        }

        public string Ip
        {
            get;set;
        }

        public ushort Port
        {
            get;set;
        }

        public string UserName
        {
            get;set;
        }

        public string Password
        {
            get;set;
        }

        public PictureBox RealPlayPicBox
        {
            get;set;
        }

        public bool IsRunning
        {
            get;set;
        }
        #endregion
        public CHCCameraForTwoVideo(string ip, ushort port, string userName, string password, string direction, PictureBox snapPic,PictureBox showPic)
        {
            IsRunning = false;
            Id = -1;
            Ip = ip;
            Port = port;
            UserName = userName;
            Password = password;
            Direction = direction;
            RealPlayPicBox = showPic;

            showPicBox = showPic;
            snapPicBox = snapPic;

            //初始化设备
            m_bInitSDK = CHCNetSDK.NET_DVR_Init();
            if (m_bInitSDK == false)
            {
                log.Error("海康摄像头初始化失败!");
                return;
            }
            log.Info("海康摄像头初始化成功!");

            //登录设备 Login the device
            CHCNetSDK.NET_DVR_DEVICEINFO_V30 DeviceInfo = new CHCNetSDK.NET_DVR_DEVICEINFO_V30();
            m_lUserID = CHCNetSDK.NET_DVR_Login_V30(ip, port, userName, password, ref DeviceInfo);
            if (m_lUserID < 0)
            {
                iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                log.Error("海康摄像头登陆失败,错误代码: " + iLastErr);
                return;
            }
            log.Info("海康摄像头登陆成功!");

            //预览视频 抓图用
            CHCNetSDK.NET_DVR_PREVIEWINFO lpPreviewInfo = new CHCNetSDK.NET_DVR_PREVIEWINFO();
            lpPreviewInfo.hPlayWnd = snapPic.Handle;//预览窗口句柄
            lpPreviewInfo.lChannel = 1;//预览的设备通道
            lpPreviewInfo.dwStreamType = 0;//码流类型:0-主码流,1-子码流,2-码流3,3-码流4,以此类推
            lpPreviewInfo.dwLinkMode = 0;//连接方式:0- TCP方式,1- UDP方式,2- 多播方式,3- RTP方式,4-RTP/RTSP,5-RSTP/HTTP 
            lpPreviewInfo.bBlocked = true; //0- 非阻塞取流,1- 阻塞取流
            lpPreviewInfo.dwDisplayBufNum = 15; //播放库播放缓冲区最大缓冲帧数

            m_lRealHandle_snap = CHCNetSDK.NET_DVR_RealPlay_V40(m_lUserID, ref lpPreviewInfo, null/*RealData*/, IntPtr.Zero);
            if (m_lRealHandle_snap < 0)
            {
                iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                log.Error("海康摄像头抓图视频预览失败,错误代码: " + iLastErr);
                return;
            }
            else
            {
                CHCNetSDK.NET_DVR_SetCapturePictureMode(0);//BMP_MODE    = 0,JPEG_MODE   = 1
                IsRunning = true;
            }
            log.Info("海康摄像头抓图视频预览成功");
            //解码视频,播放用
            d3dSource = new D3DImageSource();
            if (!d3dSource.SetupSurface(showVideoWidth, showVideoHeight, FrameFormat.YV12))
            {
                log.Error("D3D初始化失败,本机不支持这种格式");
                d3dSource.Clear();
                d3dSource.Dispose();
                return;
            }
            log.Info("D3D初始化成功!");

            RealData = new CHCNetSDK.REALDATACALLBACK(RealDataCallBack);//预览实时流回调函数
            CHCNetSDK.NET_DVR_PREVIEWINFO lpPreviewInfo_show = new CHCNetSDK.NET_DVR_PREVIEWINFO();
            lpPreviewInfo_show.hPlayWnd = IntPtr.Zero;//预览窗口句柄
            lpPreviewInfo_show.lChannel = 1;//预览的设备通道
            lpPreviewInfo_show.dwStreamType = 1;//码流类型:0-主码流,1-子码流,2-码流3,3-码流4,以此类推
            lpPreviewInfo_show.dwLinkMode = 0;//连接方式:0- TCP方式,1- UDP方式,2- 多播方式,3- RTP方式,4-RTP/RTSP,5-RSTP/HTTP 
            lpPreviewInfo_show.bBlocked = true; //0- 非阻塞取流,1- 阻塞取流
            lpPreviewInfo_show.dwDisplayBufNum = 15; //播放库播放缓冲区最大缓冲帧数
            m_lRealHandle_show = CHCNetSDK.NET_DVR_RealPlay_V40(m_lUserID, ref lpPreviewInfo_show, RealData, IntPtr.Zero);

        }


        public Image CapturePicture()
        {
            if (m_lRealHandle_snap >= 0)
            {
                /************************************内存抓拍,不存文件方式**************/

                byte[] bmpBytes = new byte[3072 * 2048 * 4 + 100];
                UInt32 sizeReturned = 0;
                if (!CHCNetSDK.NET_DVR_CapturePictureBlock_New(m_lRealHandle_snap, bmpBytes, bmpBytes.Length, ref sizeReturned))
                {
                    iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                    log.Error("海康摄像头抓拍图片失败,失败原因: " + iLastErr);
                    return null;
                }
                byte[] realBytes = new byte[sizeReturned];
                Buffer.BlockCopy(bmpBytes, 0, realBytes, 0, realBytes.Length);
                MemoryStream ms = new MemoryStream(realBytes);
                Bitmap bm = (Bitmap)Image.FromStream(ms);
                return new Image(bm);

                /*
                //图片保存路径和文件名 the path and file name to save
                string sBmpPicFileName = "temp.bmp";

                if (!CHCNetSDK.NET_DVR_CapturePicture(m_lRealHandle, sBmpPicFileName))
                {
                    iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                    log.Error("海康摄像头抓拍图片失败,失败原因: "+iLastErr);
                    return null;
                }
                else
                {
                    log_debug("海康摄像头抓拍图片成功,$AppStartPath\temp.bmp");
                }
                try
                {
                    return new Image(sBmpPicFileName);
                }catch(Exception ex)
                {
                    log.Error("海康摄像头抓图成功,返回失败",ex);
                }
                */
            }

            return null;
        }
        private static PlayCtrl.DECCBFUN m_fDisplayFun = null;
        string str;
        //预览实时流回调处理方法
        private void RealDataCallBack(Int32 lRealHandle, UInt32 dwDataType, IntPtr pBuffer, UInt32 dwBufSize, IntPtr pUser)
        {
            switch (dwDataType)
            {
                case CHCNetSDK.NET_DVR_SYSHEAD://系统头

                    if (dwBufSize > 0)
                    {
                        if (lPort >= 0)
                        {
                            return;//同一路码流不需要多次调用开流接口
                        }
                        if (!PlayCtrl.PlayM4_GetPort(ref lPort))
                        {
                            iLastErr = PlayCtrl.PlayM4_GetLastError(lPort);
                            str = "PlayM4_GetPort failed, error code= " + iLastErr;
                            //this.BeginInvoke(AlarmInfo, str);

                            break;
                        }
                        //设置实时流播放模式
                        if (!PlayCtrl.PlayM4_SetStreamOpenMode(lPort, PlayCtrl.STREAME_REALTIME))
                        {
                            iLastErr = PlayCtrl.PlayM4_GetLastError(lPort);
                            str = "Set STREAME_REALTIME mode failed, error code= " + iLastErr;

                            break;
                        }
                        //打开流接口
                        if (!PlayCtrl.PlayM4_OpenStream(lPort, pBuffer, dwBufSize, 1024 * 1024))
                        {
                            iLastErr = PlayCtrl.PlayM4_GetLastError(lPort);
                            str = "PlayM4_OpenStream failed, error code= " + iLastErr;

                            break;
                        }
                        //设置显示缓冲区个数 Set the display buffer number
                        if (!PlayCtrl.PlayM4_SetDisplayBuf(lPort, 15))
                        {
                            iLastErr = PlayCtrl.PlayM4_GetLastError(lPort);
                            str = "PlayM4_SetDisplayBuf failed, error code= " + iLastErr;

                        }
                        //设置解码回调函数,获取解码后音视频原始数据 Set callback function of decoded data
                        m_fDisplayFun = new PlayCtrl.DECCBFUN(DecCallbackFUN);
                        if (!PlayCtrl.PlayM4_SetDecCallBackEx(lPort, m_fDisplayFun, IntPtr.Zero, 0))
                        {
                            iLastErr = PlayCtrl.PlayM4_GetLastError(lPort);
                            str = "PlayM4_SetDisplayBuf failed, error code= " + iLastErr;

                            break;
                        }
                        //设置硬解码
                        //if (!PlayCtrl.PlayM4_SetDecodeEngineEx(lPort, PlayCtrl.HARD_DECODE_ENGINE))
                        //{
                        //    break;
                        //}
                        //播放开始
                        if (!PlayCtrl.PlayM4_Play(lPort, IntPtr.Zero))
                        {
                            iLastErr = PlayCtrl.PlayM4_GetLastError(lPort);
                            str = "PlayM4_SetDisplayBuf failed, error code= " + iLastErr;

                            break;
                        }
                    }
                    break;
                case CHCNetSDK.NET_DVR_STREAMDATA://码流数据
                    if (dwBufSize > 0 && lPort != -1)
                    {
                        for (int i = 0; i < 999; i++)
                        {
                            //送入码流数据进行解码 Input the stream data to decode
                            if (!PlayCtrl.PlayM4_InputData(lPort, pBuffer, dwBufSize))
                            {
                                iLastErr = PlayCtrl.PlayM4_GetLastError(lPort);
                                str = "PlayM4_InputData failed, error code= " + iLastErr;

                                Thread.Sleep(2);
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                    break;
                default://其他数据
                    if (dwBufSize > 0 && lPort != -1)
                    {
                        //送入其他数据 Input the other data
                        for (int i = 0; i < 999; i++)
                        {
                            if (!PlayCtrl.PlayM4_InputData(lPort, pBuffer, dwBufSize))
                            {
                                iLastErr = PlayCtrl.PlayM4_GetLastError(lPort);
                                str = "PlayM4_InputData failed, error code= " + iLastErr;
                                Thread.Sleep(2);
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                    break;
            }
        }
        //解码回调
        private void DecCallbackFUN(int nPort, IntPtr pBuf, int nSize, ref PlayCtrl.FRAME_INFO pFrameInfo, int nReserved1, int nReserved2)
        {
            // 将pBuf解码后视频输入写入文件中(解码后YUV数据量极大,尤其是高清码流,不建议在回调函数中处理)
            if (pFrameInfo.nType == 3) //#define T_YV12	3
            {
                try
                {
                    d3dSource.Render(pBuf);
                    Surface s = d3dSource.RenderSurface;

                    using (var stream = Surface.ToStream(s, ImageFileFormat.Bmp))
                    {
                        Bitmap bmp = new Bitmap(stream);
                        Image currentFrame = new Image(bmp);
                        Image gray_frame = currentFrame.Convert();
                        FaceInfo[] faceinfo = FaceDetection.frontal_surveillance(gray_frame);
                        for (int i = 0; i < faceinfo.Length; i++)// (Rectangle face_found in facesDetected)
                        {
                            Rectangle rect = new Rectangle(faceinfo[i].x, faceinfo[i].y, faceinfo[i].w, faceinfo[i].h);
                            currentFrame.Draw(rect, new Bgr(Color.Red), 1);
                            //  currentFrame.Draw(faceinfo[i].w + " * " + faceinfo[i].h, ref font, new Point(faceinfo[i].x + 20, faceinfo[i].y + faceinfo[i].h + 20), new Bgr(Color.Green));
                        }
                        showPicBox.Image =currentFrame.ToBitmap();
                        bmp.Dispose();

                    }
                    //画人脸框
                   
                }
                catch (Exception ex)
                {

                }

            }
        }

        public void Dispose()
        {
            IsRunning = false;
            if (m_lRealHandle_snap >= 0)
            {
                CHCNetSDK.NET_DVR_StopRealPlay(m_lRealHandle_snap);
            }
            if (m_lRealHandle_show >= 0)
            {
                CHCNetSDK.NET_DVR_StopRealPlay(m_lRealHandle_show);
            }
            if (m_lUserID >= 0)
            {
                CHCNetSDK.NET_DVR_Logout(m_lUserID);
            }
            if (m_bInitSDK == true)
            {
                CHCNetSDK.NET_DVR_Cleanup();
            }
            if (d3dSource != null)
            {
                //d3dSource.Clear();
                d3dSource.Dispose();
            }
        }
    }

你可能感兴趣的:(视频监控,C#,摄像头,播放)