海康威视实时预览回调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 \n");	
				}	
				//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\r\n", 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

  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
### 回答1: 要实现java海康威视摄像头的实时预览视频流保存到指定文件,需要先安装海康威视SDK,并使用Java SDK开发工具包的类库来开发应用程序。 首先,在应用程序引入海康威视SDK库,包括HCNetSDK.dll、PlayCtrl.dll、HCAlarm.dll等。然后,使用HCNetSDK类库提供的方法来实现视频实时预览功能,并将预览视频流通过PlayCtrl.dll提供的方法进行渲染和显示。 同时,在将视频流保存到指定文件时,可以使用Java的IO流进行文件操作。首先在程序创建File对象指定文件路径,然后使用FileOutputStream类创建输出流对象,通过读取预览视频流数据的byte数组并将其写入到输出实现将视频流保存到文件的功能。 需要注意的是,保存到文件时,时间戳的处理,文件格式等问题都需要按照实际需求进行处理。 总之,要实现java海康威视摄像头实时预览视频流保存到指定文件,需要结合使用海康威视SDK和Java SDK开发工具包,具体实现过程需要根据实际情况灵活处理。 ### 回答2: Java是一种广泛应用于各种领域的高级编程语言,海康威视摄像头是一种高清晰度的视频监控设备。如何实现将海康威视摄像头的实时预览视频流保存到指定文件呢?下面以Java编程语言为主体进行分析探讨。 首先,需要了解Java的多媒体相关类库和海康威视摄像头的API接口。Java多媒体相关类库包括javax.sound.sampled和javax.media包。javax.sound.sampled是Java音频API,可以处理音频文件的读、写、播放和录制等操作;javax.media则是Java多媒体API,可以处理音频、视频和图像等媒体数据。海康威视摄像头的API接口包括SDKHCNetSDK和PlayCtrl等。 其次,需要进行海康威视摄像头的实时预览视频流以及保存到指定文件的操作。具体步骤如下: 1. 初始化海康威视摄像头SDK,包括设备登录、设备初始化和预览四个步骤。设备登录是使用设备账号密码进行登录,设备初始化是对设备进行初始化设置,预览则是打开视频流并进行播放。 2. 在预览添加截图功能,通过调用SDK的抓图函数将视频帧数据保存到内存的一个缓冲区。抓取一帧数据需要使用NET_DVR_CaptureJPEGPicture_V30函数,并将数据放置到指定的缓存区。 3. 将缓冲区的数据保存到本地文件。在Java可以使用BufferedImage类来保存JPEG图像数据,使用ImageIO类将缓冲区的图像数据保存到指定的文件。 4. 关闭设备预览,退出SDK。 需要注意的是,保存视频流到文件需要根据需求进行设置参数,包括视频流的编码格式、分辨率、帧率等。在进行保存时还应该进行异常处理,例如文件不存在、写入失败等异常情况的处理。 总之,Java实现海康威视摄像头实时预览视频流保存到指定文件需要进行多项操作,包括海康威视SDK的初始化和调用、截图和保存等。具体操作可以根据实际需要进行调整和修改,最终实现预览视频流保存到文件的功能。 ### 回答3: java是一种广泛使用的编程语言,可用于开发各种应用程序,包括与摄像头相关的应用程序。海康威视(Hikvision)是一家专业从事视频监控设备制造的企业,提供多种摄像头系列产品。本文将介绍如何使用java编写程序,实现海康威视摄像头实时预览视频流,并将视频流保存到指定文件。 首先,要实现海康威视摄像头实时预览视频流,需要使用其提供的软件开发包(SDK),该SDK提供了一组API,用于控制海康威视摄像头的各种功能。在使用SDK前,需要先在操作系统安装相关依赖库,并且在开发环境配置好SDK相关参数。 接下来,我们需要按照以下步骤编写java程序: 1.引入SDK相关jar包,并创建SDK实例。 import com.sun.jna.NativeLong; import com.sun.jna.Pointer; import com.sun.jna.ptr.IntByReference; import com.sun.jna.ptr.NativeLongByReference; import com.sun.jna.ptr.PointerByReference; import com.hikvision.netsdk.*; public class HikvisionTest { private HCNetSDK hCNetSDK; public static void main(String[] args) { HikvisionTest test = new HikvisionTest(); test.init(); test.preview(); } public void init() { hCNetSDK = HCNetSDK.INSTANCE; boolean initSuc = hCNetSDK.NET_DVR_Init(); if(!initSuc) { System.out.println("SDK初始化失败"); } } public void preview() { int userId = -1; HCNetSDK.NET_DVR_DEVICEINFO_V30 devInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V30(); NativeLong lRealHandle = new NativeLong(-1); NativeLong lLoginHandle = hCNetSDK.NET_DVR_Login_V30("10.10.10.1", 8000, "admin", "password", devInfo); if(lLoginHandle.longValue() < 0) { System.out.println("登录失败"); return; } HCNetSDK.NET_DVR_PREVIEWINFO previewInfo = new HCNetSDK.NET_DVR_PREVIEWINFO(); previewInfo.lChannel = 1; previewInfo.dwStreamType = 0; previewInfo.dwLinkMode = 0x80000000; Pointer hPlayWnd = null;//播放窗口句柄,为null表示不播放画面,只预览数据 lRealHandle = hCNetSDK.NET_DVR_RealPlay_V40(lLoginHandle, previewInfo, null); if(lRealHandle.longValue() < 0) { System.out.println("预览失败"); return; } //TODO: 在这里添加保存视频流到文件的代码 } } 2.登录网络摄像头,并开启实时预览。 在上述代码,我们调用了NET_DVR_Login_V30方法登录摄像头设备,该方法返回登录句柄,如果登录失败则返回-1。登录成功后,我们可以通过NET_DVR_RealPlay_V40方法开启实时预览功能,该方法调用后返回实时预览句柄,如果开启预览失败则返回-1。在实时预览时,我们可以指定播放窗口句柄,如果传入null则表示只预览播放。 3.将视频流保存到指定文件。 要将视频流保存到指定文件,我们可以在预览时添加代码,调用NET_DVR_SaveRealData保存视频流数据。 hCNetSDK.NET_DVR_SaveRealData(lRealHandle, "D:\\video\\test.mp4"); 以上代码将把视频流数据保存到指定文件路径(D:\\video\\test.mp4)。 另外,为了保证视频流数据正常保存,还需要添加停止预览和注销登录相关的代码。停止预览时,可以调用NET_DVR_StopRealPlay方法停止实时预览;注销登录时,可以调用NET_DVR_Logout方法注销登录句柄。 总之,使用java编写程序实现海康威视摄像头实时预览视频流并保存视频到指定文件,需要使用海康威视摄像头SDK提供的API来控制摄像头功能,同时需要注意代码的执行顺序和各种参数的设置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值