1.   sps 及pps 封装格式:

void yang_getConfig_Meta_H264( YangSample* psps,  YangSample* ppps,uint8_t *configBuf,int32_t *p_configLen){//type_codec1 + avc_type + composition time + fix header + count of sps + len of sps + sps + count of pps + len of pps + pps// int32_t nb_payload = 1 + 1 + 3 + 5 + 1 + 2 + sps->size + 1 + 2 + pps->size;int32_t spsLen=psps->nb;int32_t ppsLen=ppps->nb;uint8_t* sps=(uint8_t*)psps->bytes;uint8_t* pps=(uint8_t*)ppps->bytes;configBuf[0] = 0x17;configBuf[1] = 0x00;configBuf[2] = 0x00;configBuf[3] = 0x00;configBuf[4] = 0x00;configBuf[5] = 0x01;configBuf[6] = sps[1];//0x42;configBuf[7] = sps[2];//0xC0;configBuf[8] = sps[3];//0x29;        //0x29;  //AVCLevelIndication1fconfigBuf[9] = 0xff;        //03;//ff;//0x03; AVCLevelIndicationconfigBuf[10] = 0xe1;      //01;//e1;//01;numOfSequenceParameterSetsuint8_t * szTmp = configBuf + 11;yang_put_be16((char*) szTmp, (uint16_t) spsLen);szTmp+=2;//*szTmp++=0x00;// *szTmp++=spsLen;memcpy(szTmp, sps, spsLen);szTmp += spsLen;*szTmp = 0x01;szTmp += 1;yang_put_be16((char*) szTmp, (uint16_t) ppsLen);szTmp+=2;// *szTmp++=0x00;// *szTmp++=ppsLen;memcpy(szTmp, pps, ppsLen);szTmp += ppsLen;*p_configLen = szTmp -  configBuf;szTmp = NULL;
}

I 及P 帧:四个字节start code 替换成size,size  为I及P 的大小减4。

2. rtp  数据封装

封包介绍:

 2.1 RTP 头的结构:

  • V: RTP协议的版本号,占2bits,当前协议版本号为2
  • P: 填充标志,占1bit,如果P=1,则在该报文的尾部填充一个或多个额外的八位组,它们不是有效载荷的一部分。
  • X: 扩展标志,占1bit,如果X=1,则在RTP报头后跟有一个扩展报头
  • CC: CSRC计数器,占4位,指示CSRC 标识符的个数
  • M: 1bit,标记解释由设置定义,目的在于允许重要事件在包流中标记出来。如不同的有效载荷有不同的含义,对于视频,标记一帧的结束;对于音频,标记会话的开始。
  • 负载类型 Payload type(PT): 7bits
  • 注:rfc里面对一些早期的格式定义了这个payload type。但是后来的,如h264并没有分配,那就用96来代替。因此现在96以上都不表示特定的格式,具体表示什么要用sdp或者其他协议来协商。
  • 序列号 Sequence number(SN): 16bits,用于标识发送者所发送的RTP报文的序列号,每发送一个报文,序列号增1,序列号的初始值是随机产生的。可以用于检查丢包以及进行数据包排序。
  • 时间戳 Timestamp: 32bits,必须使用90kHz时钟频率。
  • 同步信源(SSRC)标识符: 32bits,用于标识同步信源。该标识符是随机随机产生的,参加同一视频会议的两个同步信源不能有相同的SSRC。
  • 特约信源(CSRC)标识符: 每个CSRC标识符占32bits,可以有0~15个。每个CSRC标识了包含在该RTP报文有效载荷中的所有特约信源。

2.2   头部FU-indicator格式为.占用一个字节:

     +---------------+|0|1|2|3|4|5|6|7|+-+-+-+-+-+-+-+-+|F|NRI|  Type   |+---------------+
  • F:在规范中规定了这一位必须为0.
  • NRI:取00~11,表示这个NALU的重要性,如00的NALU解码器可以丢弃它而不影响图像的回放.
  • Type:这个NALU单元的类型,具体如下:

2.3 单一NAL单元模式

对于 NALU 的长度小于 MTU 大小的包, 一般采用单一 NAL 单元模式.
  对于一个原始的 H.264 NALU 单元常由 [Start Code] [NALU Header] [NALU Payload] 三部分组  成, 其中 Start Code 用于标示这是一个

NALU 单元的开始, 必须是 "00 00 00 01" 或 "00 00 01", NALU 头仅一个字节, 其后都是 NALU 单元内容.
 打包时去除 "00 00 01" 或 "00 00 00 01" 的开始码, 把其他数据封包的 RTP 包即可.

       0                   1                   2                   30 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|F|NRI|  type   |                                               |+-+-+-+-+-+-+-+-+                                               ||                                                               ||               Bytes 2..n of a Single NAL unit                 ||                                                               ||                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                               :...OPTIONAL RTP padding        |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

例:
如有一个 H.264 的 NALU 是这样的:

[00 00 00 01 67 42 A0 1E 23 56 0E 2F ... ]

这是一个序列参数集 NAL 单元. [00 00 00 01] 是四个字节的开始码, 67 是 NALU 头, 42 开始的数据是 NALU 内容.

封装成 RTP 包将如下:

[ RTP Header ][FU-indicator] [ 67 42 A0 1E 23 56 0E 2F ]

即只要去掉 4 个字节的开始码就可以了.

2.4 组合封包模式

其次, 当 NALU 的长度特别小时, 可以把几个 NALU 单元封在一个 RTP 包中.

当 NALU 的长度特别小时, 可以把几个 NALU 单元封在一个 RTP 包中。比如H264的SPS和PPS数据,每个数据包前面带2bit的长度

2.5   分片的单元:

当NALU的长度超过MTU时,就必须对NALU单元进行分片封包.也称为Fragmentation Units(FUs).
  
      Figure 14.  RTP payload format for FU-A

The FU indicator octet has the following format:

  • F:值为 0 表示 NAL 单元类型八位字节和有效负载不应包含位错误或其他语法违规行为。值为 1 表示 NAL 单元类型八位字节和有效载荷可能包含位错误或其他语法违规。
  • NRI:与 H.264 规范保持不变
  • Type:FU-A(28)或FU-B(29)

The FU header has the following format:

  • S:起始位,当RTP包的有效负载是第一个NAL单元分片时,该位为1,否则为0;
  • E:结束位,当RTP包的有效负载是最后一个NAL单元分片时,该位为1,否则为0;
  • R:保留位必须等于 0
  • Type:值为H264 NALU Header中的Type。

3. metartc 封包

yang_push_h264_video 根据 数据大小与kRtpMaxPayloadSize 比较,不超过采用单一NAL单元模式。超过采用fu_a 封包模式。

int32_t yang_push_h264_video(void *psession, YangPushH264Rtp *rtp,YangFrame *videoFrame) {int32_t err = Yang_Ok;YangRtcSession *session=(YangRtcSession*)psession;if (videoFrame->nb <= kRtpMaxPayloadSize) {if ((err = yang_push_h264_package_single_nalu2(session, rtp, videoFrame))!= Yang_Ok) {return yang_error_wrap(err, "package single nalu");}session->context.stats.sendStats.videoRtpPacketCount++;} else {if ((err = yang_push_h264_package_fu_a(session, rtp, videoFrame,kRtpMaxPayloadSize)) != Yang_Ok) {return yang_error_wrap(err, "package fu-a");}}session->context.stats.sendStats.frameCount++;return err;
}

分析yang_push_h264_package_fu_a 函数。

int32_t yang_push_h264_package_fu_a(YangRtcSession *session, YangPushH264Rtp *rtp,YangFrame *videoFrame, int32_t fu_payload_size) {int32_t err = Yang_Ok;int32_t plen = videoFrame->nb;uint8_t *pdata = videoFrame->payload;char *p = (char*) pdata + 1;int32_t nb_left = plen - 1;uint8_t header = pdata[0];uint8_t nal_type = header & kNalTypeMask;int32_t num_of_packet = ((plen - 1) % fu_payload_size==0)?0:1 + (plen - 1) / fu_payload_size;for (int32_t i = 0; i < num_of_packet; ++i) {int32_t packet_size = yang_min(nb_left, fu_payload_size);yang_reset_rtpPacket(&rtp->videoFuaPacket);rtp->videoFuaPacket.header.payload_type = YangH264PayloadType;rtp->videoFuaPacket.header.ssrc = rtp->videoSsrc;rtp->videoFuaPacket.frame_type = YangFrameTypeVideo;rtp->videoFuaPacket.header.sequence = rtp->videoSeq++;rtp->videoFuaPacket.header.timestamp = videoFrame->pts;rtp->videoFuaPacket.header.marker = (i == num_of_packet - 1) ? 1 : 0;rtp->videoFuaPacket.payload_type = YangRtspPacketPayloadTypeFUA2;memset(&rtp->videoFua2Data, 0, sizeof(YangFua2H264Data));rtp->videoFua2Data.nri = (YangAvcNaluType) header;rtp->videoFua2Data.nalu_type = (YangAvcNaluType) nal_type;rtp->videoFua2Data.start = (i == 0) ? 1 : 0;rtp->videoFua2Data.end = (i == (num_of_packet - 1)) ? 1 : 0;rtp->videoFua2Data.payload = rtp->videoBuf;rtp->videoFua2Data.nb = packet_size;memcpy(rtp->videoFua2Data.payload, p, packet_size);p += packet_size;nb_left -= packet_size;
#if Yang_Using_TWCCif(i==0){rtp->rtpExtension.twcc.sn=rtp->twccSeq++ ;rtp->videoFuaPacket.header.extensions=&rtp->rtpExtension;session->context.twcc.insertLocal(&session->context.twcc.session,rtp->rtpExtension.twcc.sn);}
#endifif ((err = yang_push_h264_encodeVideo(session, rtp, &rtp->videoFuaPacket))!= Yang_Ok) {return yang_error_wrap(err, "encode packet");}rtp->videoFuaPacket.header.extensions=NULL;}return err;
}

函数数据:yang_encode_h264_fua2  分包封装及yang_encode_h264_raw single NAL 封装。

int32_t yang_push_h264_encodeVideo(YangRtcSession *session, YangPushH264Rtp *rtp,YangRtpPacket *pkt) {int err = 0;yang_init_buffer(&rtp->buf, yang_get_rtpBuffer(rtp->videoRtpBuffer),    kRtpPacketSize);if ((err = yang_encode_rtpHeader(&rtp->buf, &pkt->header)) != Yang_Ok) {return yang_error_wrap(err, "rtp header(%d) encode packet fail",pkt->payload_type);}if (pkt->payload_type == YangRtspPacketPayloadTypeRaw) {err = yang_encode_h264_raw(&rtp->buf, &rtp->videoRawData);} else if (pkt->payload_type == YangRtspPacketPayloadTypeFUA2) {err = yang_encode_h264_fua2(&rtp->buf, &rtp->videoFua2Data);} else if (pkt->payload_type == YangRtspPacketPayloadTypeSTAP) {err = yang_encode_h264_stap(&rtp->buf, &rtp->stapData);yang_reset_h2645_stap(&rtp->stapData);}if (err != Yang_Ok) {return yang_error_wrap(err, "rtp payload(%d) encode packet fail",pkt->payload_type);}if (pkt->header.padding_length > 0) {uint8_t padding = pkt->header.padding_length;if (!yang_buffer_require(&rtp->buf, padding)) {return yang_error_wrap(ERROR_RTC_RTP_MUXER,"padding requires %d bytes", padding);}memset(rtp->buf.head, padding, padding);yang_buffer_skip(&rtp->buf, padding);}session->context.stats.on_pub_videoRtp(&session->context.stats.sendStats,pkt,&rtp->buf);return yang_send_avpacket(session, pkt, &rtp->buf);
}

yang_encode_h264_fua2 组成rtp 数据包;

int32_t yang_encode_h264_fua2(YangBuffer* buf,YangFua2H264Data* pkt){if (!yang_buffer_require(buf,2 + pkt->nb)) {return yang_error_wrap(ERROR_RTC_RTP_MUXER, "requires %d bytes", 1);}char *p = buf->head;   // rtp header 数据包uint8_t fu_indicate = kFuA;fu_indicate |= (pkt->nri & (~kNalTypeMask));*p++ = fu_indicate;   // 一个字节fu_indicate // FU header, @see https://tools.ietf.org/html/rfc6184#section-5.8uint8_t fu_header = pkt->nalu_type;if (pkt->start) {fu_header |= kStart; }if (pkt->end) {fu_header |= kEnd;}*p++ = fu_header;    // 一个字节fu_header,表示分包,开始-》中间-》结束// FU payload, @see https://tools.ietf.org/html/rfc6184#section-5.8memcpy(p, pkt->payload, pkt->nb);    // 数据部分// Consume bytes.yang_buffer_skip(buf,2 + pkt->nb);return Yang_Ok;
}

流媒体协议分析之webrtc之rtp相关推荐

  1. 流媒体协议分析之webrtc 协议 srs 服务器实现

    1.信令交互  ,sdp信令交互. listen_udp : 注册udp 监听: listen_api :注册信令交互接口: #ifdef SRS_RTC_srs_hybrid->registe ...

  2. 网络流媒体协议的联系与区别(RTP RTCP RTSP RTMP HLS)

    简结">三句话简结 RTP RTCP RTSP RTMP HLS区别与联系 RTP传输流媒体数据.RTCP对RTP进行控制,同步.RTSP发起/终止流媒体 RTP和RTCP互为姐妹关系 ...

  3. 低延迟流媒体协议SRT、WebRTC、LL-HLS、UDP、TCP、RTMP详解

    低广播延迟已经成为任何关于建设源端站和CDN的招标和竞争中的必要特性.以前这种标准只适用于体育广播,但现在运营商要求每个领域的广播设备供应商提供低延迟,比如:广播新闻.音乐会.表演.采访.谈话节目.辩 ...

  4. WebRTC中RTP协议详解

    WebRTC中RTP协议详解 WebRTC中RTP协议详解 WebRTC中RTP协议详解 前言 一.RTP/RTCP在协议栈中的位置 1. RTP传输流程图 二.RTP Header 的结构图 1.R ...

  5. 流媒体学习之路(WebRTC)——GCC分析(1)

    流媒体学习之路(WebRTC)--GCC整体分析(1) 文章目录 流媒体学习之路(WebRTC)--GCC整体分析(1) 一.简介 二.类分析 2.1 RtpTransportControllerSe ...

  6. webrtc 和 rtp 协议

    我会开辟一个空间rtp协议,包含vp9 h264 h265 aac opus 等rtp实例,包含实例代码,让看文章的人得到真实的提升 一.webrtc rtp协议为实时传输协议 real transf ...

  7. 流媒体协议初探(MPEG2-TS、RTSP、RTP、RTCP、SDP、RTMP、HLS、HDS、HSS、MPEG-DASH)

    目录 一.综述 需求分析 协议定制 二.MPEG2-TS协议 三.RTSP协议.RTP.RTCP.SDP RTSP RTP.RTCP.SDP 四.RTMP 五.HLS.HDS.HSS HLS HDS和 ...

  8. 私有RTP协议和标准流媒体协议

    先介绍下RTP协议: 实时传输协议RTP(Real-time Transport Protocol)是一个网络传输协议 ,该协议详细说明了在互联网上传递音频和视频的标准数据包格式 . RTP标准定义了 ...

  9. 网络流媒体协议之——RTP协议概述

    网络流媒体协议系列: 网络流媒体协议之--MPEG-DASH协议简述 网络流媒体协议之--HLS概述 网络流媒体协议之--UDP协议概述 今天来整理一下RTP. RTP(Real-time Trans ...

最新文章

  1. php读取cookie文件,PHP读取CURL模拟登录时生成Cookie文件的方法,_PHP教程
  2. 《Git in Practice》作者访谈:关于Git的八个问题
  3. iptables基本配置方法
  4. 为特使构建控制平面的指南-为可插入性构建
  5. 变异检测VarScan软件使用说明
  6. 【6.24-AppCan移动开发大会倒计时】科大讯飞来了!
  7. 软考信息安全工程师好考吗?
  8. 机器人SCI期刊及其特点、评价、投稿之我见
  9. RHCE-ansible第二次实验,通过ansible远程yum安装
  10. 小米运动蓝牙耳机重新配对_小米运动蓝牙耳机怎么连接手机
  11. bde访问64位oracle,Delphi5企业版使用BDE访问Oracle方法
  12. php程序员 一万小时定律,科学网—一万小时定律——阅读笔记 - 贾琳的博文
  13. App开发智能车载应用之概述篇
  14. 用计算机计算下列各式 11x,用计算器计算有理数的乘方教学设计实例
  15. max std value 宏_新药临床试验统计分析中计量资料的SAS宏实现
  16. 兄弟连兄弟会机构好不好
  17. python人脸识别、语音合成、智能签到系统
  18. ARCGIS SERVER:未指定的错误
  19. 更深、更轻量级的Transformer!Facebook提出:DeLighT
  20. 交换友情链接需要注意哪些问题,友链交换平台有哪些

热门文章

  1. 今日头条视频伪原创处理软件
  2. 期货开户如何确定期货公司正规性?
  3. Go :生成索引和切片边界检查的测试(附完整源码)
  4. Spring Boot入门操作(轻熟易懂)
  5. 【算法 独孤九剑】算法模型训练的一般流程
  6. MacBook Pro使用Gitee教程
  7. 您尝试购买的项目已停止供货
  8. ubuntu 修改apache2 默认网站目录和默认主页文档
  9. Django学习之路由分发和反向解析
  10. word中数学公式的输入