首页 > 其他分享 >使用QAudioDecoder + QAudioSink实现音频播放

使用QAudioDecoder + QAudioSink实现音频播放

时间:2024-12-12 12:20:20浏览次数:3  
标签:format 解码 QAudioDecoder 播放 QAudioSink 音频

要实现 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_OBJECT

public:
    CustomAudioPlayer() {
        // **Step 1: 配置音频格式**
        QAudioFormat format;
        format.setSampleRate(44100); // 采样率 44.1kHz
        format.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/O
    QAudioDecoder *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 不同,你可以完全控制音频数据流(如音频数据分析、滤波处理等)。

标签:format,解码,QAudioDecoder,播放,QAudioSink,音频
From: https://www.cnblogs.com/wuhaiqiong/p/18593485

相关文章

  • Qt编写RK3588视频播放器/支持RKMPP硬解/支持各种视音频文件和视频流/海康大华视频监控
    一、前言用ffmpeg做硬解码开发,参考自带的示例hw_decode.c即可,里面提供了通用的dxva2/d3d11va/vaapi这种系统层面封装的硬解码,也就是无需区分用的何种显卡,操作系统自动调度,基本上满足了各种场景的需要,这种方式很通用也便捷,但是一些特殊场景必须要用指定硬解码器名称的方式,比如指定......
  • AI测试 前 OpenAI 音频 AI 负责人获投 4000 万,打造情感通用智能;TEN Agent 一键让 Coze
       开发者朋友们大家好: 这里是「RTE开发者日报」,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享RTE(Real-TimeEngagement)领域内「有话题的新闻」、「有态度的观点」、「有意思的数据」、「有思考的文章」、「有看点的会议」,但内容仅代表编......
  • 四种音频混音算法
    此篇文章在2022年11月18日被记录最近需要混音算法,上网查阅了四种常用的混音算法,用python运行来做测试,测试完成的语音数据放在结尾可以下载混音算法一:加权平均这种方法很简单,直接将两个PCM样本相加,为了防止溢出再除以二,但是这种方式会导致声音细节丢失声音会变小,并且混入通......
  • 违规抽烟识别智慧矿山一体机未戴安全帽识别:网络摄像机中的音频及音频编码阐述
    在现代网络摄像机的设计中,音频功能已成为一个不可或缺的组成部分,它不仅增强了监控系统的能力,还为用户提供了更丰富的现场信息。音频功能使得网络摄像机能够捕捉到环境中的声音,从而在安全监控、远程通信以及其他多种应用中发挥重要作用。本文将详细探讨网络摄像机中的音频功能及其......
  • AI智能分析视频分析网关摄像机实时接入分析平台:海康/宇视安防摄像机中支持哪些音频格
    在安防监控系统中,音频编码和传输技术与视频同样重要,它们共同构成了一个完整的监控解决方案。海康和宇视作为安防领域的两大品牌,提供了多种音频编码格式以满足不同场景的需求。本文将详细介绍这些音频编码格式,探讨摄像机的音频输入输出类型,以及音频线的选择和使用。此外还将介绍一......
  • 在H5中如何预加载音频?
    在H5中预加载音频,你可以使用HTML5的<audio>元素,并结合JavaScript来实现。以下是几种常见的方法:1.使用preload属性:这是最简单的方法,直接在<audio>标签中设置preload属性。preload属性有三个值:auto:浏览器会尝试立即下载整个音频文件。这是最积极的预加载方......
  • 关于 MIC 音频连接器电路原理的介绍
     音频接口是连接音频设备、传输音频信号的重要组件,本节介绍3.5mm音频底座和音频插件的引脚说明以及相关电路的设计。一、常见类型3.5mm音频接口:常见于耳机、音箱、手机等设备,分三段式和四段式,小巧便携但信号质量有限。6.35mm音频接口:又称“大三芯”,用于专业音频设备,连......
  • 使用QMediaPlayer播放音频
    测试扬声器的实现主要播放设备:我们使用的是QMediaPlayer来实现播放音频。实现步骤使用QMediaDevices::audioOutputs()方法来获取电脑上的所有音频输出设备。并存放到QList<QAudioDevice>outputDevices中;默认使用系统默认的输出即耳机,下标为0的outputDevices中;我们初始化的输......
  • 基于Java+SSM+HTML5音乐播放器系统(源码+LW+调试文档+讲解等)/音乐播放器/音乐播放系
    博主介绍......
  • android手机能同时播放两个video音频吗?
    一般来说,Android手机不能同时播放两个视频的音频。Android系统的音频焦点机制通常只允许一个应用同时控制音频输出。如果第二个视频开始播放,第一个视频的音频通常会被暂停。然而,有一些方法可以实现类似的效果,但都需要一些额外的技巧或限制:混合音频:前端可以使用WebAudio......