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

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

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 
#include 
#include 
#include 
#include 
#include 
#include 

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 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

<ui version="4.0">
 <class>MainWindowclass>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0x>
    <y>0y>
    <width>800width>
    <height>600height>
   rect>
  property>
  <property name="windowTitle">
   <string>MainWindowstring>
  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>0x>
     <y>0y>
     <width>800width>
     <height>22height>
    rect>
   property>
  widget>
  <widget class="QStatusBar" name="statusbar"/>
 widget>
 <resources/>
 <connections/>
ui>

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/607052.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-14
下一篇 2022-04-14

发表评论

登录后才能评论

评论列表(0条)

保存