zoukankan      html  css  js  c++  java
  • 【秒懂音视频开发】11_播放WAV

    对于WAV文件来说,可以直接使用ffplay命令播放,而且不用像PCM那样增加额外的参数。因为WAV的文件头中已经包含了相关的音频参数信息。

    ffplay in.wav
    

    接下来演示一下如何使用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;
    

    如果想要轻松加载MP3、Ogg、FLAC等格式的音频文件,可以使用第三方库:SDL_mixer

    打开音频设备

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

    开始播放

    // 开始播放(0是取消暂停)
    SDL_PauseAudio(0);
    
    while (!isInterruptionRequested()) {
        if (buffer.len > 0) continue;
        // 每一个样本的大小
        int size = spec.channels * SDL_AUDIO_BITSIZE(spec.format) / 8;
        // 最后一次播放的样本数量
        int samples = buffer.pullLen / size;
        // 最后一次播放的时长
        int ms = samples * 1000 / spec.freq;
        SDL_Delay(ms);
        break;
    }
    

    回调函数

    // 等待音频设备回调(会回调多次)
    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;
    
        // 文件数据还没准备好
        if (buffer->len <= 0) return;
    
        // 取len、bufferLen的最小值
        buffer->pullLen = (len > (int) buffer->len) ? buffer->len : len;
    
        // 填充数据
        SDL_MixAudio(stream,
                     buffer->data,
                     buffer->pullLen,
                     SDL_MIX_MAXVOLUME);
        buffer->data += buffer->pullLen;
        buffer->len -= buffer->pullLen;
    }
    

    释放资源

    // 释放WAV文件数据
    SDL_FreeWAV(data);
    
    // 关闭设备
    SDL_CloseAudio();
    
    // 清除所有的子系统
    SDL_Quit();
    
  • 相关阅读:
    【BZOJ-4592】脑洞治疗仪 线段树
    【BZOJ-1369】Gem 树形DP
    【BZOJ-3696】化合物 树形DP + 母函数(什么鬼)
    【BZOJ-2435】道路修建 (树形DP?)DFS
    【BZOJ-4590】自动刷题机 二分 + 判定
    【BZOJ-4591】超能粒子炮·改 数论 + 组合数 + Lucas定理
    【BZOJ-1492】货币兑换Cash DP + 斜率优化 + CDQ分治
    【BZOJ-1324】Exca王者之剑 最小割
    【BZOJ-1017】魔兽地图DotR 树形DP + 背包
    【BZOJ-1131】Sta 树形DP
  • 原文地址:https://www.cnblogs.com/mjios/p/14582322.html
Copyright © 2011-2022 走看看