RTSP
1. RTSP协议简介
配置属性 -> 调试 -> 环境 :
PATH=D:\ffmpeg\ffmpeg-master-latest-win64-gpl-shared\bin;D:\ffmpeg\SDL2-2.28.5\lib\x64
用分号来写多个路径,可以指定dll文件,不必再必须配置环境变量
.
配置属性 -> VC++目录 -> 包含目录 :
D:\ffmpeg\SDL2-2.28.5\include
D:\ffmpeg\ffmpeg-master-latest-win64-gpl-shared\include
D:\ffmpeg\vcpkg\include
.
配置属性 -> VC++目录 -> 库目录 :
D:\ffmpeg\ffmpeg-master-latest-win64-gpl-shared\lib
D:\ffmpeg\SDL2-2.28.5\lib\x64
D:\ffmpeg\vcpkg\lib
.
链接器 -> 输入 -> 附加依赖项 :
avcodec.lib
avdevice.lib
avfilter.lib
avformat.lib
avutil.lib
postproc.lib
swresample.lib
swscale.lib
SDL2.lib
SDL2main.lib
SDL2test.lib
fdk-aac.lib
zlib.lib
event.lib
event_core.lib
event_extra.lib
1.1 RTSP服务器基础框架
以下代码并没有使用功能,只是通过wireshark进行抓包分析来了解RTSP协议的大致流程
1 |
|
1.2 分析抓包数据
以下服务器的回复抓包数据都是根据以上代码的接受发送数据决定的
客户端第一次发出请求(OPTIONS)
向服务器询问有那种请求方式
服务器回应OPTIONS
服务器给出发出请求的方式
客户端第二次发出请求(DESCRIBE)
请求指定流媒体的描述信息(SDP
,Session Description Protocol)
服务器回应DESCRIBE
回应会话描述(SDP
) 返回流媒体的描述信息,包括媒体类型、编解码器、流地址等。
客户端第三次发出请求(SETUP)
请求建立媒体流传输的通道
两个(RTCP和RTP通道)端口号
服务器回应SETUP
返回确认或者错误消息。
在这个步骤中,可以指定传输协议(UDP、TCP、RTP 等)和端口号等参数。
客户端第四次发出请求(PLAY)
请求开始播放流媒体
服务器回应PLAY
接受请求,并开始向客户端发送媒体数据。
2. UDP的RTP传输h264的RTSP服务器,能拉流播放
上一部分已经实现了一个
RTSP
协议交互的案例,客户端播放器能够向我们的RTSP服务端发起连接建立的请求,并且客户端在发起RTSP的Play
请求以后,RTSP服务端也已经回复了Play
请求的确认。
这部分需要实现,客户端建立与RTSP服务端的连接后,并且在RTSP服务端回复了客户端的Play请求以后.
服务端需要源源不断的读取一个本地h264视频文件,并将读取到的h264视频流封装到RTP数据包中,再推送至客户端。
这样我们就实现了一个简单的支持RTSP协议流媒体分发服务。
问题的关键就是 如何将H264封装到RTP数据包
2.1 RTP理解
2.1.1 RTP简述
RTP:实时传输协议(Real-time Transport Protocol或简写RTP)是一个网络传输协议.
RTP定义了两种报文:RTP报文
和RTCP报文
RTP报文
用于传送媒体数据(如音频和视频,包括自定义类型,如字幕等)
它由 RTP报头和数据两部分组成,RTP数据部分称为有效载荷(payload);RTCP报文
用于传送控制信息,以实现协议控制功能。RTP报文和RTCP报文
将作为下层协议的数据单元进行传输。
如果使用UDP,则RTP报文和RTCP报文分别使用两个相邻的UDP端口,RTP报文使用低端口,RTCP报文使用高端口。
如果使用其它的下层协议,RTP报文和RTCP报文可以合并,放在一个数据单元中一起传送,控制信息在前
,媒体数据在后
。通常,RTP是由应用程序实现的。
eg: TCP作为协议时,RTP和RTCP甚至RTSP都是一个通道进行传输的
2.1.2 RTP报文格式
V
:RTP协议的版本号,占2位
当前协议版本号为2。P
:填充标志,占1位
如果P=1,则在该报文的尾部填充一个或多个额外的八位组,它们不是有效载荷的一部分。X
:扩展标志,占1位
如果X=1,则在RTP报头后跟有一个扩展报头。CC
:CSRC计数器,占4位
指示CSRC 标识符的个数。M
: 标记,占1位
, 不同的有效载荷有不同的含义
对于视频,标记一帧的结束;
对于音频,标记会话的开始。PT
: 有效载荷类型,占7位
用于说明RTP报文中有效载荷的类型,如GSM音频、JPEM图像等。序列号
:占16位
用于标识发送者所发送的RTP报文的序列号,每发送一个报文,序列号增1。
接收者通过序列号来检测报文丢失情况,重新排序报文,恢复数据。时戳(Timestamp)
:占32位
,时戳反映了该RTP报文的第一个八位组的采样时刻。
接收者使用时戳来计算延迟和延迟抖动,并进行同步控制。同步信源(SSRC)标识符
:占32位
,用于标识同步信源。
该标识符是随机选择的,参加同一视频会议的两个同步信源不能有相同的SSRC。特约信源(CSRC)标识符
:每个CSRC标识符占32位
,可以有0~15个。
每个CSRC标识了包含在该RTP报文有效载荷中的所有特约信源。
每一行占4字节,32位
视频会议,直播连麦等类似情况时(多路流汇成一路流),CSRC才会存在(多个SSRC汇集为CSRC)
1 |
|
2.1.3 RTP包发送前缀
RTP,RTCP 数据和 RTSP 数据共享
TCP 数据通道,所以必须有一个标识来区别三种数据。
RTP 和 RTCP
数据会以 $符号 + 1 个字节的通道编号 + 2 个字节的数据长度
共 4 个字节的前缀开始,RTSP 数据没有前缀数据
RTP 数据和 RTCP 数据的区别在于第二个字节的通道编号, RTP 通道编号是偶数,RTCP通道编号是奇数。
2.2 H264理解
2.2.1 压缩方式
H264压缩技术主要采用了以下几种方法对视频数据进行压缩:
- 帧内预测压缩,解决的是空域数据冗余问题。(eg:jpg) 不借助于其他数据
- 帧间预测压缩(运动估计与补偿),解决的是时域数据冗徐问题。
- 整数离散余弦变换(DCT),将空间上的相关性变为频域上无关的数据然后进行量化。
- CABAC压缩。
经过压缩后
的帧分为:I帧,P帧和B帧:
- I帧:关键帧,采用
帧内压缩
技术。 - P帧:向前参考帧,在压缩时,只参考前面已经处理的帧。
采用帧间压缩技术。占I帧的一半大小 - B帧:双向参考帧,在压缩时,它即参考前而的帧,又参考它后面的帧。采用帧间压缩技术。占I帧1/4大小
- 图像序列GOP(GOP组),将一个视频分为若干部分,防止因为部分帧损坏而导致视频崩盘.GOP至少有一个I帧
虽然B帧的压缩率是最高,但是他占用的CPU以及耗时非常多,既然耗时,在实时直播视频情况就会导致一个延迟的情况。
如果只是想减少空间大小,B帧将是一个很好的选择。
所以一般在直播中是没有B帧,只有I帧和P帧。
IDR帧和I帧的关系。
IDR(Instantannous Decoder Refresh) 解码器立即刷新
作用:在解码的过程,一旦有一帧数据出现错误,将是无法恢复的过程,后面数据帧不能使用。
当有了IDR帧,解码器收到IDR帧时,就会将缓冲区的数据清空
,找到第一个IDR帧,重新解码。
I和IDR帧都使用帧内预测
,在编码解码中为了方便,首个I帧要和其他I帧区别开,把第一个I帧叫IDR
,这样方便控制编码和解码流程。
IDR帧必须是一个I帧,但是I帧不一定是IDR帧,这个帧出现的时候,是告诉解码器,可以清除掉所有的参考帧,这是一个全新的序列,新的GOP
已经开始。I帧有被跨帧参考的可能,IDR不会。
每个GOP中的第一帧就是IDR帧。IDR帧是一种特殊的I帧。
帧与分组的关系:
2.2.2 h264组成
- 网络提取层 (Network Abstraction Layer,
NAL
), 编码(压缩)后的流 - 视讯编码层 (Video Coding Layer,
VCL
), 产生NAL的过程
2.2.3 码流结构
H.264的功能分为两层,视频编码层(VCL)和网络提取层(NAL)。
1.VCL数据即被压缩编码后的视频数据序列。
2.在VCL数据要封装到NAL单元中之后,才可以用来传输或存储。
- SPS:序列参数集,作用于一系列连续的编码图像;
包含视频序列的全局参数信息,比如图像的宽度和高度、帧率、色度格式等。这些信息对于整个视频流是固定的,或者在一段时间内是固定的。 - PPS:图像参数集,作用于编码视频序列中一个或多个独立的图像;
包含具体图像的参数,比如解码参数、量化参数等。PPS 也是在一段时间内固定的,不会频繁变化。
NALU根据nal_unit_type
的类型,可以分为:VCL的NAL单元
和 非VCL的NAL单元
2.3 解封装mp4生成h264文件
1 | ffmpeg -i test.mp4 -codec copy -bsf: h264_mp4toannexb -f h264 test.h264 |
2.4 将H264封装到RTP数据包
H.264由一个一个的NALU组成,每个NALU之间使用00 00 00 01
或00 00 01
分隔开,每个NALU的第一次字节都有特殊的含义,
F(forbiden):禁止位
,占用NAL头的第一个位,当禁止位值为1时表示语法错误;NRI:参考级别
,占用NAL头的第二到第三个位;值越大,该NAL越重要。Type:Nal单元数据类型
,也就是标识该NAL单元的数据类型是哪种,占用NAL头的第四到第8个位;
常用Nalu_type:
0x06 (0 00 00110)
SEI
type = 6
0x67 (0 11 00111)SPS
type = 7
0x68 (0 11 01000)PPS
type = 80x65 (0 11 00101)
IDR
type = 5
0x61 (0 11 00001)I帧
type = 1
0x41 (0 10 00001)P帧
type = 1
0x01 (0 00 00001)B帧
type = 1
0x09 (0 00 01001)AUD
type = 9
访问单元分隔符(Access Unit Delimiter,
AUD
)AU Delimiter
是用于标记接入单元的起始位置
接入单元是一个视频帧或一组视频帧的集合,这些帧可以独立解码, AU Delimiter 帮助解码器识别接入单元的边界
AUD 是一个可选的 NALU(网络抽象层单元),可以用于在基本流中分隔帧
它不是必需的(除非容器/协议另有规定,例如 TS),并且通常不包括在内以节省空间,但它在不需要完全解析每个 NALU 的情况下找到帧的起始位置时非常有用
在处理 H.264 视频数据时,Access Unit Delimiter (AUD) 类型的 NALU 通常并不包含视频数据本身,而是用于标记接入单元(即帧)的起始位置。
为了节省空间,AUD 通常是可选的,因此解析器在遇到 AUD 类型的 NALU 时通常会跳过它并继续处理下一个 NALU
对于H.264格式了解这些就够了,我们的目的是想从一个H.264的文件中将一个一个的NALU提取出来,然后封装成RTP包,下面介绍如何将NALU封装成RTP包。
H.264可以由三种RTP打包方式
单NALU打包
: 一个RTP包包含一个完整的NALU聚合打包
:对于较小的NALU,一个RTP包可包含多个完整的NALU分片打包
:对于较大的NALU,一个NALU可以分为多个RTP包发送
注意
:这里要区分好概念,每一个RTP包都包含一个RTP头部和RTP荷载,这是固定的。而H.264发送数据可支持三种RTP打包方式
比较常用的是单NALU打包和分片打包,这里只介绍两种
单NALU打包
所谓单NALU打包就是将一整个NALU的数据放入RTP包的载荷中,这是最简单的一种方式。
分片打包
每个RTP包都有大小限制的,因为RTP一般都是使用UDP发送,UDP没有流量控制,所以要限制每一次发送的大小,所以如果一个NALU的太大,就需要分成多个RTP包发送,至于如何分成多个RTP包,如下:
首先要明确,RTP包的格式是绝不会变的,永远多是RTP头+RTP载荷
RTP头部是固定的,那么只能在RTP载荷中去添加额外信息来说明这个RTP包是表示同一个NALU
如果是分片打包的话,那么在RTP载荷开始有两个字节的信息,然后再是NALU的内容
第一个字节位FU Indicator
,其格式如下
高三位:与NALU第一个字节的高三位相同
Type:28
,表示该RTP包一个分片,为什么是28?
因为H.264的规范中定义的,此外还有许多其他Type
第二个字节位FU Header
,其格式如下
S:标记该分片打包的第一个RTP包
E:比较该分片打包的最后一个RTP包
Type:NALU的Type
2.5 代码实现
rtp.h
1 | //#pragma once |
rtp.cpp
1 |
|
main.cpp
1 | //关于程序ffplay后速度和帧率都比较small的解释 |
3. 音频原理
3.1 PCM数据格式
PCM
(Pulse Code Modulation)也被称为 脉码编码调制。
PCM中的声音数据没有被压缩,如果是单声道的文件,采样数据按时间的先后顺序依次存入。(它的基本组织单位是BYTE(8bit)或WORD(16bit))
一般情况下,一帧PCM是由2048
次采样组成的
如果是双声道的文件,采样数据按时间先后顺序交叉地存入。如图所示:
对于解析PCM数据有所帮助
麦克风在录音采样后,直接获得的就是音频原始数据pcm。
但由于pcm数据较大,所以通常需要压缩之后才能传输或保存,常见的音频压缩技术有aac,g711,opus,mp3等,最常用的就是aac
。
1秒钟的pcm的声音大小 = 44100 * 2(声道) * 2(字节) / 1024 * 60(秒) /1024
一分钟约等于5MB
3.2 几个可能会用到的命令行
1 | //指定时间段录制 |
3.3 代码
Adts.h
1 |
|
Adts.cpp
1 |
|
decode_aac, aac格式转pcm格式
1 |
|
sdl2_play_aac.cpp播放aac音频
1 | //播放aac格式的音频 |
sdl2_play_pcm.cpp, 播放pcm音频
1 |
|
4. UDP的RTP传输音频aac的RTSP服务器,能拉流播放
4.1 aac码流格式
ADIF(Audio Data Interchage Format)
,音频数据交换格式:
只有一个统一的头,必须得到所有数据后解码,适用于本地文件。ADTS(Audio Data Transport Stream)
,音视数据传输流:
每一帧都有头信息,任意帧解码,适用于传输流。
AAC共有9种规格,以适应不同的场合的需要:
MPEG-2 AAC LC
低复杂度规格(Low Complexity) 注:比较简单,没有增益控制,但提高了编码效率,在中等码率的编码效率以及音质方面,都能找到平衡点MPEG-2 AAC Main
主规格MPEG-2 AAC SSR
可变采样率规格(Scaleable Sample Rate)MPEG-4 AAC LC
低复杂度规格(Low Complexity)—现在的手机比较常见的MP4文件中的音频部份就包括了该规格音频文件MPEG-4 AAC Main
主规格 注:包含了除增益控制之外的全部功能,其音质最好MPEG-4 AAC SSR
可变采样率规格(Scaleable Sample Rate)MPEG-4 AAC LTP
长时期预测规格(Long Term Predicition)MPEG-4 AAC LD
低延迟规格(Low Delay)MPEG-4 AAC HE
高效率规格(High Efficiency)—这种规格适合用于低码率编码,有Nero ACC 编码器支持
序号 | 字段 | 长度 | 说明 |
---|---|---|---|
1 | synword | 12bit | 同步头,总是0xFFF,代表着1个ADTS帧的开始。 |
2 | id | 1bit | 设置MPEG标识符,1bit,0标识MPEG-4,1标识MPEG-2。 |
3 | layer | 2bit | 总是00。 |
4 | protection_absent | 1bit | 误码校验,标识是否进行误码校验。0表示有CRC校验,1表示没有CRC校验。为0时头部7bytes后面+2bytesCRC检验位。 |
5 | profile | 2bit | AAC级别,0表示AAC Main, 1表示AAC LC, 2表示AAC SSR。 profile的值等于Audio Object Type的值减1。 |
6 | sampling_frequency_index | 4bit | 采样率下标,下标对应的采样率如下: 0: 96000 Hz 1: 88200 Hz 2 : 64000 Hz 3 : 48000 Hz 4 : 44100 Hz 5 : 32000 Hz 6 : 24000 Hz 7 : 22050 Hz 8 : 16000 Hz 9 : 12000 Hz 10 : 11025 Hz 11 : 8000 Hz 12 : 7350 Hz 13 : Reserved 14 : Reserved 15 : frequency is written explictly |
7 | private_bit | 1bit | 私有位,编码时设置为0,解码时忽略。 |
8 | channel_configuration | 3bit | 声道数。 0: Defined in AOT Specifc Config 1: 1 channel : front - center 2 : 2 channels : front - left, front - right 3 : 3 channels : front - center, front - left, front - right 4 : 4 channels : front - center, front - left, front - right, back - center 5 : 5 channels : front - center, front - left, front - right, back - left, back - right 6 : 6 channels : front - center, front - left, front - right, back - left, back - right, LFE - channel 7 : 8 channels : front - center, front - left, front - right, side - left, side - right, back - left, back - right, LFE - channel 8 - 15 : Reserved |
9 | orininal_copy | 1bit | 编码时设置为0,解码时忽略。 |
10 | home | 1bit | 编码时设置为0,解码时忽略。 |
11 | copyrigth_identification_bit | 1bit | 编码时设置为0,解码时忽略。 |
12 | copyrigth_identification_stat | 1bit | 编码时设置为0,解码时忽略。 |
13 | aac_frame_length | 13bit | 一个ADTS帧的长度,包括ADTS头和AAC原始流。 |
14 | adts_bufferfullness | 11bit | 缓冲区充满度,0x7FF说明是码率可变的码流,不需要此字段。CBR可能需要此字段,不同编码器使用情况不同。具体查看附录。 |
15 | number_of_raw_data_blocks_in_frame | 2bit | 表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧,为0表示说ADTS帧中只有一个AAC数据. |
16 | CRC | 16bit | CRC校验码 |
序号 | 字段 | 长度 | 值 |
---|---|---|---|
1 | synword | 12bit | 111111111111 |
2 | id | 1bit | 0 |
3 | layer | 2bit | 00 |
4 | protection_absent | 1bit | 1 |
5 | profile | 2bit | 01 |
6 | sampling_frequency_index | 4bit | 0100(十进制4) |
7 | private_bit | 1bit | 0 |
8 | channel_configuration | 3bit | 010 (十进制2) |
9 | orininal_copy | 1bit | 0 |
10 | home | 1bit | 0 |
11 | copyrigth_identification_bit | 1bit | 0 |
12 | copyrigth_identification_stat | 1bit | 0 |
13 | aac_frame_length | 13bit | 0000101111100(十进制380) |
14 | adts_bufferfullness | 11bit | 00010010000 |
15 | number_of_raw_data_blocks_in_frame | 2bit | 00 |
aac的RTP打包方式
AAC的RTP打包方式并没有向H.264那样丰富,一种方式,主要AAC一帧数据大小都是几百个字节,不会向H.264那么少则几个字节,多则几千。
AAC的RTP打包方式就是将ADTS帧取出ADTS头部,取出AAC数据,每帧数据封装成一个RTP包
需要注意的是,并不是将AAC数据直接拷贝到RTP的载荷中
。AAC封装成RTP包,在RTP载荷中的前四个字节是有特殊含义的,然后再是AAC数据,如下图所示。
其中RTP载荷的一个字节为0x00,第二个字节为0x10
第三个字节和第四个字节保存AAC Data的大小,最多只能保存13bit
第三个字节保存数据大小的高八位
第四个字节的高5位保存数据大小的低5位.
1 | rtpPacket->payload[0] = 0x00; |
RTP包时间戳的计算
假设音频的采样率位44100,即每秒钟采样44100次。
AAC一般将1024次采样编码成一帧,所以一秒就有44100/1024=43帧。
RTP包发送的每一帧数据的时间增量为44100/43=1025。
每一帧数据的时间间隔为1000/43=23ms。
可能会用到的ffmpeg命令行
1 | //ffmpeg命令行 从mp4视频文件提取aac 音频文件 |
4.2 代码实现
rtp.h
1 |
|
rtp.cpp
1 |
|
main.cpp
1 | //关闭SDL检查 |
5. TCP的RTP同时传输h264和aac的RTSP服务器,能拉流播放
相对于之前实现的功能,
变化
如下
1,客户端请求RTSP的Describe请求时,RTSP服务器返回的SDP协议,需要同时包含音频流和视频流的信息。
2,客户端请求RTSP的Setup请求时,RTSP服务器不需要再对应创建RTP和RTCP的UDP连接通道,因为TCP版的RTP传输,客户端与服务器交互时,无论是RTSP信令还是RTP数据包或者是RTCP数据包,都是使用同一个tcp连接通道。只不过这个tcp连接通道在发送rtp数据包或者rtcp数据包时,需要加一些分隔字节。
3,客户端请求RTSP的Play请求时,RTSP服务器在对Play请求回复以后,还需要源源不断的同时向客户端发送音频流和视频流的RTP数据包。
4,有几点注意,在这个案例项目中,使用的h264视频文件,对应的fps需要是25。另外由于Nalu的数量并不等于视频帧数量的原因,该案例的音视频并不能同步。
1 | ffplay -i -rtsp_transport tcp rtsp://127.0.0.1:8554 |
5.1 ffmpeg命令行
1 | //ffmpeg命令行 从mp4视频文件提取h264 码流文件 |
5.2 代码实现
rtp.h
1 |
|
rtp.cpp
1 |
|
main.cpp
1 |
|
5.3 分析抓包理解源码
两个
m
第一路流的rtp和rtcp的通道序号
返回的同理,第一路流的0通道和1通道在这里插入图片描述
同理第二路流用2,3通道,replay同理
97代表的是aac, 96代表的是h264
$符号(间隔符),通道00,第一路流的第一个通道,长度
$符号,02,第二路流的第一个通道,长度
6. RTSPServer
整体逻辑如下图
Linux配置环境
- 配置SDL环境
1 | tar -zxvf SDL-1.2.15.tar.gz |
- 安装ffmpeg库
1 | sudo apt install ffmpeg |
- 整理文件
先切换到RTSP_Server目录中
1 | mkdir src |
准备好 .aac 和 .h264 文件放置RTSP_Server目录中
- 运行
1 | cd build |
另起一个终端
1 | #over tcp |
7. RTCP
实时传输控制协议(Real-time ControlProtocol,RTCP)是和 RTP一起工作的控制协议。
在RTP会话期间,Udp传输时通过使用不同的端口号可把RTP数据包和RTCP信息包区分开来
Tcp使用相同的端口号, 每个会话参与者周期性地向所有其他参与者发送RTCP控制信息包。
功能:
在RTP会话期间,每个会话参与者周期性地向所有其他参与者发送RTCP控制信息包。
每个RTCP信息包不是
封装声音或者视频数据,而是封装发送端或接收端的统计报表。
这些信息包括发送的信息包数目、丢失的信息包数目和信息包的抖动等情况
信息包具体的有: 假设是直播推流的场景,
截至目前已经发送了多少的RTP数据包, RTP对应的字节流的长度的数据, RTP最新的时间戳, NTP(精准时间戳,ms级)等
1.1 RTCP包类型
根据所携带的控制信息不同,RTCP信息包可分为
RR(接收者报告包)、SR(源报告包)、SEDS(源描述包)、BYE(离开申明)和APP(特殊应用包)
类型 | 缩写 | 用途 |
---|---|---|
200 | SR | 发送端报告 |
201 | RR | 接收端报告 |
202 | SDES | 源点描述 |
203 | BYE | 结束传输 |
204 | APP | 特定应用 |
实际RTCP真正拥有的类型有20多种
SR:
版本(V)
:2比特,RTCP版本。填充(P)
:1比特,如果该位置为1,则该RTCP包的尾部就包含附加的填充字节。接收报告计数器(RC)
:5比特,该SR包中的接收报告块的数目,可以为零。包类型(PT)
:8比特,SR包是200。长度域(Length)
:16比特,RTCP包的长度,包括填充的内容。同步源(SSRC of sender)
:32比特,SR包发送者的同步源标识符。与对应RTP包中的SSRC一样。NTP timestamp(MSW+LWS)
:64比特, 表示发送此报告时以挂钟时间测量的时间点。 结合来自各个接收器的接收报告中返回的时间戳,它可用于估计往返于接收器的往返传播时间。RTP timestamp
:32比特,与NTP时间戳对应,与RTP数据包中的RTP时间戳具有相同的单位和随机初始值。Sender’s packet count
:32比特,从开始发送包到产生这个SR包这段时间里,发送者发送的RTP数据包的总数. SSRC改变时,这个域清零。Senders octet count
:32比特,从开始发送包到产生这个SR包这段时间里,发送者发送的净荷数据的总字节数(不包括头部和填充)。发送者改变其SSRC时,这个域要清零。SSRC_n
:32比特,在此块中报告其接收的发送者的 SSRC 标识符丢失率(Fraction Lost)
:8比特,表明从上一个SR或RR包发出以来从同步源n(SSRC_n)来的RTP数据包的丢失率累计的包丢失数目(cumulative number of packets lost )
:24比特,从开始接收到SSRC_n的包到发送SR,从SSRC_n传过来的RTP数据包的丢失总数。收到的扩展最大序列号(extended highest sequence number received EHSN )
:
从SSRC_n收到的RTP数据包中最大的序列号uint16_t seq_cycles
; //Sequence number cycles count (序列号循环计数
uint16_t seq_max
; //highest sequence number received (序列最大值接收抖动(Interarrival jitter)
:32比特,RTP数据包接受时间的统计方差估计上次SR时间戳(Last SR,LSR)
:32比特,取最近从SSRC_n收到的SR包中的NTP时间戳的中间32比特。如果目前还没收到SR包,则该域清零上次SR以来的延时(Delay since last SR,DLSR)
:32比特,上次从SSRC_n收到SR包到发送本报告的延时- 扩展字段 profile-specific extensions
1.2 RTCP抓包
服务段先发送RR, 推流端收到RR后发送SR
推流端第一次发送SR
Sender's packet count
: 截止到当前发送RTP包的数量Sender's octet count
: 发送RTP包对应字节流的长度RTP timestamp
: 当前发送RTCP时RTP最新的RTPHeader时间戳Timestamp, MSW
和Timestamp, LSW
: NTP用两个字段用来表示和传输
第二次发送SR:
demo(未完成): 6,7 RTCP
client实际发送的数据目前未知,client端表示发送成功, server端表示接受的ssrc,packetcount等超过类型最大值,cout失败
推测端口被占用
8. RTSP客户端
ffmpeg向RTSPServer推流, RTSPClient再向RTSPServer拉流 生成可播放的h264文件
1. SDP(Session Description Protocol) 简介
SDP 完全是一种
会话描述格式
, 它不属于传输协议
它只使用于不同的适当的传输协议,包括会话通知协议(SAP)、会话初始协议(SIP)、实时流协议(RTSP)、MIME 扩展协议的电子邮件以及超文本传输协议(HTTP)。
SDP协议是也是基于文本的协议
,这样就能保证协议的可扩展性比较强,这样就使其具有广泛的应用范围。SDP 不支持会话内容或媒体编码的协商,所以在流媒体中只用来描述媒体信息
。媒体协商这一块要用RTSP来实现.
SDP 信息是文本信息,UTF-8 编码采用 ISO 10646 字符设置。
SDP 会话描述如下(标注*
符号的表示可选字段):
v= (协议版本)
o= (所有者/创建者和会话标识符)
s= (会话名称)
i=* (会话信息)
u=* (URI 描述)
e=* (Email 地址)
p=* (电话号码)
c=* (连接信息 ― 如果包含在所有媒体中,则不需要该字段)
b=* (带宽信息)
一个或更多时间描述(如下所示):
z=* (时间区域调整)
k=* (加密密钥)
a=* (0个或多个会话属性线路)
0个或多个媒体描述(如下所示):
时间描述
t= (会话活动时间)
r=* (0或多次重复次数)
媒体描述:
m= (媒体名称和传输地址)
i=* (媒体标题)
c=* (连接信息 — 如果包含在会话层则该字段可选)
b=* (带宽信息)
k=* (加密密钥)
a=* (0个或多个会话属性线路)
SDP示例
1 | v=0 |
SDP解释
1 | //字段解释 |
2. 向 RTSP服务端 推流的ffmpeg命令
1 | ffmpeg -re -stream_loop -1 -i xxx.mp4 \ |
3. WireShark 常用过滤 及 抓包分析
1 | tcp.srcport != 63639 and rtsp and !rtcp |
抓包分析:
Option
Reply1 : public 是允许的字段
Describe
Reply 2: 包含SDP(回应describe后, 由于SDP, 以后不管推拉流都要包含session中独特的序列
Setup 1 : 视频流
Reply 3:
Setup 2 : 音频流
Reply 4:
Play:
Reply 5:
**SetUp中若有,字幕流,弹幕流等 Setup就会++**
4. windows下查看端口命令
1 | #windows查看端口占用进程 |