ffmpeg解析pcm文件进行播放

初始化音频子系统是使用 SDL 播放音频之前的一个必要步骤。这确保了 SDL 能够正确地配置和使用音频硬件。如果你不进行初始化,试图使用音频功能可能会导致未定义的行为或错误。

为什么需要初始化音频子系统?

1.资源分配:

SDL 需要为音频设备分配资源,比如设置缓冲区大小、采样率等。

初始化确保 SDL 可以适当地配置音频设备。

2.设备兼容性:

不同的操作系统和硬件平台有不同的音频设备驱动程序。

初始化过程确保 SDL 使用正确的驱动程序与音频硬件通信。

3.状态设置:

初始化过程中可以设置音频输出的基本参数,如通道数、采样率、格式等。

这些设置对于播放音频是必需的。

4.错误检测:

初始化时 SDL 会尝试检测并报告任何潜在的问题,如音频设备不可用或驱动程序错误。

bash 复制代码
//初始化Audio子系统
    if(SDL_Init(SDL_INIT_AUDIO))
    {
        qDebug() << "SDL_Init error" << SDL_GetError();
        return;
    }
bash 复制代码
#include "playthread.h"
#include <SDL2/SDL.h>
#include <QDebug>
#include <QFile>

#define FILENAME "D:/ffmpeg/ffm.pcm"
#define SAMPLE_RATE 44100
#define SAMPLE_FORMAT AUDIO_S16LSB
#define SAMPLE_SIZE (SAMPLE_FORMAT & 0xFF)//== SDL_AUDIO_BITSIZE() = 16;
#define CHANNELS 2

//缓冲区样本数量
#define SAMPLES 1024
//每个样本占用多少字节
#define BYTES_PER_SAMPLE ((SAMPLE_SIZE * CHANNELS)/8) // 4
//文件缓冲区大小
#define BUFFER_SIZE BYTES_PER_SAMPLE * SAMPLES//4096

typedef struct
{
    int len = 0;
    int pullLen = 0;
    char* data = nullptr;
}AudioBuffer;
bash 复制代码
//音频参数
    SDL_AudioSpec spec;
    //采样率
    spec.freq = SAMPLE_RATE;
    //采集格式(s16le)
    spec.format = AUDIO_S16LSB;//小端读取
    //声道数
    spec.channels = CHANNELS;
    //音频缓冲区的样本数量(这个值必须是2的幂)
    spec.samples = 1024;
    //回调
    spec.callback = pull_audio_data;

    //传递给回调函数的参数
    AudioBuffer buffer;
    spec.userdata = &buffer;

    //打开设备
    if(SDL_OpenAudio(&spec,nullptr))
    {
        qDebug() << "SDL 0penAudio error" << SDL_GetError();
        //清楚所有子系统
        SDL_Quit();
        return;
    }

    //打开文件
    QFile file(FILENAME);
    if(!(file.open(QFile::ReadOnly)))
    {
        qDebug() << "file open error" << FILENAME;
        //关闭设备
        SDL_CloseAudio();
        //清除所有子系统
        SDL_Quit();
        return;
    }

    //开始播放(0是取消暂停) -- 开始后会一直调用回调函数
    SDL_PauseAudio(0);

    //存放从文件中读取的数据
    char data[BUFFER_SIZE];
    while(!isInterruptionRequested())
    {
        //只要从文件中读取的音频数据,还没有填充完毕,就跳过
        if(buffer.len > 0) continue;
        buffer.len = file.read(data,BUFFER_SIZE);
        if(buffer.len <= 0)
        {
            //剩余的样本数量
            int samples = buffer.pullLen / BYTES_PER_SAMPLE;
            int ms = samples * 1000 / SAMPLE_RATE;
            qDebug() << ms;
            break;
        }

        //读取到了文件数据
        buffer.data = data;
    }

    //关闭文件
    file.close();

    //关闭设备
    SDL_CloseAudio();

    //清除所有子系统
    SDL_Quit();

当进行传参并进行设置回调函数后,线程就会不停歇的进行调用回调函数,知道线程结束

bash 复制代码
//等待音视频设备回调(会回调多次)
void pull_audio_data(void *userdata,
                     //需要往stream中填充PCM数据
                     Uint8 *stream,
                     //希望填充的大小(samples *format *channels / 8)
                     int len)
{
    //清空stream
    SDL_memset(stream,0,len);

    AudioBuffer* buffer = (AudioBuffer*)userdata;
    //如果bufferLen的长度为0说明还没有准备好
    if(buffer->len <= 0) return;

    //取len、bufferLen的最小值(防止指针越界)
    buffer->pullLen = (len > buffer->len) ? buffer->len : len;

    //填充数据进行播放
    SDL_MixAudio(stream,(Uint8*)buffer->data,buffer->pullLen,SDL_MIX_MAXVOLUME);

    buffer->data += buffer->pullLen;
    buffer->len -= buffer->pullLen;
}
相关推荐
EasyCVR5 小时前
EHOME视频平台EasyCVR视频融合平台使用OBS进行RTMP推流,WebRTC播放出现抖动、卡顿如何解决?
人工智能·算法·ffmpeg·音视频·webrtc·监控视频接入
简鹿办公6 小时前
使用 FFmpeg 进行音视频转换的相关命令行参数解释
ffmpeg·简鹿视频格式转换器·ffmpeg视频转换
EasyCVR9 小时前
萤石设备视频接入平台EasyCVR多品牌摄像机视频平台海康ehome平台(ISUP)接入EasyCVR不在线如何排查?
运维·服务器·网络·人工智能·ffmpeg·音视频
runing_an_min9 小时前
ffmpeg 视频滤镜:屏蔽边框杂色- fillborders
ffmpeg·音视频·fillborders
岁月小龙20 小时前
如何让ffmpeg运行时从当前目录加载库,而不是从/lib64
ffmpeg·origin·ffprobe·rpath
行者记2 天前
ffmpeg命令——从wireshark包中的rtp包中分离h264
测试工具·ffmpeg·wireshark
EasyCVR2 天前
国标GB28181视频平台EasyCVR私有化视频平台工地防盗视频监控系统方案
运维·科技·ffmpeg·音视频·1024程序员节·监控视频接入
hypoqqq2 天前
使用ffmpeg播放rtsp视频流
ffmpeg
cuijiecheng20182 天前
音视频入门基础:FLV专题(24)——FFmpeg源码中,获取FLV文件视频信息的实现
ffmpeg·音视频
QMCY_jason2 天前
黑豹X2 armbian 编译rkmpp ffmpeg 实现CPU视频转码
ffmpeg