Qt SDL2播放Wav音频

这篇具有很好参考价值的文章主要介绍了Qt SDL2播放Wav音频。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

这里介绍两种方法来实现Qt播放Wav音频数据。

方法一:使用QAudioOutput

pro文件中加入multimedia模块。

#include <QApplication>
#include <QFile>
#include <QAudioFormat>
#include <QAudioOutput>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QFile inputFile;
    inputFile.setFileName("test.wav");
    inputFile.open(QIODevice::ReadOnly);

    //设置采样格式
    QAudioFormat audioFormat;
    //设置采样率
    audioFormat.setSampleRate(44100);
    //设置通道数
    audioFormat.setChannelCount(2);
    //设置采样大小,一般为8位或16位
    audioFormat.setSampleSize(16);
    //设置编码方式
    audioFormat.setCodec("audio/pcm");
    //设置字节序
    audioFormat.setByteOrder(QAudioFormat::LittleEndian);
    //设置样本数据类型
    audioFormat.setSampleType(QAudioFormat::UnSignedInt);

    QAudioOutput *audio = new QAudioOutput( audioFormat, 0);
    audio->start(&inputFile);
    return a.exec();
}

注意这里采样率、通道数和采样大小的设置,本例只能用来播放无损的WAV。

方法二:使用SDL2来播放

接下来演示一下如何使用SDL播放WAV文件。

初始化子系统:

// 初始化Audio子系统
if (SDL_Init(SDL_INIT_AUDIO)) {
    qDebug() << "SDL_Init error:" << SDL_GetError();
    return;
}

 加载WAV文件:

// 存放WAV的PCM数据和数据长度
typedef struct {
    Uint32 len = 0;
    int pullLen = 0;
    Uint8 *data = nullptr;
} AudioBuffer;
 
// WAV中的PCM数据
Uint8 *data;
// WAV中的PCM数据大小(字节)
Uint32 len;
// 音频参数
SDL_AudioSpec spec;
 
// 加载wav文件
if (!SDL_LoadWAV(FILENAME, &spec, &data, &len)) {
    qDebug() << "SDL_LoadWAV error:" << SDL_GetError();
    // 清除所有的子系统
    SDL_Quit();
    return;
}
 
// 回调
spec.callback = pull_audio_data;
// 传递给回调函数的userdata
AudioBuffer buffer;
buffer.len = len;
buffer.data = data;
spec.userdata = &buffer;

打开音频设备:

// 打开设备
if (SDL_OpenAudio(&spec, nullptr)) {
    qDebug() << "SDL_OpenAudio error:" << SDL_GetError();
    // 释放文件数据
    SDL_FreeWAV(data);
    // 清除所有的子系统
    SDL_Quit();
    return;
}

开始播放:

		// 每一个样本大小
		int size = SDL_AUDIO_BITSIZE(m_spec.format) * m_spec.channels / 8;
		// 最后一次播放的样本数量
		int leftSample = m_buffer.pullLen / size;
		// 最后一次播放的时长ms
		int ms = leftSample * 1000 / m_spec.freq;
		SDL_Delay(ms);

回调:

static void fill_audio(void *userdata, Uint8 *stream, int len)
{
	AudioPlayThread::AudioBuffer *buffer = (AudioPlayThread::AudioBuffer *)userdata;
	SDL_memset(stream, 0, len);
	if (buffer->len <= 0) 
		return;

	if (buffer->thread->m_isPause)
		return;

	buffer->pullLen = buffer->len > len ? len : buffer->len;
	SDL_MixAudio(stream, buffer->data, buffer->pullLen, SDL_MIX_MAXVOLUME);
	buffer->data += buffer->pullLen;
	buffer->len -= buffer->pullLen;
	//未播放的时间
	int unPlayTime = (buffer->thread->m_totalTime) - (buffer->len / buffer->thread->m_perByte);
	buffer->thread->m_timeFunc(unPlayTime,buffer->thread->m_totalTime);
}

释放资源:

// 释放WAV文件数据
SDL_FreeWAV(data);
 
// 关闭设备
SDL_CloseAudio();
 
// 清除所有的子系统
SDL_Quit();

运行效果图:

Qt SDL2播放Wav音频,SDL2,Qt进阶,qt,音视频,SDL,wav,QAudioOutput

音频界面构造:

Qt SDL2播放Wav音频,SDL2,Qt进阶,qt,音视频,SDL,wav,QAudioOutput

音频播放界面:AudioPlayWidget类。

#ifndef AUDIOPLAYWIDGET_H
#define AUDIOPLAYWIDGET_H

#include <QWidget>

namespace Ui {
class AudioPlayWidget;
}

class AudioPlayThread;
class AudioPlayWidget : public QWidget
{
    Q_OBJECT

public:
	explicit AudioPlayWidget(const QString &name, const QString &url, QWidget *parent = 0);
    ~AudioPlayWidget();

private slots:
    void on_btnPlay_clicked();
    void slotFinished();
	void slotShowTime(int playTime, int totalTime);

private:
    Ui::AudioPlayWidget *ui;

private:
    bool m_play = false;
    AudioPlayThread *m_thread = nullptr;
	bool m_isExistPlay = false;

	QString m_url;
};

#endif // AUDIOPLAYWIDGET_H



#include "AudioPlayWidget.h"
#include "ui_AudioPlayWidget.h"
#include "BaseHelper.h"
#include "AudioPlayThread.h"
#include <QTime>
#include "mymessagebox.h"

const QString playStyle = "QPushButton#btnPlay\
{\
    border-image: url(\":/image/audioPlay.png\");\
}";

const QString pauseStyle = "QPushButton#btnPlay\
{\
    border-image: url(\":/image/audioPause.png\");\
}";

AudioPlayWidget::AudioPlayWidget(const QString &name, const QString &url,QWidget *parent) :
    QWidget(parent),
    ui(new Ui::AudioPlayWidget),
	m_url(url)
{
    ui->setupUi(this);

    m_thread = new AudioPlayThread(this);
    connect(m_thread,&AudioPlayThread::finished,
            this,&AudioPlayWidget::slotFinished);
    BaseHelper::load(":/qss/AudioPlayWidget.qss",this);
}

AudioPlayWidget::~AudioPlayWidget()
{
    delete ui;

    if(m_thread)
    {
        m_thread->stop();
        m_thread->wait();
    }
}

void AudioPlayWidget::on_btnPlay_clicked()
{
	if (!BaseHelper::fileExist(m_url))
	{
		MyMessageBox::showMyMessageBox(this, QString("文件丢失"),
			QString("打开的音频文件丢失?"), MESSAGE_WARNNING, BUTTON_OK, true);
		return;
	}
    m_play = !m_play;
    if(m_play)
    {
		ui->btnPlay->setStyleSheet(pauseStyle);
		if (!m_isExistPlay)
		{
			TimeFunc totalTimeFunc = std::bind(&AudioPlayWidget::slotShowTime, this,
				std::placeholders::_1, std::placeholders::_2);

			m_thread->open(m_url, totalTimeFunc);
			m_thread->start();
			m_isExistPlay = true;
		}
		else
		{
			m_thread->resume();
		}
    }
    else
    {
        ui->btnPlay->setStyleSheet(playStyle);
        m_thread->pause();
    }
}

void AudioPlayWidget::slotFinished()
{
	if (m_isExistPlay)
		m_isExistPlay = false;

	m_play = !m_play;
	ui->lbPlay->setText("00:00:00");
	ui->lbTotal->setText("00:00:00");
	ui->horizontalSlider->setValue(0);
	ui->btnPlay->setStyleSheet(playStyle);
}

void AudioPlayWidget::slotShowTime(int playTime, int totalTime)
{
	QString strPlayTime = QTime::fromMSecsSinceStartOfDay(playTime* 1000).toString("hh:mm:ss");
	QString strTotalTime = QTime::fromMSecsSinceStartOfDay(totalTime*1000).toString("hh:mm:ss");
	
	ui->lbPlay->setText(strPlayTime);
	ui->lbTotal->setText(strTotalTime);

	ui->horizontalSlider->setMaximum(totalTime);
	ui->horizontalSlider->setMinimum(0);
	ui->horizontalSlider->setValue(playTime);
}

音频播放线程:文章来源地址https://www.toymoban.com/news/detail-802220.html

#ifndef AUDIOPLAYTHREAD_H
#define AUDIOPLAYTHREAD_H

#include <QThread>
#include "global.h"

class AudioPlayThread : public QThread
{
public:
    AudioPlayThread(QObject *parent = nullptr);

	typedef struct AudioBuffer {
		int len = 0;
		int pullLen = 0;
		uint8_t *data = nullptr;
		AudioPlayThread *thread = nullptr;
	} AudioBuffer;

public:
    int open(const QString &fileName, TimeFunc timeFunc);
    void stop();
    void pause();
	void resume();

protected:
    void run();

public:
	TimeFunc m_timeFunc;
	int m_totalTime = 0; //单位s
	int m_perByte = 0;//1s字节数
	bool m_isPause = false;

private:
    bool m_isExit = false; 
	Uint8 *m_data = nullptr;
	Uint32 m_len = 0;
	AudioBuffer m_buffer;
	SDL_AudioSpec m_spec;
};

#endif // AUDIOPLAYTHREAD_H

#include "AudioPlayThread.h"

static void fill_audio(void *userdata, Uint8 *stream, int len)
{
	AudioPlayThread::AudioBuffer *buffer = (AudioPlayThread::AudioBuffer *)userdata;
	SDL_memset(stream, 0, len);
	if (buffer->len <= 0) 
		return;

	if (buffer->thread->m_isPause)
		return;

	buffer->pullLen = buffer->len > len ? len : buffer->len;
	SDL_MixAudio(stream, buffer->data, buffer->pullLen, SDL_MIX_MAXVOLUME);
	buffer->data += buffer->pullLen;
	buffer->len -= buffer->pullLen;
	//未播放的时间
	int unPlayTime = (buffer->thread->m_totalTime) - (buffer->len / buffer->thread->m_perByte);
	buffer->thread->m_timeFunc(unPlayTime,buffer->thread->m_totalTime);
}

AudioPlayThread::AudioPlayThread(QObject *parent)
    : QThread(parent)
{
}

int AudioPlayThread::open(const QString &fileName, TimeFunc timeFunc)
{
	m_timeFunc = timeFunc;
	// 加载 WAV 文件
	if (!SDL_LoadWAV(fileName.toStdString().c_str(), &m_spec, &m_data, &m_len))
	{
		printf("load wav error \n");
		return -1;
	}

	//计算1s钟字节大小
	m_perByte = (SDL_AUDIO_BITSIZE(m_spec.format) * m_spec.channels / 8 * m_spec.freq);
	m_totalTime = m_len / m_perByte;
	m_timeFunc(0, m_totalTime);

	printf("===============Wav params=============\n");
	printf("======size = %d\n", m_len);
	printf("======channels = %d\n", m_spec.channels);
	printf("======samples = %d\n", m_spec.samples);
	printf("======freq = %d\n", m_spec.freq);
	printf("======time = %d\n", m_totalTime);
	printf("===============Wav params=============\n");
	
	m_buffer.data = m_data;
	m_buffer.len = m_len;
	m_buffer.thread = this;
	m_spec.userdata = &m_buffer;
	m_spec.callback = fill_audio;

	// 打开音频设备
	if (SDL_OpenAudio(&m_spec, nullptr))
	{
		printf("SDL_OpenAudio error \n");
		SDL_FreeWAV(m_data);
		return  -1;
	}

	return 0;
}

void AudioPlayThread::stop()
{
    m_isExit = true;
}

void AudioPlayThread::pause()
{
    m_isPause = true;
}

void AudioPlayThread::resume()
{
	m_isPause = false;
}

void AudioPlayThread::run()
{
    SDL_PauseAudio(0);
    while(!m_isExit)
    {
		if (m_buffer.len > 0) 
			continue;

		// 每一个样本大小
		int size = SDL_AUDIO_BITSIZE(m_spec.format) * m_spec.channels / 8;
		// 最后一次播放的样本数量
		int leftSample = m_buffer.pullLen / size;
		// 最后一次播放的时长ms
		int ms = leftSample * 1000 / m_spec.freq;
		SDL_Delay(ms);

		break;
    }

	// 释放 WAV 数据
	SDL_FreeWAV(m_data);
    SDL_CloseAudio();

	printf("=======Play Wav thread exit===\n");
}

到了这里,关于Qt SDL2播放Wav音频的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 音视频开发系列(10):基于qt的音频推流

    今天分享一下利用qt录制音频,然后再利用ffmpeg推流到nginx服务器,最后再利用vlc进行拉流的demo。 首先介绍一下如何利用qt来进行音频的录制,qt的音频录制主要利用qt的QAudioFormat先进行音频信息的配置。主要需要配置以下的信息: 然后使用QAudioDeviceInfo来获取是否支持改设置

    2024年02月02日
    浏览(60)
  • Qt 多媒体音频模拟按钮发音(音视频启动)

    ## 项目演示 平台 :windows或者ubuntu  要求 :平台需要支持音频播放功能 文件格式 :.wav 可以使用剪映生成,音频部分,我这里是简短的音乐 # Qt 多媒体简介 Qt QSound是Qt框架中的一个类,用于播放音频文件。它可以在Qt应用程序中实现简单的音频播放功能,包括播放、暂停和停

    2024年02月03日
    浏览(53)
  • FFMpeg-3、基于QT实现音视频播放显示

    1、音视频播放的基础知识 内容来自雷神博客 1、在Windows平台下的视频播放技术主要有以下三种:GDI,Direct3D和OpenGL;音频播放技术主要是DirectSound。 SDL本身并不具有播放显示的功能,它只是封装了底层播放显示的代码 记录三种视频显示技术:GDI,Direct3D,OpenGL。其中Direct3D包

    2024年02月03日
    浏览(67)
  • Qt之基于QMediaPlayer的音视频播放器(支持常见音视频格式)

    Qt自带了一个Media Player的例子,如下图所示: 但是运行这个例子机会发现,连最基本的MP4格式视频都播放不了。因为QMediaPlayer是个壳(也可以叫框架),依赖本地解码器,视频这块默认基本上就播放个MP4,甚至连MP4都不能播放,如果要支持其他格式需要下载k-lite或者LAVFilter

    2024年02月02日
    浏览(70)
  • 音视频项目—基于FFmpeg和SDL的音视频播放器解析(三)

    介绍 在本系列,我打算花大篇幅讲解我的 gitee 项目音视频播放器,在这个项目,您可以学到音视频解封装,解码,SDL渲染相关的知识。您对源代码感兴趣的话,请查看基于FFmpeg和SDL的音视频播放器 如果您不理解本文,可参考我的前一篇文章音视频项目—基于FFmpeg和SDL的音视

    2024年02月05日
    浏览(73)
  • 音视频项目—基于FFmpeg和SDL的音视频播放器解析(二十一)

    介绍 在本系列,我打算花大篇幅讲解我的 gitee 项目音视频播放器,在这个项目,您可以学到音视频解封装,解码,SDL渲染相关的知识。您对源代码感兴趣的话,请查看基于FFmpeg和SDL的音视频播放器 如果您不理解本文,可参考我的前一篇文章音视频项目—基于FFmpeg和SDL的音视

    2024年02月02日
    浏览(75)
  • Qt音视频开发41-文件推流(支持网页和播放器播放并切换进度)

    本功能最初也是有一些人提过类似的需求,就是能不能将本地的音视频文件,通过纯Qt程序推流出去,然后用户可以直接在网页上播放,也可以用各种播放器播放,然后还可以任意切换播放进度,其实说白了就是个文件服务器,用户通过网络地址访问以后,告诉对方当前是媒

    2024年02月01日
    浏览(73)
  • 【音视频 | wav】wav音频文件格式详解——包含RIFF规范、完整的各个块解析、PCM转wav代码

    😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭 🤣本文内容🤣:🍭介绍wav音频格式🍭 😎金句分享😎:🍭子曰:父母在,不远游,游必有方。 ——《论语·里仁篇》。意思是,父母还健在时,就不要

    2024年02月06日
    浏览(60)
  • 用Qt开发的ffmpeg流媒体播放器,支持截图、录像,支持音视频播放,支持本地文件播放、网络流播放

    本工程qt用的版本是5.8-32位,ffmpeg用的版本是较新的5.1版本。它支持TCP或UDP方式拉取实时流,实时流我采用的是监控摄像头的RTSP流。音频播放采用的是QAudioOutput,视频经ffmpeg解码并由YUV转RGB后是在QOpenGLWidget下进行渲染显示。本工程的代码有注释,可以通过本博客查看代码或者

    2024年02月03日
    浏览(105)
  • QtAV:基于Qt和FFmpeg的跨平台高性能音视频播放框架

    目录 一.简介 1.特性 2.支持的平台 3.简单易用的接口 二.编译 1.下载依赖包 2.开始编译 2.1克隆 2.2修改配置文件 2.3编译 三.试用 官网地址:http://www.qtav.org/ Github地址:https://github.com/wang-bin/QtAV ●支持大部分播放功能 ●播放、暂停、播放速度、快进快退、字幕、音量、声道、音

    2024年01月22日
    浏览(167)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包