打开媒体函数,先上全部源码。然后逐语句分析。
int avformat_open_input(AVFormatContext **ps, const char *filename,
ff_const59 AVInputFormat *fmt, AVDictionary **options)
{
//第一部分解析
AVFormatContext *s = *ps;
int i, ret = 0;
AVDictionary *tmp = NULL;
ID3v2ExtraMeta *id3v2_extra_meta = NULL;
//第二部分解析
if (!s && !(s = avformat_alloc_context()))
return AVERROR(ENOMEM);
if (!s->av_class) {
av_log(NULL, AV_LOG_ERROR, "Input context has not been properly allocated by avformat_alloc_context() and is not NULL either\n");
return AVERROR(EINVAL);
}
//第三部分解析
//如果用户指定了输入格式,直接使用它
if (fmt)
s->iformat = fmt;
//===================================================================================
if (options)
av_dict_copy(&tmp, *options, 0);
if (s->pb) // must be before any goto fail
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 FF_API_FORMAT_FILENAME
FF_DISABLE_DEPRECATION_WARNINGS
av_strlcpy(s->filename, filename ? filename : "", sizeof(s->filename));
FF_ENABLE_DEPRECATION_WARNINGS
#endif
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_list(s->iformat->name, s->format_whitelist, ',') <= 0) {
av_log(s, AV_LOG_ERROR, "Format not on whitelist \'%s\'\n", s->format_whitelist);
ret = AVERROR(EINVAL);
goto fail;
}
avio_skip(s->pb, s->skip_initial_bytes);
/* Check filename in case an image number is expected. */
if (s->iformat->flags & AVFMT_NEEDNUMBER) {
if (!av_filename_number_test(filename)) {
ret = AVERROR(EINVAL);
goto fail;
}
}
s->duration = s->start_time = AV_NOPTS_VALUE;
/* Allocate private data. */
if (s->iformat->priv_data_size > 0) {
if (!(s->priv_data = av_mallocz(s->iformat->priv_data_size))) {
ret = AVERROR(ENOMEM);
goto fail;
}
if (s->iformat->priv_class) {
*(const AVClass **) s->priv_data = s->iformat->priv_class;
av_opt_set_defaults(s->priv_data);
if ((ret = av_opt_set_dict(s->priv_data, &tmp)) < 0)
goto fail;
}
}
/* e.g. AVFMT_NOFILE formats will not have a AVIOContext */
if (s->pb)
ff_id3v2_read_dict(s->pb, &s->internal->id3v2_meta, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta);
if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->iformat->read_header)
if ((ret = s->iformat->read_header(s)) < 0)
goto fail;
if (!s->metadata) {
s->metadata = s->internal->id3v2_meta;
s->internal->id3v2_meta = NULL;
} else if (s->internal->id3v2_meta) {
av_log(s, AV_LOG_WARNING, "Discarding ID3 tags because more suitable tags were found.\n");
av_dict_free(&s->internal->id3v2_meta);
}
if (id3v2_extra_meta) {
if (!strcmp(s->iformat->name, "mp3") || !strcmp(s->iformat->name, "aac") ||
!strcmp(s->iformat->name, "tta") || !strcmp(s->iformat->name, "wav")) {
if ((ret = ff_id3v2_parse_apic(s, id3v2_extra_meta)) < 0)
goto close;
if ((ret = ff_id3v2_parse_chapters(s, id3v2_extra_meta)) < 0)
goto close;
if ((ret = ff_id3v2_parse_priv(s, id3v2_extra_meta)) < 0)
goto close;
} else
av_log(s, AV_LOG_DEBUG, "demuxer does not support additional id3 data, skipping\n");
}
ff_id3v2_free_extra_meta(&id3v2_extra_meta);
if ((ret = avformat_queue_attached_pictures(s)) < 0)
goto close;
if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->pb && !s->internal->data_offset)
s->internal->data_offset = avio_tell(s->pb);
s->internal->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;
update_stream_avctx(s);
for (i = 0; i < s->nb_streams; i++)
s->streams[i]->internal->orig_codec_id = s->streams[i]->codecpar->codec_id;
if (options) {
av_dict_free(options);
*options = tmp;
}
*ps = s;
return 0;
close:
if (s->iformat->read_close)
s->iformat->read_close(s);
fail:
ff_id3v2_free_extra_meta(&id3v2_extra_meta);
av_dict_free(&tmp);
if (s->pb && !(s->flags & AVFMT_FLAG_CUSTOM_IO))
avio_closep(&s->pb);
avformat_free_context(s);
*ps = NULL;
return ret;
}
AVFormatContext *s = *ps;
int i, ret = 0;
AVDictionary *tmp = NULL;
ID3v2ExtraMeta *id3v2_extra_meta = NULL;
if (!s && !(s = avformat_alloc_context()))
return AVERROR(ENOMEM);
AVFormatContext *avformat_alloc_context(void)
{
//定义封装上下文结构体
AVFormatContext *ic;
AVFormatInternal *internal;
//使用sizeof计算结构体大小并且分配空间
ic = av_malloc(sizeof(AVFormatContext));
if (!ic) return ic;
internal = av_mallocz(sizeof(*internal));
if (!internal) {
av_free(ic);
return NULL;
}
avformat_get_context_defaults(ic);
ic->internal = internal;
ic->internal->offset = AV_NOPTS_VALUE;
ic->internal->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;
ic->internal->shortest_end = AV_NOPTS_VALUE;
return ic;
}
其中av_malloc封装了c的malloc内存分配函数
void *av_malloc(size_t size)
{
void *ptr = NULL;
//max_aloc_size 为 2147483647
if (size > max_alloc_size)
return NULL;
#if HAVE_POSIX_MEMALIGN
if (size) //OS X on SDK 10.6 has a broken posix_memalign implementation
if (posix_memalign(&ptr, ALIGN, size))
ptr = NULL;
#elif HAVE_ALIGNED_MALLOC
ptr = _aligned_malloc(size, ALIGN);
#elif HAVE_MEMALIGN
#ifndef __DJGPP__
ptr = memalign(ALIGN, size);
#else
ptr = memalign(size, ALIGN);
#endif
/* Why 64?
* Indeed, we should align it:
* on 4 for 386
* on 16 for 486
* on 32 for 586, PPro - K6-III
* on 64 for K7 (maybe for P3 too).
* Because L1 and L2 caches are aligned on those values.
* But I don't want to code such logic here!
*/
/* Why 32?
* For AVX ASM. SSE / NEON needs only 16.
* Why not larger? Because I did not see a difference in benchmarks ...
*/
/* benchmarks with P3
* memalign(64) + 1 3071, 3051, 3032
* memalign(64) + 2 3051, 3032, 3041
* memalign(64) + 4 2911, 2896, 2915
* memalign(64) + 8 2545, 2554, 2550
* memalign(64) + 16 2543, 2572, 2563
* memalign(64) + 32 2546, 2545, 2571
* memalign(64) + 64 2570, 2533, 2558
*
* BTW, malloc seems to do 8-byte alignment by default here.
*/
#else
ptr = malloc(size);
#endif
if(!ptr && !size) {
size = 1;
ptr= av_malloc(1);
}
#if CONFIG_MEMORY_POISONING
if (ptr)
memset(ptr, FF_MEMORY_POISON, size);
#endif
return ptr;
}
如果已经事先定义好了AVInputFormat那么就把定义好的直接赋予在这里。具体结构可以参考下面
typedef struct AVInputFormat {
const char *name; // 输入格式的短名称
const char *long_name; // 格式的长名称(相对于短名称而言,更易于阅读)
/**
* Can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_SHOW_IDS,
* AVFMT_GENERIC_INDEX, AVFMT_TS_DISCONT, AVFMT_NOBINSEARCH,
* AVFMT_NOGENSEARCH, AVFMT_NO_BYTE_SEEK, AVFMT_SEEK_TO_PTS.
*/
int flags;
const char *extensions; // 如果定义了扩展,就不会进行格式探测。但因为该功能目前支持不够,不推荐使用
const struct AVCodecTag * const *codec_tag; // 见名知意
const AVClass *priv_class; ///< AVClass for the private context
const char *mime_type; // mime类型,它用于在探测时检查匹配的mime类型。
/* 此行下方的任何字段都不是公共API的一部分。 它们不能在libavformat之外使用,可以随意更改和删除。
* 应在上方添加新的公共字段。*/
struct AVInputFormat *next; // 用于链接下一个AVInputFormat
int raw_codec_id; // 原始demuxers将它们的解码器id保存在这里。
int priv_data_size; // 私有数据大小,可以用于确定需要分配多大的内存来容纳下这些数据。
/**
* 判断给定文件是否有可能被解析为此格式。 提供的缓冲区保证为AVPROBE_PADDING_SIZE字节大,因此除非您需 * 要更多,否则无需检查。
*/
int (*read_probe)(AVProbeData *);
/**
* 读取格式头,并初始化AVFormatContext结构体
* @return 0 表示操作成功
*/
int (*read_header)(struct AVFormatContext *);
/**
* 读取一个packet并存入pkt指针中。pts和flags会被同时设置。
* @return 0 表示操作成功, < 0 发生异常
* 当返回异常时,pkt可定没有allocated或者在函数返回之前被释放了。
*/
int (*read_packet)(struct AVFormatContext *, AVPacket *pkt);
// 关闭流,AVFormatContext和AVStreams并不会被这个函数释放。
int (*read_close)(struct AVFormatContext *);
/**
* 在stream_index的流中,使用一个给定的timestamp,seek到附近帧。
* @param stream_index 不能为-1
* @param flags 如果没有完全匹配,决定向前还是向后匹配。
* @return >= 0 成功
*/
int (*read_seek)(struct AVFormatContext *,
int stream_index, int64_t timestamp, int flags);
// 获取stream[stream_index]的下一个时间戳,如果发生异常返回AV_NOPTS_VALUE
int64_t (*read_timestamp)(struct AVFormatContext *s, int stream_index,
int64_t *pos, int64_t pos_limit);
// 开始或者恢复播放,只有在播放rtsp格式的网络格式才有意义。
int (*read_play)(struct AVFormatContext *);
int (*read_pause)(struct AVFormatContext *);// 暂停播放,只有在播放rtsp格式的网络格式才有意义。
/**
* 快进到指定的时间戳
* @param stream_index 需要快进操作的流
* @param ts 需要快进到的地方
* @param min_ts max_ts seek的区间,ts需要在这个范围中。
*/
int (*read_seek2)(struct AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags);
// 返回设备列表和其属性
int (*get_device_list)(struct AVFormatContext *s, struct AVDeviceInfoList *device_list);
// 初始化设备能力子模块
int (*create_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps);
// 释放设备能力子模块
int (*free_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps);
} AVInputFormat;