RTP 发送PS流零拷贝方案
Posted qianbo_insist
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RTP 发送PS流零拷贝方案相关的知识,希望对你有一定的参考价值。
代码依然在gitee上,逐步修改
https://gitee.com/guanzhi0319/rtp
数据达到发送RTP
数据收集到后,编码h264,或者h265,发送ps流或者h264裸流到指定服务器。
void LiveRTPUdpEncoder::OnCaptureVideoBuffer(uint8_t *data, int len, unsigned int timestamp, bool isKeyframe)
#define D(x) *(data+x)
if (SimpleThread::IsStop()) return;
#if 0
char buffer[32];
sprintf_s(buffer, "QB:%02x %02x %02x %02x %02x %02x",
D(0), D(1), D(2), D(3), D(4), D(5));
OutputDebugStringA(buffer);
return;
#endif
uint8_t* odata = NULL;
int olen = 0;
uint8_t n = D(4) & 0x1f;
int isIFrame = n == 0x07;
switch (v_stream_type)
case en_rtp:
odata = data;
olen = len;
break;
case en_ps_over_rtp:
uint8_t* odata;
int olen;
v_ps.packagingPs(isIFrame, timestamp, data, len, &odata, &olen);
break;
//timestamp = GetTimestamp();
Lock lock(this);
if(v_stream_type == en_ps_over_rtp)
uint8_t* ps = odata + RTP_UDP_HEAD_LEN;
olen = olen - RTP_UDP_HEAD_LEN;
v_rtp.send_video_ps(ps, olen, convertToRTPTimestamp(), isKeyframe);
delete[]odata;
else if (v_stream_type == en_rtp)
v_rtp.send_video(odata, olen, convertToRTPTimestamp(), isKeyframe);
if (!gVideoBegin)
gVideoBegin = true;
发送RTP ps
在ps流的前面留空12字节,每次1400字节发送的时候,修改前面12字节RTP包,注意也就是修改了数据包,不复用,并且发送一定是同步的才能正确,好处是避免了数据拷贝。
避免数据拷贝的方式有两种,
1、一种是同步缓冲区,但是异步发送
2、同步发送
3、使用协程,同步发送。
这里是客户端,发送时只有一路,使用了UDP,直接同步发送就行。申请ps内存的时候为了不拷贝数据,前面留空了12字节作为RTP UDP的头部。那么在发送每隔包的时候,在发送的数据往前倒推12字节,避免拷贝,但是这样修改了缓冲区里的数据,如果想复用,每次在覆盖的时候先把12字节赋值,发送完毕,再把字节恢复。
int c_rtp::send_video_ps(uint8_t* data, int len, uint32_t timestamp, bool iskeyframe)
//data 前面有12 字节为空,构造 ps 流时留空
uint8_t* x = data;
int num = (len - 1) / 1400 + 1;
for (int i = 0; i < num; i++)
uint8_t* pos = x - 12;
memset(pos, 0, 12);
RTP_FIXED_HEADER* rtp_hdr; //RTP头部
rtp_hdr = (RTP_FIXED_HEADER*)data;
//设置RTP HEADER,
rtp_hdr->payload = H264; //负载类型号,
rtp_hdr->version = 2; //版本号,此版本固定为2
rtp_hdr->marker = 0; //标志位,由具体协议规定其值。
rtp_hdr->ssrc = little2big(1111);
rtp_hdr->timestamp = little2big(timestamp);
if (i < num-1)
v_sock.SendTo(pos, 12 + 1400, v_sockaddr);
else
v_sock.SendTo(pos, 12 + len -1400*i,v_sockaddr);
x += 1400;
这里的v_sock 就是简单的同步发送socket。读者有兴趣,可以自己改为异步方式。
以上是关于RTP 发送PS流零拷贝方案的主要内容,如果未能解决你的问题,请参考以下文章