【音视频】AVIO输入模式

news2025/7/19 3:20:30

内存IO模式

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)
);

参数说明:

  • opaque是 read_packet / write_packet 的第⼀个参数,指向⽤户数据。
  • buffer和buffer_size是 read_packet / write_packet 的第⼆个和第三个参数,是供FFmpeg使⽤的数据区。
  • buffer ⽤作FFmpeg输⼊时,由⽤户负责向 buffer 中填充数据,FFmpeg取⾛数据。
  • buffer ⽤作FFmpeg输出时,由FFmpeg负责向 buffer 中填充数据,⽤户取⾛数据。
  • write_flag是缓冲区读写标志,读写的主语是指FFmpeg。
  • write_flag 为1时, buffer ⽤于写,即作为FFmpeg输出。
  • write_flag 为0时, buffer ⽤于读,即作为FFmpeg输⼊。
  • read_packet和write_packet是函数指针,指向⽤户编写的回调函数。
  • seek也是函数指针,需要⽀持seek时使⽤。 可以类⽐fseek的机制

一、avio_alloc_context 的环形缓冲本质

avio_alloc_context 创建的 AVIOContext 结构体 内部维护了一个环形缓冲区,其核心特性包括:

  1. 循环存储机制
    • 缓冲区逻辑上首尾相连,数据写入时自动回绕(Wrap-Around),避免频繁内存分配。
    • 例如,当缓冲区写满后,新数据会覆盖最早写入的数据(取决于配置)。
  2. 双指针管理
    • 读指针(buf_ptr):指向当前读取位置。
    • 写指针(buf_end):指向当前写入位置。
    • 通过模运算(%)实现指针的循环移动,例如:
      buf_ptr = (buf_ptr + size) % buffer_size
  3. 缓冲与性能优化
    • 预分配固定大小的内存(如 4KB、8KB),减少系统调用次数。
    • 适用于网络流、内存数据流等需要连续读写的场景。

实现流程

准备文件

build路径下准备相关mp3aac文件

在这里插入图片描述

添加main函数参数,表示输入文件和输出文件

在这里插入图片描述

打开文件

使用FILE二进制打开输入文件和输出文件

const char *in_file_name = argv[1];
const char *out_file_name = argv[2];
FILE *in_file = NULL;
FILE *out_file = NULL;
	// 1. 打开参数文件
in_file = fopen(in_file_name, "rb");
if(!in_file) {
	printf("open file %s failed\n", in_file_name);
	return  -1;
}
out_file = fopen(out_file_name, "wb");
if(!out_file) {
	printf("open file %s failed\n", out_file_name);
	return  -1;
}
自定义IO读取
  • AVFormatContex添加自定义读取规则,即自己实现一个AVIOContext,而不是使用默认的
  • AVIOContext使用的是环形缓冲区,即缓冲区满的时候覆盖前面的缓冲区
  • 需要设置环形缓冲区的大小、文件指针、以及缓冲内存回调函数,在内存数据读完的时候触发回调函数,继续从文件读取数据到环形缓冲区
  uint8_t *io_buffer = av_malloc(BUF_SIZE);
AVIOContext *avio_ctx = avio_alloc_context(io_buffer, BUF_SIZE, 0, (void *)in_file,    \
										   read_packet, NULL, NULL);
AVFormatContext *format_ctx = avformat_alloc_context();
format_ctx->pb = avio_ctx;
int ret = avformat_open_input(&format_ctx, NULL, NULL, NULL);
if(ret < 0) {
	printf("avformat_open_input failed:%s\n", av_err2str(ret));
	return -1;
}

read_packet回调函数

static int read_packet(void *opaque, uint8_t *buf, int buf_size)
{
    FILE *in_file = (FILE *)opaque;
    int read_size = fread(buf, 1, buf_size, in_file);
    // printf("read_packet read/*_*/size:%d, buf_size:%d\n", read_size, buf_size);
    if(read_size <=0) {
        return AVERROR_EOF;     // 数据读取完毕
    }
    return read_size;
}
查找解码器
  • 根据ID查找解码器,这里直接查找AAC解码器
  • 分配解码器上下文,将解码器绑定到上下文中
AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
if(!codec_ctx) {
	printf("avcodec_alloc_context3 failed\n");
	return -1;
}
ret = avcodec_open2(codec_ctx, codec, NULL);
if(ret < 0) {
	printf("avcodec_open2 failed:%s\n", av_err2str(ret));
	return -1;
}
解码并写入文件
  • 将格式上下文信息拷贝到数据包(packet)中
AVPacket *packet = av_packet_alloc();
ret = av_read_frame(format_ctx, packet);
  • 发送packet到解码器
ret = avcodec_send_packet(dec_ctx, packet);
  • 使用帧(frame)接收解码后的裸流数据
ret = avcodec_receive_frame(dec_ctx, frame);
  • 获取单个采样点的数据大小,左右声道依次写入数据
int data_size = av_get_bytes_per_sample(dec_ctx->sample_fmt);
for(int i = 0; i < frame->nb_samples; i++) {
for(int ch = 0; ch < dec_ctx->channels; ch++) {
	fwrite(frame->data[ch] + data_size *i, 1, data_size, outfile);
	}
}
  • 操作代码如下
while (1) {
	ret = av_read_frame(format_ctx, packet);
	if(ret < 0) {
		printf("av_read_frame failed:%s\n", av_err2str(ret));
		break;
	}
	decode(codec_ctx, packet, frame, out_file);
}

decode函数

static void decode(AVCodecContext *dec_ctx, AVPacket *packet, AVFrame *frame,
                   FILE *outfile)
{
    int ret = 0;
    ret = avcodec_send_packet(dec_ctx, packet);
    if(ret == AVERROR(EAGAIN)) {
        printf("Receive_frame and send_packet both returned EAGAIN, which is an API violation.\n");
    } else if(ret < 0) {
        printf("Error submitting the packet to the decoder, err:%s\n",
               av_get_err(ret));
        return;
    }

    while (ret >= 0) {
        ret = avcodec_receive_frame(dec_ctx, frame);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
            return;
        } else if (ret < 0)  {
            printf("Error during decoding\n");
            exit(1);
        }
        if(!packet) {
            printf("get flush frame\n");
        }
        int data_size = av_get_bytes_per_sample(dec_ctx->sample_fmt);
        //        print_sample_format(frame);
        /**
           P表示Planar(平面),其数据格式排列方式为 :
           LLLLLLRRRRRRLLLLLLRRRRRRLLLLLLRRRRRRL...(每个LLLLLLRRRRRR为一个音频帧)
           而不带P的数据格式(即交错排列)排列方式为:
           LRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRL...(每个LR为一个音频样本)
        播放范例:   ffplay -ar 48000 -ac 2 -f f32le believe.pcm
            并不是每一种都是这样的格式
        */
        // 这里的写法不是通用,通用要调用重采样的函数去实现
        // 这里只是针对解码出来是planar格式的转换
        for(int i = 0; i < frame->nb_samples; i++) {
            for(int ch = 0; ch < dec_ctx->channels; ch++) {
                fwrite(frame->data[ch] + data_size *i, 1, data_size, outfile);
            }
        }
    }
}
冲刷解码器
  • 解码结束后要冲刷解码器,刷新解码器数据
decode(codec_ctx, NULL, frame, out_file);
结束操作

退出之前要释放内存、关闭文件

fclose(in_file);
fclose(out_file);

av_free(io_buffer);
av_frame_free(frame);
av_packet_free(packet);

avformat_close_input(&format_ctx);
avcodec_free_context(&codec_ctx);

更多资料:https://github.com/0voice

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

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

相关文章

Uniapp:scroll-view(区域滑动视图)

目录 一、基本概述二、属性说明三、基本使用3.1 纵向滚动3.2 横向滚动一、基本概述 scroll-view,可滚动视图区域。用于区域滚动。 二、属性说明 属性名类型默认值说明平台差异说明scroll-xBooleanfalse允许横向滚动scroll-yBooleanfalse允许纵向滚动三、基本使用 3.1 纵向滚…

单精度浮点运算/定点运算下 MATLAB (VS) VIVADO

VIVADO中单精度浮点数IP核计算结果与MATLAB单精度浮点数计算结果的对比 MATLAB定点运算仿真&#xff0c;对比VIVADO计算的结果 目录 前言 一、VIVADO与MATLAB单精度浮点数运算结果对比 二、MATLAB定点运算仿真 总结 前言 本文介绍了怎么在MATLAB中使用单精度浮点数进行运算…

【AI插件开发】Notepad++ AI插件开发1.0发布和使用说明

一、产品简介 AiCoder是一款为Notepad设计的轻量级AI辅助插件&#xff0c;提供以下核心功能&#xff1a; 嵌入式提问&#xff1a;对选中的文本内容进行AI分析&#xff0c;通过侧边栏聊天界面与AI交互&#xff0c;实现多轮对话、问题解答或代码生成。对话式提问&#xff1a;独…

【MySQL数据库入门到精通-07 函数-字符串函数、数值函数、日期函数和流程函数】

文章目录 一、字符串函数1. MySQL中的函数主要分为以下四类&#xff1a; 字符串函数、数值函数、日期函数、流程函数。下面是字符串函数常见的函数&#xff0c;见下表。2.具体代码实现3.结果 二、数值函数1.知识点2.具体代码实现3.结果 三、日期函数1.知识点2.具体代码实现3.结…

Python图像处理——基于Retinex算法的低光照图像增强系统

1.项目内容 &#xff08;1&#xff09;算法介绍 ①MSRCR (Multi-Scale Retinex with Color Restoration) MSRCR 是多尺度 Retinex 算法&#xff08;MSR&#xff09;的扩展版&#xff0c;引入了色彩恢复机制以进一步提升图像增强质量。MSR 能有效地压缩图像动态范围&#xff…

如何在JDK17项目中改成1.8

1.调整 Spring Boot 版本 由于 Spring Boot 3.x 最低要求 JDK 17&#xff0c;所以如果要使用 JDK 8&#xff0c;需要把 spring-boot-starter-parent 的版本降低到 2.7.x 系列&#xff0c;这个系列是支持 JDK 8 的。示例如下&#xff1a; <parent><groupId>org.sp…

【不同名字的yolo的yaml文件名是什么意思】

以下是这些 YOLO 系列配置文件的详细解析&#xff0c;按版本和功能分类说明&#xff1a; 一、YOLOv3 系列 文件名核心特性适用场景yolov3.yaml原始 YOLOv3 结构&#xff0c;3 尺度预测&#xff08;13x13,26x26,52x52&#xff09;通用目标检测yolov3-spp.yaml增加 SPP&#xff…

Zephyr kernel Build System (CMake)介绍

目录 概述 1. 结构介绍 2 构建和配置阶段 2.1 配置阶段 2.2 Cmake编译 3 Zephy项目目录结构 3.1 文件架构 3.2 文件content 概述 本文主要介绍Zephyr kernel Build System CMake的功能&#xff0c;以及使用该工具构建项目&#xff0c;并详细介绍了每个目录以及目录下文…

相对论大师-记录型正负性质BFS/图论-链表/数据结构

看到这一题我的第一个思路就是双向bfs 起点是a&#xff0c;终点还是a&#xff0c;但是flag是相反的&#xff08;“越”的方向&#xff09; tip1.可以用字典vis来存储flag 刚开始初始化时vissta,visend一个对应0、1 要求两个队列相…

Jenkins流水线管理工具

文章目录 前言&#xff1a; DevOps时代的自动化核心 —Jenkins一、Jenkins是什么&#xff1f;二、Linux安装Jenkinswar包方式安装依赖环境下载 Jenkins WAR 包启动 Jenkins 服务启动日志验证配置插件镜像源 docker镜像方式安装依赖环境拉取 Jenkins 镜像运行 Jenkins 容器获取初…

嵌入式开发:基础知识介绍

一、嵌入式系统 1、介绍 以提高对象体系智能性、控制力和人机交互能力为目的&#xff0c;通过相互作用和内在指标评价的&#xff0c;嵌入到对象体系中的专用计算机系统。 2、分类 按其形态的差异&#xff0c;一般可将嵌入式系统分为&#xff1a;芯片级&#xff08;MCU、SoC&am…

el-table中el-input的autofocus无法自动聚焦的解决方案

需求 有一个表格展示了一些进度信息&#xff0c;进度信息可以修改&#xff0c;需要点击进度信息旁边的编辑按钮时&#xff0c;把进度变为输入框且自动聚焦&#xff0c;当鼠标失去焦点时自动请求更新接口。 注&#xff1a;本例以vue2 element UI为例 分析 这个需求看着挺简单…

一文了解智慧教育顶刊TLT的研究热点

本文聚焦于IEEE Transactions on Learning Technologies&#xff08;TLT&#xff09;期刊&#xff0c;通过图文结合的方式&#xff0c;梳理了2025年第18卷的研究热点&#xff0c;帮助读者把握教育技术与人工智能交叉领域的研究进展&#xff0c;深入了解智能学习系统、自适应学习…

统计术语学习

基期、现期 作为对比参照的时期称为基期&#xff0c;而相对于基期的称为现期。 描述具体数值时我们称之为基期量和现期量。 【例 1】2017 年比 2016 年第三产业 GDP 增长 6.8%&#xff0c; &#xff08;2016&#xff09;为基期&#xff0c;&#xff08;2017&#xff09; 为现…

飞机会员日

各航空公司会员日日期 主要航空公司会员日整理如下&#xff08;数据截至2025年3月最新信息&#xff09;&#xff1a;‌ 1 2 ‌中国国际航空&#xff08;国航&#xff09;‌ 每月"同月同日"&#xff08;如1月1日、2月2日类推&#xff09; ‌中国南方航空&#xff08…

论分布式事务及其解决方案 架构师论文范文(考试笔记)

请围绕“论分布式事务及其解决方案”论题&#xff0c;依次从以下三个方面进行论述。 1、概要叙述你参与分析设计的软件项目以及你在其中所承担的主要工作。 2、请介绍4种分布式事务的解决方案及简单说明。 3、具体阐述你参与的软件项目是如何做到分布式事务的&#xff0c;过程中…

ROS 快速入门教程04

12.激光雷达工作原理 激光雷达的作用是探照周围障碍物的距离&#xff0c;按照测量维度可以分为单线雷达和多线雷达。 按照测量原理可以分为三角测距雷达和TOF雷达。按照工作方式可以分为固态雷达和机械旋转雷达。 本次讲解以TOF雷达为例&#xff0c;雷达发射器发射激光遇到障碍…

2025 年导游证报考条件新政策解读与应对策略

2025 年导游证报考政策有了不少新变化&#xff0c;这些变化会对报考者产生哪些影响&#xff1f;我们又该如何应对&#xff1f;下面就为大家详细解读新政策&#xff0c;并提供实用的应对策略。 最引人注目的变化当属中职旅游类专业学生的报考政策。以往&#xff0c;中专学历报考…

vscode切换Python环境

跑深度学习项目通常需要切换python环境&#xff0c;下面介绍如何在vscode切换python环境&#xff1a; 1.点击vscode界面左上角 2.在弹出框选择对应kernel

Spark-Streaming(三)

一. kafka和flume的整合 任务需求一:利用flume监控某目录中新生成的文件&#xff0c;将监控到的变更数据发送给kafka&#xff0c;kafka将收到的数据打印到控制台 1. 在flume/conf/目录下添加flume-kafka.conf文件 配置文件如下 2. 启动flume和kafka消费者 3. 传入数据 查看fl…