FFmpeg源码:avformat_new_stream函数分析
一、avformat_new_stream函数的声明
avformat_new_stream函数定义在FFmpeg源码(本文演示用的FFmpeg源码版本为7.0.1)的头文件libavformat/avformat.h中:
/*** Add a new stream to a media file.** When demuxing, it is called by the demuxer in read_header(). If the* flag AVFMTCTX_NOHEADER is set in s.ctx_flags, then it may also* be called in read_packet().** When muxing, should be called by the user before avformat_write_header().** User is required to call avformat_free_context() to clean up the allocation* by avformat_new_stream().** @param s media file handle* @param c unused, does nothing** @return newly created stream or NULL on error.*/
AVStream *avformat_new_stream(AVFormatContext *s, const struct AVCodec *c);
该函数作用是:给一个媒体文件增加新流。即给形参s的streams数组增加新的元素,新元素会被初始化。
形参s:输出型参数,指向一个AVFormatContext对象。AVFormatContext结构体中有一个成员变量streams,为指针的指针。streams指向一个AVStream指针数组,该数组的每个元素都指向一个AVStream结构,每一个AVStream结构都存贮媒体文件/媒体流中一路流的信息,流的类型可以为视频流、音频流、字幕流等。
AVFormatContext结构体中的nb_streams成员存放该媒体文件/媒体流中流的个数,也是AVStream指针数组(形参s的streams数组)的元素个数。
执行avformat_new_stream函数后,形参s的streams数组会增加新的元素,也就是会给媒体文件增加新流:
typedef struct AVFormatContext {
//.../*** Number of elements in AVFormatContext.streams.** Set by avformat_new_stream(), must not be modified by any other code.*/unsigned int nb_streams;/*** A list of all streams in the file. New streams are created with* avformat_new_stream().** - demuxing: streams are created by libavformat in avformat_open_input().* If AVFMTCTX_NOHEADER is set in ctx_flags, then new streams may also* appear in av_read_frame().* - muxing: streams are created by the user before avformat_write_header().** Freed by libavformat in avformat_free_context().*/AVStream **streams;
//...
} AVFormatContext;
形参c:该参数没有被用到,可忽略。
返回值:成功返回新流对应的AVStream结构,失败返回NULL。
二、avformat_new_stream函数的定义
avformat_new_stream函数定义在源文件libavformat/options.c中:
AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c)
{FFFormatContext *const si = ffformatcontext(s);FFStream *sti;AVStream *st;AVStream **streams;if (s->nb_streams >= s->max_streams) {av_log(s, AV_LOG_ERROR, "Number of streams exceeds max_streams parameter"" (%d), see the documentation if you wish to increase it\n",s->max_streams);return NULL;}streams = av_realloc_array(s->streams, s->nb_streams + 1, sizeof(*streams));if (!streams)return NULL;s->streams = streams;sti = av_mallocz(sizeof(*sti));if (!sti)return NULL;st = &sti->pub;st->av_class = &stream_class;st->codecpar = avcodec_parameters_alloc();if (!st->codecpar)goto fail;sti->fmtctx = s;if (s->iformat) {sti->avctx = avcodec_alloc_context3(NULL);if (!sti->avctx)goto fail;sti->info = av_mallocz(sizeof(*sti->info));if (!sti->info)goto fail;#if FF_API_R_FRAME_RATEsti->info->last_dts = AV_NOPTS_VALUE;
#endifsti->info->fps_first_dts = AV_NOPTS_VALUE;sti->info->fps_last_dts = AV_NOPTS_VALUE;/* default pts setting is MPEG-like */avpriv_set_pts_info(st, 33, 1, 90000);/* we set the current DTS to 0 so that formats without any timestamps* but durations get some timestamps, formats with some unknown* timestamps have their first few packets buffered and the* timestamps corrected before they are returned to the user */sti->cur_dts = RELATIVE_TS_BASE;} else {sti->cur_dts = AV_NOPTS_VALUE;}st->index = s->nb_streams;st->start_time = AV_NOPTS_VALUE;st->duration = AV_NOPTS_VALUE;sti->first_dts = AV_NOPTS_VALUE;sti->probe_packets = s->max_probe_packets;sti->pts_wrap_reference = AV_NOPTS_VALUE;sti->pts_wrap_behavior = AV_PTS_WRAP_IGNORE;sti->last_IP_pts = AV_NOPTS_VALUE;sti->last_dts_for_order_check = AV_NOPTS_VALUE;for (int i = 0; i < MAX_REORDER_DELAY + 1; i++)sti->pts_buffer[i] = AV_NOPTS_VALUE;st->sample_aspect_ratio = (AVRational) { 0, 1 };sti->transferred_mux_tb = (AVRational) { 0, 1 };;#if FF_API_AVSTREAM_SIDE_DATAsti->inject_global_side_data = si->inject_global_side_data;
#endifsti->need_context_update = 1;s->streams[s->nb_streams++] = st;return st;
fail:ff_free_stream(&st);return NULL;
}
三、avformat_new_stream函数的内部实现分析
avformat_new_stream函数内部,首先会判断该媒体文件/媒体流中已经存在的流的个数是否超过“限制的最大数量”,“限制的最大数量”(s->max_streams)默认是1000,该值可以设置。如果超过,打印日志:“Number of streams exceeds max_streams parameter”,avformat_new_stream函数返回NULL:
if (s->nb_streams >= s->max_streams) {av_log(s, AV_LOG_ERROR, "Number of streams exceeds max_streams parameter"" (%d), see the documentation if you wish to increase it\n",s->max_streams);return NULL;}
通过下面语句,给新流对应的AVStream指针分配内存,给形参s的streams数组增加新的元素(即增加新流对应的AVStream指针)。注意:这一步只会给AVStream的指针分配内存,不会给AVStream本身分配内存。关于av_realloc_array函数的用法可以参考:《FFmpeg源码:av_malloc_array、av_realloc_array函数分析》:
streams = av_realloc_array(s->streams, s->nb_streams + 1, sizeof(*streams));if (!streams)return NULL;s->streams = streams;
给新流对应的FFStream和AVStream结构本身分配内存:
sti = av_mallocz(sizeof(*sti));if (!sti)return NULL;st = &sti->pub;
//...s->streams[s->nb_streams++] = st;
给新流对应的AVStream结构的其它成员分配内存和初始化。语句:avpriv_set_pts_info(st, 33, 1, 90000)是给AVStream的time_base设置一个默认值,关于avpriv_set_pts_info函数的用法可以参考:《FFmpeg源码:avpriv_set_pts_info函数分析》:
st->av_class = &stream_class;st->codecpar = avcodec_parameters_alloc();if (!st->codecpar)goto fail;sti->fmtctx = s;if (s->iformat) {sti->avctx = avcodec_alloc_context3(NULL);if (!sti->avctx)goto fail;sti->info = av_mallocz(sizeof(*sti->info));if (!sti->info)goto fail;#if FF_API_R_FRAME_RATEsti->info->last_dts = AV_NOPTS_VALUE;
#endifsti->info->fps_first_dts = AV_NOPTS_VALUE;sti->info->fps_last_dts = AV_NOPTS_VALUE;/* default pts setting is MPEG-like */avpriv_set_pts_info(st, 33, 1, 90000);/* we set the current DTS to 0 so that formats without any timestamps* but durations get some timestamps, formats with some unknown* timestamps have their first few packets buffered and the* timestamps corrected before they are returned to the user */sti->cur_dts = RELATIVE_TS_BASE;} else {sti->cur_dts = AV_NOPTS_VALUE;}st->index = s->nb_streams;st->start_time = AV_NOPTS_VALUE;st->duration = AV_NOPTS_VALUE;sti->first_dts = AV_NOPTS_VALUE;sti->probe_packets = s->max_probe_packets;sti->pts_wrap_reference = AV_NOPTS_VALUE;sti->pts_wrap_behavior = AV_PTS_WRAP_IGNORE;sti->last_IP_pts = AV_NOPTS_VALUE;sti->last_dts_for_order_check = AV_NOPTS_VALUE;for (int i = 0; i < MAX_REORDER_DELAY + 1; i++)sti->pts_buffer[i] = AV_NOPTS_VALUE;st->sample_aspect_ratio = (AVRational) { 0, 1 };sti->transferred_mux_tb = (AVRational) { 0, 1 };;#if FF_API_AVSTREAM_SIDE_DATAsti->inject_global_side_data = si->inject_global_side_data;
#endifsti->need_context_update = 1;
相关文章:
FFmpeg源码:avformat_new_stream函数分析
一、avformat_new_stream函数的声明 avformat_new_stream函数定义在FFmpeg源码(本文演示用的FFmpeg源码版本为7.0.1)的头文件libavformat/avformat.h中: /*** Add a new stream to a media file.** When demuxing, it is called by the dem…...
【java】深入解析Lambda表达式
Lambda表达式是Java 8引入的一项重要特性,它提供了一种简洁的方式来实现函数式编程。Lambda表达式的使用广泛而且灵活,可以简化代码并提高可读性。本篇文章将深入解析Lambda表达式,包括使用场景、基础学习、代码案例、实现方法和注意事项等方…...
Chromium html<img>对应c++接口定义
<img src"tulip.jpg" alt"上海鲜花港 - 郁金香" /> 1、html_tag_names.json5中接口定义: (third_party\blink\renderer\core\html\html_tag_names.json5) {name: "img",constructorNeedsCreateElementF…...
卸载Python
1、查看安装框架位置并删除 Sudo rm -rf /Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8 2、查看应用并删除 在 /Applications/Python 3.x 看是否存在,如果存在并删除。 3、删除软连接 ls -l /usr/bin/py* 或 ls -…...
算法剖析:二分查找
文章目录 前言二分查找模板朴素模板左右查找模板 一、二分查找二、 在排序数组中查找元素的第一个和最后一个位置三、搜索插入位置四、x 的平方根五、山脉数组的峰顶索引六、寻找峰值七、寻找旋转排序数组中的最小值八、 点名总结 前言 二分查找是一种高效的查找算法ÿ…...
Invoke 和 InvokeRequired以及他们两个的区别
在.NET中,Invoke和InvokeRequired是Windows Forms编程中用于确保线程安全的关键方法和属性。它们通常用在多线程环境中,以确保UI控件的更新操作在创建控件的线程上执行,避免因跨线程操作导致的异常。 InvokeRequired 属性 InvokeRequired属…...
SpringBoot概览及核心原理
Spring Boot 是由Pivotal 团队设计的全新框架,其目的是用来简化 Spring 应用开发过程。该框架使用了特定的方式来进行配置,从而使得开发人员不再需要定义一系列样板化的配置文件,而专注于核心业务开发,项目涉及的一些基础设施则交…...
根据basic auth请求https获取token
根据basic auth请求https获取token 对接第三方接口,给了接口文档,但是没有示例代码,postman一直可请求成功,java就是不行。百思不得其解,最后请求公司大神,得到一套秘籍。 第一步 第二步 Authorization&am…...
【基础版】React缓存路由
前言 项目背景 Reactumireact-router5 需求 用户在某一页面操作后点击跳转到其详情页,返回到列表页还是之前操作过的页面,即把页面缓存下来(基础版先处理路由缓存,tab页展示先不处理) 实践 在布局页面对页面进行…...
Java基础15-Java高级
十五、Java高级 单元测试、反射、注解、动态代理。 1、单元测试 定义:就是针对最小的功能单元(方法),编写测试代码对其进行正确性测试。 1.1 Junit单元测试框架 可以用来对方 法进行测试,它是第三方公司开源出来的(很多开发工具已经集成了Junit框架&…...
selenium工具的几种截屏方法介绍(9)
在使用selenium做自动化的时候,可以对于某些场景截图保存当时的执行情况,方便后续定位问题或者作为一些证据保留现场。 获取元素后将元素截屏 我们获取元素后,使用函数screenshot将元素截屏,参数filename传入完整的png文件名路径…...
【设计模式】深入理解Python中的过滤器模式(Filter Pattern)
深入理解Python中的过滤器模式(Filter Pattern) 在软件设计中,面对复杂的数据处理需求时,我们常常需要从一组数据中筛选出符合特定条件的子集。**过滤器模式(Filter Pattern)**是一种能够简化这种操作的设…...
vue的动态组件 keep-alive
1. 什么是动态组件 动态组件指的是 动态切换组件的显示与隐藏 2. 如何实现动态组件渲染 vue提供了一个内置的<component>组件,专门用来实现动态组件的渲染。 作用:组件的占位符is的值表示要渲染的组件 示例代码如下: Left.vue的代…...
现代框架开发官网
一、项目背景 维护过 灵犀官网、企业邮官网、免费邮官网 均使用 jquery webpack多页面打包的方式 开发起来较为繁琐 新的官网项目,想使用现代前端框架,但SPA应用不利于SEO 使用SSR方案又依赖运维,增加维护和沟通成本 二、SSG vs 预渲染 S…...
一篇文章快速认识YOLO11 | 关键改进点 | 安装使用 | 模型训练和推理
前言 本文分享YOLO11的关键改进点、性能对比、安装使用、模型训练和推理等内容。 YOLO11 是 Ultralytics 最新的实时目标检测器,凭借更高的精度、速度和效率重新定义了可能性。 除了传统的目标检测外,YOLO11 还支持目标跟踪、实例分割、姿态估计、OBB…...
AtCoder Beginner Contest 375(A,B,C,D,E,F)(大模拟,前缀和,dp,离线处理,Floyd)
比赛链接 AtCoder Beginner Contest 375 A题 代码 #pragma GCC optimize("O2") #pragma GCC optimize("O3") #include <bits/stdc.h> using namespace std; #define int long long const int N 2e5 5, M 1e6 5; const int inf 0x3f3f3f3f3f…...
认识maven
什么是 Maven? Maven 是一个开源的项目管理工具,主要用于 Java 项目的构建、依赖管理和项目生命周期管理。它提供了一种标准的项目结构和管理流程,使得开发人员能够更轻松地管理项目的构建过程,提高代码的可重用性和可维护性。 …...
OSINT技术情报精选·2024年10月第2周
OSINT技术情报精选2024年10月第2周 2024.10.16版权声明:本文为博主chszs的原创文章,未经博主允许不得转载。 1、亿欧智库:《2024中国高精定位服务产业白皮书》 报告的主要内容如下: 产业背景:在“北斗”发展态势的…...
中企通信赋能中信戴卡入选工信部颁发的2023年工业互联网试点示范名单
2024年10月17日,北京-随着工业互联网的迅猛发展,网络安全已成为国家关注的重点议题之一。日前,工业和信息化部(工信部)公布了2023年工业互联网试点示范名单,中企网络通信技术有限公司(简称“中企…...
【C语言】函数的声明与定义
函数的声明 用户自定义函数需要在main函数之前进行声明,用分号结尾。 函数的定义 用户自定义函数在main函数之后进行定义,需要写出具体形参的变量名。注意函数的返回值和返回值类型要一一对应。 函数的调用 调用时,直接使用函数名进行调用&am…...
AI开始替人办事后,最危险的不是模型不够强,而是它把旧资料当真了
AI开始替人办事后,最危险的不是模型不够强,而是它把旧资料当真了2026年真正值得重视的AI底层能力,是让模型知道该信谁 你有没有发现一个很扎心的变化。 以前我们用AI,最怕它不会。 现在我们用AI,最怕它太会了。 它能写…...
终极免费方案:WandEnhancer完整解锁WeMod Pro功能快速指南
终极免费方案:WandEnhancer完整解锁WeMod Pro功能快速指南 【免费下载链接】Wand-Enhancer Advanced UX and interoperability extension for Wand (WeMod) app 项目地址: https://gitcode.com/gh_mirrors/we/Wand-Enhancer 你是否渴望享受WeMod Pro会员的所…...
5个必知的Universal-Updater高级功能:从QR扫描到后台安装
5个必知的Universal-Updater高级功能:从QR扫描到后台安装 【免费下载链接】Universal-Updater An easy to use app for installing and updating 3DS homebrew 项目地址: https://gitcode.com/gh_mirrors/un/Universal-Updater Universal-Updater是一款专为任…...
保姆级教程:在Ubuntu上配置Frida环境,搞定Android App的IO重定向与签名绕过
在Ubuntu上构建Android逆向工程环境:Frida实战与IO重定向技术解析 对于习惯Linux环境的安全研究人员而言,Windows-centric的逆向工具链往往带来诸多不便。本文将系统性地介绍如何在Ubuntu上搭建完整的Android逆向环境,并深入探讨如何利用Frid…...
从模糊到电影级景深:Midjourney + Topaz Gigapixel联调方案(含LUT预设包+PSD分层模板)
更多请点击: https://codechina.net 第一章:从模糊到电影级景深:Midjourney Topaz Gigapixel联调方案(含LUT预设包PSD分层模板) 当Midjourney生成的图像存在主体边缘柔化、背景层次缺失或分辨率不足等问题时…...
Claude Code用户告别封号与Token焦虑,无缝切换至Taotoken平台
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 Claude Code用户告别封号与Token焦虑,无缝切换至Taotoken平台 对于依赖Claude Code进行编程辅助的开发者而言ÿ…...
使用libusb-win32驱动复活老旧USB硬件:以Elektor Magic Eye为例
1. 项目概述:让老硬件在新时代焕发新生手头有一台十多年前的《Elektor》杂志上刊登的“Magic Eye EM84”复古VFD显示屏项目,想把它接到Windows 10电脑上当个酷炫的CPU占用率显示器,却发现官方提供的“AVR309”USB驱动在新系统上彻底罢工了。这…...
AICoverGen终极指南:快速创建AI翻唱歌曲的完整教程
AICoverGen终极指南:快速创建AI翻唱歌曲的完整教程 【免费下载链接】AICoverGen A WebUI to create song covers with any RVC v2 trained AI voice from YouTube videos or audio files. 项目地址: https://gitcode.com/gh_mirrors/ai/AICoverGen 想要让你的…...
自动加字幕软件推荐:口播视频如何批量加字幕过
口播视频加字幕,为什么越做越累?一位知识类博主连续两周日更3条口播视频,每条12–18分钟,需手动校对字幕、拆分金句切片、补气口停顿、匹配背景音乐——最后一条视频发布时,字幕错漏率达17%,平台审核未过。…...
终极艾尔登法环存档迁移指南:3分钟学会角色无损转移
终极艾尔登法环存档迁移指南:3分钟学会角色无损转移 【免费下载链接】EldenRingSaveCopier 项目地址: https://gitcode.com/gh_mirrors/el/EldenRingSaveCopier 还在为《艾尔登法环》存档迁移而烦恼吗?当游戏版本更新后,你辛辛苦苦培…...
