首先:音频的解码和视频的解码流程是一样的。
1.找到音频流:
audioStream = -1;
for (i = 0; i < pFormatCtx->nb_streams; i++) {
if (pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO
&& audioStream < 0) {
audioStream = i;
}
}
if (audioStream == -1)
return -1;
2.找到音频编解码器:
aCodecCtx=pFormatCtx->streams[audioStream]->codec;
3.需要用到SDL播放音频。这里用到SDL_AudioSpec结构体。
SDL_AudioSpec是包含音频输出格式的结构体:
typedef struct{
int freq;
Uint16 format;
Uint8 channels;
Uint8 silence;
Uint16 samples;
Uint32 size;
void (*callback)(void *userdata, Uint8 *stream, int len);
void *userdata;
} SDL_AudioSpec;
int | freq | 采样率。可选为11025(11.025KHZ), 22050(22.05KHZ) 和44100(44.1KHZ)。数值越高越好。44.1KHZ是理论上的CD音质界限。 |
SDL_AudioFormat | format | 音频数据格式;format 告诉SDL我们将要给的格式。在“S16SYS”中的S表示有符号的signed,16表示每个样本是16位长的,SYS表示大小头的顺序是与使用的系统相同的。这些格式是由avcodec_decode_audio2为我们给出来的输入音频的格式。 |
Uint8 | channels | 声音的通道数 1 单声道, 2 立体声; |
Uint8 | silence | 表示静音的值。因为声音采样是有符号的,所以0当然就是这个值。 |
Uint16 | samples | audio buffer size in samples (power of 2); 详情参考“讨论” |
Uint32 | size | 音频缓存区大小(字节数),当我们想要更多声音的时候,我们想让SDL给出来的声音缓冲区的尺寸。一个比较合适的值在512到8192之间;ffplay使用1024。 |
SDL_AudioCallback | callback | 当音频设备需要更多数据时调用的回调函数; |
void* | userdata | 这个是SDL供给回调函数运行的参数。我们将让回调函数得到整个编解码的上下文信息; |
4.打开音频设备:
if (SDL_OpenAudio(&wanted_spec, &spec) < 0) {
fprintf(stderr, "SDL_OpenAudio: %s/n", SDL_GetError());
return -1;
}
5.avcodec_decode_audio4()解码输出后的音频采样数据格式为AV_SAMPLE_FMT_FLTP,但是SDL能直接识别的格式为AV_SAMPLE_FMT_S16。解决方式是:
int out_linesize;
//输出内存大小
int out_buffer_size=av_samples_get_buffer_size(&out_linesize, pCodecCtx->channels,pCodecCtx->frame_size,pCodecCtx->sample_fmt, 1);
uint8_t *out_buffer=new uint8_t[out_buffer_size];
...
au_convert_ctx = swr_alloc();
au_convert_ctx=swr_alloc_set_opts(au_convert_ctx,AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16, 44100,
pCodecCtx->channel_layout,pCodecCtx->sample_fmt , pCodecCtx->sample_rate,0, NULL);
swr_init(au_convert_ctx);
while(av_read_frame(pFormatCtx, packet)>=0){
......
swr_convert(au_convert_ctx,&out_buffer, out_linesize,(const uint8_t **)pFrame->data , pFrame->nb_samples);
......
}
可以参考这篇文章:
int | freq | 采样率 |
SDL_AudioFormat | format | 音频数据格式;format 告诉SDL我们将要给的格式。在“S16SYS”中的S表示有符号的signed,16表示每个样本是16位长的,SYS表示大小头的顺序是与使用的系统相同的。这些格式是由avcodec_decode_audio2为我们给出来的输入音频的格式。 |
Uint8 | channels | 声音的通道数 1 单声道, 2 立体声; |
Uint8 | silence | 表示静音的值。因为声音采样是有符号的,所以0当然就是这个值。 |
Uint16 | samples | audio buffer size in samples (power of 2); 详情参考“讨论” |
Uint32 | size | 音频缓存区大小(字节数),当我们想要更多声音的时候,我们想让SDL给出来的声音缓冲区的尺寸。一个比较合适的值在512到8192之间;ffplay使用1024。 |
SDL_AudioCallback | callback | 当音频设备需要更多数据时调用的回调函数; |
void* | userdata | 这个是SDL供给回调函数运行的参数。我们将让回调函数得到整个编解码的上下文信息; |