当前位置: 首页 > news >正文

qt+ffmpeg 实现音视频播放(二)之音频播放

一、音频播放流程

1、打开音频文件

通过  avformat_open_input() 打开媒体文件并分配和初始化  AVFormatContext  结构体。

函数原型如下:
int avformat_open_input(AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options);

参数说明:
- `ps`:指向 `AVFormatContext` 结构体指针的指针,用于存储打开的媒体文件的信息。
- `url`:要打开的媒体文件的 URL 或文件路径。
- `fmt`:指定输入格式,通常可以设置为 `NULL`,由 FFmpeg 根据文件内容自动检测。
- `options`:附加选项,可以传入一些额外的选项参数。

2、查找输入流信息

调用  avformat_find_stream_info()  函数将会读取媒体文件中的帧,解析它们的头部,
并填充 AVFormatContext 中的流信息,通过访问 AVFormatContext 的 streams 字段来获取每个流的详细信息。

函数原型如下:
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);

参数说明:
- `ic`:指向已打开媒体文件的 `AVFormatContext` 结构体的指针。
- `options`:指向包含附加选项的 `AVDictionary` 指针。

3、查找流索引

使用 av_find_best_stream() 从媒体文件中找到最佳的流索引

函数原型如下:
int av_find_best_stream(AVFormatContext *ic, enum AVMediaType type, int wanted_stream, int related_stream, AVCodec **decoder_ret, int flags);

参数说明:
- `ic`:指向已打开媒体文件的 `AVFormatContext` 结构体的指针。
- `type`:要查找的流类型,可以是 `AVMEDIA_TYPE_VIDEO`、`AVMEDIA_TYPE_AUDIO` 等。
- `wanted_stream`:期望的流索引,如果为负值,则表示没有特定的偏好。
- `related_stream`:相关流索引,用于查找与之相关的最佳流。
- `decoder_ret`:用于返回找到的解码器。
- `flags`:附加标志,可以用来指定额外的查找选项。

4、查找解码器

使用 avcodec_find_decoder() 查找符合指定解码器名称的解码器。

函数原型如下:
AVCodec *avcodec_find_decoder(enum AVCodecID id);

参数说明:
- `id`:要查找的解码器的 ID。

5、初始化解码上下文

调用  avcodec_alloc_context3()  函数会为特定的编解码器分配一个  AVCodecContext  结构体,并对其进行初始化。 AVCodecContext  结构体包含了编解码器的相关参数和状态信息,比如编解码器类型、解码参数、帧率等。

函数原型如下:
AVCodecContext *avcodec_alloc_context3(const AVCodec *codec);
参数说明:
- `codec`:指定要使用的编解码器,可以通过 `avcodec_find_decoder()` 或其他方式获取。

6、获取解码参数

调用 `avcodec_parameters_to_context()` 函数可以方便地将 `AVCodecParameters` 结构体中的参数(如编解码器类型、帧率、分辨率等)复制到 `AVCodecContext` 结构体中,从而准备进行编解码操作。

函数原型如下:
int avcodec_parameters_to_context(AVCodecContext *codec, const AVCodecParameters *par);

参数说明:
- `codec`:要填充参数的 `AVCodecContext` 结构体指针。
- `par`:包含编解码器参数的 `AVCodecParameters` 结构体指针。

7、打开解码器

调用 `avcodec_open2()` 函数可以打开并初始化指定的编解码器上下文,使其准备好进行编解码操作。

函数原型如下:
int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options);
参数说明:
- `avctx`:要打开和初始化的编解码器上下文。
- `codec`:要使用的编解码器,可以通过 `avcodec_find_decoder()` 或其他方式获取。
- `options`:可选的字典参数,用于设置编解码器的选项。

打开解码器时可以使用多线程参数优化解码速度。

AVDictionary* opts = NULL;
//使用多线程解码
if (!av_dict_get(opts, "threads", NULL, 0))
    av_dict_set(&opts, "threads", "auto", 0);

8、创建音频重采样上下文

调用 `swr_alloc_set_opts()` 函数可以创建一个音频重采样上下文,并设置其参数。这个函数可以方便地指定输入和输出音频的通道布局、采样格式和采样率等参数。
 

函数原型如下:
struct SwrContext *swr_alloc_set_opts(struct SwrContext *s,
                                      int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate,
                                      int64_t in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate,
                                      int log_offset, void *log_ctx);
参数说明:
- `s`:要创建或设置参数的音频重采样上下文。如果传入非空指针,则会设置现有上下文的参数;如果传入空指针,则会创建一个新的上下文。
- `out_ch_layout`:输出音频的通道布局(channel layout)。
- `out_sample_fmt`:输出音频的采样格式(sample format)。
- `out_sample_rate`:输出音频的采样率(sample rate)。
- `in_ch_layout`:输入音频的通道布局。
- `in_sample_fmt`:输入音频的采样格式。
- `in_sample_rate`:输入音频的采样率。
- `log_offset`:日志输出偏移量。
- `log_ctx`:日志上下文。

9、初始化音频重采样上下文

调用 `swr_init()` 函数可以初始化音频重采样上下文,使其准备好进行音频重采样操作。


函数原型如下:
int swr_init(struct SwrContext *s);
参数说明:
- `s`: 要初始化的音频重采样上下文。

10、分配并初始化一个临时的帧和包

调用 `av_packet_alloc()` 函数可以分配一个 AVPacket 结构体,并返回指向该结构体的指针。AVPacket 结构体用于存储音视频数据,包括数据缓冲区、大小、时间戳等信息。

调用 `av_frame_alloc()` 函数可以分配一个 AVFrame 结构体,并返回指向该结构体的指针。AVFrame 结构体用于存储音视频帧的数据,包括像素数据、采样数据、时间戳等信息。
 

函数原型如下:

AVPacket *av_packet_alloc(void);
AVFrame *av_frame_alloc(void);

11、读取音视频源文件

调用 `av_read_frame()` 函数可以从输入文件或流中读取一帧音视频数据,并将其存储在 AVPacket 结构体中。

函数原型如下:
int av_read_frame(AVFormatContext *s, AVPacket *pkt);
参数说明:
- `s`:输入文件或流的 AVFormatContext 上下文。
- `pkt`:存储读取到的音视频帧数据的 AVPacket 结构体。

12、发送音频数据到解码器

调用 `avcodec_send_packet()` 函数可以将 AVPacket 数据包发送给解码器进行解码。在发送完所有数据包后,需要调用 `avcodec_send_packet()` 传递一个空的 AVPacket 指针,以便告知解码器已经发送完所有数据。

函数原型如下:
int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt);
参数说明:
- `avctx`:指向 AVCodecContext 结构体的指针,表示解码器上下文。
- `avpkt`:指向要发送给解码器的 AVPacket 数据包的指针。

13、从解码器接收解码后的音频数据

调用 `avcodec_receive_frame()` 函数可以从解码器中接收解码后的音视频帧数据,并将其存储在 AVFrame 结构体中。


函数原型如下:
int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame);
参数说明:
- `avctx`:指向 AVCodecContext 结构体的指针,表示解码器上下文。
- `frame`:用于存储接收到的解码后的 AVFrame 帧数据的结构体。
 

14、进行音频重采样

调用 `swr_convert()` 函数可以将输入缓冲区中的音频数据进行重采样,并将结果存储到输出缓冲区中。

函数原型如下:
int swr_convert(struct SwrContext *s, uint8_t **out, int out_count, const uint8_t **in, int in_count);
参数说明:
- `s`:指向 SwrContext 结构体的指针,表示音频重采样上下文。
- `out`:指向输出音频数据缓冲区的指针数组。
- `out_count`:输出缓冲区中的样本数。
- `in`:指向输入音频数据缓冲区的指针数组。
- `in_count`:输入缓冲区中的样本数。


15、播放音频

将重采样后的数据写入声卡中进行播放。

简洁流程如下:

其他重要API:
void av_dump_format(const AVFormatContext *ic, int index,
                    const char *url, int is_output);

 //可以将输入/输出文件的格式信息以人类可读的形式打印出来,包括流的详细信息、编解码器信息等。这对于调试和了解输入/输出文件的结构和信息非常有帮助。
参数说明:
- `ic`:指向 AVFormatContext 结构体的指针,表示要进行格式信息输出的输入/输出文件的 AVFormatContext。
- `index`:如果为非负值,表示要输出的流的索引;如果为负值,表示输出所有流信息。
- `url`:文件的 URL 或名称,在打印信息时会用到。
- `is_output`:如果为非零值,表示输出的是输出文件的格式信息;如果为 0,表示输出的是输入文件的格式信息。

int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples, enum AVSampleFormat sample_fmt, int align);

//计算出存储指定数量音频样本所需的缓冲区大小。这个函数通常用于动态分配音频样本数据缓冲区的场景。
参数说明:
- `linesize`:指向存储每个通道数据大小的数组的指针。
- `nb_channels`:音频通道数。
- `nb_samples`:每个通道中的音频样本数。
- `sample_fmt`:音频样本格式,使用 AVSampleFormat 枚举类型。
- `align`:对齐方式,通常为 0。

AVFormatContext *avformat_alloc_context(void);

//用于分配内存并返回一个初始化后的 AVFormatContext 结构体指针。

AVFormatContext 结构体里面有一个重要的参数 interrupt_callback.callback ,用来设置回调函数。当调用av_read_frame或avformat_find_stream_info会阻塞执行很长时间的时候,只要设置该回调函数返回 1 ,那么就会不再阻塞,立即返回。

代码例程:点击跳转

相关文章:

qt+ffmpeg 实现音视频播放(二)之音频播放

一、音频播放流程 1、打开音频文件 通过 avformat_open_input() 打开媒体文件并分配和初始化 AVFormatContext 结构体。 函数原型如下: int avformat_open_input(AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options); 参数说…...

Bash Shell中双引号中的感叹号问题详解

Bash Shell中双引号中的感叹号问题详解 在Bash Shell中,感叹号(!)是一个特殊字符,主要用于历史扩展。历史扩展允许你使用!来引用历史命令。然而,当你在双引号中使用感叹号时,如果你在双引号中直接使用感叹号,它可能会…...

MFC中CString的用法及使用示例

CString 是 Microsoft Foundation Classes (MFC) 库中的一个类,用于处理 C 风格的字符串。它提供了很多有用的方法和函数,使得字符串的操作变得更加简单和安全。下面是一些 CString 的基本用法和使用示例: 1. 包含头文件 首先,你…...

注册个人小程序

访问地址 https://mp.weixin.qq.com/ 立即注册 选择小程序 注册 填写信息 登录邮箱 访问邮箱的链接激活账号 选择个人,填写信息 注册完成,即可登录进入填写信息...

VTK----VTK的事件机制

事件的发送和接收对于一个应用或系统来说是一个基本的功能,所以一些通用的库对应地也建立了自己的一套管理事件的机制,例如QT、VTK都有自己的事件管理机制。VTK库中定义了很多的事件,这些事件是如何进行管理的,下面从三个方面来详细的说明。 1 事件的管理 在讲述VTK的事件…...

常用的vim和linux命令

常用的vim命令和linux命令 vim编辑器有三种模式 命令模式、编辑模式、末行模式 模式间切换方法: 1.命令模式下,输入:后,进入末行模式 2.末行模式下,按esc慢退、按两次esc快退、或者删除所有命令,可以回…...

生产环境中间件服务集群搭建-zk-activeMQ-kafka-reids-nacos

环境: 系统:centos7.9 工作目录:/home 安装包位置:/home/op/tools 1.系统初始化 安装依赖环境 yum -y install net-tools vim screen telnet vim gcc gcc-c 修改主机名,为另外两台添加hosts文件 [rootmq01 conf…...

Smart Light Random Memory Sprays Retinex 传统图像增强 SLRMSR

文章目录 前言1、Smart Light Random Memory Sprays Retinex概况2、Smart Light Random Memory Sprays Retinex的实现2.1、SLRMSR算法的伪代码2.2、初始化记忆喷雾(CreateInitialMemorySpray)2.3、更新记忆喷雾 (UpdateMemorySpray)2.4、计算颜色校正因子…...

Oracle数据库实例概述

Oracle数据库实例是由内存结构(SGA和PGA)及后台进程这两大部分组成。 内存结构 SGA (System Global Area):这是数据库实例的共享内存区域,所有与该实例连接的进程都可以访问。SGA包含多个内存结构,例如: 数…...

Odoo17免费开源ERP开发技巧:如何在表单视图中调用JS类

文/Odoo亚太金牌服务开源智造 老杨 在Odoo最新V17新版中,其突出功能之一是能够构建个性化视图,允许用户以独特的方式与数据互动。本文深入探讨了如何使用 JavaScript 类来呈现表单视图来创建自定义视图。通过学习本教程,你将获得关于开发Odo…...

[RCTF2015]EasySQL ---不会编程的崽

今天也是sql注入的新类型---二次注入。不得不说花样真的多哦。 既然真的是sql注入了。那就不测试其他地方了。现在注册进去看一下界面 单纯的回显了名字。源代码里发现user.php。 可以修改密码?二次注入应该就在用户名这里了。因为修改密码时,用户名会被…...

Memcached-分布式内存对象缓存系统

目录 一、NoSQL 介绍 二、Memcached 1、Memcached 介绍 1.1 Memcached 概念 1.2 Memcached 特性 1.3 Memcached 和 Redis 区别 1.4 Memcached 工作机制 1.4.1 内存分配机制 1.4.2 懒惰期 Lazy Expiration 1.4.3 LRU(最近最少使用算法) 1.4.4…...

bash: sqlplus: command not found 问题解决方法

一、问题描述 在Linux中Oracle安装成功后,首次启动使用时,出现 sqlplus 命令不识别的问题,现象如下: $ sqlplus / as sysdba bash: sqlplus: command not found...二、问题分析 查看环境变量是否正确配置: $ vim .ba…...

大模型-Prompt

一、prompt是什么 在大型语言模型集成中,"prompt" 是指您向模型提供的输入文本或指令,以引导模型生成特定类型的响应。这个 prompt 可以是一个问题、一段描述、一个任务说明,甚至是一部分对话历史记录等。通过设计和优化 prompt&a…...

Python实战:SQLAlchemy ORM使用教程

一、SQLAlchemy ORM使用教程 SQLAlchemy是一个流行的Python SQL工具包和对象关系映射(ORM)框架,它为开发人员提供了一种高效、灵活的方式来与数据库进行交互。在本篇博客中,我们将深入探讨SQLAlchemy ORM的核心知识,并…...

能不能绕过c去学c++?

目前做工程开发,基本都是c/c混着用的,c/c是同源的,c/是在c的基础上发展起来的,它们之间有些联系和区别: 区别: 1.可用库不同 c基本是系统底层语言,一般系统底层开发用c(例如&…...

Python 小爬虫:爬取 bing 每日壁纸设为桌面壁纸

请求 URLJSON 版示例代码代码片段注意点headers 中的 User-Agent响应头中的 Content-Type终端通过代理API从 bing.com 找Bing 每日壁纸设置为桌面壁纸代码设定计划任务自动执行 python 脚本请求 URL 通过模仿必应(Bing)自己的 AJAX 调用方式获得请求 URL。 JSON 格式:...

利用textarea和white-space实现最简单的文章编辑器 支持缩进和换行

当你遇到一个非常基础的文章发布和展示的需求,只需要保留换行和空格缩进,你是否会犹豫要使用富文本编辑器?实际上这个用原生的标签两步就能搞定! 1.直接用textarea当编辑器 textarea本身就可以保存空格和换行符,示例如…...

总结mac下解决matplotlib中文显示问题的几种方法

一、前言: 使⽤matplotlib画图时,由于matplotlib默认没有中⽂,显⽰中文时会出现空⽩⼩⽅块。 二、方法: 2.1 matplotlib中使用SimHei字体 1)进入终端后查看matplotlib的字体路径: $ python >>&g…...

探索区块链世界:从加密货币到去中心化应用

相信提到区块链,很多人会想到比特币这样的加密货币,但实际上,区块链技术远不止于此,它正在深刻地改变我们的生活和商业。 首先,让我们来简单了解一下什么是区块链。区块链是一种分布式数据库技术,它通过将…...

synchronized 学习

学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...

Linux链表操作全解析

Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

黑马Mybatis

Mybatis 表现层&#xff1a;页面展示 业务层&#xff1a;逻辑处理 持久层&#xff1a;持久数据化保存 在这里插入图片描述 Mybatis快速入门 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6501c2109c4442118ceb6014725e48e4.png //logback.xml <?xml ver…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

在 Spring Boot 中使用 JSP

jsp&#xff1f; 好多年没用了。重新整一下 还费了点时间&#xff0c;记录一下。 项目结构&#xff1a; pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...

前端调试HTTP状态码

1xx&#xff08;信息类状态码&#xff09; 这类状态码表示临时响应&#xff0c;需要客户端继续处理请求。 100 Continue 服务器已收到请求的初始部分&#xff0c;客户端应继续发送剩余部分。 2xx&#xff08;成功类状态码&#xff09; 表示请求已成功被服务器接收、理解并处…...

高端性能封装正在突破性能壁垒,其芯片集成技术助力人工智能革命。

2024 年&#xff0c;高端封装市场规模为 80 亿美元&#xff0c;预计到 2030 年将超过 280 亿美元&#xff0c;2024-2030 年复合年增长率为 23%。 细分到各个终端市场&#xff0c;最大的高端性能封装市场是“电信和基础设施”&#xff0c;2024 年该市场创造了超过 67% 的收入。…...

第2课 SiC MOSFET与 Si IGBT 静态特性对比

2.1 输出特性对比 2.2 转移特性对比 2.1 输出特性对比 器件的输出特性描述了当温度和栅源电压(栅射电压)为某一具体数值时,漏极电流(集电极电流...