用QT使用SDL播放pcm文件

主要程序片断:

Copy
#include "playthread.h" #include <QDebug> #include <SDL2/SDL.h> #include <QDebug> #include <QFile> #define FILENAME "../../haha/02_09_21_46_02.pcm" #define SAMPLE_RATE 44100 #define SAMPLE_SIZE AUDIO_S16LSB #define CHANNELS 2 #define BUFFER_SIZE 4096 //当缓存区小于音频缓存区时播放会出错,例如此处宏设为2048 PlayThread::PlayThread(QObject *parent):QThread(parent) { connect(this, &PlayThread::finished, this, &PlayThread::deleteLater); //线程结束后自动释放内存 } PlayThread::~PlayThread() { disconnect(); requestInterruption(); quit(); wait(); qDebug()<< this <<"析构" << endl; } char *bufferData; int bufferLen; //等待音频设备回调(会回调多次);回调函数会在子线程(自己创建的),说明存在两个子线程 void pull_audio_data (void *userdata, Uint8 * stream, int len) //需要往stream中填充pcm数据;希望填充len这么大(samples*format*channels);本例中为4096个字节 { qDebug() << "pull_audio_data" << len << endl; //len = samples*format*channels //清空stream SDL_memset(stream, 0,len); //文件数据还没准备好 if(bufferLen <= 0) return; //取bufferLen和len的最小值 len = (len > bufferLen) ? bufferLen : len; //主要是为了处理最后剩下的一点点数据,两个缓存区大小不一样时也需要判断(本例中是一样的) //填充数据 SDL_MixAudio(stream, (const Uint8*)bufferData, len, SDL_MIX_MAXVOLUME); bufferData += len; //指针向前移 bufferLen -= len; } void PlayThread::run() { //初始化Audio子系统 if(SDL_Init(SDL_INIT_AUDIO) < 0) { qDebug()<<"SDL_Init error" << SDL_GetError(); return; } //音频参数 SDL_AudioSpec spec; //采样率 spec.freq = SAMPLE_RATE; //通道数 spec.channels = CHANNELS; //采样格式 spec.format = SAMPLE_SIZE; //回调 spec.callback = pull_audio_data; //音频缓冲区的样本数(这个值必须是2的幂) spec.samples = 1024; //缓冲区实际字节数:1024X通道数2X采样格式16/8=4096个字节 //打开设备 if(SDL_OpenAudio(&spec, nullptr)) { qDebug()<<"SDL_OpenAudio error" << SDL_GetError(); //清除所有子系统 SDL_Quit(); } //打开文件 QFile file(FILENAME); if(!file.open(QFile::ReadOnly)) { qDebug() << "file open error" << endl; SDL_CloseAudio(); //清除所有子系统 SDL_Quit(); } //开始播放 SDL_PauseAudio(0); //存放从文件中读取的数据 char data[BUFFER_SIZE]; while(!isInterruptionRequested()) { bufferLen = file.read(data, BUFFER_SIZE); if(bufferLen <=0) break; bufferData = data; while (bufferLen > 0) { //大于零,说明缓存区还有数据, 在此死循环,bufferLen会在子线程中被修改 } } file.close(); //关闭设备 SDL_CloseAudio(); //清除所有子系统 SDL_Quit(); }

代码中数据走向如下图所示:

但是此项目还存在一个问题,就是当数据缓存区小于音频缓存区时播放会出错,例如当数据大小宏设为2048时

[项目源码]项目名为sdl_test 链接:https://pan.baidu.com/s/1gMactd9alFY4PAhhAapY4Q?pwd=8888

posted @   一颗蘋果  阅读(96)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示