FFmpeg内存IO模式

news2024/11/26 13:34:30

ffmpeg 支持从网络流 或者本地文件读取数据,然后拿去丢给解码器解码,但是有一种特殊情况,就是数据不是从网络来的,也不在本地文件里面,而是在某块内存里面的。

这时候 av_read_frame() 函数怎样才能从内存把 AVPacket 读出来呢?

FFmpeg 的开发者一早就考虑到这个问题了,所以他们提供了一个自定义 avio 的功能。利用这个功能,你可以自定义封装层的输入函数,也可以自定义封装层的输出函数。

没错,输出你也可以输出到一块内存里面,而不是保存到本地文件。


本文的代码下载地址:GitHub,编译环境是 Qt 5.15.2 跟 MSVC2019_64bit 。

avio 项目 是从 output 项目改造来的,所以一些代码是类似的。

avio 项目的整个流程是这样的,先用了 readFile() 函数读取本地的 mp4 文件到内存,来模拟内存场景。然后调 avio_alloc_context() 自定义输入跟 seek 函数。

重点讲一下 avio_alloc_context() 函数的用法,定义如下:

AVIOContext *avio_alloc_context(
                  unsigned char *buffer,
                  int buffer_size,
                  int write_flag,
                  void *opaque,
                  int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
                  int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
                  int64_t (*seek)(void *opaque, int64_t offset, int whence));

参数如下:

1,unsigned char *buffer,这是一个指针,指向一块 av_malloc() 申请的内存。这是我们的自定义函数跟 FFmpeg 的 API 函数沟通的桥梁。

当 write_flag 为 0 时,由 自定义的回调函数 向 buffer 填充数据,FFmpeg API 函数取走数据。

当 write_flag 为 1 时,由 FFmpeg API 函数 向 buffer 填充数据,自定义的回调函数 取走数据。

补充,我测试的时候,这里的 buffer 指针跟 回调函数 里面的 buf 指针,好像不是同一块内存,FFmpeg 注释说,buffer 可能会被替换成另一块内存。

2,int buffer_sizebuffer 内存的大小,通常设置为 4kb 大小即可,对于一些有固定块大小的格式,例如 TS 格式,TS流的包结构是固定长度188字节的,所以你需要设置为 188 字节大小。如果这个值设置得不对,性能会下降得比较厉害,但是不会报错。

3,int write_flag ,write_flag 可以是 0 或者 1,作用是标记 buffer 内存的用途。

4,void *opaque,传递给我们自定义函数用的。

5,int (*read_packet)(...),输入函数的指针。

6,int (*write_packet)(...),输出函数的指针。

7,int (*seek)(...),seek 函数的指针。


再来看一下我们自定义的输入函数 read_packet(),如下:

buf 跟 buf_size 都是 FFmpeg 告诉我们的,告诉我们的自定义函数,要往哪里(buf)写数据,写多少(buf_size)数据。

read_packet() 函数的返回值是实际写入的数据大小,如果是一些网络流,在某个时间确实没从网络读到数据,不能返回 0 ,需要返回错误码,例如 EAGAIN。


再来看一下自定义的 seek 函数 seek_in_buffer(),如下:

这个 seek 函数是必须实现,如果不实现这个函数,直接传 NULL 给 avio_alloc_context() ,在 mp4 格式下会导致 av_read_frame() 读不出来 AVPacket

但是在 flv 格式下是可以不实现 seek 函数的,需不需要实现 seek 是由封装格式决定的。

seek_in_buffer 函数的 offset 跟 whence 参数特别重要。

whence 代表 seek 的类型,主要有 2 个值,如下:

1,AVSEEK_SIZE,不进行 seek 操作,而是返回 视频 buffer 整体的大小。也就是文件大小。

2,SEEK_SET,要进行 seek 操作,seek 到 offset 参数的位置,也就是需要 seek 到 第 offset 个字节。需要把 bd->ptr 指向第 offset 个字节


后面的逻辑就是 av_read_frame() 从内存读到 AVPacket 之后,就丢给解码器,然后再重新编码,输出成另一个 mp4。

最后需要调 avio_context_free(&avio_ctx) 来释放这个 自定义的 avio 上下文。


在 main.c 里面只定义了输入函数,输出函数是在另一个文件 main_write.c 里面的。你只需要修改一下 avio.pro 文件即可调试,如下:

SOURCES += main.c 
改成
SOURCES += main_write.c

main_write.c 里面的重点代码如下:

main_write.c 的逻辑是申请了 100M 的内存,然后把 av_interleaved_write_frame() 输出的数据,全部保存到这 100M 内存里面,可能没用完100M内存。

上图中我新申请了一个 avio 上下文实例来给输出用,不能跟输入用同一个 avio 实例。然后封装格式指定位 flv 了,因为 flv 格式可以不实现 seek

mp4 格式的输出对应的 seek 函数我也不知道怎么实现。可能跟输入一样吧,这里埋个坑,后面填。

然后直接赋值 fmt_ctx_out->pb 即可

fmt_ctx_out->pb = avio_ctx_out;

内存IO模式输出,是不需要调 avio_open2() 的了。


参考文章:

1,ffmpeg AVIOContext 自定义 IO 及 seek

2,FFmpeg内存IO模式(内存区作输入或输出) - 叶余


推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:

Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习

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

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

相关文章

TensorFlow的GPU使用相关设置整理

前言 TensorFlow是一个在机器学习和深度学习领域被广泛使用的开源软件库,用于各种感知和语言理解任务的机器学习。 默认情况下,TensorFlow 会映射进程可见的所有 GPU(取决于 CUDA_VISIBLE_DEVICES)的几乎全部内存。这是为了减少内…

国考省考行测:问题型材料主旨分析,有问题有对策,主旨是对策,有问题无对策,要合理引申对策

国考省考行测:问题型材料主旨分析,有问题有对策,主旨是对策,有问题无对策,要合理引申对策 2022找工作是学历、能力和运气的超强结合体! 公务员特招重点就是专业技能,附带行测和申论,而常规国考…

【Linux】Linux背景、环境的搭建以及用XShell实现远程登陆

目录Linux 背景Linux环境搭建Linux远程登陆Linux 背景 肯尼斯蓝汤普森最早用汇编语言创建了UNIX系统,后来与他的好“基友”丹尼斯里奇(C语言之父),他们两个一同用C语言重新写了UNIX系统,但是操作系统的使用是需要收费…

ActiveState Platform - November 2022

ActiveState Platform - November 2022 ActiveState平台定期更新新的、修补的和版本化的软件包和语言。 Python 3.10.7、3.9.14、3.8.14-解决了许多安全问题的点发布。 Python C库-ibxml 2.10.3、libxslt 1.1.37、libexpat 2.4.9、zlib 1.2.13、curl 7.85.0和sqlite3 3.39.4&am…

Python添加水印简简单单,三行代码教你批量添加

环境使用: Python 3.8Pycharm 如何配置pycharm里面的python解释器? 选择file(文件) >>> setting(设置) >>> Project(项目) >>> python interpreter(python解释器)点击齿轮, 选择add添加python安装路径 pycharm如何安装插件? 选择file(文件) …

使用Python PyQt5完成残缺棋盘覆盖仿真作业

摘要:本文内容是关于如何实现残缺棋盘覆盖仿真软件,算法课作业要求设计开发一个残缺棋盘覆盖仿真软件。使用”分治算法“求解问题,Python编程语言实现功能;使用PyQt5和Python热力图实现界面和仿真效果展示。 1 残缺棋盘覆盖仿真作…

[Linux打怪升级之路]-yun安装和gcc的使用

前言 作者:小蜗牛向前冲 名言:我可以接受失败,但我不能接受放弃 如果觉的博主的文章还不错的话,还请点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正。 本期学习目标&am…

Java:外包Java项目有什么好处?

Java已经成为众多解决方案的通用开发语言,包括web应用、游戏、软件开发等等。超过710万全球的Java程序员都在忙着为业界下一个最好的应用程序编码。 随着企业努力在当今的全球市场中保持竞争力,对Java项目外包的需求不断增加。 以下是你的企业通过外包Ja…

python基于PHP+MySQL的论坛管理系统

互联网给了我们一个互通互信的途径,但是如何能够更加高效的进行各种问题的分享和交流是很多人关心的问题,市面上比较知名的一些分享交流平台也很多,比如百度的贴吧,知乎等高质量内容分享平台,本系统是一个类似这样的论坛分享系统 随着互联网的发展人们分享和交流的分享也变的越…

leetcode刷题(128)——1575. 统计所有可行路径,动态规划解法

leetcode刷题(127)——1575. 统计所有可行路径,DFS解法 给你一个 互不相同 的整数数组,其中 locations[i] 表示第 i 个城市的位置。同时给你 start,finish 和 fuel 分别表示出发城市、目的地城市和你初始拥有的汽油总…

【CSS】CSS字体样式【CSS基础知识详解】

👨‍💻个人主页:花无缺 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 本文由 花无缺 原创 本文章收录于专栏 【CSS】 【CSS专栏】已发布文章 📁【CSS基础认知】 📁【CSS选择器全解指南】 本文目录【CS…

物联网感知-光纤光栅传感器技术

一、光纤光栅传感技术 光纤光栅是利用光纤材料的光敏性,通过紫外光曝光的方法将入射光相干场图样写入纤芯,将周期性微扰作用于光纤纤芯,在纤芯内产生沿纤芯轴向的折射率周期性变化,从而形成永久性空间的相位光栅,其作用…

MySQL数据库的基本操作及存储引擎的使用

大家好呀!我是猿童学🐵,最近在学习Mysql数据库,给初学者分享一些知识,也是学习的总结,关注我将会不断地更新数据库知识,也欢迎大家指点一二🌹。 目录 一、常用的MySQL语句 二、创建…

使用ThinkMusic网站源码配合cpolar,发布本地音乐网站

1、前言 在我们的日常生活中,音乐已经成为不可或缺的要素之一,听几首喜欢的音乐,能让原本糟糕的心情变得好起来。虽然现在使用电脑或移动电子设备听歌都很方便,但难免受到诸多会员或VIP限制,难免让我们回想起音乐网站…

【JavaScript】常用内置对象——数组(Array)对象

文章目录什么是数组创建数组访问数组数组常用方法和属性投票传送门什么是数组 数组(Array)是最基本的集合类型,由于JavaScript是弱类型语言,因此JavaScript的数组和大多数语言的数组有所区别。在大多数语言中,当声明一…

ubuntu 20.04 qemu u-boot-2022.10 开发环境搭建

开发环境 ubuntu 20.04 VMware Workstation Pro 16 基于qemu(模拟器),vexpress-a9 平台 搭建 u-boot-2022.10 (当前最新版本) 准备工作 u-boot下载,下载最新稳定版本,当前为 u-boot-2022.10&#xff0…

代码随想录49——动态规划:121买卖股票的最佳时机、122买卖股票的最佳时机II

文章目录1.121买卖股票的最佳时机1.1.题目1.2.解答1.2.1.贪心算法1.2.2.动态规划2.122买卖股票的最佳时机II2.1.题目2.2.解答1.121买卖股票的最佳时机 参考:代码随想录,121买卖股票的最佳时机;力扣题目链接 1.1.题目 1.2.解答 1.2.1.贪心算…

第七节:类和对象【一】【java】

目录 🧾1. 面向对象的初步认知 1.1 什么是面向对象 1.2 面向对象与面向过程 📕2. 类定义和使用 2.1 简单认识类 2.2 类的定义格式 2.3 课堂练习 🎒3. 类的实例化 3.1 什么是实例化 3.2 类和对象的说明 3.3练习 🧾1. 面…

Hbase2.4.11安装

Hbase2.4.11安装 文章目录Hbase2.4.11安装一、前期准备二、安装三、配置文件(一)添加环境变量(二)修改hbase配置文件1.修改hbase-env.sh 中内容2.在hbase-site.xml中添加以下内容3. 编辑regionservers四、分发文件到Hadoop2、Hadoop3中一、前期准备 hba…

SpringBoot+Vue实现前后端分离的学生选课系统

文末获取源码 开发语言:Java 使用框架:spring boot 前端技术:JavaScript、Vue.js 、css3 开发工具:IDEA/MyEclipse/Eclipse、Visual Studio Code 数据库:MySQL 5.7/8.0 数据库管理工具:phpstudy/Navicat JD…