一、引言
通過FFmpeg命令可以獲取到SDP文件描述的RTP流的視頻壓縮編碼格式、色彩格式(像素格式)、分辨率、幀率信息:
ffmpeg -protocol_whitelist "file,rtp,udp" -i XXX.sdp
本文以H.264為例講述FFmpeg到底是從哪個地方獲取到這些視頻信息的。?
二、視頻壓縮編碼格式
FFmpeg獲取SDP文件描述的RTP流的視頻壓縮編碼格式,是從SDP的“a=rtpmap”這一行獲取的。比如SDP文件中某一行的內容為:
a=rtpmap:96 H264/90000
FFmpeg識別到上述“a=rtpmap”這個<type>后,會把后面的字符串“H.264”提取出來,檢測是否存在相應的音視頻壓縮編碼格式。如果存在,FFmpeg就會判斷該SDP描述的RTP流的視頻壓縮編碼格式為H.264。
具體可以參考:《音視頻入門基礎:RTP專題(5)——FFmpeg源碼中,解析SDP的實現》。
a=rtpmap時,SDP的該行格式為:
a=rtpmap:<payload type> <encoding name>/<clock rate> [/<encoding parameters>],sdp_parse_line函數中會執行下面代碼塊把SDP中描述的音視頻壓縮編碼格式賦值給st->codecpar->codec_id(即AVCodecParameters的codec_id):
else if (av_strstart(p, "rtpmap:", &p) && s->nb_streams > 0) {/* NOTE: rtpmap is only supported AFTER the 'm=' tag */get_word(buf1, sizeof(buf1), &p);payload_type = atoi(buf1);rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1];if (rtsp_st->stream_index >= 0) {st = s->streams[rtsp_st->stream_index];sdp_parse_rtpmap(s, st, rtsp_st, payload_type, p);}s1->seen_rtpmap = 1;if (s1->seen_fmtp) {parse_fmtp(s, rt, payload_type, s1->delayed_fmtp);}}
然后在sdp_parse_line函數外部,通過avcodec_parameters_to_context函數將AVCodecParameters的codec_id賦值給AVCodecContext的codec_id:
int avcodec_parameters_to_context(AVCodecContext *codec,const AVCodecParameters *par)
{
//...codec->codec_id = par->codec_id;
//...
}
然后在dump_stream_format函數中,通過avcodec_string函數中的語句:codec_name = avcodec_get_name(enc->codec_id) 拿到AVCodecContext的codec_id對應的視頻壓縮編碼格式名稱。最后再在dump_stream_format函數中將視頻壓縮編碼格式打印出來:
void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
{
//...codec_name = avcodec_get_name(enc->codec_id);
//...
}
所以FFmpeg獲取SDP描述的RTP流的視頻壓縮編碼格式,是從SDP的“a=rtpmap”這一行獲取的:
三、視頻壓縮編碼格式的profile
FFmpeg獲取SDP文件描述的RTP流的視頻壓縮編碼格式的profile,是從SDP的“a=fmtp”這一行獲取的。比如SDP文件中某一行的內容為:
a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z2QAH6zZgFAFuwFqAgICgAAAAwCAAAAZB4wYzQ==,aOl7LIs=; profile-level-id=64001F
sprop-parameter-sets屬性的'='號之后攜帶以BASE64編碼和逗號分隔的SPS和PPS。FFmpeg首先會把SDP中的SPS信息提取出來,進行BASE64解碼(具體可以參考:《音視頻入門基礎:RTP專題(6)——FFmpeg源碼中,解析SDP中的packetization-mode、profile-level-id和sprop-parameter-sets實現》),然后通過SPS的profile_idc屬性獲取視頻壓縮編碼格式的profile(具體可以參考:《音視頻入門基礎:H.264專題(17)——FFmpeg源碼中,獲取H.264視頻的profile的實現》):
四、視頻的色彩格式
如果SDP文件描述的RTP流的視頻壓縮編碼格式為H.264,FFmpeg獲取其視頻的色彩格式,是通過SPS中的屬性chroma_format_idc獲取到的,具體可以參考:《音視頻入門基礎:H.264專題(13)——FFmpeg源碼中通過SPS屬性獲取視頻色彩格式的實現》:
五、視頻分辨率
如果SDP文件描述的RTP流的視頻壓縮編碼格式為H.264,FFmpeg獲取其視頻分辨率,是通過SPS中的屬性獲取的,具體可以參考:《音視頻入門基礎:H.264專題(12)——FFmpeg源碼中通過SPS屬性計算視頻分辨率的實現》:
?六、視頻碼率
由于SDP中不包含視頻碼率信息,所以無法通過FFmpeg直接獲取到其視頻碼率。與之對應,由于FLV文件的Script Tag中包含視頻碼率信息,所以FFmpeg可以直接打印FLV文件的視頻碼率,具體可以參考:《音視頻入門基礎:FLV專題(24)——FFmpeg源碼中,獲取FLV文件視頻信息的實現》。
七、視頻幀率
如果SDP文件描述的RTP流的視頻壓縮編碼格式為H.264,對其視頻進行編解碼時,FFmpeg源碼內部使用的是通過SPS中的屬性計算得到的視頻幀率(具體可以參考:《音視頻入門基礎:H.264專題(15)——FFmpeg源碼中通過SPS屬性獲取視頻幀率的實現》):
八、可能遇到的問題
比如,獲取RTP流信息時報錯:“Could not find codec parameters for stream 0 (Video: h264, none): unspecified size Consider increasing the value for the 'analyzeduration' (0) and 'probesize' (5000000) options”。可以參考《FFmpeg獲取RTP流信息時報錯:Could not find codec parameters for stream 0 (Video: h264, none)》解決。