使用QAudioDecoder + QAudioSink实现音频播放

news/2024/12/12 12:19:15/文章来源:https://www.cnblogs.com/wuhaiqiong/p/18593485

要实现 QAudioDecoder + QAudioSink 的音频播放,主要是将 MP3、AAC 等压缩格式的音频文件,使用 QAudioDecoder 解码成 PCM 格式,然后通过 QAudioSink 播放出来。

QAudioSink基本概念

QAudioSink 是 Qt 6 中用于播放音频的类。它提供了低级别的接口,可以直接控制音频数据的播放和输出到设备。QAudioSink 通常用于需要更灵活地处理音频流的场景;

实现思路

  1. 解码器 (QAudioDecoder)

    • 将 MP3、AAC 等压缩音频格式解码成 PCM 格式,输出为音频缓冲区 (QAudioBuffer)
  2. 音频播放 (QAudioSink)

    • QAudioSink 负责接收解码后的 PCM 数据流,并将其传输到音频输出设备(如耳机、扬声器等)。
    • 通过 audioSink->start() 启动音频输出,返回一个 QIODevice,将解码后的数据流写入这个 QIODevice

实现流程

  1. 创建 QAudioDecoder,设置解码音频的格式、文件路径。
  2. 创建 QAudioSink,配置音频格式(采样率、位深度、通道数等)。
  3. 连接 QAudioDecoder 的 bufferReady() 信号,当解码器有新数据时,将数据写入 QAudioSink。
  4. 开始解码,当解码完成后,自动停止音频播放。

完整代码示例

#include <QCoreApplication>
#include <QAudioDecoder>
#include <QAudioSink>
#include <QAudioFormat>
#include <QFile>
#include <QDebug>class CustomAudioPlayer : public QObject
{Q_OBJECTpublic:CustomAudioPlayer() {// **Step 1: 配置音频格式**QAudioFormat format;format.setSampleRate(44100); // 采样率 44.1kHzformat.setChannelCount(2);   // 立体声format.setSampleSize(16);    // 每个样本 16 位format.setCodec("audio/pcm"); format.setByteOrder(QAudioFormat::LittleEndian); // 小端存储format.setSampleType(QAudioFormat::SignedInt); // 有符号整数// **Step 2: 创建 QAudioSink**audioSink = new QAudioSink(format, this);audioDevice = audioSink->start(); // 启动 QIODevice,接收音频数据// **Step 3: 创建 QAudioDecoder**decoder = new QAudioDecoder(this);decoder->setSourceFilename("test.mp3"); // MP3 文件路径// 连接 QAudioDecoder 的信号connect(decoder, &QAudioDecoder::bufferReady, this, &CustomAudioPlayer::onBufferReady);connect(decoder, &QAudioDecoder::finished, this, &CustomAudioPlayer::onDecodingFinished);connect(decoder, &QAudioDecoder::error, this, &CustomAudioPlayer::onDecodingError);// **Step 4: 启动解码器**decoder->start();qDebug() << "开始解码音频...";}public slots:// **当 QAudioDecoder 有新的音频数据时调用此函数**void onBufferReady() {QAudioBuffer buffer = decoder->read(); // 读取音频缓冲区if (!buffer.isValid()) {qWarning() << "无效的音频缓冲区";return;}// **将音频数据写入 QAudioSink**QByteArray data = QByteArray::fromRawData(reinterpret_cast<const char*>(buffer.data()), buffer.byteCount());audioDevice->write(data);qDebug() << "已播放数据:" << buffer.byteCount() << "字节";}// **当解码完成时调用**void onDecodingFinished() {qInfo() << "音频解码完成";audioSink->stop();}// **当解码发生错误时调用**void onDecodingError(QAudioDecoder::Error error) {qWarning() << "解码错误:" << decoder->errorString();}private:QAudioSink *audioSink;       // 音频播放设备QIODevice *audioDevice;      // 音频设备 I/OQAudioDecoder *decoder;      // 音频解码器
};int main(int argc, char *argv[])
{QCoreApplication app(argc, argv);CustomAudioPlayer player;return app.exec();
}

关键讲解

1. QAudioFormat

QAudioFormat 用于配置音频格式,解码后的 PCM 数据格式必须与 QAudioSink 的格式匹配。

QAudioFormat format;
format.setSampleRate(44100);        // 采样率 44.1kHz
format.setChannelCount(2);          // 立体声
format.setSampleSize(16);           // 16 位
format.setCodec("audio/pcm");       // PCM 音频
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::SignedInt);

注意:
QAudioSink 和 QAudioDecoder 必须使用相同的音频格式,否则音频播放可能会失败。


2. QAudioSink

  • audioSink->start():启动音频播放设备,返回一个 QIODevice,你可以将数据写入这个 I/O 设备。
  • audioDevice->write(data):将数据流写入音频设备data解码后的 PCM 数据

3. QAudioDecoder

  • decoder->setSourceFilename("test.mp3"):指定要解码的文件。
  • connect(decoder, &QAudioDecoder::bufferReady, this, &CustomAudioPlayer::onBufferReady)
    • 当解码器有新数据时,调用 onBufferReady
    • bufferReady() 信号触发的间隔由解码器的缓冲区大小决定。

4. QAudioBuffer

  • QAudioBuffer buffer = decoder->read();
  • buffer.data() 返回原始音频数据。
  • buffer.byteCount() 返回缓冲区中的字节数。

示例输出

开始解码音频...
已播放数据: 1024 字节
已播放数据: 2048 字节
已播放数据: 1024 字节
音频解码完成

常见问题和解决方法

问题 原因 解决方案
无声音播放 音频格式不匹配 确保 QAudioFormat 与 QAudioSink、QAudioDecoder 格式一致
缓冲区溢出 数据未及时写入 增大缓冲区、使用更高的 QIODevice 速率
解码器报错 文件路径不正确或不支持的文件格式 检查音频路径,或确认音频格式是否被支持(MP3、WAV 通常是被支持的)
噪音或卡顿 缓冲区数据不稳定 检查解码器的缓冲区,确保数据连续传输
QAudioDecoder 错误 不支持的文件格式 确保音频是 MP3、AAC 等受支持的格式,或使用 ffmpeg 转换为 PCM 文件

扩展功能

  1. 实时音量控制
    可以在播放时调用 audioSink->setVolume(0.5) 设置音量。

  2. 设备选择
    使用 QMediaDevices::audioOutputs() 获取系统中的扬声器、耳机等设备,将 QAudioSink 指定为特定的音频设备。

  3. 流式数据播放
    替换 QAudioDecoder 的输入源为 QBufferQNetworkAccessManager,实现网络流媒体音频播放。

  4. 动态控制播放
    实现暂停、恢复、停止,可调用:

audioSink->suspend(); // 暂停
audioSink->resume();  // 恢复
audioSink->stop();    // 停止

总结

  • QAudioDecoder + QAudioSink 是播放音频的底层实现方案
  • QAudioDecoder 负责解码音频(如 MP3、AAC),QAudioSink 负责播放解码后的 PCM 数据。
  • QMediaPlayer 不同,你可以完全控制音频数据流(如音频数据分析、滤波处理等)。

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

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

相关文章

.NET Core 堆结构(Heap)底层原理浅谈

https://www.cnblogs.com/lmy5215006/p/18583743 .Net托管堆布局加载堆 主要是供CLR内部使用,作为承载程序的元数据。HighFrequencyHeap存放CLR高频使用的内部数据,比如MethodTable,MethodDesc.通过is判断类型之间的继承关系,调用接口的方法和虚方法,都需要访问MethodTable…

简化版 先求每个商品品类中亏损的最大的 写入新的表中

import pandas as pd # 读取原始表 简化为仅求亏损最大的 # 路径需要双斜杠 data = pd.read_excel(D:\\work\\2\\配料统计表.xlsx,sheet_name=Sheet1) # 对数据做处理 #第一步 找到亏损类和涨出类 如果金额大于0 是亏损;否则是涨出 data_loss= data[data[差异金额]>0] …

ABB IRB4400机器人示教器维修黑屏问题

当ABB机器人IRB4400的示教器出现黑屏问题时,可能的原因包括硬件故障、软件冲突或外部干扰。以下是一些可能的解决方法:硬件故障检查:检查示教器显示屏是否损坏或老化。检查与显示屏连接的电缆或电路板是否出现故障。更换损坏的部件。软件冲突检查:检查示教器的操作系统或应…

使用正点原子的直流无刷驱动板自写FOC控制永磁同步(PMSM)电机(开环位置)

由于ST官方MotorControlWorkbench生成的FOC代码过于复杂,决定自己使用正点原子的直流无刷驱动板自己编写FOC去控制PMSM电机。FOC代码参考的是灯哥的教材DengFOC官方文档。 1、配置TIM1高级定时器 2、foc.c代码/** foc.c** Created on: Dec 11, 2024* Author: ME-LZQ*/#i…

【Office Access 2024软件下载与安装教程】

1、安装包 「Office LTSC 2024」: 链接:下载地址2、安装教程(建议关闭杀毒软件和系统防护) 1) 下载并解压下载的安装包,双击Setup.exe安装,弹窗安装对话框2) 只留Access选项,点击一键安装3) 保持联网状态 部分在线下载更新4) 安装完成后,解压…

冬季节假日跨境电商运营压力大,哪六款软件能提升效率?

在跨境电商行业,冬季节假日的订单高峰期犹如一场紧张而关键的战役。每一个环节都需要紧密衔接、高效运转,才能在汹涌的订单浪潮中乘风破浪,收获丰硕成果。对于 J 人主导的跨境电商团队公司而言,可视化团队协作办公软件就如同战场上的精良武器,助力团队精准作战,高效协同。…

年底了,产品经理如何写好一份年终工作报告?

项目管理软件在产品经理年终汇报中发挥着关键作用。它不仅帮助产品经理高效整理和展示数据,提高汇报的准确性和逻辑性;还通过实时同步项目进度和风险管理功能,帮助产品经理及时发现问题并采取措施;同时,通过制定详细的汇报大纲和数据驱动的汇报方式,提高了汇报的专业性和…

告别混乱:文档管理系统如何重塑团队工作?

在当今数字化飞速发展的时代,团队协作效率成为企业成功的关键因素之一。而一款出色的文档管理系统软件,就如同团队的智慧中枢,默默地为各项工作提供强大的支持。 以一个项目制的营销团队为例,在日常工作中,从项目策划到执行,涉及大量的文档资料。如市场调研报告、创意策划…

信而泰推出POE交换机一站式自动化测试方案

方案背景 传统POE交换机测试工序主要有扫条码,接网线,POE供电测试,流量测试,LED测试,信息核对等,基本都依赖于手工操作,效率偏低,并且LED测试,POE供电测试依赖人工判断是否良品,容易误测。如果再考虑到操作员工变动等因素,培训员工的时间,员工操作方法不统一等情况…

自定义typeHandler将包含经纬度对象插入到mysql的point类型的字段中

自定义typeHandler将包含经纬度对象插入到mysql的point类型的字段中博客:https://www.emanjusaka.top 公众号:emanjusaka的编程栈 下面给出关键部分代码,完整代码请访问原文地址mysql 中的 point 类型在 java 中没有对应的类型匹配,需要我们自定义 typeHandler 去处理。 环…

cortex-m3基础-概览

cortex-m3是一个32位处理器内核:总线(数据、地址)宽度是32位、寄存器位宽是32位;内核结构为哈佛结构,拥有独立的数据总线和指令总线,可以并行进行指令执行和数据访问;简介cortex-m3是一个32位处理器内核:总线(数据、地址)宽度是32位、寄存器位宽是32位;内核结构为哈…

渠道管理智慧:与新华三谈数字化革新与共赢策略

智算智存全能担当 新华三集团作为数字化解决方案领导者,致力于成为客户业务创新、数字化转型值得信赖的合作伙伴。作为紫光集团旗下的核心企业,新华三通过深度布局"云-网-算-存-端"全产业链,不断提升数字化和智能化赋能水平。新华三拥有计算、存储、网络、5G、安全、…