Android 音視頻之音頻AAC編碼

AAC介紹

介紹
AAC,全稱Advanced Audio Coding具则,是一種專為聲音數(shù)據(jù)設(shè)計的文件壓縮格式稼钩。他的目的是為了取代MP3格式,與MP3不同苟呐,它采用了全新的算法進(jìn)行編碼痒芝,更加高效,具有更高的“性價比”牵素。利用AAC格式严衬,可使人感覺聲音質(zhì)量沒有明顯降低的前提下,更加小巧笆呆。

為什么重點(diǎn)介紹AAC
1.他的應(yīng)用范圍廣请琳。目前市場上泛娛樂化直播系統(tǒng),90%以上都是采用AAC編碼
2.目前的傳輸協(xié)議赠幕,一般采用rtmp協(xié)議俄精,此協(xié)議支持aac,但是不支持OPUS??(因?yàn)镺PUS是最近才推出的榕堰,雖然強(qiáng)竖慧,但是還不通用)
3.AAC本身編解碼器質(zhì)量非常高。作為一種高壓縮比的音頻壓縮算法逆屡,AAC通常壓縮比為18:1??(也有資料說為20:1)圾旨,但是還能保存較好的音質(zhì)。

AAC音頻格式
ADIF (Audio Data Interchange Format)
這種格式只需要在文件開頭存一個很小的頭魏蔗,包括采樣率砍的,采樣大小,聲道數(shù)量等基本信息莺治,就可以對文件進(jìn)行解讀挨约。這種格式只能從頭開始解碼味混,常用在磁盤文件中。
ADTS (Audio Data transport Stream)
這種格式每一幀前面都有一個同步字诫惭,占用7-9個字節(jié),好處是可以在音頻流的任何位置開始解碼蔓挖,他類似于數(shù)據(jù)流格式夕土。因?yàn)槊恳粠懊娑加型阶郑訟DTS文件要比ADIF增加一些數(shù)據(jù)量

AAC產(chǎn)生原因
AAC產(chǎn)生目的就是為了取代MP3瘟判。
AAC之前怨绣,大部分音頻都還是使用MP3格式。MP3的使用規(guī)范是MPEG-2拷获,他對于音頻編解碼篮撑,主要思想還是有損壓縮。有損壓縮在《Android 音視頻之音頻入門講解》也介紹過匆瓜,被壓縮的數(shù)據(jù)不能完全還原回來赢笨,所以音質(zhì)上會有一定損耗。而且在碼率比較高的情況下驮吱,壓縮比要非常高的情況下茧妒,損耗性會非常大。AAC恰巧彌補(bǔ)了這個問題左冬,AAC對原始數(shù)據(jù)損耗很低桐筏,但是壓縮效率很高。
在2000年拇砰,MPEG-4標(biāo)準(zhǔn)出現(xiàn)后梅忌,AAC還加入了SBR技術(shù)和PS技術(shù)。
AAC LC :
LC (Low Complexity) 低復(fù)雜度

AAC HE V1 : AAC LC + SBR
SBR(Spectral Band Replication)是增頻復(fù)用除破。我們知道牧氮,音頻頻帶分為高頻和低頻。所以低頻的20hz皂岔,如果我們采用44.1khz的采樣率蹋笼,就采樣2000次,他就可以完整記錄下模擬聲波躁垛,但是我們沒必要進(jìn)行這么多的采樣剖毯。高頻的20khz,我們采用44.1khz的采樣率教馆,結(jié)果只采樣2次逊谋,這樣保真性就很差。而采用了SBR技術(shù)土铺,SBR把頻譜切割開來胶滋,低頻單獨(dú)編碼保存主要成分板鬓, 高頻單獨(dú)放大編碼保存音質(zhì),這樣高頻就增加了采樣究恤。這樣的好處俭令,一是減少了碼率,二是提高了音頻的質(zhì)量部宿。

AAC HE V2 : AAC + SBR + PS
PS(Parametric Stereo)是雙聲道分別保存抄腔,一個聲道完整保存,另一個只存差異的理张,參數(shù)的部分赫蛇。因?yàn)閮蓚€聲道相關(guān)性非常強(qiáng),我們可以通過某種函數(shù)雾叭,完全恢復(fù)以前的聲音悟耘。基于這些原因织狐,所以他只要存一些參數(shù)就可以了暂幼。


AAC優(yōu)點(diǎn)
①提升的壓縮率:可以以更小的文件大小獲得更高的音質(zhì);
②支持多聲道:可提供最多48個全音域聲道赚瘦;
③更高的解析度:最高支持96KHz的采樣頻率粟誓;
④提升的解碼效率:解碼播放所占的資源更少;

AAC編解碼庫
Libfdk_AAC > ffmpeg AAC > libaac > libvo_aacenc

AAC編碼使用

使用ffmpeg對音頻進(jìn)行AAC編碼

不好意思起意,前段時間想采用ffmpeg去對AAC進(jìn)行編碼鹰服,結(jié)果開發(fā)過程中,發(fā)現(xiàn)ffmpeg avcodec_encode_audio2返回-22揽咕,導(dǎo)致編碼不成功悲酷,一直找不到原因。后期修改好了亲善,我一定在文章和項(xiàng)目中補(bǔ)上设易。

使用MediaCodec對音頻進(jìn)行AAC硬編碼

????????Android中可以使用MediaCodec來訪問底層的媒體編解碼器,可以對媒體進(jìn)行編/解碼。
????????舉例,比如之前文章《Android 音視頻之音頻錄制》哼绑,我們使用AudioRecord錄制了一個pcm文件诅挑。我們要將文件數(shù)據(jù)進(jìn)行AAC編碼始赎,需要先初始化一個MediaCodec對象,設(shè)置他的MediaFormat為MediaFormat.MIMETYPE_AUDIO_AAC。如果想使用其他壓縮編碼,類似讼昆。代碼如下:

    /**
     * 初始化AAC編碼器
     */
    private void initAACMediaEncode() {
        try {
            //參數(shù)對應(yīng)-> mime type、采樣率骚烧、聲道數(shù)
            MediaFormat encodeFormat = MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_AAC, 44100, 2);
            encodeFormat.setInteger(MediaFormat.KEY_BIT_RATE, 64000);//比特率
            encodeFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
            encodeFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 100 * 1024);
            mediaEncode = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AAC);
            mediaEncode.configure(encodeFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
        } catch (IOException e) {
            e.printStackTrace();
        }

        if (mediaEncode == null) {
            Log.e(TAG, "create mediaEncode failed");
            return;
        }

        mediaEncode.start();
        encodeInputBuffers = mediaEncode.getInputBuffers();
        encodeOutputBuffers = mediaEncode.getOutputBuffers();
        encodeBufferInfo = new MediaCodec.BufferInfo();
    }

初始化編碼器后浸赫,將pcm數(shù)據(jù)傳入到下面這個方法中進(jìn)行AAC編碼闰围。

    /**
     * 編碼,得到{@link #encodeType}格式的音頻文件既峡,并保存到{@link #dstPath}
     * @param data
     */
    public void encodeData(byte[] data){
        //dequeueInputBuffer(time)需要傳入一個時間值羡榴,-1表示一直等待,0表示不等待有可能會丟幀涧狮,其他表示等待多少毫秒
        int inputIndex = mediaEncode.dequeueInputBuffer(-1);//獲取輸入緩存的index
        if (inputIndex >= 0) {
            ByteBuffer inputByteBuf = encodeInputBuffers[inputIndex];
            inputByteBuf.clear();
            inputByteBuf.put(data);//添加數(shù)據(jù)
            inputByteBuf.limit(data.length);//限制ByteBuffer的訪問長度
            mediaEncode.queueInputBuffer(inputIndex, 0, data.length, 0, 0);//把輸入緩存塞回去給MediaCodec
        }

        int outputIndex = mediaEncode.dequeueOutputBuffer(encodeBufferInfo, 0);//獲取輸出緩存的index
        while (outputIndex >= 0) {
            //獲取緩存信息的長度
            int byteBufSize = encodeBufferInfo.size;
            //添加ADTS頭部后的長度
            int bytePacketSize = byteBufSize + 7;
            //拿到輸出Buffer
            ByteBuffer  outPutBuf = encodeOutputBuffers[outputIndex];
            outPutBuf.position(encodeBufferInfo.offset);
            outPutBuf.limit(encodeBufferInfo.offset+encodeBufferInfo.size);

            byte[]  targetByte = new byte[bytePacketSize];
            //添加ADTS頭部
            addADTStoPacket(targetByte, bytePacketSize);
            /*
            get(byte[] dst,int offset,int length):ByteBuffer從position位置開始讀炕矮,讀取length個byte,并寫入dst下
            標(biāo)從offset到offset + length的區(qū)域
             */
            outPutBuf.get(targetByte,7,byteBufSize);

            outPutBuf.position(encodeBufferInfo.offset);

            try {
                bos.write(targetByte);
            } catch (IOException e) {
                e.printStackTrace();
            }
            //釋放
            mediaEncode.releaseOutputBuffer(outputIndex,false);
            outputIndex = mediaEncode.dequeueOutputBuffer(encodeBufferInfo, 0);
        }
    }

如果是錄制過程中者冤,可以使用

audioRecord.read(audiodata, 0, bufferSizeInBytes);

方法拉取pcm數(shù)據(jù),把數(shù)據(jù)傳入到編碼方法中档痪,可以一邊錄制一邊編碼涉枫。

如果是已經(jīng)錄制好的pcm文件,同樣可以把文件轉(zhuǎn)換成流數(shù)據(jù)腐螟,再編碼愿汰。

    /**
     * 開始編碼
     * PCM數(shù)據(jù)在編碼成想要得到的{@link #encodeType}音頻格式
     * PCM->aac
     */
    public void startAsync() {
        Log.i(TAG, "start");
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    File file = new File(srcPath);
                    FileInputStream fis = new FileInputStream(file);
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    byte[] b = new byte[1024];
                    int n;
                    while ((n = fis.read(b)) != -1) {
                        bos.write(b, 0, n);
                        encodeData(bos.toByteArray());
                        bos.reset();
                    }
                    fis.close();
                    bos.close();
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

最后可以在目標(biāo)路徑下得到一個編碼格式為aac的文件,可以直接播放乐纸。

如果我們想把m4a衬廷,mp3的文件,進(jìn)行aac編碼汽绢。那就需要進(jìn)行轉(zhuǎn)碼吗跋,我們需要先對其進(jìn)行解碼成pcm數(shù)據(jù),再進(jìn)行編碼宁昭。后面我會在《Android 音視頻之音頻編碼轉(zhuǎn)換》中簡單介紹跌宛。

github項(xiàng)目地址

未完待更新...

上一篇:《Android 音視頻之音頻編碼》
下一篇:《Android 音視頻之音頻編碼轉(zhuǎn)換》

有問題的地方請大家?guī)兔χ赋觯x謝积仗。
持續(xù)更新中...

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末疆拘,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子寂曹,更是在濱河造成了極大的恐慌哎迄,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件隆圆,死亡現(xiàn)場離奇詭異漱挚,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)匾灶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門棱烂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人阶女,你說我怎么就攤上這事颊糜×ㄖ危” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵衬鱼,是天一觀的道長业筏。 經(jīng)常有香客問我,道長鸟赫,這世上最難降的妖魔是什么蒜胖? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮抛蚤,結(jié)果婚禮上台谢,老公的妹妹穿的比我還像新娘。我一直安慰自己岁经,他們只是感情好朋沮,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著缀壤,像睡著了一般樊拓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上塘慕,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天筋夏,我揣著相機(jī)與錄音,去河邊找鬼图呢。 笑死条篷,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的岳瞭。 我是一名探鬼主播拥娄,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼瞳筏!你這毒婦竟也來了稚瘾?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤姚炕,失蹤者是張志新(化名)和其女友劉穎摊欠,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體柱宦,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡些椒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了掸刊。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片免糕。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出石窑,到底是詐尸還是另有隱情牌芋,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布松逊,位于F島的核電站躺屁,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏经宏。R本人自食惡果不足惜犀暑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望烁兰。 院中可真熱鬧耐亏,春花似錦、人聲如沸沪斟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽币喧。三九已至,卻和暖如春袱耽,著一層夾襖步出監(jiān)牢的瞬間杀餐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工朱巨, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留史翘,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓冀续,卻偏偏與公主長得像琼讽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子洪唐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 介紹 AAC(Advanced Audio Coding)钻蹬,中文稱為“高級音頻編碼”,出現(xiàn)于1997年凭需,基于 MP...
    sxyxsp123閱讀 6,850評論 0 7
  • 前言 本篇開始講解在Android平臺上進(jìn)行的音頻編輯開發(fā)问欠,首先需要對音頻相關(guān)概念有基礎(chǔ)的認(rèn)識。所以本篇要講解以下...
    Ihesong閱讀 7,753評論 2 18
  • 音頻技術(shù)開發(fā)粒蜈,我們得對聲音有所了解顺献,掌握音頻的基礎(chǔ)知識,這才能更好地去做技術(shù)開發(fā)枯怖。首先介紹音頻基礎(chǔ)知識注整,然后介紹音...
    安仔夏天勤奮閱讀 7,431評論 3 18
  • 手機(jī)里總是有些不愿刪掉的歌肿轨,也許不再那么喜歡寿冕,可是始終不忍丟棄。 你有沒有改不掉的習(xí)慣萝招,比如說蚂斤,因?yàn)槟臣掳疽梗?..
    長亭微雨閱讀 266評論 0 0
  • 你是否在某段時期槐沼,內(nèi)心感覺極度壓抑曙蒸,辦事處處碰壁不順。人生經(jīng)歷這么些許岗钩,雖然知道以后總會有風(fēng)光精彩纽窟,普希金的假如生...
    蕭能志閱讀 217評論 0 0