逻辑流程
#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;
}