C# 海康摄像头视频播放的两种方式
生活随笔
收集整理的這篇文章主要介紹了
C# 海康摄像头视频播放的两种方式
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
? ? ? ?題外話:看到很多朋友有此方面的問題,各種途徑聯系到我,在此聲明,可以發郵件到jimi080180@qq.com進行溝通,也提供有償項目模塊外包服務。
? ? ? ?目前市面上海康的攝像頭占有率還是很高的,如果要用海康的攝像頭進行視頻播放,可以去海康官網下載SDK,里面包含的有demo,可以很快完成
簡單的開發工作。
? ? ?? 海康的demo只寫清楚了自帶的預覽視頻播放方式(不用自己解碼,直接給顯示控件的句柄就可以顯示,性能很好,可以多路高清視頻顯示),而對于進行自解碼播放卻沒有真實的例子,只是給出了獲取到YUV數據的示例。我們有很多時候還是需要進行圖像處理,所以還是需要自己去解碼圖像,YUV數據的處理是個考驗性能的地方,一般如果采用軟件算法將YUV轉為RGB然后送給PictureBox顯示,將會很慢,高清視頻還會卡。我這里就簡單給出一份采用D3D解碼的方案,也是參考別人的博客“WPF下YUV播放的D3D解決方案”。
? ? ???下面的代碼有點亂,因為寫了兩種視頻播放的方式,一路播放的主碼流,采用的是不自己解碼的方式,另一路播放的次碼流,采用自己解碼的方式。為了方便調用D3D,使用了SlimDX庫。
?
/// <summary>/// 海康攝像頭,雙路視頻,主碼流用于抓取人臉,次碼流用于自解碼添加人臉框顯示/// </summary>public class CHCCameraForTwoVideo:ICamera{private static readonly ILog log = LogManager.GetLogger(typeof(CHCCameraForTwoVideo));private readonly int showVideoWidth = 704;//子碼流1大小704*576 子碼流2大小640*480private 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;}#endregionpublic 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 deviceCHCNetSDK.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 = 1IsRunning = 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<Bgr, byte> 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<Bgr, byte>(bm);/*//圖片保存路徑和文件名 the path and file name to savestring 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<Bgr, byte>(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 numberif (!PlayCtrl.PlayM4_SetDisplayBuf(lPort, 15)){iLastErr = PlayCtrl.PlayM4_GetLastError(lPort);str = "PlayM4_SetDisplayBuf failed, error code= " + iLastErr;}//設置解碼回調函數,獲取解碼后音視頻原始數據 Set callback function of decoded datam_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 decodeif (!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 datafor (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<Bgr, byte> currentFrame = new Image<Bgr, byte>(bmp);Image<Gray, byte> gray_frame = currentFrame.Convert<Gray, Byte>();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# 海康摄像头视频播放的两种方式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Ubuntu命令卸载软件(经过sudo
- 下一篇: C#:使用海康SDK解码回调函数DecC