FFmpeg5.0源码阅读——avformat_find_stream_info

  摘要:在使用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;elseduration -= 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.hqwc.cn/news/490.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用Python写了一个下载网站所有内容的软件,可见即可下

目录标题 前言效果展示环境介绍:代码实战获取数据获取视频采集弹幕采集评论 GUI部分尾语 前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 今天我们分享一个用Python写下载视频弹幕评论的代码。 顺便把这些写成GUI&#xff0c;把这些功能放到一起让朋友用起来更方便~ 效果…

git——使用ssh连接远程仓库

文章目录 前言一. 获取邮箱和密码1. 本地配置你的名字和邮箱2. 使用命令获取你本地的邮箱和密码 二、生成ssh公钥1.任意一个文件夹路径打开Git Bash Here并输入以下命令连按三次回车2. 根据上面红框部分的地址打开文件夹3. 打开并查看id_rsa.pub 文件 三、在GitHub上连接ssh1. …

Go语言单元测试

1、Go语言单元测试 Go语言中的测试依赖 go test 命令&#xff0c;go test 命令是一个按照一定约定和组织的测试代码的驱动程序。在包目录 内&#xff0c;所有以 _test.go 为后缀名的源代码文件都是 go test 测试的一部分&#xff0c;不会被 go build 编译到最终的可执行 文件…

Efficient Video Transformers with Spatial-Temporal Token Selection阅读笔记

摘要 Video Transformers在主要视频识别基准测试中取得了令人印象深刻的结果&#xff0c;但其计算成本很高。 在本文中&#xff0c;我们提出了 STTS&#xff0c;这是一种令牌选择框架&#xff0c;它根据输入视频样本在时间和空间维度上动态选择一些信息丰富的令牌。 具体来说&…

C++ 第四弹动态内存管理

目录 1. C/C程序内存划分 2. C语言中内存管理的方式 3. new /delete 和 new[]/delete[] 4. void* operator new(size_t size) 和 void operator delete(void*) 可以重载的 5. 定义为new表达式 6. 常见的面试题 1. C/C程序内存划分 1. 栈 又叫堆栈 -- 非静态局部变量 / 函数…

Paragon NTFS2023Mac读取、写入外置移动硬盘软件

在我们日常使用电脑时常常会出现NTFS格式分区&#xff0c;那你知道NTFS For Mac是什么&#xff1f;简单的理解就是让你在mac系统下&#xff0c;可以正常读写Windows的Ntfs格式的分区。其中还包括Windows NT 4&#xff0c;2000&#xff0c;XP&#xff0c;2003&#xff0c;Vista&…

金融科技领先者Broadridge选择CloudBees CI来加速软件交付

Broadridge公司是全球金融科技领先者&#xff0c;通过丰富客户参与度、控制风险、优化效率和创造收入增长的解决方案为客户推动业务转型。 借助CloudBees CI&#xff0c;Broadridge为所有使用Jenkins的开发团队提供了集中管理和自助服务的体验。Broadridge能够不断为客户提供新…

Mysql批量插入1000条数据

使用mysql的存储过程 1.现有如下一张表&#xff1a;site_row 2.创建存储过程 CREATE PROCEDURE p01 () BEGIN declare i int; set i1;while i<1000 doINSERT INTO site_row(row_id,row_num) VALUES ( i,i);set ii1; end WHILE;END; 3.执行存储过程 CALL p01(); 4.查看效…

【论文笔记】FASTER SEGMENT ANYTHING:TOWARDS LIGHTWEIGHT SAM FOR MOBILE APPLICATIONS

前脚fast SAM刚发完&#xff0c;后脚mobile SAM就发了 &#xff0c;之前的论文笔记中我一直就认为fast SAM其实应该算是yolo的扩展工作&#xff0c;和原生的SAM架构相去甚远&#xff0c;而且在简介上直接就对&#xff08;gong&#xff09;比&#xff08;ji&#xff09;了FastSA…

多模态学习

什么是多模态学习&#xff1f; 模态 模态是指一些表达或感知事物的方式&#xff0c;每一种信息的来源或者形式&#xff0c;都可以称为一种模态 视频图像文本音频 多模态 多模态即是从多个模态表达或感知事物 多模态学习 从多种模态的数据中学习并且提升自身的算法 多…

springBoot学习——spring+springMVC 集成mybatis 拦截器

目录 引出入门案例&#xff1a;登陆和注册 & 用户信息分页 之 固定的步骤&#xff1a;&#xff08;1&#xff09;建普通项目配置pom.xml文件&#xff08;2&#xff09;写主启动类 application.yml文件【bug】pom.xml文件导了mybatis的包&#xff0c;但是application.yml文…

低代码可视化拖拽编辑器实现方案

一、前言 随着业务不断发展&#xff0c;低代码、无代码平台越来越常见&#xff0c;它降低开发门槛、快速响应业务需求、提升开发效率。零开发经验的业务人员通过可视化拖拽等方式&#xff0c;即可快速搭建各种应用。本文主要是讲解低代码可视化拖拽平台前端展示层面的实现逻辑…