摘要:本文主要描述了FFmpeg中用于打开文件接口avformat_open_input的具体调用流程,详细描述了该接口被调用时所作的具体工作。
  关键字ffmpegavformat_open_input
  注意:读者需要了解FFmpeg的基本使用流程,以及一些FFmpeg的基本常识,了解FFmpegIO相关的内容,以及大致的解码流程。

1 avformat_open_input大致流程

  在了解avformat_open_input的具体实现之前,我们先简单看下具体的函数声明和使用方式。avformat_open_input函数调用时会检测一部分当前格式的信息,更多的信息需要调用avformat_find_stream_info获取更加准确的信息。在函数调用时可以强制指定对应格式的格式,即参数AVInputFormat,否则FFmpeg内部会根据扩展名,数据格式等进行检测。另外也可以设置options,该option控制了探测码流的一些标志位,一般情况下不会设置,但是有些情况下需要根据具体的场景设置,比如有些素材普通的方式检测不到就需要设置probesize才能准确的检测到码流的属性等。

/*** Open an input stream and read the header. The codecs are not opened.* The stream must be closed with avformat_close_input().** @param ps Pointer to user-supplied AVFormatContext (allocated by avformat_alloc_context).*           May be a pointer to NULL, in which case an AVFormatContext is allocated by this*           function and written into ps.*           Note that a user-supplied AVFormatContext will be freed on failure.* @param url URL of the stream to open.* @param fmt If non-NULL, this parameter forces a specific input format.*            Otherwise the format is autodetected.* @param options  A dictionary filled with AVFormatContext and demuxer-private options.*                 On return this parameter will be destroyed and replaced with a dict containing*                 options that were not found. May be NULL.** @return 0 on success, a negative AVERROR on failure.** @note If you want to use custom IO, preallocate the format context and set its pb field.*/
int avformat_open_input(AVFormatContext **ps, const char *url, const AVInputFormat *fmt, AVDictionary **options);

  从上面的流程图(图中省略了ID3V2 metadata获取的相关内容)中我们能够看出avformat_open_input的主要工作就是打开文件流然后探测文件的码流检测出当前文件的格式。

2 调用流程详情

  avformat_alloc_context,如果用户指定的AVFormatContext指针为空内部就会创建一个。而该函数主要的工作就是利用av_malloc申请一个AVFormatContext然后设置默认值。av_opt_set_dict就是设置基本的参数到当前的Context中。
  init_input主要工作就是打开输入流,并探测对应的流内容,对流进行打分,分支越高对应格式的可能性越高否则越低。打开流的工作就是利用avio的打开流,根据不同的流类型会调用不同的打开API,文件就是调用open。在进行流探测是分别调用av_probe_input_buffer2av_probe_input_format2对码流进行打分,前者最终也是调用后者实现的。

static int init_input(AVFormatContext *s, const char *filename,AVDictionary **options)
{int ret;AVProbeData pd = { filename, NULL, 0 };int score = AVPROBE_SCORE_RETRY;if (s->pb) {s->flags |= AVFMT_FLAG_CUSTOM_IO;if (!s->iformat)return av_probe_input_buffer2(s->pb, &s->iformat, filename,s, 0, s->format_probesize);else if (s->iformat->flags & AVFMT_NOFILE)av_log(s, AV_LOG_WARNING, "Custom AVIOContext makes no sense and ""will be ignored with AVFMT_NOFILE format.\n");return 0;}//文件流已经被打开过了就直接调用av_probe_input_format2进行格式检测if ((s->iformat && s->iformat->flags & AVFMT_NOFILE) ||(!s->iformat && (s->iformat = av_probe_input_format2(&pd, 0, &score))))return score;//打开文件流if ((ret = s->io_open(s, &s->pb, filename, AVIO_FLAG_READ | s->avio_flags, options)) < 0)return ret;if (s->iformat)return 0;return av_probe_input_buffer2(s->pb, &s->iformat, filename,s, 0, s->format_probesize);
}

  av_probe_input_format3内通过遍历一个全局的demuxer_list表格,利用每种封装格式的探测指针对流进行打分,选择分值最高的作为最终的流格式。demuxer_list是一个自动生成的全局数组,如果没有编译FFmpeg是不会看到该数组的。

static const AVInputFormat *demuxer_list[] = {&ff_aa_demuxer,&ff_aac_demuxer,&ff_aax_demuxer...&ff_libmodplug_demuxer,NULL
};

  av_probe_input_format3的核心代码如下,遍历已知的格式列表,如果探测不到就会常使用mime_type和扩展名作为依据。

while ((fmt1 = av_demuxer_iterate(&i))) {if (!is_opened == !(fmt1->flags & AVFMT_NOFILE) && strcmp(fmt1->name, "image2"))continue;score = 0;if (fmt1->read_probe) {score = fmt1->read_probe(&lpd);if (score)av_log(NULL, AV_LOG_TRACE, "Probing %s score:%d size:%d\n", fmt1->name, score, lpd.buf_size);if (fmt1->extensions && av_match_ext(lpd.filename, fmt1->extensions)) {switch (nodat) {case NO_ID3:score = FFMAX(score, 1);break;case ID3_GREATER_PROBE:case ID3_ALMOST_GREATER_PROBE:score = FFMAX(score, AVPROBE_SCORE_EXTENSION / 2 - 1);break;case ID3_GREATER_MAX_PROBE:score = FFMAX(score, AVPROBE_SCORE_EXTENSION);break;}}} else if (fmt1->extensions) {if (av_match_ext(lpd.filename, fmt1->extensions))score = AVPROBE_SCORE_EXTENSION;}if (av_match_name(lpd.mime_type, fmt1->mime_type)) {if (AVPROBE_SCORE_MIME > score) {av_log(NULL, AV_LOG_DEBUG, "Probing %s score:%d increased to %d due to MIME type\n", fmt1->name, score, AVPROBE_SCORE_MIME);score = AVPROBE_SCORE_MIME;}}if (score > score_max) {score_max = score;fmt       = fmt1;} else if (score == score_max)fmt = NULL;
}

  随后就是调用read_header取读取一些基本的参数,比如流的数量,时长等。其他代码就是一些检查类以及参数更新类代码了。

3 参考文献

  • ID3
  • FFmpeg源代码简单分析:avformat_open_input()

FFmpeg5.0源码阅读——avformat_open_input相关推荐

  1. FFmpeg5.0源码阅读之AVClass和AVOption

      摘要:本文通过阅读FFmpeg源码来理解FFmpeg中AVOption的实现原理和具体的使用方式.   关键字:AVClss,AVOption,AVOptionRange   版本:FFmpeg5 ...

  2. FFmpeg5.0源码阅读——AVFrame

      摘要:AVFrame是FFmpeg中表示裸数据的结构体,是FFmpeg最重要的结构体之一.本篇文章针对FFmpeg源码理解AVFrame的作用,相关的结构定义以及一些操作API的具体实现.   关 ...

  3. FFmpeg5.0源码阅读——mov文件格式解析

    摘要:之前在Mp4格式详解中详细描述了Mp4文件格式的具体布局方式.为了更加深入理解mp4文件格式,本文记录了ffmpeg中解封装mp4文件的基本实现. 关键字:mov.FFmpeg.mp4 1 简介 ...

  4. FFmpeg5.0源码阅读—— av_read_frame

      摘要:本文主要描述了FFmpeg中用于打开编解码器接口av_read_frame的具体调用流程,详细描述了该接口被调用时所作的具体工作.   关键字:ffmpeg.av_read_frame    ...

  5. FFmpeg5.0源码阅读——av_interleaved_write_frame

      摘要:本文主要详细描述FFmpeg中封装时写packet到媒体文件的函数av_interleaved_write_frame的实现.   关键字:av_interleaved_write_fram ...

  6. FFmpeg5.0源码阅读—— avcodec_open2

      摘要:本文主要描述了FFmpeg中用于打开编解码器接口avcodec_open2大致流程的具体调用流程,详细描述了该接口被调用时所作的具体工作.   关键字:ffmpeg.avcodec_open ...

  7. Spring Boot 2.0系列文章(四):Spring Boot 2.0 源码阅读环境搭建

    前提 前几天面试的时候,被问过 Spring Boot 的自动配置源码怎么实现的,没看过源码的我只能投降��了. 这不,赶紧来补补了,所以才有了这篇文章的出现,Spring Boot 2. 0 源码阅 ...

  8. CloudSim 4.0源码阅读笔记(功耗实例)

    文章目录 一.NonPowerAware案例 1.1 基本概述 1.2 云任务/虚机/主机/功耗模型参数设置 1.3 初始化云任务(CloudletList)-如何载入自定义真实数据集中的CPU利用率 ...

  9. AFNetworking 3.0源码阅读 - AFURLResponseSerialization

    这次来说一下AFURLResponseSerialization这个HTTP响应类. 定义了一个协议,该协议返回序列化后的结果.后续的AFHTTPResponseSerializer以及他的子类都遵循 ...

最新文章

  1. Java 使用 Redis
  2. linux服务器配置php mysql,Linux系统如何安装配置Apache+PHP+MySQL服务器环境
  3. Vue使用v-bind绑定动态数据
  4. oracle 0值处理判断,ORACLE数据统计0的处理
  5. 硬核!原型和原型链详解
  6. c++ list 获取元素_Python中最常见的10个问题(list)
  7. 男生眼中“理想女友”工作排名,程序员排名第三,幼师倒数第一
  8. linux中批量创文件夹的方法
  9. C3P0组件+DbUtils组件实现一个JdbcUtils工具类
  10. Java中迭代Map的方法
  11. Chrome远程调试手机端UC浏览器
  12. 1024程序员节,160元买400元图书专属优惠券,速来
  13. IDEA:如何彻底删除工程文件(转载)
  14. tomcat两种启动方式
  15. python-docx官方文档翻译--用户指南06--使用页眉和页脚
  16. 推荐google浏览器插件(为专注工作使用)
  17. AWS Academy 学习平台建立 Learner Lab - 教师
  18. 国外人气最旺的软件测试网站
  19. 特征缩放+无量纲化:最小最大缩放 - Python代码实现
  20. js根据出生日期 计算岁数

热门文章

  1. python图片增强 曝光度,亮度
  2. Internet基础
  3. 在遗忘了风声的边界,听不懂潮水的呜咽.
  4. 关于Git执行命令git config --list后迟迟不显示的问题
  5. 钢铁是怎样炼成的第一部第二章
  6. Error: Could not open client transport with JDBC Uri 解决方案
  7. 计算机控制技术与系统仿真翟天嵩,计算机控制技术与系统仿真
  8. 【JAVA】简单程序实现人机对抗:剪刀石头布
  9. CPS1848国产替代芯片 国产SRIO交换芯片
  10. 为什么炒股不如炒汇?