在上一篇博文中介绍了一个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