天天看点

如何读取H264并用RTP发送(VsParserSendH264)

在上一篇博文中介绍了一个H264文件的解析封装类(https://blog.csdn.net/toshiba689/article/details/86747620),而这篇博文给大家介绍怎么把读出来的H264数据以RTP协议发送出去。我继续以前面读H264的代码为例子,加上发送H264的功能。

这个例子的main函数代码如下:

int _tmain(int argc, _TCHAR* argv[])
{
	CFrameExtractFilter fileParser;

	fileParser.SetLoopMode(FALSE);
	if(fileParser.OpenFile(_T("D:\\videos\\185.1080P.264"), H264_DEC) != 0)
	{
		printf(("OpenFile failed \n"));
		return -1;
	}

	unsigned int current_timestamp = 0; //当前时间戳
	unsigned int timestamp_increase= 3600; //时间戳增量,90000/25 = 3600
    unsigned int frame_duration = 1000/25; //帧的间隔时间 

	unsigned char * pFrameBuffer = (unsigned char*)malloc(1000*1024);
    unsigned int nFrameSize = 0;
	char cType = '\0';

	// Init WinSock
	WSADATA   data;
	int ret = WSAStartup(0x0202, &data);
	if (ret != 0)
	{
		return -2;
	}

	H264Handler * pH264Handler = new H264Handler();
	pH264Handler->SetPayloadType(96);

	RTSPStream     StreamSender(10);
	StreamSender.InitUDPSocket(56120, "127.0.0.1", 1234);

	while(1)
	{
		nFrameSize = 0;
		if(fileParser.GetNextFrame(pFrameBuffer, &nFrameSize, &cType) <= 0) //获取每一帧的数据内容,数据长度,帧类型(I/P/B)
		{
			break;
		}
		printf(("GetNextFrame got size: %d, frame_type: %c \n"), nFrameSize, cType);

	   //StreamSender.SendFrame(pFrameBuffer, nFrameSize, 96, current_timestamp);
		pH264Handler->WriteData(pFrameBuffer, nFrameSize, current_timestamp, &StreamSender);

		current_timestamp += timestamp_increase;

		Sleep(frame_duration);
	}

	free(pFrameBuffer);
    delete pH264Handler;

	WSACleanup();

	return 0;
}
           

跟之前的例子不同,这里多定义了两个变量:一个是H264Hander类型的指针变量pH264Handler,另外一个是RTSPStream类型的变量StreamSender。前者是负责将H264的帧切分成NALU单元,然后再以FU-A的打包格式把NALU封装到RTP包里;后者是用来发送RTP包的,只支持UDP发送。RTPStream类型的对象在初始化时需要设置接收端的IP地址、目标端口号以及本地绑定的端口信息(这个端口可以随意设置,只要没有被其他进程占用)。

H264Handler * pH264Handler = new H264Handler();
	pH264Handler->SetPayloadType(96);

	RTSPStream     StreamSender(10);
	StreamSender.InitUDPSocket(56120, "127.0.0.1", 1234);
           

然后,通过调用GetNextFrame获得一个帧的数据,注意这个帧是不能马上打包成RTP发送的,因为它不是一个NALU,按照H264的规范,需要以NALU为单位切分,然后再封装到RTP包里,一个NALU可以封装到一个或多个RTP包里面。前面说了,切分NALU和打包RTP都是由H264Handler类来处理,而实际上是由H264Handler::WriteData函数来处理,该函数内部组成RTP包,并且发送包到目标的IP地址。调用WriteData的示例代码如下:

pH264Handler->WriteData(pFrameBuffer, nFrameSize, current_timestamp, &StreamSender);
           

传给这个函数的参数除了帧的Buffer地址,帧的大小,RTSPStream类型的实例指针,还有时间戳。其中时间戳是一个32位的无符号整型,发送一帧后时间值会递增,增加多少呢?这个是根据流的时钟频率和帧率来确定的,一般H264流的时钟频率是90000,我们可以理解为将1秒分成90000份,而单位时间就是1/90000秒。如果1秒有25帧,那么每一个帧的Duration Time就有90000/25=3600,所以每次处理完一帧都将时间戳加上3600。

好了,介绍到这里,其他大家看代码吧!

代码下载地址:https://download.csdn.net/download/toshiba689/10948166

继续阅读