02 Qt6.2.3播放PCM文件,使用QAudioSink替代老版本的QAudioOutput

Qt6.2.3播放PCM文件,使用QAudioSink替代老版本的QAudioOutput

作者将狼才鲸
创建日期2022-03-29

Gitee源码工程目录:qt_gui_simple2complex/ source / 004_MultiMedia_VideoAudio / 006_qt6-2-3_pcm_play
CSDN文章阅读地址:
B站视频讲解地址(待完成):才鲸嵌入式

Qt5版本的PCM播放工程Gitee目录: qt_gui_simple2complex/ source / 004_MultiMedia_VideoAudio / 002_pcm_audio_play


一、工程说明

  • 因为网上能搜到的都是Qt老版本QAudioFormat+QAudioOutput播放pcm的示例代码,在Qt6中用不了,所以自己写一个Qt6版本的示例。

  • Qt6.2.3中需要使用QAudioSink+QIODevice+QMediaDevices替代Qt5的QAudioOutput。

  • 使用QAudioSink进行输出时需要注册QMediaDevices中的默认设备,QAudioSink开始播放时需要传入一个QIODevice虚拟输入设备,在QIODevice这个虚拟设备中进行pcm数据的出入。

  • 我电脑扬声器默认输出的是采样率44.1k,双通道,采样深度16bit,代码中有参数打印,你可以根据自己电脑的声音输出配置生成同样格式的pcm。

  • 生成pcm文件我使用的是ffmpeg软件,测试时我直接使用本工程同级目录另一个工程里的文件。

  • 本地pcm文件路径:…/002_pcm_audio_play/002_pcm_audio_play.pcm

  • ffmpeg生成pcm文件的命令:

ffmpeg -i roar.wav -acodec pcm_s16le -f s16le -ac 2 -ar 44100 001_pcm_audio_play.pcm
  • 生成并截取片段:
ffmpeg -i roar.wav -ss 00:00:00 -t 00:00:03 -acodec pcm_s16le -f s16le -ac 2 -ar 44100 002_pcm_audio_play.pcm
  • 播放pcm文件测试
ffplay -ar 44100 -ac 2 -f s16le -i output.pcm
  • 参考了官方的源码。
  • Qt6软件安装目录本地播放音频的示例:Qt\Examples\Qt-6.2.3\multimedia\audiooutput
  • 官方示例讲解地址:Audio Output Example

二、工程源码展示

  • mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"

PcmInputDevice::PcmInputDevice()
{
    m_inputFile.setFileName("../002_pcm_audio_play/002_pcm_audio_play.pcm");
    m_inputFile.open(QIODevice::ReadOnly);
}

void PcmInputDevice::start()
{
    open(QIODevice::ReadOnly);
}

void PcmInputDevice::stop()
{
    close();
}

PcmInputDevice::~PcmInputDevice()
{
    m_inputFile.close();
}

/**
 * \brief 扬声器缺少数据时会自动调用这个方法
 */
qint64 PcmInputDevice::readData(char *data, qint64 len)
{
    m_inputFile.read(data, len);

    return len;
}

qint64 PcmInputDevice::writeData(const char *data, qint64 len)
{
    Q_UNUSED(data);
    Q_UNUSED(len);

    return 0;
}

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    m_outputDevices = new QMediaDevices(this);
    m_outputDevice = m_outputDevices->defaultAudioOutput();
    QAudioFormat format = m_outputDevice.preferredFormat();
    // ChannelConfigStereo is 2, Int16 is 2
    qDebug("sampleRate: %d, channelCount: %d, sampleFormat: %d",
           format.sampleRate(), format.channelCount(), format.sampleFormat()
           );
    m_audioSinkOutput = new QAudioSink(m_outputDevice, format);

    m_pcmInputDevice = new PcmInputDevice;
    m_pcmInputDevice->start();
    m_audioSinkOutput->start(m_pcmInputDevice);
}

MainWindow::~MainWindow()
{
    m_pcmInputDevice->stop();
    m_audioSinkOutput->stop();
    delete ui;
}
  • mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QFile>
#include <QDebug>
#include <QIODevice>
#include <QMediaDevices>
#include <QAudioFormat>
#include <QAudioSink>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

/**
 * \brief 播放的输入数据必须从QIODevice设备中送往QAudioSink
 */
class PcmInputDevice : public QIODevice
{
    Q_OBJECT

public:
    PcmInputDevice();
    ~PcmInputDevice();
    void start();
    void stop();
    qint64 readData(char *data, qint64 maxlen) override;
    qint64 writeData(const char *data, qint64 len) override;

private:
    QFile m_inputFile;
};

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
    QAudioSink *m_audioSinkOutput;
    QMediaDevices *m_outputDevices;
    QAudioDevice m_outputDevice;
    PcmInputDevice *m_pcmInputDevice;
};
#endif // MAINWINDOW_H
  • main.cpp
/**
 * \brief 使用Qt6.2.3播放pcm音频
 * \details 使用QAudioSink+QIODevice+QMediaDevices替代Qt5的QAudioOutput。
 *          使用QAudioSink进行输出时需要注册QMediaDevices中的默认设备,
 *          QAudioSink开始播放时需要传入一个QIODevice虚拟输入设备,在QIODevice
 *          这个虚拟设备中进行pcm数据的出入。
 *          我电脑扬声器默认输出的是采样率44.1k,双通道,采样深度16bit,
 *          生成pcm文件我使用的是ffmpeg软件,测试时我直接使用另一个工程里的文件,
 *          本地pcm文件路径:../002_pcm_audio_play/002_pcm_audio_play.pcm
 *          ffmpeg生成pcm文件的命令:
 *          ffmpeg -i roar.wav -acodec pcm_s16le -f s16le -ac 2 -ar 44100 001_pcm_audio_play.pcm
 *          生成并截取片段:
 *          ffmpeg -i roar.wav -ss 00:00:00 -t 00:00:03 -acodec pcm_s16le -f s16le -ac 2 -ar 44100 002_pcm_audio_play.pcm
 *          播放pcm文件测试
 *          ffplay -ar 44100 -ac 2 -f s16le -i output.pcm
 * \author 将狼才鲸
 * \date 2022-03-29
 * \note 因为网上能搜到的都是Qt老版本QAudioFormat+QAudioOutput播放pcm的示例代码,在Qt6中用不了,
 *       所以自己写一个Qt6版本的示例。
 *       Qt6软件安装目录本地播放音频的示例:Qt\Examples\Qt-6.2.3\multimedia\audiooutput
 *       官方示例讲解地址:[Audio Output Example](https://doc.qt.io/qt-6/qtmultimedia-multimedia-audiooutput-example.html)
 */

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}
  • pcm_play.pro
QT       += core gui
QT       += multimedia

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    mainwindow.cpp

HEADERS += \
    mainwindow.h

FORMS += \
    mainwindow.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
  • mainwindow.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QHBoxLayout" name="horizontalLayout">
    <item>
     <widget class="QPushButton" name="pushButton">
      <property name="text">
       <string>你会听到5秒的音乐播放,然后是重复的杂音(事先保证你的电脑没有设置为静音)</string>
      </property>
     </widget>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>22</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值