RTSP 协议
一次交互数据分析
// OPTIONS 是客户端向服务器询问可用的方法
2019-02-04 20:57:41.554 9784-9851/com.zpf.androidshow E/RtspServer: OPTIONS rtsp://192.168.3.23:8086
2019-02-04 20:57:41.554 9784-9851/com.zpf.androidshow E/RtspServer: 请求内容:
CSeq: 2
User-Agent: LibVLC/3.0.6 (LIVE555 Streaming Media v2016.11.28)
// 响应 DESCRIBE,SETUP,TEARDOWN,PLAY,PAUSE
2019-02-04 20:57:41.556 9784-9851/com.zpf.androidshow D/RtspServer: 响应内容:
RTSP/1.0 200 OK
Server: MajorKernelPanic RTSP Server
Cseq: 2
Content-Length: 0
Public: DESCRIBE,SETUP,TEARDOWN,PLAY,PAUSE
//DESCRIBE 客户端向服务器请求媒体资源描述, 服务器端通过SDP(Session Description Protocol)格式回应客户端的请求;
2019-02-04 20:57:41.595 9784-9851/com.zpf.androidshow E/RtspServer: DESCRIBE rtsp://192.168.3.23:8086
2019-02-04 20:57:41.595 9784-9851/com.zpf.androidshow E/RtspServer: 请求内容:
CSeq: 3
User-Agent: LibVLC/3.0.6 (LIVE555 Streaming Media v2016.11.28)
Accept: application/sdp
//这时候响应sdp
2019-02-04 20:57:41.616 9784-9851/com.zpf.androidshow I/MediaStream: Phone supports the MediaCoded API
2019-02-04 20:57:41.644 9784-9851/com.zpf.androidshow D/RtspServer: 响应内容:
RTSP/1.0 200 OK
Server: MajorKernelPanic RTSP Server
Cseq: 3
Content-Length: 241
Content-Base: 192.168.3.23:8086/
Content-Type: application/sdp
v=0
o=- 0 0 IN IP4 192.168.3.23
s=Unnamed
i=N/A
c=IN IP4 192.168.3.188
t=0 0
a=recvonly
m=video 0 RTP/AVP 96
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1;profile-level-id=000042;sprop-parameter-sets=;
a=control:trackID=1
//SETUP请求确定了具体的媒体流如何传输, 该请求必须在PLAY请求之前发送; SETUP请求包含媒体流的URL和客户端用于接收RTP数据(audio or video)的端口以及接收RTCP数据(meta information)的端口; 服务器端的回复通常包含客户端请求参数的确认, 并会补充缺失的部分, 比如服务器选择的发送端口; 每一个媒体流在发送PLAY请求之前, 都要首先通过SETUP请求来进行相应的配置;
//示例: client_port=50152-50153, server_port=20024-20025;其中50152对应20024进行音频或视频传输, 50153对应20025进行rtcp控制协议传输;
2019-02-04 20:57:41.665 9784-9851/com.zpf.androidshow E/RtspServer: SETUP 192.168.3.23:8086/trackID=1
2019-02-04 20:57:41.665 9784-9851/com.zpf.androidshow E/RtspServer: 请求内容:
CSeq: 4
User-Agent: LibVLC/3.0.6 (LIVE555 Streaming Media v2016.11.28)
Transport: RTP/AVP;unicast;client_port=61386-61387
2019-02-04 20:57:41.671 9784-9853/com.zpf.androidshow D/H264Packetizer: H264 packetizer started !
2019-02-04 20:57:41.673 9784-9851/com.zpf.androidshow D/RtspServer: 响应内容:
RTSP/1.0 200 OK
Server: MajorKernelPanic RTSP Server
Cseq: 4
Content-Length: 0
Transport: RTP/AVP/UDP;unicast;destination=192.168.3.188;client_port=61386-61387;server_port=41548-33086;ssrc=f821639b;mode=play
Session: 1185d20035702ca
Cache-Control: no-cache
//客户端通过PLAY请求来播放一个或全部媒体流, PLAY请求可以发送一次或多次, 发送一次时, URL为包含所有媒体流的地址, 发送多次时, 每一次请求携带的URL只包含一个相应的媒体流; PLAY请求中可指定播放的range
2019-02-04 20:57:41.905 9784-9851/com.zpf.androidshow E/RtspServer: PLAY 192.168.3.23:8086/
2019-02-04 20:57:41.905 9784-9851/com.zpf.androidshow E/RtspServer: 请求内容:
CSeq: 5
User-Agent: LibVLC/3.0.6 (LIVE555 Streaming Media v2016.11.28)
Session: 1185d20035702caRange: npt=0.000-
2019-02-04 20:57:41.905 9784-9851/com.zpf.androidshow D/RtspServer: 响应内容:
RTSP/1.0 200 OK
Server: MajorKernelPanic RTSP Server
Cseq: 5
Content-Length: 0
RTP-Info: url=rtsp://192.168.3.23:8086/trackID=1;seq=0
Session: 1185d20035702ca
//TEARDOWN 结束会话请求, 该请求会停止所有媒体流, 并释放服务器上的相关会话数据;
2019-02-04 20:58:10.622 9784-9851/com.zpf.androidshow E/RtspServer: TEARDOWN 192.168.3.23:8086/
2019-02-04 20:58:10.623 9784-9851/com.zpf.androidshow E/RtspServer: 请求内容:
CSeq: 6
User-Agent: LibVLC/3.0.6 (LIVE555 Streaming Media v2016.11.28)
Session: 1185d20035702ca
2019-02-04 20:58:10.623 9784-9851/com.zpf.androidshow D/RtspServer: 响应内容:
RTSP/1.0 200 OK
Server: MajorKernelPanic RTSP Server
Cseq: 6
Content-Length: 0
2019-02-04 20:58:10.626 9784-9851/com.zpf.androidshow I/RtspServer: Client disconnected
RTP 协议
RTP协议头格式:
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 |
| .... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+上图引自rfc3550, 由上图中可知道RTP报文由两个部分构成—RTP报头和RTP的负载: RTP报文由两部分组成: 报头和有效载荷; RTP报头格式如图6.7所示, 其中:
-
V: RTP协议的版本号, 占2位, 当前协议版本号为2;
-
P: 填充标志, 占1位, 如果P=1, 则在该报文的尾部填充一个或多个额外的八位组, 它们不是有效载荷的一部分;
-
X: 扩展标志, 占1位, 如果X=1, 则在RTP报头后跟有一个扩展报头;
-
CC: CSRC 计数器, 占4位, 指示CSRC 标识符的个数;
[1b] 5. M: 标记, 占1位, 不同的有效载荷有不同的含义, 对于视频, 标记一帧的结束; 对于音频, 标记会话的开始;
[7b] 6. PT: 有效载荷类型, 占7位, 用于说明RTP报文中有效载荷的类型, 如GSM音频, JPEM图像等,在流媒体中大部分是用来区分音频流和视频流的, 这样便于客户端进行解析;
[2b] 7. 序列号: 占16位, 用于标识发送者所发送的RTP报文的序列号, 每发送一个报文, 序列号增1; 这个字段当下层的承载协议用UDP的时候, 网络状况不好的时候可以用来检查丢包; 同时出现网络抖动的情况可以用来对数据进行重新排序, 在helix服务器中这个字段是从0开始的, 同时音频包和视频包的sequence是分别记数的;
[4b] 8. 时戳(Timestamp): 占32位, 时戳反映了该RTP报文的第一个八位组的采样时刻; 接收者使用时戳来计算延迟和延迟抖动, 并进行同步控制;
[8b] 9. 同步信源(SSRC)标识符: 占32位, 用于标识同步信源; 该标识符是随机选择的, 参加同一视频会议的两个同步信源不能有相同的SSRC;
[12b] 10. 特约信源(CSRC)标识符: 每个CSRC标识符占32位, 可以有0~15个; 每个CSRC标识了包含在该RTP报文有效载荷中的所有特约信源;
[16b] 如果扩展标志被置位则说明紧跟在报头后面是一个头扩展, 其格式如下:
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| defined by profile | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| header extension |
| .... |SDP
SDP 参数中指定; 如: m=video 49170 RTP/AVP 98 a=rtpmap:98 H264/90000 a=fmtp:98 profile-level-id=42A01E; packetization-mode=1; sprop-parameter-sets=Z0IACpZTBYmI,aMljiA==
常用的参数:
packetization-mode: 表示支持的封包模式.
当 packetization-mode 的值为 0 时或不存在时, 必须使用单一 NALU 单元模式.
当 packetization-mode 的值为 1 时必须使用非交错(non-interleaved)封包模式.
当 packetization-mode 的值为 2 时必须使用交错(interleaved)封包模式.
sprop-parameter-sets: SPS,PPS
这个参数可以用于传输 H.264 的序列参数集和图像参数 NAL 单元. 这个参数的值采用 Base64 进行编码. 不同的参数集间用”,“号隔开;
profile-level-id:
这个参数用于指示 H.264 流的 profile 类型和级别. 由 Base16(十六进制) 表示的 3 个字节. 第一个字节表示 H.264 的 Profile 类型, 第三个字节表示 H.264 的 Profile 级别
打包NAL单元类型
| NAL单元类型 | 值 | 描述 | 常见场景 |
|---|---|---|---|
| 未指定 | 0 | 保留值,未使用 | - |
| 非IDR图像的编码条带 | 1 | 非关键帧的条带数据(P帧或B帧) | 普通视频帧 |
| 编码条带数据分割块A | 2 | 包含宏块头和运动向量的数据块 | 数据分割流 |
| 编码条带数据分割块B | 3 | 包含帧内编码块模式和帧内系数的数据块 | 数据分割流 |
| 编码条带数据分割块C | 4 | 包含帧间编码块模式和帧间系数的数据块 | 数据分割流 |
| IDR图像的编码条带 | 5 | 关键帧数据(I帧),解码器从此开始重建图像 | 关键帧/场景切换 |
| SEI | 6 | 补充增强信息(如时间码、字幕、编码参数等) | 元数据嵌入 |
| SPS | 7 | 序列参数集(包含视频分辨率、帧率、档次级别等全局参数) | 视频流开头 |
| PPS | 8 | 图像参数集(包含熵编码模式、切片组等帧级参数) | SPS之后 |
| 访问单元分隔符 | 9 | 标识视频帧的开始 | 流同步 |
| 序列结尾 | 10 | 表示序列结束 | 视频流结尾 |
| 码流结尾 | 11 | 表示码流结束 | 码流结尾 |
| 填充数据 | 12 | 用于填充的数据 | 字节对齐 |
| 保留 | 13-23 | 保留值 | - |
| 未指定 | 24-31 | 保留值 | |
每个打包方式允许的NAL单元类型总结(yes = 允许, no = 不允许, ig = 忽略)
| Type | Packet | Single NAL Unit Mode | Non-Interleaved Mode | Interleaved Mode |
|---|---|---|---|---|
| 0 | undefined | ig | ig | ig |
| 1-23 | NAL unit | yes | yes | no |
| 24 | STAP-A | no | yes | no |
| 25 | STAP-B | no | no | yes |
| 26 | MTAP16 | no | no | yes |
| 27 | MTAP24 | no | no | yes |
| 28 | FU-A | no | yes | yes |
| 29 | FU-B | no | no | yes |
| 30-31 | undefined | ig | ig | ig |
参考: RTP协议全解析(H264码流和PS流) - https://blog.csdn.net/chen495810242/article/details/39207305
实例封包
功能分两层: VCL(Video Codeing Layer): 视频编码层, 负责的是视频内容的处理, 重点在编解码算法; NAL(Network Abstraction Layer): 网络抽象层, 负责将编码后的数据以网络要求的格式进行打包和传输;
对于一个原始的 H.264 NALU 单元常由 [Start Code] [NALU Header] [NALU Payload] 三部分组成, 其中 Start Code 用于标示这是一个 NALU 单元的开始, 必须是 “00 00 00 01” 或 “00 00 01”, NALU 头仅一个字节, 其后都是 NALU 单元内容. 打包时去除 [Start Code] “00 00 01” 或 “00 00 00 01” 的开始码, 把其他数据封包的 RTP 包即可.
//不分片 的情况
80 60 01 0f 00 0e 10 00 00 00 00 00 7c 85 88 82 ...
//
80 60 01 0f 00 0e 10 00 00 00 00 00//rtp 十二字节头
7c//[NALU Payload] h264 负载类型字节, 即Type 是24以后的
88 82 ...//负载内容
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+
//其中 Type 5比特 , h264仅用1-23,24以后的用在RTP H264负载类型头中
//TODO 分片结构
组合封包
TODO 巨tm复杂, 待研究 ———————————————— 参考 - RTP封装h264