安卓錄製MP3(一) - 數字音頻基礎 數字音頻基礎 MP3編碼

在安卓上實現錄音功能有兩種方式使用AudioRecord錄製PCM裸流,或者用MediaRecorder錄製編碼後的音頻流。但是MediaRecorder的編碼格式並不包括MP3格式:

/**
 * Defines the audio encoding. These constants are used with
 * {@link MediaRecorder#setAudioEncoder(int)}.
 */
public final class AudioEncoder {
    /* Do not change these values without updating their counterparts
     * in include/media/mediarecorder.h!
     */
    private AudioEncoder() {}
    public static final int DEFAULT = 0;
    /** AMR (Narrowband) audio codec */
    public static final int AMR_NB = 1;
    /** AMR (Wideband) audio codec */
    public static final int AMR_WB = 2;
    /** AAC Low Complexity (AAC-LC) audio codec */
    public static final int AAC = 3;
    /** High Efficiency AAC (HE-AAC) audio codec */
    public static final int HE_AAC = 4;
    /** Enhanced Low Delay AAC (AAC-ELD) audio codec */
    public static final int AAC_ELD = 5;
    /** Ogg Vorbis audio codec (Support is optional) */
    public static final int VORBIS = 6;
    /** Opus audio codec */
    public static final int OPUS = 7;
}

所以如果想要將錄製的音頻保存成MP3,就需要我們自行對PCM裸流進行編碼。常用的是LAME庫去編碼,不過在學習怎樣使用LAME之前我們先稍微瞭解下數字音頻的一些基礎知識。

數字音頻基礎

我們都知道聲音是一種波:

它在時間上是連續的,如果我們想把他保存成2進制的音頻數據,就只能隔一段時間對這個波形進行一次採樣,讀取那個時刻聲波的具體數值:

採樣率

採樣的間隔越短,就越接近原始的音波,錄製下來的音質也就越好。一般我們不直接用採樣間隔,而是使用採樣率來描述。採樣率代表一秒鐘採樣的次數,單位爲Hz。例如8000 Hz就代表1秒鐘採樣8000次。所以採樣率越高採樣間隔就越短。

常見的採樣率有8000Hz、11025Hz、32000Hz 、44100Hz等。根據奈奎斯特定理(也稱爲採樣定理, 根據奈奎斯特定理(也稱爲採樣定理),當採樣頻率大於信號中最高頻率的2倍時,採樣之後的數字信號完整地保留了原始信號中的信息。由於人耳能聽到的聲音頻率爲20Hz~20000Hz,所以採樣率一般會使用44100Hz

AudioFormat

AudioFormat代表我們可以用8bit、16bit或者一個浮點數去保存每一次採樣獲取的數字:

/** Audio data format: PCM 16 bit per sample. Guaranteed to be supported by devices. */
public static final int ENCODING_PCM_16BIT = 2;

/** Audio data format: PCM 8 bit per sample. Not guaranteed to be supported by devices. */
public static final int ENCODING_PCM_8BIT = 3;

/** Audio data format: single-precision floating-point per sample */
public static final int ENCODING_PCM_FLOAT = 4;

通道數

由於左右耳朵聽到的聲音並不完全一樣,所以常見的pcm流會有左右兩個通道的數據,意味着我們可以從中拆分出兩條音波曲線分別播放給左右耳朵:

/**
 * 單通道
 */
public static final int CHANNEL_IN_MONO = CHANNEL_IN_FRONT;

/**
 * 雙通道
 */
public static final int CHANNEL_IN_STEREO = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT);

PCM大小計算

假設我們錄製44100Hz、16bit、雙通道的音頻數據:

  • 1秒鐘的數據大小爲 44100 * 16 * 2 = 1411200 bit = 176400 byte = 172 KB
  • 1分鐘的數據大小爲 172 * 60 = 10320 KB = 10 MB

MP3編碼

從上面的計算我們可以得知,如果直接使用PCM裸流去保存,一首歌大約三到五分鐘就有30~50MB。這樣的數據量的確過於龐大了,所以我們對其進行壓縮編碼得到AAC、MP3、Ogg等格式的音頻文件。

這篇文章就只介紹MP3格式,在MP3裏面有個很重要的概念是bitrate(比特率),它代表的是1秒鐘的音頻MP3格式需要用多少bit去表示,單位爲bps(Bit Per Second)或者kbps(1kbps = 1000bps)。

mp3的比特率默認是128kbps,也就是說這種比特率的MP3文件:

  • 1秒鐘的數據大小爲 128000 bit = 16000 byte = 15 KB
  • 1分鐘的數據大小爲 15 * 60 = 240 KB

CBR

MP3中常用固定比特率CBR(Constant Bit-Rate)去進行壓縮,這種類型的mp3每一幀的比特率都是固定的。

CBR由於每秒的bit數是固定的:

  1. 音頻時長可以通過文件大小計算 - 時長 = (文件大小 - 文件頭大小) / bitrate
  2. seek操作容易實現 - 文件位置 = 文件頭大小 + 目標時間 * bitrate

但是一般來講一個聲音片段音調越高,代表它的頻率越高,數據就越密集,壓縮之後的大小也就越大。相反如果一個聲音音調低,理論上我們壓縮之後他的數據大小會越小。但是由於我們使用了固定的bitrate,那麼在低音部分就會有部分的數據冗餘。

VBR

可變比特率VBR(Variable Bit-Rate)就很好的解決了這個這個數據冗餘問題,這種類型每一幀的比特率是不固定的,在數據複雜的地方bitrate高,在數據簡單的地方bitrate低。它的好處顯而易見是可以節約更多的空間。但是也有下面缺點:

  1. 音頻時長需要額外的字段去保存,或者解析整個MP3文件去計算
  2. seek操作複雜,需要保存關鍵時間點的文件位置,然後進行計算和插值

ABR

MP3格式還存在一種平均比特率ABR(Average Bit-Rate)的編碼,它大多數音頻幀以固定bitrate編碼,但會在個別的幀使用高bitrate編碼。但是通常這些幀一般比較少,所以在文件大小上跟CBR相比沒有太大的差異,因此這種類型並不常見。

MP3幀長度

上面其實也有提到MP3的幀,在不同的規範中每一幀包含的採樣點數量是不一樣的:

MPEG 1 MPEG 2 (LSF) MPEG 2.5 (LSF)
Layer I 384 384 384
Layer II 1152 1152 1152
Layer III 1152 576 576

以常見的Layer II爲例子,假設採樣率爲44100Hz,一秒鐘有44100個採樣點,一幀只包含1152個,那麼:

一幀的時長 = 1152 / 44100 = 0.02608s = 26.08ms

這也是MP3一幀26ms的由來

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章