sdl实战--播放pcm音频

ffmpeg是音视频必备,感兴趣添加笔者VX:YQW1163720468,加入ffmpegVX群讨论。备注:ffmpeg爱好者

流程:
打开音频设备->给设备设置音频参数->向声卡喂pcm 数据->播放音频->关闭设备

设置音频参数,包括声道,采样率,位深,使得设备知道怎么播放这些音频

播放音频的基本原则:
1.声卡向你要数据而不是你主动推给声卡,无论使用sdl还是其他库都是这样,这是声卡的工作原理。当声卡需要数据时它会调用回调函数,来向我们要数据。我们要写这个回调函数。
2.每次要的数据大小由之前设置的音频参数决定。且声卡会维护一个缓冲区,用来存放接收的数据。

SDL_OpenAudio()/SDL_CloseAudio() //打开音频设备和关闭音频设备
SDL_PauseAudio() //暂停或播放,有两个状态
SDL_MixAudio //混音,多路音频叠加,要注意值越界带来的失真。

每次从文件中读取4M的pcm放在缓冲区buf,声卡缓冲区不足时调用回调函数从buf中读取,若buf被读完数据,则再次去文件中读取4M,直到文件中的数据被读取完毕。
推荐一套音视频免费课程,笔者听完了,nice!免费报名可听!

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

#define BLOCK_SIZE 4096000

static Uint8 *audio_buf = NULL;
static Uint8 *audio_pos = NULL;
static size_t buffer_len = 0;

//callback function for audio devcie
void read_audio_data(void *udata, Uint8 *stream, int len){

    if(buffer_len == 0){
        return;
    }

    SDL_memset(stream, 0, len);

    len = (len < buffer_len) ? len : buffer_len;
    SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME);

    audio_pos += len;
    buffer_len -= len;
}


int main(int argc, char *argv[])
{
    int ret = -1;

    FILE *audio_fd = NULL;

    SDL_AudioSpec spec;

    char *path = "./test.pcm";

    //SDL initialize
    if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)){
        fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
        return ret;
    }

    //open pcm file
    audio_fd = fopen(path, "r");
    if(!audio_fd){
        fprintf(stderr, "Failed to open pcm file!\n");
        goto __FAIL;
    }

    //alloc memory for audio
    audio_buf = (Uint8*)malloc(BLOCK_SIZE);
    if(!audio_buf){
        goto __FAIL;
    }

    //SDL_AudioSpec
    spec.freq = 44100;
    spec.format = AUDIO_S16SYS;
    spec.channels = 2;
    spec.silence = 0;
    spec.samples = 2048;
    spec.callback = read_audio_data;
    spec.userdata = NULL;

    //open audio devcie
    if(SDL_OpenAudio(&spec, NULL)){
        fprintf(stderr, "Failed to open audio device, %s\n", SDL_GetError());
        goto __FAIL;
    }

    //play audio
    SDL_PauseAudio(0);//此时已启动线程,开始调用回调函数从缓冲区读取数据,并且播放。

    do{
        //read data from pcm file
        buffer_len = fread(audio_buf, 1, BLOCK_SIZE, audio_fd);
        fprintf(stderr, "block size is %zu\n", buffer_len);

        audio_pos = audio_buf;

        //the main thread wait for a moment
        while(audio_pos < (audio_buf + buffer_len)) {
            SDL_Delay(1);//主线程每隔1ms检查一下audio_buf中的数据是否已被回调函数读取完毕。
        }

    }while(buffer_len !=0);

    //close audio device
    SDL_CloseAudio();

    ret = 0;

__FAIL:
    //release some resources
    if(audio_buf){
        free(audio_buf);
    }

    if(audio_fd){
        fclose(audio_fd);
    }

    //quit SDL
    SDL_Quit();

    return ret;
}

//这个程序还有一个小问题,就是最后一次从文件中读取的内容可能还没来得及全部被回调函数读完,程序就停止了。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

、、、、南山小雨、、、、

分享对你有帮助,打赏一下吧!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值