音频三元组:通道数(channels,比特率(sample_rate),位深(sample_fmt)
这三个元素转换一个或以上,就叫作重采样。
这里主要讨论48000->44100可能会犯得错误。
swr_convert(asc, dst_ptr, dst_nb_samples, src_ptr, src_nb_samples)
参数依次是重采样配置上下文,接收转换后的数据存储地址,往dst_data存储多少个音频采样,待转换的数据地址,放入转换的音频采样数。
假如说是48000->44100,那么如果放入的src_nb_samples不是48000,那么取出的dst_nb_samples也就不是44100,是多少呢:
44100/48000 = dst_nb_samples/src_nb_samples
另一个问题,假如我用aac压缩音频,aac规定每帧音频只能有1024个采样,如果放入src_nb_samples是1920,那么按照上面的公式dst_nb_samples=1764。但是我每次只取1024个采样,用于压缩aac,那么没取的1764-1024=76个字节放哪里去了呢,会不会丢失呢,它其实放在了swr_convert这个函数维护的一个缓冲区中,当你再次调用swr_convert(asc, dst_ptr, dst_nb_samples, NULL, 0)时,把后两个参数置NULL,0,就会把上次没取完的数据取出dst_nb_samples(如果有这么多的话)个采样,它其实是个队列的原理。
最后一个问题,swr_get_out_samples(…)的返回值是缓冲区中的采样个数,那么这个值是指转换后的采样个数还是转换前的呢,经手动验证是转换前的。其实也就是函数只转换dst_nb_samples个采样输出,剩余的值下次调用再转换。
假如我们想取1024个值,那么应该这样调用:
int fifo_size = swr_get_out_samples(asc, 0); if (fifo_size >= 1115) //x = (1920/1764) * 1024 { int len_left = swr_convert(asc, dst_ptr, dst_nb_samples, NULL, 0) }
意思是48000->44100时,只有缓冲区有1115个采样时,才能得到1024个采样。
当44100->48000时,当送进去1024采样时,理论上会得到1114.5个输出采样,那么我们输出dst_nb_samples参数应该填多少呢,只要大于等于1115,就可以了,实测输出的采样数len = 1115,1114交替输出。
当dst_nb_samples大于理论输出值时,并不会阻塞,等得到dst_nb_samples个采样才输出,而是输出理论值,由len返回获得理论值。
int len = swr_convert(asc, dst_ptr, dst_nb_samples,
src_ptr, src_nb_samples)
补充:
正常人听觉的频率范围大约在20Hz~20kHz之间,
根据奈奎斯特采样理论(2倍),为了保证声音不失真,采样频率应该在40kHz左右。(采样频率必须大于等于音频信号的最大频率的两倍,记住,是最大频率。)
目前语音识别服务只支持16000Hz和8000Hz两种采样率,其中8000Hz一般是电话业务使用,其余都使用16000Hz。 22050
的采样频率是常用的,44100已是CD音质。
44100 Hz - 音频 CD, 也常用于 MPEG-1 音频(VCD,SVCD,MP3)所用采样率 48000 Hz - miniDV、数字电视、DVD、DAT、电影和专业音频所用的数字声音所用采样率 8000 Hz - 电话所用采样率, 对于人的说话已经足够 22050 Hz - 无线电广播所用采样率 引用链接:https://blog.csdn.net/Osean_li/article/details/84107451
出于历史原因,所有CD一律采用44.1KHz,而DVD/BD视频音轨一律采用48KHz。所以不出意外,你听到的那些音乐都是44.1KHz,而你看的视频,它们的音频一般都采用48KHz的采样率。
aac为有损压缩,同时48000->44100的转换对音质也有损伤。
由于人耳听觉范围是20Hz~20kHz,根据香农采样定理(也叫奈奎斯特采样定理),理论上来说采样率大于40kHz的音频格式都可以称之为无损格式。
我们的耳朵听到的频率间隔为20-20KHZ,我们的发声频率为100-3KHZ左右,所以可以看出如果只是单纯的采集发声频率可以使用8KHZ就可以,采样率必须是输入信号最高频率的2倍以上,这样才会最大可能的保存信号信息.故我们的听到的样本的采样率一般都为44.1KHZ及以上.
fdk_aac 支持的音频采样率:7350 8000 11025 12000 16000 22050 24000 32000 44100 48000 64000 88200 96000
fdk_aac 样本类型:只支持16bit pcm输入.
CBR模式:
设置目标码率,当样本之间差异较小时,可以通过该方法更好地控制文件大小,设置每个通道为64kbps.立体声为128kbps
VBR模式:
指定目标质量,而不是码率,质量从1到5由低到高.使用参数-vbr,vbr模式下大致给出了每个通道对应的码率,参考libfdk_aac介绍
首先需要了解的是AAC文件格式有ADIF和ADTS两种,其中ADIF(Audio Data Interchange Format 音频数据交换格式)的特征是解码必须在明确定义的开始处进行,不能从数据流中间开始;而ADTS(Audio Data Transport Stream 音频数据传输流)则相反,这种格式的特征是有同步字,解码可以在这个流中任何位置开始,正如它的名字一样,这是一种和TS流类似的格式。
ADTS格式中每一帧都有头信息,具备流特征,适合于网络传输与处理,而ADIF只有一个统一的头,并且这两种格式的header格式也是不同的。目前主流使用的都是ADTS格式。
正确的说法是不同profile决定了每个aac帧含有多少个sample,具体来说,对应关系如下:
AACENC_GRANULE_LENGTH =
0x0105, /*!< Core encoder (AAC) audio frame length in samples:
- 2048 HE-AAC v1/v2
- 1024: Default configuration.//AAC-LC 1024
- 512: Default length in LD/ELD configuration.
- 480: Length in LD/ELD configuration.
- 256: Length for ELD reduced delay mode (x2).
- 240: Length for ELD reduced delay mode (x2).
- 128: Length for ELD reduced delay mode (x4).
- 120: Length for ELD reduced delay mode (x4). */
其中LC即Low Complexity,HE即High Efficiency,注意,其中数据表示单通道的采样数,如1024,表示单通道每秒采样1024帧。每次送入编码器的数据必须是上述设定或默认的数据,如果不是的话会在缓冲区中暂存,然后够了之后再送进去。
声道数:
0: Defined in AOT Specifc Config
1: 1 channel: front-center
2: 2 channels: front-left, front-right
3: 3 channels: front-center, front-left, front-right
4: 4 channels: front-center, front-left, front-right, back-center
5: 5 channels: front-center, front-left, front-right, back-left, back-right
6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel
7: 8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel
8-15: Reserved
SwrContext * asc = NULL; asc = swr_alloc_set_opts(asc, AV_CH_LAYOUT_STEREO, (AVSampleFormat)a_frame->format, a_frame->sample_rate, AV_CH_LAYOUT_STEREO, (AVSampleFormat)a_frame->format, 48000, 0, 0); if (!asc) { printf("swr_alloc_set_opts failed!\n"); return -1; } int ret_asc = swr_init(asc); if (ret_asc != 0) { printf("swr_init failed!\n"); char err[1024] = {0}; av_strerror(ret_asc, err, sizeof(err) - 1); return -1; } int fifo_size_1 = swr_get_out_samples(asc, 0); int len = swr_convert(asc, a_frame->data, a_frame->nb_samples, indata, frame_num); if (len >= 1024) {//.... } /* int fifo_size_2 = swr_get_out_samples(asc, 0); if (fifo_size_2 >= 1115) //x = (1920/1764) * 1024 { int len_left = swr_convert(asc, a_frame->data, a_frame->nb_samples, NULL, 0); if (len_left >= 1024) {//... } } */