SDL播放PCM音频数据

Posted vczf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SDL播放PCM音频数据相关的知识,希望对你有一定的参考价值。

#include <stdio.h>
#include <SDL.h>

// 每次读取2帧数据, 以1024个采样点一帧 2通道 16bit采样点为例
#define PCM_BUFFER_SIZE (1024*2*2*2)

// 音频PCM数据缓存
static Uint8 *s_audio_buf = NULL;
// 目前读取的位置
static Uint8 *s_audio_pos = NULL;
// 缓存结束位置
static Uint8 *s_audio_end = NULL;


// 音频设备回调函数
void fill_audio_pcm(void *udata, Uint8 *stream, int len)
{
    SDL_memset(stream, 0, len);

    if(s_audio_pos >= s_audio_end) // 数据读取完毕
    {
        return;
    }

    // 数据够了就读预设长度,数据不够就只读部分(不够的时候剩多少就读取多少)
    int remain_buffer_len = s_audio_end - s_audio_pos;
    len = (len < remain_buffer_len) ? len : remain_buffer_len;
    // 拷贝数据到stream并调整音量
    SDL_MixAudio(stream, s_audio_pos, len, SDL_MIX_MAXVOLUME/8);
    printf("len = %d
", len);
    s_audio_pos += len;  // 移动缓存指针
}

// 提取PCM文件
// ffmpeg -i input.mp4 -t 20 -codec:a pcm_s16le -ar 44100 -ac 2 -f s16le 44100_16bit_2ch.pcm
// 测试PCM文件
// ffplay -ar 44100 -ac 2 -f s16le 44100_16bit_2ch.pcm

#undef main
int main(int argc, char* argv[])
{
    // 1.初始化SDL
    if (SDL_Init(SDL_INIT_AUDIO)) {
        fprintf(stderr, "SDL_Init error: %s
", SDL_GetError());
        return -1;
    }

    // 2.打开PCM文件
    FILE *audio_fd = fopen("44100_16bit_2ch.pcm", "rb");
    if (audio_fd == NULL) {
        printf("fopen pcm file error.
");
        return -1;
    }

    // 3.打开音频设备
    SDL_Audiospec spec;
    spec.freq = 44100;          // 采样频率
    spec.format = AUDIO_S16SYS; // 采样格式
    spec.channels = 2;          // 通道
    spec.silence = 0;           // 静音值
    spec.samples = 1024;        // 采样个数
    spec.callback = fill_audio_pcm;
    spec.userdata = NULL;
    if (SDL_OpenAudio(&spec, NULL)) {
        fprintf(stderr, "SDL_OpenAudio error: %s
", SDL_GetError());
        fclose(audio_fd);
        SDL_Quit();
        return -1;
    }

    // 5.播放音频
    SDL_PauseAudio(0);
    int data_count = 0;
    s_audio_buf = (uint8_t *)malloc(PCM_BUFFER_SIZE);
    while(1) {
        // 读取pcm数据
        size_t len = fread(s_audio_buf, 1, PCM_BUFFER_SIZE, audio_fd);
        if (len == 0) {
            break;
        }
        data_count += len;
        printf("now playing %10d bytes data.
",data_count);
        s_audio_end = s_audio_buf + len;
        s_audio_pos = s_audio_buf;
        while(s_audio_pos < s_audio_end)
        {
            SDL_Delay(10);  // 等待PCM数据消耗
        }
    }

    // 6.关闭音频设备
    printf("play PCM finish
");
    SDL_CloseAudio();

    // 7.退出
    if (s_audio_buf) {
        free(s_audio_buf);
    }
    if (audio_fd) {
        fclose(audio_fd);
    }
    SDL_Quit();
    return 0;
}

 

以上是关于SDL播放PCM音频数据的主要内容,如果未能解决你的问题,请参考以下文章

流媒体开发16SDL-PCM播放

音视频连载-007基础学习篇-SDL 播放 PCM 音频文件(上)

golang调用sdl2,播放pcm音频,报错signal arrived during external code execution。

SDL:升级 OpenAudio 至 OpenAudioDevice 后不能播放音频

如何将 PCM 音频流转换为在线播放

使用音频队列服务通过套接字连接播放 PCM 数据