zoukankan      html  css  js  c++  java
  • 海康威视实时预览回调PS流用EasyRTMP向RTMP服务器推流中视频数据处理的代码

    在上一篇方案《EasyRTMP结合海康HCNetSDK获取海康摄像机H.264实时流并转化成为RTMP直播推流(附源码)》我们介绍了将海康安防摄像机进行互联网直播的整体方案流程,其中有一个流程“数据处理与分析”我们当时没有展开详述,今天我们将海康HCNetSDK实时预览回调接口数据处理的过程,尤其是在RealDataCallback中对AVData的处理过程:

    		case NET_DVR_STREAMDATA:
    			{
    				BOOL inData=PlayM4_InputData(nPort,pBuffer,dwBufSize);
    				while (!inData)
    				{
    					Sleep(10);
    					inData=PlayM4_InputData(nPort,pBuffer,dwBufSize);
    					OutputDebugString("PlayM4_InputData failed 
    ");	
    				}	
    				//PS流数据解析处理		
    				{
    					int nI = 0;
    					int nCacheSize = 0;
    					nI = m_mFrameCacheLenth[lRealHandle];
    
    					//直接--提取H264数据
    					BOOL bVideo = FALSE;
    					BOOL bPatialData = FALSE;
    					bPatialData = GetH246FromPS(pBuffer,dwBufSize, &m_pFrameCache[lRealHandle][nI].pCacheBuffer, 
    						m_pFrameCache[lRealHandle][nI].nCacheBufLenth, bVideo);
    
    					if (bVideo)
    					{
    						if (bPatialData)//部分包数据
    						{
    							//缓存数据
    							m_pFrameCache[lRealHandle][nI].lTimeStamp = clock();
    							m_mFrameCacheLenth[lRealHandle]++;
    						} 
    						else//包头
    						{
    							int i = 0;
    							if(m_mFrameCacheLenth[lRealHandle]>0)
    							{
    								long lH264DataLenth = m_mFrameCacheLenth[lRealHandle]*MAX_PACK_SIZE;
    								BYTE* pH264Nal =  NULL;
    								pH264Nal = new BYTE[lH264DataLenth];
    								memset(pH264Nal, 0x00, lH264DataLenth);
    								BYTE* pTempBuffer = pH264Nal;
    								int nTempBufLenth = 0;
    
    								//TRACE("m_mFrameCacheLenth==%d
    ", pDemoDlg->m_mFrameCacheLenth);
    
    								// 最大缓存数据个数设为pDemoDlg->m_mFrameCacheLenth,程序会过程中报错,Why? [5/6/2014-13:19:51 Dingshuai]
    								for (i=0; i</*MAX_FRAME_LENTH*/m_mFrameCacheLenth[lRealHandle]; i++)
    								{
    									if(m_pFrameCache[lRealHandle][i].pCacheBuffer!=NULL&&m_pFrameCache[lRealHandle][i].nCacheBufLenth>0)
    									{
    										// 										memcpy(pTempBuffer, m_pFrameCache[i].pCacheBuffer, m_pFrameCache[i].nCacheBufLenth);
    										// 										pTempBuffer = pTempBuffer + m_pFrameCache[i].nCacheBufLenth;
    
    										memcpy(pH264Nal+nTempBufLenth, m_pFrameCache[lRealHandle][i].pCacheBuffer, 
    											m_pFrameCache[lRealHandle][i].nCacheBufLenth);
    										nTempBufLenth += m_pFrameCache[lRealHandle][i].nCacheBufLenth;
    									}
    									if (m_pFrameCache[lRealHandle][i].pCacheBuffer)
    									{
    										delete [](m_pFrameCache[lRealHandle][i].pCacheBuffer);
    										m_pFrameCache[lRealHandle][i].pCacheBuffer = NULL;
    									}	
    									m_pFrameCache[lRealHandle][i].nCacheBufLenth = 0; 
    								}
    
    								if (m_bRtmpRunning && pH264Nal && nTempBufLenth>0)
    								{
    									BOOL bIsKeyFrame = FALSE;
    									//查找是否为关键帧
    									if(pH264Nal[4]==0x67)
    									{
    										bIsKeyFrame = TRUE;
    									}
    									long lTimeStamp = clock();
    									WriteH264DataToChace(lRealHandle, pH264Nal, nTempBufLenth, bIsKeyFrame, lTimeStamp);
    								}
    
    								if (pH264Nal)
    								{
    									delete []pH264Nal;
    									pH264Nal = NULL;
    								}
    								// 缓存数据个数 清0
    								m_mFrameCacheLenth[lRealHandle] = 0;
    							}
    						}
    					}
    				}
    			}
    

    通过对上述代码的分析,整个视频流回调过程还是比较简单的:判断回调数据类型(NET_DVR_STREAMDATA)–》海康PS数据Demux成音视频ES数据(GetH246FromPS)–》对关键帧数据做缓存和处理(bIsKeyFrame )–》进入转推RTMP缓存队列(WriteH264DataToChace)

    海康PS流解析:

    BOOL CDecCallBack_DemoDlg::GetH246FromPS(IN BYTE* pBuffer, IN int nBufLenth, BYTE** pH264, int& nH264Lenth, BOOL& bVideo)
    {
    	if (!pBuffer || nBufLenth<=0)
    	{
    		return FALSE;
    	}
    
    	BYTE* pH264Buffer = NULL;
    	int nHerderLen = 0;
    	
    	if( pBuffer
    		&& pBuffer[0]==0x00
    		&& pBuffer[1]==0x00 
    		&& pBuffer[2]==0x01
    		&& pBuffer[3]==0xE0)//E==视频数据(此处E0标识为视频)
    	{
    		bVideo = TRUE;
    		nHerderLen = 9 + (int)pBuffer[8];//9个为固定的数据包头长度,pBuffer[8]为填充头部分的长度
    		pH264Buffer = pBuffer+nHerderLen;
    		if (*pH264 == NULL)
    		{
    			*pH264 = new BYTE[nBufLenth];
    		}
    		if (*pH264&&pH264Buffer&&(nBufLenth-nHerderLen)>0)
    		{	
    			memcpy(*pH264, pH264Buffer, (nBufLenth-nHerderLen));
    		}	
    		nH264Lenth = nBufLenth-nHerderLen;
    	
    		return TRUE;
    	}	
    	else if(pBuffer 
    		&& pBuffer[0]==0x00
    		&& pBuffer[1]==0x00
    		&& pBuffer[2]==0x01
    		&& pBuffer[3]==0xC0) //C==音频数据
    	{
    		*pH264 = NULL;
    		nH264Lenth = 0;
    		bVideo = FALSE;
    	}
    	else if(pBuffer 
    		&& pBuffer[0]==0x00
    		&& pBuffer[1]==0x00
    		&& pBuffer[2]==0x01
    		&& pBuffer[3]==0xBA)//视频流数据包 包头
    	{
    		bVideo = TRUE;
    		*pH264 = NULL;
    		nH264Lenth = 0;
    		return FALSE;
    	}
    	return FALSE;
    }
    

    海康音视频数据进行RTMP推流:

    int CDecCallBack_DemoDlg::WriteH264DataToChace(int nDevId, BYTE* pBuffer, int nBufSize, BOOL bIsKeyFrame, long lTimeStamp)
    {
    	if (!pBuffer || nBufSize<=0 || lTimeStamp<0)
    	{
    		return -1;
    	}
    
    	BOOL bKeyFrame  = bIsKeyFrame;
    	int nDeviceType = nDevId+1;
    	if (m_RtmpHandle && m_bRtmpRunning)
    	{
    		//H264推送RTMP
    		EASY_AV_Frame	avFrame;
    		memset(&avFrame, 0x00, sizeof(EASY_AV_Frame));
    
    		avFrame.pBuffer = (unsigned char*)pBuffer;
    		avFrame.u32AVFrameLen = nBufSize;
    		avFrame.u32VFrameType = (bKeyFrame)?EASY_SDK_VIDEO_FRAME_I:EASY_SDK_VIDEO_FRAME_P;
    		avFrame.u32AVFrameFlag = EASY_SDK_VIDEO_FRAME_FLAG;
    		avFrame.u32TimestampSec = lTimeStamp/1000000;
    		avFrame.u32TimestampUsec = (lTimeStamp%1000000);
    
    		//EnterCriticalSection(&m_cs);
    		EasyRTMP_SendPacket(m_RtmpHandle, &avFrame);	
    	}
    
    	return 1;
    }
    

    经过上述步骤,基本完成了对一路SDK数据回调的处理,如果需要一个完整的、系统的、中间件级别的流转服务,那还需要一套完整的控制机制和配套接口以及前端界面,就类似于EasyNVR一样。

    本文中所述详细代码见:https://github.com/EasyDSS/EasyRTMP/tree/master/EasyRTMP_HIK

  • 相关阅读:
    spring 整合 shiro框架
    Kafka常见问题及解决方法
    设计模式之解释器模式规则你来定(二十五)
    设计模式之原型模式简单即复杂(二十四)
    设计模式之访问者模式层次操作(二十三)
    设计模式之状态模式IFORNOIF(二十二)
    设计模式之职责链模式永不罢休(二十一)
    设计模式之组合模式透明实用(二十)
    设计模式之享元模式高效复用(十九)
    设计模式之迭代器模式解析学习源码(十八)
  • 原文地址:https://www.cnblogs.com/babosa/p/11124024.html
Copyright © 2011-2022 走看看