FFmpeg5.0源码阅读——avformat_find_stream_info

news2025/2/23 5:36:51

  摘要:在使用FFmpeg库时通常使用avformat_find_stream_info相关函数来探测流的基本信息,为了更加深入理解FFmpeg的基本流程,本文根据FFmpeg 5.0的源码详细描述了该函数的具体实现。
  关键字:FFmpeg
  读者须知:读者需要了解FFmpeg的基本使用流程,以及一些FFmpeg的基本常识,了解FFmpegIO相关的内容,以及大致的解码流程。

1 avformat_find_stream_info

  avformat_open_input的主要工作时打开流并且对流进行初步的检测设置一些当前流的基本属性。而avformat_find_stream_info在调用时其耗时是比较久做的流信息探测的工作更多。avformat_find_stream_info比仅仅会读取文件来获取流信息,而且会尝试进行部分解码,根据AVPcaketAVFrame更加准确的判断流的基本信息。部分场景下虽然跳过解码过程可以提升avformat_find_stream_info的执行速度,但是也会导致流探测的信息不准确。

/**
 * Read packets of a media file to get stream information. This
 * is useful for file formats with no headers such as MPEG. This
 * function also computes the real framerate in case of MPEG-2 repeat
 * frame mode.
 * The logical file position is not changed by this function;
 * examined packets may be buffered for later processing.
 *
 * @param ic media file handle
 * @param options  If non-NULL, an ic.nb_streams long array of pointers to
 *                 dictionaries, where i-th member contains options for
 *                 codec corresponding to i-th stream.
 *                 On return each dictionary will be filled with options that were not found.
 * @return >=0 if OK, AVERROR_xxx on error
 *
 * @note this function isn't guaranteed to open all the codecs, so
 *       options being non-empty at return is a perfectly normal behavior.
 *
 * @todo Let the user decide somehow what information is needed so that
 *       we do not waste time getting stuff the user does not need.
 */
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);

  avformat_find_stream_info的最终目的就是获取目标流的详细信息如果拿不到就会尝试获取码流AVPacket,从码流中解析相关流信息,如果码流中也拿不到就会尝试解码从AVFrame中获取。
在这里插入图片描述

2 详细调用过程

  avformat_find_stream_info代码的内容非常难以阅读,这里不贴对应的代码了,我们简单分析下。
  在进行探测前下面这部分代码用来设置探测的时长,可以看到部分时长是和格式强相关的,应该和文件本身关系比较大。

max_stream_analyze_duration = max_analyze_duration;
max_subtitle_analyze_duration = max_analyze_duration;
if (!max_analyze_duration) {
    max_stream_analyze_duration =
    max_analyze_duration        = 5*AV_TIME_BASE;
    max_subtitle_analyze_duration = 30*AV_TIME_BASE;
    if (!strcmp(ic->iformat->name, "flv"))
        max_stream_analyze_duration = 90*AV_TIME_BASE;
    if (!strcmp(ic->iformat->name, "mpeg") || !strcmp(ic->iformat->name, "mpegts"))
        max_stream_analyze_duration = 7*AV_TIME_BASE;
}

  然后就是循环遍历打开每个流的解码器,为后续解码做准备,这部分就是调用avcodec_find_decoderavcodec_open2查找解码器和打开解码器,具体实现等到讲解码时再说。
  之后便是不断循环检测,循环内部会不断判断当前是否已经成功获取完整的流信息,成功或者超出探测时长上限的话就结束;否则就会从读取AVPacket和解码帧AVFrame,读取AVPacket和解码AVFrame分别是调用ff_read_packetavcodec_send_packet,avcodec_receive_frame进行码流的读取和解码。
  estimate_timings用于估算当前媒体文件的时长,根据不同的格式会采取不同的方式:

  1. mpegmpegts会采用pts的方式估算,即调用estimate_timings_from_pts估算;
  2. 如果非情况1且流本身已经探测到一部分时长信息,则调用fill_all_stream_timings根据已有的时长相关信息进行统一;
  3. 其他情况调用estimate_timings_from_bit_rate,利用文件码流大小和码率估算;

  estimate_timings_from_pts核心就是累加AVPacket的时长,如下:

for (;;) {
    if (read_size >= DURATION_MAX_READ_SIZE << (FFMAX(retry - 1, 0)))
        break;

    do {
        ret = ff_read_packet(ic, pkt);
    } while (ret == AVERROR(EAGAIN));
    if (ret != 0)
        break;
    read_size += pkt->size;
    st         = ic->streams[pkt->stream_index];
    if (pkt->pts != AV_NOPTS_VALUE &&
        (st->start_time != AV_NOPTS_VALUE ||
            st->internal->first_dts  != AV_NOPTS_VALUE)) {
        if (pkt->duration == 0) {
            ff_compute_frame_duration(ic, &num, &den, st, st->internal->parser, pkt);
            if (den && num) {
                pkt->duration = av_rescale_rnd(1,
                                    num * (int64_t) st->time_base.den,
                                    den * (int64_t) st->time_base.num,
                                    AV_ROUND_DOWN);
            }
        }
        duration = pkt->pts + pkt->duration;
        found_duration = 1;
        if (st->start_time != AV_NOPTS_VALUE)
            duration -= st->start_time;
        else
            duration -= st->internal->first_dts;
        if (duration > 0) {
            if (st->duration == AV_NOPTS_VALUE || st->internal->info->last_duration<= 0 ||
                (st->duration < duration && FFABS(duration - st->internal->info->last_duration) < 60LL*st->time_base.den / st->time_base.num))
                st->duration = duration;
            st->internal->info->last_duration = duration;
        }
    }
    av_packet_unref(pkt);
}

  而estimate_timings_from_bit_rate代码比较简单就是duration=filesize/bitrate

 duration = av_rescale(filesize, 8LL * st->time_base.den,
                                          ic->bit_rate *
                                          (int64_t) st->time_base.num);
                    st->duration = duration;

  最后根据已经探测的的信息统一对时间等信息进行统一。

3 参考文献

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/680383.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数学之美:神奇的杨辉三角形,比帕斯卡早了近600年,致敬中国古代数学家(63)

小朋友们好&#xff0c;大朋友们好&#xff01; 我是猫妹&#xff0c;一名爱上Python编程的小学生。 和猫妹学Python&#xff0c;一起趣味学编程。 今日主题 什么是杨辉三角形&#xff1f; 杨辉三角形有什么规律&#xff1f; 中国古代数学家杨辉。 西方科学家帕斯卡。 杨…

【开源与项目实战:开源实战】81 | 开源实战三(上):借Google Guava学习发现和开发通用功能模块

上几节课&#xff0c;我们拿 Unix 这个超级大型开源软件的开发作为引子&#xff0c;从代码设计编写和研发管理两个角度&#xff0c;讲了如何应对大型复杂项目的开发。接下来&#xff0c;我们再讲一下 Google 开源的 Java 开发库 Google Guava。 Google Guava 是一个非常成功、…

智能指针类模板:auto_ptr、unique_ptr、shared_ptr的原理与使用

1. 什么是智能指针 智能指针是行为类似于指针的类对象&#xff0c;通常用于管理动态内存分配。C程序通常手动动态分配堆内存&#xff0c;但如果动态分配的内存没有释放&#xff0c;则会发生内存泄漏。 例如代码段1.1。 // 代码段1.1 void demo() {double *pd new double;*pd…

使用STM32F103的串口实现IAP程序升级功能

使用STM32F103的串口实现IAP程序升级功能 &#x1f3ac;IAP程序烧录全过程演示&#xff1a; ✨这几天折腾IAP升级功能&#xff0c;狂补了很多相关BootLoader相关的知识。本来最想实现IAP升级程序的方式是&#xff0c;基于SPI通讯的SD卡&#xff0c;借助挂载的FatFS文件系统&am…

C++中的内存分区

目录 操作系统的内存区域 C内存分区模型 1. 程序运行前 2. 程序运行后 3. new 操作符的使用 操作系统的内存区域 text段&#xff1a;存储程序的二进制指令&#xff0c;即程序源码编译后的二进制代码data段&#xff1a;存储已被初始化的全局变量、常量bss段&#xff1a;存储…

ES-工作原理

前言 ​ 搜索引擎是对数据的检索&#xff0c;而数据总体分为两种&#xff1a;结构化数据和非结构化数据。而对于结构化数据&#xff0c;因为他们具有特定的结构&#xff0c;所以一般都是可以通过关系型数据库MySQL/oracle的二维表的方式存储和搜索&#xff0c;也可以建立索引。…

Redis的简单使用 (实现Session持久化)

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 一、Redis数据类型的使用 1. 字符串&#xff…

Redis【入门篇】---- Redis的Java客户端-Jedis

Redis【入门篇】---- Redis的Java客户端-Jedis 1. Jedis快速入门2. Jedis连接池1. 创建Jedis连接池2. 改造原始代码 在Redis官网中提供了各种语言的客户端&#xff0c;地址&#xff1a;https://redis.io/docs/clients/ 其中Java客户端也包含很多&#xff1a; 标记为❤的就是推荐…

密码学证明方案寒武纪大爆发——扩容、透明性和隐私的变革潜力

1. 引言 前序博客有&#xff1a; ZKP大爆炸 本文主要参考&#xff1a; StarkWare 2023年6月博客 Cambrian Explosion of Cryptographic Proofs----The transformative potential for scalability, transparency, and privacy2023年3月Eli Ben-Sasson在The 13th BIU Winter …

JavaWeb之Cookie和Session

文章目录 CookieCookie基本介绍Cookie的基本使用Cookie的创建从服务器获取CookieCookie值的修改方案一方案二 浏览器查看CookieCookie声明控制Cookie有效路径Path的设置 SessionSession基本介绍Session的创建和获取&#xff08;id号&#xff0c;是否为新&#xff09;Session域数…

【SQL server关键字】

目录&#xff1a; 前言一、CREATE -- 创建二、INSERT INTO VALUES -- 插入数据三、SELECT FROM -- 查找数据1.SEKECT简单了解2.函数的使用3.选择列表与group by子句的对应4.exists子查询 四、UPDATE SET -- 更改数据五、ALTER -- 修改属性六、JOIN ON-- 链接多个表1. join初…

JDBC 望舒客栈项目 万字详解

目录 一、前言 二、项目结构 三、准备工作 1.建立子包 : 2.导入jar包 : 3.工具类 : 1 Utility工具类 2 JDBCUtilsDruid工具类 4.导入配置文件 : 5.引入BasicDAO : 四、项目主体 1.界面显示 : 1 代码演示 2 运行测试 2.用户登录 : 1 创建员工表employee 2 创建Ja…

JavaScript 事件加载有哪些应用场景?

&#x1f482; 个人网站:【海拥】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 目录 前言什么是JavaScript事…

VUE L MVVM模型 ③

目录 文章有误请指正&#xff0c;如果觉得对你有用&#xff0c;请点三连一波&#xff0c;蟹蟹支持✨ V u e j s Vuejs Vuejs M V V M MVVM MVVM模型Data与El的2种写法总结 文章有误请指正&#xff0c;如果觉得对你有用&#xff0c;请点三连一波&#xff0c;蟹蟹支持✨ ⡖⠒⠒⠒…

多线程中的wait和notify

1、wait和notify 由于线程之间是抢占式执行的&#xff0c;所以线程之间的执行先后顺序难以预知。但实际上是希望合理的协调多个线程之间的执行先后顺序。 完成这个协调工作&#xff0c;主要涉及到三个方法 *wait()/wait(long timeout);让当前线程进入等待状态。 *notify()/n…

【每日算法 数据结构(C++)】—— 02 | 数组的并交集(解题思路、流程图、代码片段)

文章目录 01 | &#x1f451; 题目描述02 | &#x1f50b; 解题思路交集并集 03 | &#x1f9e2; 代码片段交集并集 When you feel like giving up, remember why you started. 当你想放弃时&#xff0c;请记住为什么你开始 01 | &#x1f451; 题目描述 给你两个数组&#xff…

学习机组过程中的疑难问题与解决 -----(1)

本文章是在学习计算机组成原理过程中个人感觉需要理解与记忆的问题&#xff0c;还有一些在学习过程中自己产生的疑问以及解答,本文章可能排版不良&#xff0c;精力有限&#xff0c;还请见谅 第一章&#xff1a; &#xff08;1&#xff09;MAR的位数对应着存储单元的个数&#…

前端三剑客简介

文章目录 css的导入方式CSS选择器 JavascriptJavascript的引入方式输出语句变量数据类型javascript对象String对象 BOM对象DOM对象 W3C标准&#xff1a;网页主要由三部分组成 结构&#xff1a;html表现&#xff1a;css&#xff0c;层叠样式表行为&#xff1a;JavaScript css的…