主要框架
avformat_alloc_context(void)//option.c
{
avformat_get_context_defaults(ic)//option.c
s->av_class = &av_format_context_class;//静态类,函数相关指针
.option = avformat_options//option.c
avformat_options//options_table.h, 设置probsize等
s->io_open = io_open_default//option.c,初始化函数指针io_open
/*-------------为后面的avformat_open_input做准备-------*/
ffio_open_whitelist//aviobuf.c这部分还不不会调用,只是方便理解,先把他的流程写出来
ffurl_alloc//avio.c
ffurl_connect//avio.c
/*--------------------------------------------------*/
s->io_close = io_close_default//option.c
av_opt_set_defaults(s)//option.c
av_opt_next//opt.c
class->option
}
avformat_alloc_context这个函数主要实现了分配一个AVFormatContext。他可用于由框架分配的在上下文和所有内容 ,即分配解复用器上下文
/**
* Allocate an AVFormatContext.
* avformat_free_context() can be used to free the context and everything
* allocated by the framework within it.
*/
AVFormatContext *avformat_alloc_context(void)
{
AVFormatContext *ic;
ic = av_malloc(sizeof(AVFormatContext));
if (!ic) return ic;
/* 设置 ic 中各成员的默认值 */
avformat_get_context_defaults(ic);
/* internal:
* An opaque field for libavformat internal usage.
* Must not be accessed in any way by callers. */
ic->internal = av_mallocz(sizeof(*ic->internal));
if (!ic->internal) {
avformat_free_context(ic);
return NULL;
}
/* offset:
* 偏移重新映射时间戳为非负值
* 以时间戳为单位表示.
* @see AVStream.mux_ts_offset */
ic->internal->offset = AV_NOPTS_VALUE;
/* raw_packet_buffer_remaining_size:
* raw_packet_buffer 缓存中剩余可用的字节数
* 初值为 2500000 */
ic->internal->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;
/* shortest_end:
* 最短的流结束的时间戳 */
ic->internal->shortest_end = AV_NOPTS_VALUE;
return ic;
}
av_malloc(sizeof(AVFormatContext))这个是内存分配,这个是没什么可以解释的
typedef struct AVFormatContext {
AVIOContext *pb;//输入数据的缓存
unsigned int nb_streams;//视音频流的个数
AVStream **streams;//视频流指针
char filename[1024];//文件名
int64_t start_time;播放开始时间
int64_t bit_rate;
AVDictionary *metadata;//元数据
protocol_blacklist;协议黑名单
protocol_whitelist;协议白名单
AVFormatContext是一个贯穿始终的数据结构,很多函数都要用到它作为参数。它是FFMPEG解封装(flv,mp4,rmvb,avi)功能的结构体。avformat_alloc_context首先为 AVFormatContext 结构体分配动态内存,然后调用 avformat_get_context_defaults 函数获取该 AVFormatContext 的默认值。
static void avformat_get_context_defaults(AVFormatContext *s)
{
memset(s, 0, sizeof(AVFormatContext));
s->av_class = &av_format_context_class;
s->io_open = io_open_default;
s->io_close = io_close_default;
av_opt_set_defaults(s);
}
首先,s->av_class 指向一个全局静态结构体变量 av_format_context_class,给结构体变量的定义如下.
static const AVClass av_format_context_class = {
/**
* 类的名字,通常它与 AVClass 关联的上下文结构体类型的名字相同。
* 这里类名为"AVFormatContext",说明该 AVClass 关联的上下文结构体为
* AVFormatContext.
*/
.class_name = "AVFormatContext",
/**
* 这里这个函数返回的是 AVFormatContext 中 iformat->name
* 或者 oformat->name 字符串.
*/
.item_name = format_to_name,
/**
* avformat_options 是一个 AVOption 结构体类的数组,
* 该数组中的元素为 AVFormatContext 中的一个个字段,
* 以后可以通过 av_opt_* 系列函数对 AVFormatContext
* 中的字段进行操作。
*/
.option = avformat_options,
.version = LIBAVUTIL_VERSION_INT,
/**
* 返回下一个启用 AVOption 的子项
*/
.child_next = format_child_next,
.child_class_next = format_child_class_next,
.category = AV_CLASS_CATEGORY_MUXER,
.get_category = get_category,
};
初始化函数指针io_open和io_close
static int io_open_default(AVFormatContext *s, AVIOContext **pb,
const char *url, int flags, AVDictionary **options)
{
int loglevel;
if (!strcmp(url, s->filename) ||
s->iformat && !strcmp(s->iformat->name, "image2") ||
s->oformat && !strcmp(s->oformat->name, "image2")
) {
loglevel = AV_LOG_DEBUG;
} else
loglevel = AV_LOG_INFO;
av_log(s, loglevel, "Opening \'%s\' for %s\n", url, flags & AVIO_FLAG_WRITE ? "writing" : "reading");
#if FF_API_OLD_OPEN_CALLBACKS
FF_DISABLE_DEPRECATION_WARNINGS
if (s->open_cb)
return s->open_cb(s, pb, url, flags, &s->interrupt_callback, options);
FF_ENABLE_DEPRECATION_WARNINGS
#endif
return ffio_open_whitelist(pb, url, flags, &s->interrupt_callback, options, s->protocol_whitelist, s->protocol_blacklist);
}
使用ffio_open_whitelist()函数打开URL
ffio_open_whitelist() 声明:
所属库:libavformat(lavf)
头文件:libavformat/avio_internal.h 如其名,是IO内部使用的函数,不是public api
声明:
int ffio_open_whitelist(AVIOContext **s, const char *url, int flags,
const AVIOInterruptCB *int_cb, AVDictionary **options,
const char *whitelist, const char *blacklist);
文件:libavformat/aviobuf.c, 源码如下所示:
int ffio_open_whitelist(AVIOContext **s, const char *filename, int flags,
const AVIOInterruptCB *int_cb, AVDictionary **options,
const char *whitelist, const char *blacklist
)
{
URLContext *h;
int err;
err = ffurl_open_whitelist(&h, filename, flags, int_cb, options, whitelist, blacklist, NULL);
if (err < 0)
return err;
err = ffio_fdopen(s, h);
if (err < 0) {
ffurl_close(h);
return err;
}
return 0;
}
ffurl_open_whitelist() 声明:
所属库:libavformat(lavf)
头文件:libavformat/url.h
功能说明:根据URL来创建一个URLContext对象,用来访问URL所定位的资源,并打开之。对于该函数的入参以及返回值说明如下源码:
/**
* Create an URLContext for accessing to the resource indicated by
* url, and open it.
*
* puc指向成功打开后的URLContext对象
* @param puc pointer to the location where, in case of success, the
* function puts the pointer to the created URLContext
*
* flags参数控制如何打开url指定的资源
* @param flags flags which control how the resource indicated by url
* is to be opened
*
* int_cb 中断函数,供URLContext使用,可空
* @param int_cb interrupt callback to use for the URLContext, may be
* NULL
*
* options参数,传入协议私有的选项。生效的选项,对应条目将被销毁,未生效的选项在本函数执
* 行之后仍保留在该参数中。该参数可空。
* @param options A dictionary filled with protocol-private options. On return
* this parameter will be destroyed and replaced with a dict containing options
* that were not found. May be NULL.
*
* parent参数代表创建成功的URLContext的父URLContext对象,父URLContext对象的通用选项
* 也应用到创建的URLContext对象中。
* @param parent An enclosing URLContext, whose generic options should
* be applied to this URLContext as well.
* 成功返回0或正数,失败返回负数,并且是由AVERROR宏返回的错误码
* @return >= 0 in case of success, a negative value corresponding to an
* AVERROR code in case of failure
*/
int ffurl_open_whitelist(URLContext **puc, const char *filename, int flags,
const AVIOInterruptCB *int_cb, AVDictionary **options,
const char *whitelist, const char* blacklist,
URLContext *parent);
ffio_open_whitelist函数
int ffurl_open_whitelist(URLContext **puc, const char *filename, int flags,
const AVIOInterruptCB *int_cb, AVDictionary **options,
const char *whitelist, const char* blacklist,
URLContext *parent)
{
AVDictionary *tmp_opts = NULL;
AVDictionaryEntry *e;
int ret = ffurl_alloc(puc, filename, flags, int_cb); // 创建URLContext
if (ret < 0)
return ret;
if (parent)
av_opt_copy(*puc, parent); // 拷贝父URLContext的选项->子URLContext
// 设置用户传入的选项到URLContext
if (options &&
(ret = av_opt_set_dict(*puc, options)) < 0)
goto fail;
// 上一步中的options含有非URLContext类的直接选项信息
// 则设置用户传入的选项到URLContext.priv_data数据中
if (options && (*puc)->prot->priv_data_class &&
(ret = av_opt_set_dict((*puc)->priv_data, options)) < 0)
goto fail;
// 传入的options为空,options指向内部临时变量,后续操作黑白名单需要用上选项
// 此处操作就是为了不论是否用户传入了options,还是传入NULL,后续操作能统一使用一个变量。
if (!options)
options = &tmp_opts;
// 对白名单进行断言
av_assert0(!whitelist ||
!(e=av_dict_get(*options, "protocol_whitelist", NULL, 0)) ||
!strcmp(whitelist, e->value));
av_assert0(!blacklist ||
!(e=av_dict_get(*options, "protocol_blacklist", NULL, 0)) ||
!strcmp(blacklist, e->value));
// 将白名单放到options中
if ((ret = av_dict_set(options, "protocol_whitelist", whitelist, 0)) < 0)
goto fail;
// 将黑名单放到options中
if ((ret = av_dict_set(options, "protocol_blacklist", blacklist, 0)) < 0)
goto fail;
// 将options的黑白名单应用到URLContext
if ((ret = av_opt_set_dict(*puc, options)) < 0)
goto fail;
ret = ffurl_connect(*puc, options);
if (!ret)
return 0;
fail:
ffurl_close(*puc);
*puc = NULL;
return ret;
}
https://blog.csdn.net/ice_ly000/article/details/90339330文章介绍了io_open_default()相关的,介绍得挺好
av_opt_set_defaults根据前端设置的option进行初始化,比如前端设置的probsize等参数
#define OFFSET(x) offsetof(AVFormatContext,x)
/**
* should be NAN but it does not work as it is
* not a constant in glibc as required by ANSI/ISO C
*/
#define DEFAULT 0
// these names are too long to be readable
#define E AV_OPT_FLAG_ENCODING_PARAM
#define D AV_OPT_FLAG_DECODING_PARAM
static const AVOption avformat_options[] = {
/**
* AVOption:
* name: 该选项的名称
* help: 该选项对应的一些简短的描述
* offset: 对于命名常量,该值为0;否则为该选项在 AVFormatContext 中的偏移值
* type: 该选项的类型,为 bool,或者常量 const
* default_val:该字段是一个联合体类型,存放的是该选项的默认值
* min: 该选项的最小值
* max:该选项的最大值
* flags:标志该选项的用途,如encoding
* unit: 该选项所属的逻辑单元。非常量选项和相应的命名常量选项共享
* 同一个单元。该字段可能为 NULL。
*/
{"avioflags", NULL, OFFSET(avio_flags), AV_OPT_TYPE_FLAGS,
{.i64 = DEFAULT }, INT_MIN, INT_MAX, D|E, "avioflags"},
{"direct", "reduce buffering", 0, AV_OPT_TYPE_CONST,
{.i64 = AVIO_FLAG_DIRECT }, INT_MIN, INT_MAX, D|E, "avioflags"},
{"probesize", "set probing size", OFFSET(probesize),
AV_OPT_TYPE_INT64, {.i64 = 5000000 }, 32, INT64_MAX, D},
{"formatprobesize", "number of bytes to probe file format",
OFFSET(format_probesize), AV_OPT_TYPE_INT, {.i64 = PROBE_BUF_MAX}, 0, INT_MAX-1, D},
{"packetsize", "set packet size", OFFSET(packet_size), AV_OPT_TYPE_INT,
{.i64 = DEFAULT }, 0, INT_MAX, E},
{"fflags", NULL, OFFSET(flags), AV_OPT_TYPE_FLAGS,
{.i64 = AVFMT_FLAG_FLUSH_PACKETS | AVFMT_FLAG_AUTO_BSF },
avformat_alloc_context()主要工作:
1)创建AVFormatContext,他可用于由框架分配的在上下文和所有内容 ,即分配解复用器上下文
2)初始化io_open等函数指针,为init_input做准备
3)并初始化option相关参数给ic