要实现 QAudioDecoder + QAudioSink
的音频播放,主要是将 MP3、AAC 等压缩格式的音频文件,使用 QAudioDecoder
解码成 PCM 格式,然后通过 QAudioSink
播放出来。
QAudioSink基本概念
QAudioSink 是 Qt 6 中用于播放音频的类。它提供了低级别的接口,可以直接控制音频数据的播放和输出到设备。QAudioSink 通常用于需要更灵活地处理音频流的场景;
实现思路
-
解码器 (QAudioDecoder)
- 将 MP3、AAC 等压缩音频格式解码成 PCM 格式,输出为音频缓冲区 (QAudioBuffer)。
-
音频播放 (QAudioSink)
QAudioSink
负责接收解码后的 PCM 数据流,并将其传输到音频输出设备(如耳机、扬声器等)。- 通过
audioSink->start()
启动音频输出,返回一个 QIODevice,将解码后的数据流写入这个 QIODevice。
实现流程
- 创建 QAudioDecoder,设置解码音频的格式、文件路径。
- 创建 QAudioSink,配置音频格式(采样率、位深度、通道数等)。
- 连接 QAudioDecoder 的 bufferReady() 信号,当解码器有新数据时,将数据写入 QAudioSink。
- 开始解码,当解码完成后,自动停止音频播放。
完整代码示例
#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 文件 |
扩展功能
-
实时音量控制
可以在播放时调用audioSink->setVolume(0.5)
设置音量。 -
设备选择
使用QMediaDevices::audioOutputs()
获取系统中的扬声器、耳机等设备,将QAudioSink
指定为特定的音频设备。 -
流式数据播放
替换 QAudioDecoder 的输入源为 QBuffer 或 QNetworkAccessManager,实现网络流媒体音频播放。 -
动态控制播放
实现暂停、恢复、停止,可调用:
audioSink->suspend(); // 暂停
audioSink->resume(); // 恢复
audioSink->stop(); // 停止
总结
QAudioDecoder + QAudioSink
是播放音频的底层实现方案。- QAudioDecoder 负责解码音频(如 MP3、AAC),QAudioSink 负责播放解码后的 PCM 数据。
- 与
QMediaPlayer
不同,你可以完全控制音频数据流(如音频数据分析、滤波处理等)。