音视频开发二十:PCM音频播放器

逻辑流程

#include <stdio.h>
#include <libavutil/log.h>
#include <libavutil/avutil.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include <SDL.h>
#include <stdbool.h>





#define BLOCK_SIZE  4096000
static Uint8* audio_buf = NULL;
static Uint8* audio_pos = NULL;
static size_t buffer_len = 0;
static size_t read_buffer_len = 0;

// 音频播放的回调函数 udata是传递的回调参数,stream是音频设备需要播放缓冲区数据的缓冲区指针,len是需要填充的是数据长度。
void read_audio_data(void* udata, Uint8* stream, int len) {

    if (buffer_len == 0) {// 表示没有数据
        return;
    }

    SDL_memset(stream, 0, len);// 清空SDL的缓冲区,防止之前遗留的数据与现在的数冲突,防止对音质有影响

    // 计算从pcm文件中读取的字节长度和创缓冲区中长度作对比,取 小值
    len = (len < buffer_len) ? len : buffer_len;
    printf("read_audio_data len=%d\n", len);
    SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME);

    audio_pos += len;  // 播放的数据在自己缓冲区的位置
    printf("read_audio_data audio_pos=%d\n", audio_pos);
    buffer_len -= len; // 从本次pcm文件中获取的数据还剩多少没有播放完

}


int pcm_player() {

    int ret = -1;

    FILE* audio_fd = NULL;

    SDL_AudioSpec spec;

    char* path = "F:\\test_data\\crop_jiuzhe_summer.pcm";

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

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

    //分配内存用保存从pcm文件中读取的数据
    audio_buf = (Uint8*)malloc(BLOCK_SIZE);
    if (!audio_buf) {
        goto __FAIL;
    }

    //SDL_AudioSpec 设置播放音频的规格参数 才知道怎么播 
    spec.freq = 48000;
    spec.format = AUDIO_S16SYS;
    spec.channels = 2;
    spec.silence = 0;
    spec.samples = 1024;
    spec.callback = read_audio_data;;
    spec.userdata = NULL;

    //打开音频设备
    if (SDL_OpenAudio(&spec, NULL)) {
        fprintf(stderr, "Failed to open audio device, %s\n", SDL_GetError());
        goto __FAIL;
    }

    //play audio 播放音频开始触发回调函数
    SDL_PauseAudio(0);

    // 从pcm文件读取数据到自己的缓冲区里面
    do {
        //read data from pcm file
        // read_buffer_len 读取数据的长度
        read_buffer_len = fread(audio_buf, 1, BLOCK_SIZE, audio_fd);
        buffer_len = read_buffer_len;
        audio_pos = audio_buf;


        //the main thread wait for a moment


        while (audio_pos < (audio_buf + read_buffer_len)) {
            SDL_Delay(1);
        }

        printf("main buffer_len %d\n", read_buffer_len);

    } while (read_buffer_len);// read_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;
}

猜你喜欢

转载自blog.csdn.net/qq_38056514/article/details/130190883