RTSP解复用器
libavformat/rtspdec.c
探测输入格式根据URL起始字符进行匹配
sdp_parse_line实现SDP分析
libavformat/rtsp.c实现RTSP协议的分析
ff_rtsp_setup_input_streams创建rtsp交互连接
ff_rtsp_send_cmd优先发送DESCRIBE指令,海康和大华RTSP指令交互的区别在于,大华在OPTIONS阶段就会请求认证信息RTSP/1.0 401 Unauthorized
int ff_sdp_parse(AVFormatContext *s, const char *content) 解析SDP中的内容,实际上这里就已经完全知道码流的数据格式以及所有的流信息,根本不需要探测码流格式
sdp_parse_rtpmap函数分析出h264码流格式,保存在AVFormatContext中的stream流中
附上SDP数据
连接代码堆栈
接收代码堆栈
FU-A分包处理逻辑
重点分析函数ff_rtsp_fetch_packet,该函数调用read_packet获取到RTP数据,调用ff_rtp_parse_packet分析RTP数据,去掉RTP包头,添加起始码,然后封装成AVPacket,但是封装的AVPacket并不是完整的NAL单元的视频流,对于FU-A分包的数据,仍然需要对多个AVPacket进行重新组装
对FU-A分包的RTP格式数据,会根据是否是第一个包添加起始码,,关键是(h264_handle_packet_fu_a)start_bit = fu_header >> 7;
ff_h264_handle_frag_packet函数根据start_bit,确定是否需要添加起始码
av_read_frame分包代码剖析
ff_h264_handle_frag_packet函数会为每一个RTP包携带的NALU分片申请一个AVPacket包保存,因此需要通过ff_combine_frame函数构建一个完整的NALU单元
HEVC码流探测剖析
例如:"rtsp://admin:admin12345@192.168.28.136:554/h265/ch1/main/av_stream"
请求海康摄像机H265码流
SDP报文如下:
v=0
o=- 1566124110963848 1566124110963848 IN IP4 192.168.28.136
s=Media Presentation
e=NONE
b=AS:5100
t=0 0
a=control:rtsp://192.168.28.136:554/h265/ch1/main/av_stream/
m=video 0 RTP/AVP 96
c=IN IP4 0.0.0.0
b=AS:5000
a=recvonly
a=x-dimensions:1920,1080
a=control:rtsp://192.168.28.136:554/h265/ch1/main/av_stream/trackID=1
a=rtpmap:96 H265/90000
a=fmtp:96 sprop-sps=QgEBAWAAAAMAsAAAAwAAAwB7oAPAgBDlja5JMvTcBAQEAg==; sprop-pps=RAHA8vA8kAA=
m=audio 0 RTP/AVP 8
c=IN IP4 0.0.0.0
b=AS:50
a=recvonly
a=control:rtsp://192.168.28.136:554/h265/ch1/main/av_stream/trackID=2
a=rtpmap:8 PCMA/8000
a=Media_header:MEDIAINFO=494D4B48010200000400050011710110401F000000FA000000000000000000000000000000000000;
a=appversion:1.0
static int sdp_parse_rtpmap(AVFormatContext *s,
AVStream *st, RTSPStream *rtsp_st,
int payload_type, const char *p)
通过sdp_parse_rtpmap函数分析SDP中的a=rtpmap:96 H265/90000
在调用函数 const RTPDynamicProtocolHandler *handler =
ff_rtp_handler_find_by_name(buf, par->codec_type);中 获取到h265的处理句柄
rtsp 分包NALU
if (codec_id == AV_CODEC_ID_HEVC)
ret = hevc_parse_nal_header(nal, logctx);
else
ret = h264_parse_nal_header(nal, logctx);
static void parse_fmtp(AVFormatContext *s, RTSPState *rt,
int payload_type, const char *line)
通过h265的句柄调用
static av_cold int hevc_parse_sdp_line(AVFormatContext *ctx, int st_index,
PayloadContext *hevc_data, const char *line)
该函数将SPS/PPS的内容保存在(AVFormatContext结构体中的AVStream流中的extradata变量
创建视频流和音频流
update_stream_avctx函数只是将avcodec_parameters_to_context(st->internal->avctx, st->codecpar);
并没有做其他的操作