一帕识、音頻基礎(chǔ)知識(shí)
-
【通道數(shù)】
即聲音的通道的數(shù)目泛粹。常有單聲道和立體聲之分,單聲道的聲音只能使用一個(gè)喇叭發(fā)聲(有的也處理成兩個(gè)喇叭輸出同一個(gè)聲道的聲音)肮疗,立體聲可以使兩個(gè)喇叭都發(fā)聲(一般左右聲道有分工) ,更能感受到空間效果扒接,當(dāng)然還有更多的通道數(shù)伪货。
-
【采樣頻率】
采樣頻率即取樣頻率, 指每秒鐘取得聲音樣本的次數(shù)。采樣頻率越高,聲音的質(zhì)量也就越好,聲音的還原也就越真實(shí)钾怔,但同時(shí)它占的資源比較多碱呼。由于人耳的分辨率很有限,太高的頻率并不能分辨出來。22050 的采樣頻率是常用的, 44100已是CD音質(zhì), 超過48000或96000的采樣對(duì)人耳已經(jīng)沒有意義宗侦。
根據(jù)奈奎斯特采樣定理愚臀,當(dāng)采樣頻率fs.max大于信號(hào)中最高頻率fmax的2倍時(shí)(fs.max>2fmax),采樣之后的數(shù)字信號(hào)完整地保留了原始信號(hào)中的信息矾利。我們?nèi)硕梢月牭降穆曇纛l率在20Hz-220KHz之間的聲波姑裂,所以我們做音頻采樣時(shí)一般采用22000 * 2 + 100 = 44100 Hz(多采100Hz的偏差)
-
【采樣位數(shù)】
采樣位數(shù)即采樣值或取樣值(就是將采樣樣本幅度量化)。它是用來衡量聲音波動(dòng)變化的一個(gè)參數(shù)男旗,也可以說是聲卡的分辨率舶斧。它的數(shù)值越大,分辨率也就越高察皇,所發(fā)出聲音的能力越強(qiáng)茴厉。
每個(gè)采樣數(shù)據(jù)記錄的是振幅, 采樣精度取決于采樣位數(shù)的大小: 1 字節(jié)(也就是8bit) 只能記錄 256 個(gè)數(shù), 也就是只能將振幅劃分成 256 個(gè)等級(jí); 2 字節(jié)(也就是16bit) 可以細(xì)到 65536 個(gè)數(shù), 這已是 CD 標(biāo)準(zhǔn)了; 4 字節(jié)(也就是32bit) 能把振幅細(xì)分到 4294967296 個(gè)等級(jí), 實(shí)在是沒必要了.
-
【音頻播放】
原生的音頻格式為pcm,即我們平時(shí)的.MP3等音頻封裝格式文件最終到喇叭播放時(shí)已經(jīng)將其轉(zhuǎn)碼為pcm格式的音頻數(shù)據(jù)什荣,pcm的音頻數(shù)據(jù)體積比壓縮格式要大很多倍矾缓。
二、本地音頻轉(zhuǎn)碼成pcm輸出到文件
extern "C" {
//封裝格式
#include "libavformat/avformat.h"
//解碼
#include "libavcodec/avcodec.h"
//縮放
#include "libswscale/swscale.h"
//重采樣
#include "libswresample/swresample.h"
};
/**
* 將本地音頻文件轉(zhuǎn)碼為pcm格式并保存到一個(gè)新文件上
* input: 本地音頻文件路徑
* output:轉(zhuǎn)換后的硬盤存儲(chǔ)路徑
*/
void musicPlayer(const char *input,const char *output){
av_register_all();
AVFormatContext *pFormatCtx = avformat_alloc_context();
//打開音頻文件
if (avformat_open_input(&pFormatCtx, input, NULL, NULL) != 0) {
LOGI("%s", "無法打開音頻文件");
return;
}
//獲取輸入文件信息
if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
LOGI("%s", "無法獲取輸入文件信息");
return;
}
//獲取音頻流索引位置
int i = 0, audio_stream_idx = -1;
for (; i < pFormatCtx->nb_streams; i++) {
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
audio_stream_idx = i;
break;
}
}
//獲取解碼器
AVCodecContext *codecCtx = pFormatCtx->streams[audio_stream_idx]->codec;
AVCodec *codec = avcodec_find_decoder(codecCtx->codec_id);
//打開解碼器
if (avcodec_open2(codecCtx, codec, NULL) < 0) {
LOGI("%s", "無法打開解碼器");
return;
}
//壓縮數(shù)據(jù)
AVPacket *packet = (AVPacket *) av_malloc(sizeof(AVPacket));
//解壓縮數(shù)據(jù)
AVFrame *frame = av_frame_alloc();
//frame->16bit 44100 PCM 統(tǒng)一音頻采樣格式與采樣率
SwrContext *swrContext = swr_alloc();
//音頻格式 重采樣設(shè)置參數(shù)
AVSampleFormat in_sample = codecCtx->sample_fmt;//原音頻的采樣位數(shù)
//輸出采樣格式
AVSampleFormat out_sample = AV_SAMPLE_FMT_S16;//16位
int in_sample_rate = codecCtx->sample_rate;// 輸入采樣率
int out_sample_rate = 44100;//輸出采樣
//輸入聲道布局
uint64_t in_ch_layout = codecCtx->channel_layout;
//輸出聲道布局
uint64_t out_ch_layout = AV_CH_LAYOUT_STEREO;//2通道 立體聲
/**
* struct SwrContext *swr_alloc_set_opts(struct SwrContext *s,
int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate,
int64_t in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate,
int log_offset, void *log_ctx);
*/
swr_alloc_set_opts(swrContext, out_ch_layout, out_sample, out_sample_rate, in_ch_layout, in_sample,
in_sample_rate, 0, NULL);
swr_init(swrContext);
int got_frame = 0;
int ret;
int out_channerl_nb = av_get_channel_layout_nb_channels(out_ch_layout);
LOGE("聲道數(shù)量%d ", out_channerl_nb);
int count = 0;
//設(shè)置音頻緩沖區(qū)間 16bit 44100 PCM數(shù)據(jù)
uint8_t *out_buffer = (uint8_t *) av_malloc(2 * 44100);
FILE *fp_pcm = fopen(output, "wb");//輸出到文件
while (av_read_frame(pFormatCtx, packet) >= 0) {
ret = avcodec_decode_audio4(codecCtx, frame, &got_frame, packet);
LOGE("正在解碼%d", count++);
if (ret < 0) {
LOGE("解碼完成");
}
//解碼一幀
if (got_frame > 0) {
/**
* int swr_convert(struct SwrContext *s, uint8_t **out, int out_count,
const uint8_t **in , int in_count);
*/
swr_convert(swrContext, &out_buffer, 2 * 44100,
(const uint8_t **) frame->data, frame->nb_samples);
/**
* int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples,
enum AVSampleFormat sample_fmt, int align);
*/
int out_buffer_size = av_samples_get_buffer_size(NULL, out_channerl_nb, frame->nb_samples,
out_sample, 1);
fwrite(out_buffer, 1, out_buffer_size, fp_pcm);//輸出到文件
}
}
fclose(fp_pcm);
av_frame_free(&frame);
av_free(out_buffer);
swr_free(&swrContext);
avcodec_close(codecCtx);
avformat_close_input(&pFormatCtx);
}