ffmpeg源码分析之媒体打开过程

从打开文件开始.入口函数是avformat_open_input(),下面是对此函数的分析

//参数ps包含一切媒体相关的上下文结构,有它就有了一切,本函数如果打开媒体成功,
//会返回一个AVFormatContext的实例.
//参数filename是媒体文件名或URL.
//参数fmt是要打开的媒体格式的操作结构,因为是读,所以是inputFormat.此处可以
//传入一个调用者定义的inputFormat,对应命令行中的 -f xxx段,如果指定了它,
//在打开文件中就不会探测文件的实际格式了,以它为准了.
//参数options是对某种格式的一些操作,是为了在命令行中可以对不同的格式传入
//特殊的操作参数而建的, 为了了解流程,完全可以无视它.
int avformat_open_input(AVFormatContext **ps,
		const char *filename,
		AVInputFormat *fmt,
		AVDictionary **options)
{
	AVFormatContext *s = *ps;
	int ret = 0;
	AVFormatParameters ap = { { 0 } };
	AVDictionary *tmp = NULL;

	//创建上下文结构
	if (!s && !(s = avformat_alloc_context()))
		return AVERROR(ENOMEM);
	//如果用户指定了输入格式,直接使用它
	if (fmt)
		s->iformat = fmt;

	//忽略
	if (options)
		av_dict_copy(&tmp, *options, 0);

	if ((ret = av_opt_set_dict(s, &tmp)) < 0)
		goto fail;

	//打开输入媒体(如果需要的话),初始化所有与媒体读写有关的结构们,比如
	//AVIOContext,AVInputFormat等等
	if ((ret = init_input(s, filename)) < 0)
		goto fail;
	//执行完此函数后,s->pb和s->iformat都已经指向了有效实例.pb是用于读写数据的,它
	//把媒体数据当做流来读写,不管是什么媒体格式,而iformat把pb读出来的流按某种媒体格
	//式进行分析,也就是说pb在底层,iformat在上层.

	//很多静态图像文件格式,都被当作一个格式处理,比如要打开.jpeg文件,需要的格式
	//名为image2.此处还不是很了解具体细节,作不得准哦.
	/* 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;
	//上下文中保存下文件名
	av_strlcpy(s->filename, filename, sizeof(s->filename));

	/* allocate private data */
	//为当前格式分配私有数据,主要用于某格式的读写操作时所用的私有结构.
	//此结构的大小在定义AVInputFormat时已指定了.
	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 */
	//从mp3文件中读ID3数据并保存之.
	if (s->pb)
		ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC);

	//读一下媒体的头部,在read_header()中主要是做某种格式的初始化工作,比如填充自己的
	//私有结构,根据流的数量分配流结构并初始化,把文件指针指向数据区开始处等.
	if (!(s->flags & AVFMT_FLAG_PRIV_OPT) && s->iformat->read_header)
		if ((ret = s->iformat->read_header(s, &ap)) < 0)
			goto fail;

	//保存数据区开始的位置
	if (!(s->flags & AVFMT_FLAG_PRIV_OPT) && s->pb && !s->data_offset)
		s->data_offset = avio_tell(s->pb);

	s->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;

	if (options) {
		av_dict_free(options);
		*options = tmp;
	}
	*ps = s;
	//执行成功
	return 0;

	//执行失败
	fail: av_dict_free(&tmp);
	if (s->pb && !(s->flags & AVFMT_FLAG_CUSTOM_IO))
		avio_close(s->pb);
	avformat_free_context(s);
	*ps = NULL;
	return ret;
}

原文链接: http://blog.csdn.net/niu_gao/article/details/7043241


你可能感兴趣的:(ffmpeg源码分析之媒体打开过程)