基于ffmpeg的rtsp拉流代码分析流水账

概念

RTP: Real-time Transport Protocol,实时传输协议,一般用于多媒体数据的传输。

RTCP: RTP Control Protocol,实时传输控制协议,同RTP一起用于数据传输的监视,控制功能。

RTSP: Real Time Streaming Protocol,实时流协议,用于多媒体数据流的控制,如播放,暂停等。

RTP/RTCP相对于底层传输层,和RTSP,SIP等上层协议一起可以实现视频会议,视频直播等应用

RTP/RTSP/RTCP的区别 用一句简单的话总结:RTSP发起/终结流媒体、RTP传输流媒体数据 、RTCP对RTP进行控制,同步。

UDP:

TCP:

HTTP:

SDP:

rtsp服务器配置

基本流程 rtsp服务器配置
但是有一点需要主要的

将此mkv文件复制到和上面live555MediaServer可执行文件的同一个目录,

这里不需要将媒体文件放在live555MediaServer同一个目录,具体是看执行live555MediaServer进程的所在文件夹
例如:

Download $ ~/vendor/live/mediaServer/live555MediaServer

这时视频是Download目录下的

  • live555MediaServer传输1080p视频
    默认配置,在terminal会打印如下错误
MultiFramedRTPSink::afterGettingFrame1(): The input frame data was too large for our buffer size (100452).  27300 bytes of trailing data was dropped!  Correct this by increasing "OutPacketBuffer::maxSize" to at least 127300, *before* creating this 'RTPSink'.  (Current value is 100000.)

OutPacketBuffer::maxSize默认大小为100000
需要修改DynamicRTSPServer的代码

} else if (strcmp(extension, ".264") == 0) {
    // Assumed to be a H.264 Video Elementary Stream file:
    NEW_SMS("H.264 Video");
    OutPacketBuffer::maxSize = 157300; // allow for some possibly large H.264 frames
    sms->addSubsession(H264VideoFileServerMediaSubsession::createNew(env, fileName, reuseSource));
  } 

然后重新编译

  • 如何使用rtp over tcp
    在ffmpeg 命令中
 -rtsp_transport tcp -i rtsp://192.168.0.172:8554/bb.264  ./bbo.264

在ffmpeg 代码中

  if (av_stristart(filename, "rtsp", NULL)) {
        av_dict_set(&o->g->format_opts, "rtsp_transport", "tcp", 0);
    }

err = avformat_open_input(&ic, filename, file_iformat, &o->g->format_opts);
  • rtsp over http
    这时候就不要使用live555MediaServer开启时打印信息中的http端口
    例如
(We use port 8000 for optional RTSP-over-HTTP tunneling, or for HTTP live streaming (for indexed Transport Stream files only).)

把url的端口号换一下

  if (av_stristart(filename, "rtsp", NULL)) {
        av_dict_set(&o->g->format_opts, "rtsp_transport", "tcp", 0);
    }

err = avformat_open_input(&ic, filename, file_iformat, &o->g->format_opts);

ffmpeg代码分析

  • ffmpeg rtsp代码位置
    liveformat/rtsp.c 这个是udp里面的实现
    liveformat/rtspdec.c

avformat_open_input

avformat_open_input >>
 rtsp_read_header >>
ff_rtsp_connect>>
ff_rtsp_setup_input_streams

rtsp连接 ff_rtsp_connect

rtsp的控制方式
RTSP_MODE_PLAIN 普通rtsp
RTSP_MODE_TUNNEL 基于HTTP

  • 分割url:proto, auth, host ,port ,path

  • rtsp HTTP打开连接
    ffmpeg会在http的请求报文头发送如下格式

"x-sessioncookie: %s\r\n"
                 "Accept: application/x-rtsp-tunnelled\r\n"
                 "Pragma: no-cache\r\n"
                 "Cache-Control: no-cache\r\n",

x-sessioncookie:只是一个随机的值
即使不看方法体也能猜出来

     snprintf(sessioncookie, sizeof(sessioncookie), "%08x%08x",
                 av_get_random_seed(), av_get_random_seed());
  • rtsp tcp打开连接
    简单的建立信道

  • rtsp 发送OPTIONS命令,获取支持的命令
    rtsp 传输方式

RAW/RAW ::Support receiving plain data over UDP without any RTP encapsulation
RTP/AVP: RTP transport / audio , video , control protocol
x-pn-tng: 不懂

  • rtsp 发送 SETUP命令 ff_rtsp_make_setup_request()函数
    status_code = 461 /* Unsupported protocol */
    status_
    验证c s两端的协议,必须一致(大概是怕我们乱改代码)

interleaved :
The channel identifier is defined in the Transport header with the
interleaved parameter(Section 12.39).
个人理解,tcp是一个持续的流,所以需要一个interleaved来分割包

ff_rtsp_make_setup_request

  • ffmpeg会执行三个动作
    OPTIONS
    查看支持命令
    这里的live555并没有收到任何的报文信息

DESCRIBE 获取视频信息 --就是SDP报文
SETUP 建立RTP通道

rtsp_read_play

ff_read_packet

rtsp_read_packet >> ff_rtsp_fetch_packet

rtp playload格式

参考链接:
http://blog.rongpmcu.com/rtpxue-xi/

packetization-mode 0 : 单一NALU

单NAL单元包(Single NAL Unit Packet):负载中只包含单一的NAL单元。NAL头的类型等同于原始的NAL单元类型,也就是,1~23的范围。此种包必须只包含单个NAL单元,聚合包和分片单元都不能在这种包内使用。必须按解码顺序发送.

packetization-mode 1 : non-interleaved 非交错封包模式

用于聚合多个NAL单元为单个RTP负载。这种包存在四种版本:单时间聚合包(STAP-A),单时间聚合包(STAP-B),多时间聚合包(MTAP)带16位偏移(MTAP16),多时间聚合包(MTAP)带24位偏移(MTAP24). NAL类型号分配给STAP-A,STAP-B,MTAP16和MTAP24分别为24,25,26,27。

packetization-mode 2 : interleaved 交错封包模式

用于分割单一的NAL单元为多个RTP包,共有两个版本,FU-A和FU-B. 它们的NAL类型号分别为28,29.
分片的原因是为了传输大于64KB的NAL单元。
分片针对单个NAL单元,而不是聚合包。
FU不能嵌套。
FU的时戳设置为被分片NAL单元的NALU时间
FU-A包括一个字节的FU indicator+一个字节的FU header+FU payload

FU-B比FU-A多了一个字节的decoding order number(DON).
FU-B必须只被用在交叉包装模式下NAL分片的第一片。换句话说,在交叉包装模式,每个NALU被分片为FU-B+FU-A+FU-A+...+FU-A

ff_rtsp_fetch_packet

ff_rtsp_fetch_packet 根据lower_transport 调用不同协议read_packet的方法

执行流程
OPTIONS-> DESCRIBE->RTSP/SDP

  • SDP(Session Description Protocol)
    SDP 会话描述协议

  • 简单报文分析

v=0 协议版本
o=- 1476286318262307 1 IN IP4 192.168.31.194 (所有者/创建者和会话标识符)
s=H.264 Video, streamed by the LIVE555 Media Server (会话名称)
i=bb.264(会话信息)
t=0 0(会话活动时间)
a=tool:LIVE555 Streaming Media v2016.09.22
a=type:broadcast 
a=control:*
a=range:npt=0-
a=x-qt-text-nam:H.264 Video, streamed by the LIVE555 Media Server
a=x-qt-text-inf:bb.264
m=video 0 RTP/AVP 96(媒体名称和传输地址)
c=IN IP4 0.0.0.0(连接信息 ― 如果包含在所有媒体中,则不需要该字段)
b=AS:500(带宽信息)
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1;profile-level-id=640028;sprop-parametersets=Z2QAKKzZQHgCJ+WEAAADAAQAAAMA8Dxgxlg=,aOvjyyLA
a=control:track1
  • a=rtpmap
    H264 编码名称
    90000 时钟频率
    96 dynamically assigned
    "a=rtpmap" 行中的编码名称必须是 "H264".
    "a=rtpmap" 行中的时钟频率必须是 90000.
  • 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 级别:

参考资料

用实例分析H264 RTP payload

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容