1. 程式人生 > >多媒體開發(12):解碼aac到wav檔案

多媒體開發(12):解碼aac到wav檔案

簡單來說,aac是一種音訊編碼格式,需要解碼後才能用於音訊輸出。aac編碼格式,已經是一種很常見的音訊編碼格式,以至於很多系統都支援aac的編解碼,比如iOS上的AudioConverterRef介面、Android上的MediaCodec介面等。

但是,不要以為用了系統的介面就是用了硬體解碼,因為,這個系統介面有可能最終還是使用軟體解碼,比如有些手機(比如小米)的MediaCodec對於acc的解碼,就是軟解碼,用的是google提供的OMX.google.aac.decoder,不要以為用了系統介面解碼的速度就飛快了,要真是硬體支援才行的。

那什麼是硬解碼,什麼是軟解碼呢?很簡單,如果硬體晶片專門來做解碼,就是硬解碼,比如使用GPU或DSP之類的模組來處理解碼就是硬解碼(一般不會使用CPU),這需要硬體上的支援。而軟解碼就是用軟體來解碼了,就相當你寫一個程式來解碼,使用CPU來做事。優缺點方面,硬解速度快功耗低但相容性差,軟解速度慢功耗高但相容性好。

但話說回來,不是非得要硬解碼的,對於音訊來說,當今的手機,除非你要大量的音效運算或合成處理,否則一般的解碼,用軟解碼就足夠了,根本就不需要硬解,硬解是視訊的事情。

對於aac的解碼,使用FFmpeg也是一個選擇,但如果只為了解碼aac而用FFmpeg,就有點大材小用了,要應對比較複雜的介面呼叫,另外FFmpeg體積也比較大(即便裁剪後可以使FFmpeg編譯出來的庫小很多),那麼,是否有更加簡單一點的解碼庫可以使用呢?

這個開源庫就是faad。

本文講解使用faad,把aac音訊解碼成pcm資料,並以wav來封裝。 pcm資料,簡單來說就是未經壓縮的音訊資料,可以直接交給音訊輸出模組(比如揚聲器)進行播放,而wav檔案一般存放pcm資料。

(1)下載faad

git clone git://git.code.sf.net/p/faac/faad2 faac-faad2

檔案結構大概是這樣的:

這個開源專案,似乎一直有維護與更新(請以最新的為準):

(2)編譯faad

執行以下指令,生成configure配置檔案,以及makefile編譯指令碼,然後,再make出faad的庫檔案。

aclocal
autoconf
autoheader
libtoolize --force 
automake --add-missing
./configure
make

由於只考慮在macos(因為我的是macos)上執行,而且是在mac系統上編譯,所以confiure時並不需要指定特定的引數。

以上命令,使用automake來生成編譯指令碼(makefile),如果你發現這類指令執行不了,那有可能還沒有正確安裝,可以查閱相關的知識,也可以參考以下的內容,這是小程在網上摘錄到的內容:


====install autoconf and automake(摘錄)
curl -O http://mirrors.kernel.org/gnu/m4/m4-1.4.13.tar.gz
tar -xzvf m4-1.4.13.tar.gz
cd m4-1.4.13
./configure --prefix=/usr/local
make
sudo make install
cd ..
curl -O http://mirrors.kernel.org/gnu/autoconf/autoconf-2.65.tar.gz
tar -xzvf autoconf-2.65.tar.gz
cd autoconf-2.65
./configure --prefix=/usr/local # ironic, isn't it?
make
sudo make install
cd ..
# here you might want to restart your terminal session, to ensure the new autoconf is picked up and used in the rest of the script
curl -O http://mirrors.kernel.org/gnu/automake/automake-1.11.tar.gz
tar xzvf automake-1.11.tar.gz
cd automake-1.11
./configure --prefix=/usr/local
make
sudo make install
cd ..
curl -O http://mirrors.kernel.org/gnu/libtool/libtool-2.2.6b.tar.gz
tar xzvf libtool-2.2.6b.tar.gz
cd libtool-2.2.6b
./configure --prefix=/usr/local
make
sudo make install

最終,生成faad庫檔案:

通過lipo來檢視庫檔案支援的指令集:

(3)呼叫faad

這裡演示一下,把一個aac檔案解碼成pcm資料,並用wav容器來封裝。

demo的檔案結構:

demo的程式碼:

#include "libfaad/include/faad.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct WavFileHeader
{
    char        id[4];          // should always contain "RIFF"
    int     totallength;    // total file length minus 8
    char        wavefmt[8];     // should be "WAVEfmt "
    int     format;         // 16 for PCM format
    short     pcm;            // 1 for PCM format
    short     channels;       // channels
    int     frequency;      // sampling frequency
    int     bytes_per_second;
    short     bytes_by_capture;
    short     bits_per_sample;
    char        data[4];        // should always contain "data"
    int     bytes_in_data;
};
void write_wav_header(FILE* file, int totalsamcnt_per_channel, int samplerate, int channels){
    struct WavFileHeader filler;
    strcpy(filler.id, "RIFF");
    filler.bits_per_sample = 16;
    filler.totallength = (totalsamcnt_per_channel * channels * filler.bits_per_sample/8) + sizeof(filler) - 8; //81956
    strcpy(filler.wavefmt, "WAVEfmt ");
    filler.format = 16;
    filler.pcm = 1;
    filler.channels = channels;
    filler.frequency = samplerate;
    filler.bytes_per_second = filler.channels * filler.frequency * filler.bits_per_sample/8;
    filler.bytes_by_capture = filler.channels*filler.bits_per_sample/8;
    filler.bytes_in_data = totalsamcnt_per_channel * filler.channels * filler.bits_per_sample/8;    
    strcpy(filler.data, "data");
    fwrite(&filler, 1, sizeof(filler), file);
}

int main(int argc, char *argv[])
{
    printf("hello faad\n");
    NeAACDecHandle faadhandle = NeAACDecOpen();
    if (faadhandle) {
        printf("aacopen ok\n"); 
        const char* aacfile = "aac20s.aac";
        FILE* file = fopen(aacfile, "rb");
        if (file) {
            printf("fopen aac ok\n");
            fseek(file, 0, SEEK_END);
            long filelen = ftell(file);
            fseek(file, 0, SEEK_SET);
            unsigned char* filebuf = (unsigned char*)malloc(filelen);
            int len = fread(filebuf, 1, filelen, file);
            fclose(file);
            unsigned long samplerate = 0;
            unsigned char channel = 0;
            int ret = NeAACDecInit(faadhandle, filebuf, len, &samplerate, &channel);
            if (ret >= 0) {
                printf("aacinit ok: sam=%lu, chn=%d\n", samplerate, channel);
                NeAACDecFrameInfo frameinfo;
                unsigned char* curbyte = filebuf;
                unsigned long leftsize = len;
                const char* wavename = "out.wav";
                FILE* wavfile = fopen(wavename, "wb");
                if (wavfile) {
                    int wavheadsize = sizeof(struct WavFileHeader);
                    fseek(wavfile, wavheadsize, SEEK_SET);
                    int totalsmp_per_chl = 0;
                    void* out = NULL;
                    while (out = NeAACDecDecode(faadhandle, &frameinfo, curbyte, leftsize)) {
                        printf("decode one frame ok: sam:%ld, chn=%d, samplecount=%ld, obj_type=%d, header_type=%d, consumed=%ld\n",
                                frameinfo.samplerate, frameinfo.channels, frameinfo.samples, frameinfo.object_type,
                                frameinfo.header_type, frameinfo.bytesconsumed);
                        curbyte += frameinfo.bytesconsumed;
                        leftsize -= frameinfo.bytesconsumed;
                        fwrite(out, 1, frameinfo.samples*2, wavfile); // frameinfo.samples是所有聲道數的樣本總和;16bit位深
                        totalsmp_per_chl += frameinfo.samples / frameinfo.channels;
                    }
                    printf("aac decode done, totalsmp_per_chl=%d\n", totalsmp_per_chl);
                    fseek(wavfile, 0, SEEK_SET);
                    write_wav_header(wavfile, totalsmp_per_chl, (int)samplerate, (int)channel);
                    fclose(wavfile);
                }
            }
            free(filebuf);
        }
        NeAACDecClose(faadhandle);
    }
    return 0;
}

faad的呼叫,跟一般的c庫的使用一樣,先建立一個handel,然後init,之後就是反覆的decode,最後是close。

以上程式碼儲存到aac2pcm.c檔案,然後,makefile編譯檔案可以這樣寫(或者直接用gcc來編譯):

out=aac2pcm
obj=aac2pcm.c

$(out):$(obj)
    gcc -o $(out) $(obj) -lfaad -L./libfaad
clean:
    rm -rf $(out) *.o

執行這個程式,部分輸出:

最後的輸出:

此時,在執行目錄中,out.wav已經生成。那用faad跟用FFmpeg來解碼aac,出來的wav有多大的差別呢?

(4)pcm資料觀察

與FFmpeg的解碼作一個對比。

可以使用ffmpeg命令來解碼一個aac檔案:

ffmpeg -i aac20s.aac out_ff.wav

可以看到,faad與FFmpeg解碼出來的wav檔案的大小,有一點差別:

使用Audition,來對比FFmpeg與faad解碼後的pcm資料:

基本看不出差別。

至此,使用faad來解碼的流程就介紹完畢了。另外,對於aac的編碼,可以使用faac或fdk-aac、neroaac,或硬編等,這些小程以後再作介紹。

總結一下,本文介紹瞭如何通過faad來解碼aac格式的音訊,並儲存成wav檔案;對於faad的編譯與呼叫都作了相應介紹,最後還對比了FFmpeg與faad解碼出來的資料差異。


相關推薦

多媒體開發12解碼aac到wav檔案

簡單來說,aac是一種音訊編碼格式,需要解碼後才能用於音訊輸出。aac編碼格式,已經是一種很常見的音訊編碼格式,以至於很多系統都支援aac的編解碼,比如iOS上的AudioConverterRef介面、Android上的MediaCodec介面等。 但是,不要以為用了系統的介面就是用了硬體解碼,因為,這個系統

多媒體開發3直播

特點 nss ams 測試的 方式 input cat nginx 成功 之前介紹了如何錄制音視頻,以及相關的多媒體的概念。對於已經錄制的多媒體進行“就地”播放(參考前文),就是回放,除了“回放”這個流程,還有一個流程也會經常遇到,那就是“直播”。 本文介紹直播的實現。 “

多媒體開發6濾鏡實現各種圖片效果 | Video-Filters | 變色

命令行 let img 很多 保持 yuv 黑白 多媒體 ati 之前講過使用FFmpeg的drawtext濾鏡(把圖片或文字加到視頻上),而實際上,FFmpeg的濾鏡很強大,遠不止加字幕或加圖片的功能。濾鏡是很有趣的,可以把圖片變模糊、變色、縮放旋轉,等等。 本文介紹FF

多媒體開發8調試FFmpeg

run 包括 啟用 return tar.bz2 %d 參考 efi turn 編譯FFmpeg得到二進制文件,之後就是對二進制庫的調用,這時FFmpeg就像一個黑盒子。作為程序員,難道不想研究一下FFmpeg的具體實現?比如是怎麽拿到歌曲信息的、怎麽解碼的、怎麽推流的,等

多媒體開發9聲音采集的概念 | 振幅 | 頻率 | 共振 | 電平化

坐標 波形 上下 樣本 形狀 多少 為什麽不使用 dsd 運動 之前介紹通過ffmpeg程序來錄制聲音或圖像,這個辦法是一個操作的過程,很少涉及到概念上的東西。 而本文,要介紹的是聲音采集的一些流程與概念。 聲音的采集流程與概念,是枯燥的,你如果不想了解的話,到這裏就可以退

多媒體開發10從視訊中提取圖片

小白:提取視訊中的圖片嗎?那很簡單,播放視訊再截圖就行啦。 播放視訊再截圖的做法,當然也可以。但是,手動地截圖會太累而且無法保證準確度,特別是需要反覆提取圖片時,或者需要提取“105秒那一瞬間的美女圖片”時,或者我需要每秒出一張圖片時,那有別的辦法嗎? 本文介紹,如何使用FFmpeg實現從視訊中提取圖片的

多媒體開發11Android平臺上裁剪m4a

Android手機上設定鈴聲的操作比較靈活,你聽到一首喜歡的歌曲,馬上就可以對這首歌曲進行裁剪,裁剪到片段後,再通過系統的介面設定為鈴聲(電話鈴聲、鬧鐘鈴聲等)。前提是,播放這首歌的APP,需要提供裁剪歌曲的功能。 那麼,怎麼樣實現擷取音訊檔案的功能呢? 基於之前的介紹,你可能很自然就想到使用FFmpeg命令

多媒體開發14媒體格式的概念

之前講了一些音視訊的錄製操作,還有聲音採集的概念。採集只是多媒體操作流程中的一個環節,更多的環節可以看看這個圖: 聲音或視訊採集後,就是編碼、寫檔案或推流。不管是編碼還是寫“檔案”,你都能找到相應的程式(比如FFmpeg)來完成,一般加上自己的業務程式碼就能實現自己的功能需求。那就沒有東西好說的了? 沒東

多媒體開發15H264的常見概念

H264,是你常見的技術術語了吧。 那h264是什麼東西呢? H.264是視訊編碼標準,又是標準,得標準得天下啊。 在術語的拼寫上,小程以能理解為準。 本文介紹H264的常見概念。 預警,本文相對枯燥,你可隨時放棄閱讀。 (1)H264從哪裡來? 之前介紹媒體格式的概念時,有提到過國際標準化組織(ISO)

多媒體開發16幀率與位元速率的概念

為什麼說音視訊開發入門較難,因為涉及到很多概念,之前還專門講“媒體格式”、“h264概念”的東西。現在又來,“幀率”跟“位元速率”,這也是兩個常見的概念。你應該經常聽到“重新整理的幀率是多少”或“位元速率比較高所以網速要比較快”的表達吧。 本文介紹音視訊的幀率與位元速率的概念。 (1)幀率 幀率,表示的是頻率

多媒體開發18FFmpeg的常見結構體

除了之前講的avpacket跟avframe,FFmpeg還有其它一些結構經常在流程中出現。FFmpeg還有哪些常見的結構呢?先來看一下這個截圖: 這張圖中的主角,是AVFormatContext。AVFormatContext是FFmpeg的基本結構之一,對應於封裝格式(或容器格式)。 圍繞FFmpeg

多媒體開發2錄製視訊

上一節介紹了用ffplay來播放檔案(或url),這裡有一個概念,如果是播放已經存在的檔案,那叫“回放”,也就是Playback(從流媒體的角度也叫點播),如果播放的是正在錄製的資料(邊錄邊播),那叫直播。 不管是回放還是直播,都需要有媒體資料,那這個媒體資料是怎麼來的呢?從已有的檔案編輯而來是一個辦法,但

多媒體開發6用濾鏡實現各種圖片效果

之前講過使用FFmpeg的drawtext濾鏡(把圖片或文字加到視訊上),而實際上,FFmpeg的濾鏡很強大,遠不止加字幕或加圖片的功能。濾鏡很有趣,可以把圖片變模糊、變色、縮放旋轉,等等。 **本文介紹FFmpeg濾鏡的使用。目的是讓你感受一下FFmepg的濾鏡效果,這樣在實際需要某種效果時,可以考慮使用

多媒體開發7編譯Android與iOS平臺的FFmpeg

編譯FFmpeg,一個古老的話題,但我還是介紹一遍,就當記錄。之前介紹怎麼給視訊新增水印時,就已經提到FFmpeg的編譯,並且在編譯時指定了濾鏡的功能。 但是,在手機盛行的時代,你可能更需要的是能在iOS或Android平臺上執行的FFmpeg,而對於命令列的ffmpeg,你可以在個人電腦上面使用(因為它簡

多媒體開發8除錯FFmpeg

編譯FFmpeg得到二進位制檔案,之後就是對二進位制庫的呼叫,這時FFmpeg就像一個黑盒子。作為程式設計師,難道不想研究一下FFmpeg的具體實現?比如是怎麼拿到歌曲資訊的、怎麼解碼的、怎麼推流的,等等。 看原始碼是理解程式碼實現的一個辦法,而單步除錯能從另一個維度去幫到你。**本文介紹如何單步除錯FFm

多媒體開發9我是聲音

之前介紹通過ffmpeg程式來錄製聲音或影象,這個辦法是一個操作的過程,很少涉及到概念上的東西。而**本文,要介紹的是聲音採集的一些流程與概念。** 聲音的採集流程與概念,是枯燥的,但是,我也會盡量說一些有趣的現象來緩解這種枯燥。 聽得到的,或聽不到的聲音,抽象來說,都是模擬訊號,也可以形象一點,叫能量波

多媒體開發10提取圖片以及點陣圖儲存

> 小白:提取視訊中的圖片嗎?那很簡單,播放視訊再截圖就行啦。 播放視訊再截圖的做法,當然可以。但是,手動截圖會太累而且無法保證準確度,特別是需要反覆提取圖片時,或者需要提取“105秒那一瞬間的美女圖片”時,或者我需要每秒出一張圖片時,那有別的辦法嗎? **本文介紹,如何使用FFmpeg實現從視訊中

即時通訊音視訊開發如何開始音訊編解碼技術的學習

前言 即時通訊應用中的實時音視訊技術,幾乎是IM開發中的最後一道高牆。原因在於:實時音視訊技術 = 音視訊處理技術 + 網路傳輸技術 的橫向技術應用集合體,而公共網際網路不是為了實時通訊設計的。 系列文章 《即時通訊音視訊開發(四):視訊編解碼之預測技術介紹》 《即時通訊音

即時通訊音視訊開發視訊編解碼之預測技術介紹

前言 即時通訊應用中的實時音視訊技術,幾乎是IM開發中的最後一道高牆。原因在於:實時音視訊技術 = 音視訊處理技術 + 網路傳輸技術 的橫向技術應用集合體,而公共網際網路不是為了實時通訊設計的。 系列文章 《即時通訊音視訊開發(二):視訊編解碼之數字視訊介紹》 《即時通訊音

即時通訊音視訊開發視訊編解碼之編碼基礎

前言 即時通訊應用中的實時音視訊技術,幾乎是IM開發中的最後一道高牆。原因在於:實時音視訊技術 = 音視訊處理技術 + 網路傳輸技術 的橫向技術應用集合體,而公共網際網路不是為了實時通訊設計的。 系列文章 《即時通訊音視訊開發(一):視訊編解碼之理論概述》 《即時通訊音視訊