本文将聚焦于FFmpeg协议处理模块,以avformat_open_input函数为核心,详细剖析其在最新FFmpeg源码中的实现。
音视频处理流程简介

avformat_open_input概述
avformat_open_input是FFmpeg用于打开输入多媒体数据的关键函数。它通过统一的接口处理多种协议,使用户无需关心底层实现。该函数的声明如下,位于libavformat/avformat.h:
int avformat_open_input(AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options);
-
ps:指向
AVFormatContext结构体的指针,用于存储打开的多媒体数据上下文。 -
url:要打开的资源URL。
-
fmt:指定输入格式,如果为NULL,FFmpeg会自动探测。
-
options:用于传递其他选项(字典形式)。
这个函数主要完成的功能就是探测输入的格式,然后配置格式的上下文,
比如输入一个mp4文件的地址,它会判断出这是mp4文件,然后AVFormatContext 就知道该怎么处理这个文件了。
avformat_open_input 打开数据流
/**
* @brief 打开一个输入媒体文件。
*
* @param ps 用户提供的 AVFormatContext 的指针,可能是一个指向 NULL 的指针来分配一个新的上下文。
* @param filename 要打开的文件名。
* @param fmt 如果非 NULL,此参数强制使用特定的输入格式。
* @param options 填充 AVFormatContext 和解复用器私有选项的字典。返回时,该参数将被销毁并替换为包含未找到选项的字典。
*
* @return 成功返回0,失败返回负的 AVERROR。
*/
int avformat_open_input(AVFormatContext **ps, const char *filename,
const AVInputFormat *fmt, AVDictionary **options)
{
AVFormatContext *s = *ps; // 获取提供的格式上下文
FFFormatContext *si; // 内部格式上下文
AVDictionary *tmp = NULL; // 用于选项的临时字典
int ret = 0; // 返回值
// 如果没有提供格式上下文,则分配一个新的,也就是说这个格式上下文是可以由外部分配创建的
if (!s && !(s = avformat_alloc_context()))
return AVERROR(ENOMEM);
// 获取内部格式上下文,这相当于给AVFormatContext补充额外的上下文,这在ffmepg中是比较常见的。注意补充字段的内存是在avformat_alloc_context中分配的,所以不要自己直接malloc AVFormatContext
si = ffformatcontext(s);
if (!s->av_class) {
av_log(NULL, AV_LOG_ERROR, "输入上下文未通过 avformat_alloc_context() 正确分配\n");
return AVERROR(EINVAL);
}
if (fmt)
s->iformat = fmt; // 设置输入格式
if (options)
av_dict_copy(&tmp, *options, 0);
// 如果设置了IO上下文,则设定定制的解复用标志
if (s->pb)
s->flags |= AVFMT_FLAG_CUSTOM_IO;
if ((ret = av_opt_set_dict(s, &tmp)) < 0)
goto fail; // 设置格式上下文选项失败
// 拷贝文件名
if (!(s->url = av_strdup(filename ? filename : ""))) {
ret = AVERROR(ENOMEM);
goto fail;
}
// 【重要】探测输入格式
if ((ret = init_input(s, filename, &tmp)) < 0)
goto fail;
s->probe_score = ret; // 设置探测得分
// 复制协议白名单
if (!s->protocol_whitelist && s->pb && s->pb->protocol_whitelist) {
s->protocol_whitelist = av_strdup(s->pb->protocol_whitelist);
if (!s->protocol_whitelist) {
ret = AVERROR(ENOMEM);
goto fail;
}
}
// 复制协议黑名单
if (!s->protocol_blacklist && s->pb && s->pb->protocol_blacklist) {
s->protocol_blacklist = av_strdup(s->pb->protocol_blacklist);
if (!s->protocol_blacklist) {
ret = AVERROR(ENOMEM);
goto fail;
}
}
// 检查格式白名单
if (s->format_whitelist && av_match_

最低0.47元/天 解锁文章
1万+

被折叠的 条评论
为什么被折叠?



