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所示, 其中:

  1. V: RTP协议的版本号, 占2位, 当前协议版本号为2;

  2. P: 填充标志, 占1位, 如果P=1, 则在该报文的尾部填充一个或多个额外的八位组, 它们不是有效载荷的一部分;

  3. X: 扩展标志, 占1位, 如果X=1, 则在RTP报头后跟有一个扩展报头;

  4. 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 = 忽略)

TypePacketSingle NAL Unit ModeNon-Interleaved ModeInterleaved Mode
0undefinedigigig
1-23NAL unityesyesno
24STAP-Anoyesno
25STAP-Bnonoyes
26MTAP16nonoyes
27MTAP24nonoyes
28FU-Anoyesyes
29FU-Bnonoyes
30-31undefinedigigig

参考: 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