天天看點

aac檔案轉碼為wav檔案

本文講解把aac音頻解碼成pcm資料,并以wav來封裝。

小白:解碼是吧?用你之前介紹的FFmpeg就行啦,它這麼萬能。

花滿樓:FFmpeg可以解碼aac,但如果隻為了解碼aac而用FFmpeg,就有點大材小用了,而且要應對比較複雜的接口調用,另外體積也比較大,即便裁剪後可以讓FFmpeg編譯出來的庫小很多。

小白:是以你不是講FFmpeg?

花滿樓:這裡講faad的使用。

解碼aac,可以使用FFmpeg或者faad(或者使用平台的硬體解碼),這裡介紹faad。

另外,對于aac的編碼,可以使用faac或fdk-aac、neroaac,或硬編等。

(1)下載下傳faad

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

檔案結構大概是這樣的: 

aac檔案轉碼為wav檔案

這個開源項目,似乎一直有維護與更新: 

aac檔案轉碼為wav檔案

(2)編譯faad

執行以下指令,生成configure與makefile,并make出faad的庫檔案。

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

生成的庫檔案: 

aac檔案轉碼為wav檔案

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

aac檔案轉碼為wav檔案

由于隻考慮在macos上運作,而且是在mac系統上編譯,是以confiure時并不需要指定特定的參數。

小白:那一堆指令是什麼?

花滿樓:這個,你問一下西門吹雪,他是負責編譯環境的。

小白:…

(3)調用faad

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

demo的檔案結構: 

aac檔案轉碼為wav檔案

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;

makefile檔案可以這樣寫(或者直接用gcc來編譯):

out=aac2pcm

obj=aac2pcm.c

$(out):$(obj)

gcc -o $(out) $(obj) -lfaad -L./libfaad

clean:

rm -rf $(out) *.o

對于aac檔案,adts-aac或adif-aac封裝格式,都适用。

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

aac檔案轉碼為wav檔案

最後的輸出: 

aac檔案轉碼為wav檔案

(4)pcm資料觀察

與ffmpeg的解碼作一個對比。

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

ffmpeg -i aac20s.aac out_ff.wav

可以看到faad與ffmpeg轉碼出來的wav的檔案大小,有一點差别: 

aac檔案轉碼為wav檔案

ffmpeg與faad解碼後的pcm資料,對比圖是這樣的: 

aac檔案轉碼為wav檔案

基本看不出差别。