WebRTC之RTP包
时间:2019-02-25
本文章向大家介绍WebRTC之RTP包,主要包括WebRTC之RTP包使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
RTP固定头部
RTP的固定头部,详情可以阅读rfc文档5.1 RTP Fixed Header Fields
0 1 2 3
0 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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X| CC |M| PT | sequence number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| synchronization source (SSRC) identifier |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
| contributing source (CSRC) identifiers |
| .... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- V版本号位,必须等于2
- P填充位
- X扩展位,标志是否存在扩展
- CC CSRC个数
- M Mark标志位,标志是否是一帧的结束,音频帧几乎每个包都是一个完整的帧,所以M一般情况都等于1,视频包因为一帧比较大,会被分为几个包发送,最后一个包标志需要Mark一下
- PT负载类型,不同的负载类型对应不同的编解码类型(音频根据采样率和通道不同都要对应不同的负载类型),FEC类型等。
- sequence number,包序号,发送端指定一个起始序号(如果不指定则随机一个),然后每个包的序号依次递增;如果存在RTX,重发是此序号是rtx的序号,详情请看
RTPSender::SendPadData
的实现 - timestamp,包的时间戳,如果一个视频帧被分为几个包,则这个帧对应的几个包的时间戳是一样的;发送端可以指定一个起始时间戳timestamp_offset_(如果不指定则随机一个),然后每个帧的时间戳等于起始时间戳加上采集时间戳
timestamp_offset_ + capture_timestamp
,详情可以看RTPSender::SendOutgoingData
的实现 - SSRC,同步源的唯一标识,每一个源(音频或者视频,文件)都必须要有一个唯一的标识码,用于区分不同的流
- CSRC,贡献源,列举此SSRC的资源是由多少个其他的资源(其他资源的SSRC)混合而来的。例如MCU混音之后就需要修改这个;最多只能表示15源
RTP扩展
如果存在RTP扩展则标志位X必须置为1,除了标准扩展外,WebRTC还有自己的扩展,所以服务端如果使用标准rtp解析库需要添加一下WebRTC的RTP扩展。
扩展相关的几个文件rtp_header_extensions.h和rtp_utility.cc可以阅读一下
- kRtpExtensionTransmissionTimeOffset,一个包相对于采集时间的偏移的滴答数
# rtp_sender.cc +569
if (capture_time_ms > 0) {
padding_packet.SetExtension<TransmissionOffset>(
(now_ms - capture_time_ms) * kTimestampTicksPerMs);
}
- kRtpExtensionAudioLevel,一帧音频数据的分贝值
# rtp_sender_audio.cc +226
packet->SetExtension<AudioLevel>(frame_type == kAudioFrameSpeech, audio_level_dbov);
- kRtpExtensionAbsoluteSendTime,一个包的绝对发送时间
# rtp_sender.cc +572
padding_packet.SetExtension<AbsoluteSendTime>(AbsoluteSendTime::MsTo24Bits(now_ms));
- kRtpExtensionVideoRotation,帧视频帧的方向
# rtp_sender_video.cc +331
last_packet->SetExtension<VideoOrientation>(current_rotation);
- kRtpExtensionTransportSequenceNumber,扩展序号,不管是第一次发送还是重发的包,此需要都会递增
# rtp_sender.cc +1066
*packet_id = transport_sequence_number_allocator_->AllocateSequenceNumber();
if (!packet->SetExtension<TransportSequenceNumber>(*packet_id))
-
kRtpExtensionPlayoutDelay
-
kRtpExtensionVideoContentType,视频源是否是屏幕资源
# rtp_sender_video.cc +336
last_packet->SetExtension<VideoContentTypeExtension>(video_header->content_type);
- kRtpExtensionVideoTiming,记录视频编码开始,编码结束,打包完成,平滑发送等时间戳,不过这几个时间戳都是相对时间
# 填充此结构体 frame_object.cc +121
timing_.encode_start_ms = ntp_time_ms_ + last_packet->video_header.video_timing.encode_start_delta_ms;
timing_.encode_finish_ms = ntp_time_ms_ + last_packet->video_header.video_timing.encode_finish_delta_ms;
timing_.packetization_finish_ms = ntp_time_ms_ + last_packet->video_header.video_timing.packetization_finish_delta_ms;
timing_.pacer_exit_ms = ntp_time_ms_ + last_packet->video_header.video_timing.pacer_exit_delta_ms;
timing_.network_timestamp_ms = ntp_time_ms_ + last_packet->video_header.video_timing.network_timstamp_delta_ms;
timing_.network2_timestamp_ms = ntp_time_ms_ + last_packet->video_header.video_timing.network2_timstamp_delta_ms;
# 打包到rtp包中 rtp_sender_video.cc +340
last_packet->SetExtension<VideoTimingExtension>(video_header->video_timing);
- 这几个扩展kRtpExtensionRtpStreamId,kRtpExtensionRepairedRtpStreamId,kRtpExtensionMid,WebRTC都没有使用
- poj-------(2240)Arbitrage(最短路)
- MySQL在线DDL修改表结构的简单经验分享
- HDUOJ-----(1162)Eddy's picture(最小生成树)
- hduoj----1142A Walk Through the Forest(记忆化搜索+最短路)
- java设计之简单的JAVA计算器
- Java之线程———GUI线程(包含打字游戏和计时器俩个GUI实列)
- la----3695 City Game(最大子矩阵)
- poj------(3468)A Simple Problem with Integers(区间更新)
- hdu-------(1698)Just a Hook(线段树区间更新)
- NBitcoin:密码学第2部分
- gh-ost:在线DDL修改MySQL表结构工具
- poj-----(2828)Buy Tickets(线段树单点更新)
- javaSE之线程联合
- ASM 翻译系列第三十一弹:了解ASM文件的空间分配
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- MySQL Galera Cluster全解析 Part 10 grastate.dat文件详解
- MySQL MHA部署 Part 7 MHA手动切换测试
- 使用sysbench进行压测 Part2 sysbench语法介绍
- mysqlbinlog命令详解 Part 1-实验环境准备
- mysqlbinlog命令详解 Part 2 -MySQL 事件类型
- mysqlbinlog命令详解 Part 4 -查看行事件具体SQL语句
- mysqlbinlog命令详解 Part 5 通过位置和时间查看日志
- mysqlbinlog命令详解 Part 6 读取远程MySQL服务器日志
- mysqlbinlog命令详解 Part 7 备份二进制日志文件
- mysqlbinlog命令详解 Part 8 指定 Server ID
- mysqlbinlog命令详解 Part 9 MySQL备份策略
- mysqlbinlog命令详解 Part 10 恢复MySQL
- mysqldump命令详解 Part 2- 建立触发器 事件
- mysqlbinlog命令详解 Part 11 其他的一些参数
- mysqldump命令详解 Part 1 -MySQL测试数据的构造