一、引言
执行《音视频入门基础:RTP专题(2)------使用FFmpeg命令生成RTP流》中的"媒体文件转推RTP的FFmpeg命令"会生成一个SDP文件,该文件内容如下:
bash
v=0
o=- 0 0 IN IP4 127.0.0.1
s=No Name
t=0 0
a=tool:libavformat 61.7.100
m=video 6005 RTP/AVP 96
c=IN IP4 192.168.0.102
b=AS:1327
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z2QAH6zZgFAFuwFqAgICgAAAAwCAAAAZB4wYzQ==,aOl7LIs=; profile-level-id=64001F
m=audio 7005 RTP/AVP 97
c=IN IP4 192.168.0.102
b=AS:160
a=rtpmap:97 MPEG4-GENERIC/48000/2
a=fmtp:97 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3; config=1190
通过FFmpeg命令:
bash
ffmpeg -protocol_whitelist "file,rtp,udp" -i XXX.sdp
可以判断出该文件是否为SDP文件:
所以FFmpeg是怎样判断出某个文件是否为SDP文件呢?它内部其实是通过sdp_probe函数来判断的。从《FFmpeg源码:av_probe_input_format3函数和AVInputFormat结构体分析(FFmpeg源码5.0.3版本)》和《7.0.1版本的FFmpeg源码中av_probe_input_format3函数和AVInputFormat结构体的改变》中可以知道:FFmpeg源码中实现容器格式检测的函数是av_probe_input_format3函数,其内部通过循环while ((fmt1 = av_demuxer_iterate(&i))) 拿到所有容器格式对应的AVInputFormat结构,然后通过score = fmt1->read_probe(&lpd)语句执行不同容器格式对应的解析函数,根据是否能被解析,以及匹配程度,来判断出这是哪种容器格式。而SDP文件对应的解析函数就是sdp_probe函数。
二、sdp_probe函数的定义
sdp_probe函数定义在FFmpeg源码(本文演示用的FFmpeg源码版本为7.0.1)的源文件libavformat/rtsp.c中:
cpp
#if CONFIG_SDP_DEMUXER
static int sdp_probe(const AVProbeData *p1)
{
const char *p = p1->buf, *p_end = p1->buf + p1->buf_size;
/* we look for a line beginning "c=IN IP" */
while (p < p_end && *p != '\0') {
if (sizeof("c=IN IP") - 1 < p_end - p &&
av_strstart(p, "c=IN IP", NULL))
return AVPROBE_SCORE_EXTENSION;
while (p < p_end - 1 && *p != '\n') p++;
if (++p >= p_end)
break;
if (*p == '\r')
p++;
}
return 0;
}
该函数的作用就是检测某个文件是否为SDP文件。
形参p:输入型参数,为AVProbeData类型的指针。
AVProbeData结构体声明在libavformat/avformat.h中
cpp
/**
* This structure contains the data a format has to probe a file.
*/
typedef struct AVProbeData {
const char *filename;
unsigned char *buf; /**< Buffer must have AVPROBE_PADDING_SIZE of extra allocated bytes filled with zero. */
int buf_size; /**< Size of buf except extra allocated bytes */
const char *mime_type; /**< mime_type, when known. */
} AVProbeData;
p->filename为:需要被推测格式的文件的路径。
p->buf:指向"存放从路径为p->filename的SDP文件中读取出来的二进制数据"的缓冲区。
p->buf_size:缓冲区p->buf的大小,单位为字节。即SDP文件的大小。
p->mime_type:一般为NULL,可忽略。
返回值:返回一个类型为整形的分值。返回0表示该文件完全不符合SDP格式。返回的值越接近100表示该文件越符合SDP格式。
三、sdp_probe函数的内部实现分析
sdp_probe函数中最关键的语句就是通过av_strstart函数判断该文件中是否包含字符串"c=IN IP":
cpp
av_strstart(p, "c=IN IP", NULL)
如果包含字符串"c=IN IP",返回宏定义AVPROBE_SCORE_EXTENSION:
cpp
return AVPROBE_SCORE_EXTENSION
宏定义AVPROBE_SCORE_EXTENSION的值为50。由于其它格式的媒体文件可能也会包含字符串"c=IN IP",所以这种判断方法并不是特别准确。故最终返回的最高分值只是50,表示匹配SDP文件的程度一般:
cpp
#define AVPROBE_SCORE_EXTENSION 50 ///< score for file extension