前言
SDL_AudioSpec是包含音频输出格式的结构体,同时它也包含当音频设备需要更多数据时调用的回调函数。
解析
头文件说明
typedef struct SDL_AudioSpec
{
int freq; /**< DSP frequency -- samples per second */
SDL_AudioFormat format; /**< Audio data format */
Uint8 channels; /**< Number of channels: 1 mono, 2 stereo */
Uint8 silence; /**< Audio buffer silence value (calculated) */
Uint16 samples; /**< Audio buffer size in sample FRAMES (total samples divided by channel count) */
Uint16 padding; /**< Necessary for some compile environments */
Uint32 size; /**< Audio buffer size in bytes (calculated) */
SDL_AudioCallback callback; /**< Callback that feeds the audio device (NULL to use SDL_QueueAudio()). */
void *userdata; /**< Userdata passed to callback (ignored for NULL callbacks). */
} SDL_AudioSpec;
freq采样率
指定了每秒向音频设备发送的sample数。常用的值为:11025,22050,44100。值越高质量越好。
format音频数据格式
format 告诉SDL我们将要给的格式。在“S16SYS”中的S表示有符号的signed,16表示每个样本是16位长的,SYS表示大小头的顺序是与使用的系统相同的。这些格式是由avcodec_decode_audio2为我们给出来的输入音频的格式。
channels声音的通道数
1 单声道, 2 立体声;
silence 表示静音的值
因为声音采样是有符号的,所以0当然就是这个值
size 音频缓存区大小(字节数)
当我们想要更多声音的时候,我们想让SDL给出来的声音缓冲区的尺寸。一个比较合适的值在512到8192之间;ffplay使用1024
samples音频缓冲区中的采样个数(详细说明)
这个决定了回调len的长度,len=samples*chn*位宽(单位是字节)
摘自WIKI
samples specifies a unit of audio data. When used with SDL_OpenAudioDevice() this refers to the size of the audio buffer in sample frames. A sample frame is a chunk of audio data of the size specified in format multiplied by the number of channels. When the SDL_AudioSpec is used with SDL_LoadWAV() samples is set to 4096. This field's value must be a power of two.
理解
实际上该值是每次读取的采样数量,多久产生一次回调
例如
// 音频参数设置SDL_AudioSpec
spec.freq = 44100; // 采样频率
spec.format = AUDIO_S16SYS; // 采样点格式
spec.channels = 2; // 2通道
spec.silence = 0;
spec.samples = 1024; // 23.2ms -> 46.4ms 每次读取的采样数量,多久产生一次回调
spec.callback = fill_audio_pcm; // 回调函数
spec.userdata = NULL;
疑问
audio buffer size in samples (power of 2); 详情参考“讨论”
析疑
实际上针对AAC,M4a采样个数设置为1024,针对MP2,MP3,WMA采样个数设置为1152,不一定是2的幂指数次方,该值最好由AVFrame->nb_samples参数赋值
例子
wanted_spec.freq = aCodecCtx->sample_rate;
wanted_spec.format = AUDIO_S16SYS;
wanted_spec.channels = aCodecCtx->channels;
wanted_spec.silence = 0;
wanted_spec.samples = AVFrame->nb_samples;
wanted_spec.callback = audio_callback;
wanted_spec.userdata = aCodecCtx;