C#:使用海康SDK解码回调函数DecCallbackFUN()
簡(jiǎn)述
??使用海康攝像頭采集圖像時(shí),需要在圖像上添加圖標(biāo)、文字等額外數(shù)據(jù)。可選擇使用海康SDK繪圖回調(diào)函數(shù)疊加字符、圖像等(請(qǐng)參考上一篇文章);也可使用海康SDK的解碼回調(diào)函數(shù),對(duì)視頻流數(shù)據(jù)進(jìn)行解碼后處理。該方法流程為:調(diào)用視頻預(yù)覽函數(shù)NET_DVR_RealPlay_V40()時(shí)將第三個(gè)參數(shù)設(shè)置為實(shí)時(shí)數(shù)據(jù)回調(diào)函數(shù)RealDataCallBack()的函數(shù)指針,然后在RealDataCallBack()回調(diào)函數(shù)中注冊(cè)視頻流數(shù)據(jù)解碼函數(shù)DecCallbackFUN(),最后在DecCallbackFUN()函數(shù)中對(duì)數(shù)據(jù)解析解碼、疊加字符等處理。
??本文只調(diào)用解碼回調(diào)函數(shù)將YV12格式視頻流數(shù)據(jù)轉(zhuǎn)換為RGB32格式數(shù)據(jù),然后將RGB32格式數(shù)據(jù)轉(zhuǎn)換為Image,并使用PictrueBox顯示該Image數(shù)據(jù),暫不做疊加字符、圖像等處理。
代碼
1、攝像頭操作代碼
struct CameraInfo{public string strIP;public short nPort;public string strUserName;public string strPassword;}class IDeviceCamera{public Image m_img = null;public virtual bool InitCamera( CameraInfo stInfo ){return true;}}class DeviceCamera : IDeviceCamera{private CameraInfo m_stCameraInfo;private bool m_bInitSDK = false;private Int32 m_lUserID = -1;private Int32 m_lRealHandle = -1;private Int32 m_lPort = -1;CHCNetSDK.REALDATACALLBACK RealData = null; //必須得定義為成員變量public override bool InitCamera( CameraInfo stInfo ){m_stCameraInfo = stInfo;m_bInitSDK = CHCNetSDK.NET_DVR_Init();if ( !m_bInitSDK ){uint nError = CHCNetSDK.NET_DVR_GetLastError();}CHCNetSDK.NET_DVR_SetConnectTime( 5000, 1 );CHCNetSDK.NET_DVR_SetReconnect( 10000, 1 );if ( m_bInitSDK == false ){MessageBox.Show( "NET_DVR_Init error!" );return false;}else{//保存SDK日志 To save the SDK logCHCNetSDK.NET_DVR_SetLogToFile( 3, "C:\\SdkLog\\", true );}string DVRIPAddress = stInfo.strIP; //設(shè)備IP地址或者域名 Device IPInt16 DVRPortNumber = stInfo.nPort; //設(shè)備服務(wù)端口號(hào) Device Portstring DVRUserName = stInfo.strUserName;//設(shè)備登錄用戶名 User name to loginstring DVRPassword = stInfo.strPassword;//設(shè)備登錄密碼 Password to loginCHCNetSDK.NET_DVR_DEVICEINFO_V30 DeviceInfo = new CHCNetSDK.NET_DVR_DEVICEINFO_V30();m_lUserID = CHCNetSDK.NET_DVR_Login_V30( DVRIPAddress, DVRPortNumber, DVRUserName, DVRPassword, ref DeviceInfo );if ( m_lUserID < 0 ){MessageBox.Show( "登錄失敗!" );CHCNetSDK.NET_DVR_Cleanup();return false;}//CHCNetSDK.NET_DVR_PREVIEWINFO lpPreviewInfo = new CHCNetSDK.NET_DVR_PREVIEWINFO();lpPreviewInfo.hPlayWnd = (IntPtr)null;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; //播放庫(kù)播放緩沖區(qū)最大緩沖幀數(shù)//使用回調(diào)函數(shù)取攝像頭數(shù)據(jù)RealData = new CHCNetSDK.REALDATACALLBACK( RealDataCallBack );//預(yù)覽實(shí)時(shí)流回調(diào)函數(shù)IntPtr pUser = new IntPtr();//用戶數(shù)據(jù)m_lRealHandle = CHCNetSDK.NET_DVR_RealPlay_V40( m_lUserID, ref lpPreviewInfo, RealData, pUser );CHCNetSDK.NET_DVR_RigisterDrawFun( m_lRealHandle, new CHCNetSDK.DRAWFUN( cbDrawFun ), 0 );//回調(diào)函數(shù):繪制圖標(biāo)return true;}private uint nLastErr = 0;private static PlayCtrl.DECCBFUN m_fDisplayFun = null;private IntPtr m_ptrRealHandle;public void RealDataCallBack( Int32 lRealHandle, UInt32 dwDataType, IntPtr pBuffer, UInt32 dwBufSize, IntPtr pUser ){//下面數(shù)據(jù)處理建議使用委托的方式switch ( dwDataType ){case CHCNetSDK.NET_DVR_SYSHEAD: // sys headif ( dwBufSize > 0 ){if ( m_lPort >= 0 )return; //同一路碼流不需要多次調(diào)用開(kāi)流接口//獲取播放句柄 Get the port to playif ( !PlayCtrl.PlayM4_GetPort( ref m_lPort ) ){nLastErr = PlayCtrl.PlayM4_GetLastError( m_lPort );break;}//設(shè)置流播放模式 Set the stream mode: real-time stream modeif ( !PlayCtrl.PlayM4_SetStreamOpenMode( m_lPort, PlayCtrl.STREAME_REALTIME ) ){nLastErr = PlayCtrl.PlayM4_GetLastError( m_lPort );//str = "Set STREAME_REALTIME mode failed, error code= " + nLastErr;//this.BeginInvoke( AlarmInfo, str );}//打開(kāi)碼流,送入頭數(shù)據(jù) Open streamif ( !PlayCtrl.PlayM4_OpenStream( m_lPort, pBuffer, dwBufSize, 2 * 1024 * 1024 ) ){nLastErr = PlayCtrl.PlayM4_GetLastError( m_lPort );//str = "PlayM4_OpenStream failed, error code= " + nLastErr;//this.BeginInvoke( AlarmInfo, str );break;}//設(shè)置顯示緩沖區(qū)個(gè)數(shù) Set the display buffer numberif ( !PlayCtrl.PlayM4_SetDisplayBuf( m_lPort, 15 ) ){nLastErr = PlayCtrl.PlayM4_GetLastError( m_lPort );//str = "PlayM4_SetDisplayBuf failed, error code= " + nLastErr;//this.BeginInvoke( AlarmInfo, str );}//設(shè)置顯示模式 Set the display mode//if ( !PlayCtrl.PlayM4_SetOverlayMode( m_lPort, 0, 0) ) //play off screen //{// nLastErr = PlayCtrl.PlayM4_GetLastError( m_lPort );// //str = "PlayM4_SetOverlayMode failed, error code= " + nLastErr;// //this.BeginInvoke( AlarmInfo, str );//}//設(shè)置解碼回調(diào)函數(shù),獲取解碼后音視頻原始數(shù)據(jù) Set callback function of decoded datam_fDisplayFun = new PlayCtrl.DECCBFUN( DecCallbackFUN );if ( !PlayCtrl.PlayM4_SetDecCallBackEx( m_lPort, m_fDisplayFun, IntPtr.Zero, 0 ) ){//this.BeginInvoke( AlarmInfo, "PlayM4_SetDisplayCallBack fail" );}//開(kāi)始解碼 Start to play if ( !PlayCtrl.PlayM4_Play( m_lPort, m_ptrRealHandle ) ){nLastErr = PlayCtrl.PlayM4_GetLastError( m_lPort );//str = "PlayM4_Play failed, error code= " + nLastErr;//this.BeginInvoke( AlarmInfo, str );break;}}break;case CHCNetSDK.NET_DVR_STREAMDATA: // video stream datadefault: //the other dataif ( dwBufSize > 0 && m_lPort != -1 ){for ( int i = 0; i < 999; i++ ){//送入碼流數(shù)據(jù)進(jìn)行解碼 Input the stream data to decodeif ( !PlayCtrl.PlayM4_InputData( m_lPort, pBuffer, dwBufSize ) ){nLastErr = PlayCtrl.PlayM4_GetLastError( m_lPort );//str = "PlayM4_InputData failed, error code= " + nLastErr;Thread.Sleep( 2 );}elsebreak;}}break;}}//解碼回調(diào)函數(shù)private void DecCallbackFUN( int nPort, IntPtr pBuf, int nSize, ref PlayCtrl.FRAME_INFO pFrameInfo, int nReserved1, int nReserved2 ){if ( pFrameInfo.nType == 3 ) //#define T_YV12 3{byte[] byteBuffYV12 = new byte[ nSize ];Marshal.Copy( pBuf, byteBuffYV12, 0, nSize );long lRGBSize = (long)pFrameInfo.nWidth * pFrameInfo.nHeight * 4;byte[] bufferRGB32 = new byte[ lRGBSize ];CommonFun.YV12_to_RGB32( byteBuffYV12, bufferRGB32, pFrameInfo.nWidth, pFrameInfo.nHeight );byteBuffYV12 = null;Bitmap bmpFromGRB32 = CommonFun.RGB32_to_Image( bufferRGB32, pFrameInfo.nWidth, pFrameInfo.nHeight );bufferRGB32 = null;if ( null == bmpFromGRB32 )return;m_img = bmpFromGRB32;}}}注:得到的m_img用于PictureBox進(jìn)行顯示。
2、YV12轉(zhuǎn)換為RGB32、RGB32轉(zhuǎn)換為Image代碼
class CommonFun{public static bool YV12_to_RGB32( byte[] buffYV12, byte[] bufferRGB32, int nWidth, int nHeight ){if( buffYV12.Length < 0 || bufferRGB32.Length < 0 )return false;long nYLen = (long)nWidth * nHeight;int nHfWidth = ( nWidth >> 1 );if ( nYLen < 1 || nHfWidth < 1 )return false;byte[] byteYData = buffYV12.Skip( 0 ).Take( nWidth*nHeight ).ToArray();byte[] byteUData = buffYV12.Skip( nWidth*nHeight ).Take( (nHeight/2)*(nWidth/2) ).ToArray();byte[] byteVData = buffYV12.Skip( nWidth*nHeight + (nHeight/2)*(nWidth/2) ).Take( (nHeight/2)*(nWidth/2) ).ToArray();if ( byteYData.Length < 0 || byteVData.Length < 0 || byteUData.Length < 0 )return false;int[] nRgb = new int[4];for( int nRow = 0; nRow < nHeight; nRow++ ){for( int nCol = 0; nCol < nWidth; nCol++ ){int Y = byteYData[nRow*nWidth + nCol];int U = byteUData[(nRow / 2)*(nWidth / 2) + (nCol / 2)];int V = byteVData[(nRow / 2)*(nWidth / 2) + (nCol / 2)];int R = Y + (U - 128) + (((U - 128) * 103) >> 8);int G = Y - (((V - 128) * 88) >> 8) - (((U - 128) * 183) >> 8);int B = Y + (V - 128) + (((V - 128) * 198) >> 8);// r分量值 R = R<0 ? 0 : R;nRgb[2] = R > 255 ? 255 : R;// g分量值G = G<0 ? 0 : G;nRgb[1] = G > 255 ? 255 : G;// b分量值 B = B<0 ? 0 : B;nRgb[0] = B > 255 ? 255 : B;//A分量值nRgb[ 3 ] = 255;//Out RGB BufferbufferRGB32[4 * (nRow*nWidth + nCol) + 0] = (byte)nRgb[0];bufferRGB32[4 * (nRow*nWidth + nCol) + 1] = (byte)nRgb[1];bufferRGB32[4 * (nRow*nWidth + nCol) + 2] = (byte)nRgb[2];bufferRGB32[4 * (nRow*nWidth + nCol) + 3] = (byte)nRgb[3];}}return true;}public static Bitmap RGB32_to_Image( byte[] byteBuff, int nWidth, int nHeight ){if ( byteBuff.Length <= 0 || byteBuff.Length < nWidth*nHeight )return null;Bitmap bmp = new Bitmap( nWidth, nHeight, PixelFormat.Format32bppArgb );//鎖定內(nèi)存數(shù)據(jù)BitmapData bmpData = bmp.LockBits( new Rectangle( 0, 0, nWidth, nHeight ), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb );//輸入顏色數(shù)據(jù)System.Runtime.InteropServices.Marshal.Copy( byteBuff, 0, bmpData.Scan0, byteBuff.Length );//解鎖bmp.UnlockBits( bmpData );return bmp;}}效果
轉(zhuǎn)載于:https://blog.51cto.com/weiyuqingcheng/2323546
總結(jié)
以上是生活随笔為你收集整理的C#:使用海康SDK解码回调函数DecCallbackFUN()的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 宝马ETK数据提取导出MySQL
- 下一篇: C#Socket Clinet