Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android使用FAAC進行AAC編碼詳解必看以及注意事項

Android使用FAAC進行AAC編碼詳解必看以及注意事項

編輯:關於Android編程

使用FAAC轉換PCM為AAC

關於FAAC

FAAC是一個MPEG-4和MPEG-2的AAC編碼器,其特性是:可移植性好,快速,支持LC/Main/LTP,通過Dream支持DRM,代碼小相對於FFMPEG的AAC轉碼,FAAC實在是微乎其微,而且可以直接把代碼加到工程裡面編譯,也可使用靜態庫,而沒有巨大的動態庫的煩惱。

 

下載安裝

直接按照官方文檔所示,編譯靜態庫以供我們程序使用。(我沒這麼做,個中曲折錯誤不細數)把FAAC的代碼摳出來,直接加到我們的工程中去,或者摳出來編譯一個靜態庫,簡單暴力有效,需要的代碼是libfaac和include兩個目錄下的所有文件(不包括子目錄文件)。 目錄文件列表如下所示:
aacquant.c
aacquant.h
backpred.c
backpred.h
bitstream.c
bitstream.h
channels.c
channels.h
coder.h
faac.h
faaccfg.h
fft.c
fft.h
filtbank.c
filtbank.h
frame.c
frame.h
huffman.c
huffman.h
hufftab.h
ltp.c
ltp.h
midside.c
midside.h
psych.h
psychkni.c
tns.c
tns.h
util.c
util.h
version.h
強烈推薦使用第二種方法

主要的函數介紹

faacEncHandle FAACAPI faacEncOpen(unsigned long sampleRate,
	unsigned int numChannels,
	unsigned long *inputSamples,
	unsigned long *maxOutputBytes);
//	描述 : 打開並初始化編碼器
//	sampleRate : 編碼輸入信息的采樣率
//	numChannels : 編碼輸入信息的通道數量,1-單聲道 2-立體聲
//	inputSamples : 編碼後的數據長度
//	maxOutputBytes : 編碼後的信息最大長度
int FAACAPI faacEncClose(faacEncHandle hEncoder);
//	描述:關閉編碼器
//	hEncoder : faacEncOpen返回的編碼器句柄
faacEncConfigurationPtr FAACAPI faacEncGetCurrentConfiguration(faacEncHandle hEncoder);
//	描述 :獲取當前編碼器的配置信息
//	hEncoder : faacEncOpen返回的編碼器句柄
int FAACAPI faacEncSetConfiguration(faacEncHandle hEncoder, faacEncConfigurationPtr config);
//	描述 : 配置解碼器的參數
//	hEncoder : faacEncOpen返回的編碼器句柄
//	config : 編碼器的配置信息
int FAACAPI faacEncEncode(faacEncHandle hEncoder, 
	int32_t * inputBuffer, 
	unsigned int samplesInput,
	unsigned char *outputBuffer,
	unsigned int bufferSize);
//	描述 : 編碼一桢信息
//	hEncoder : faacEncOpen返回的編碼器句柄
//	inputBuffer : 輸入信息緩沖區
//	samplesInput : faacEncOpen編碼後的數據長度,即緩沖區長度
//	outputBuffer : 編碼後輸出信息緩沖區
//	bufferSize : 輸出信息長度
int FAACAPI faacEncGetVersion(char **faac_id_string, char **faac_copyright_string);
//	描述 : 獲取FAAC的版本信息,用以參考作用,非必須API
//	faac_id_string : faac的版本號
//	faac_copyright_string : 版權信息

代碼示例

代碼的工作流程是:
打開輸入輸出文件使用faacEncOpen打開編碼器引擎使用faacEncGetCurrentConfiguratio獲取編碼器配置配置編碼器參數使用faacEncSetConfiguration設置編碼器配置讀取一桢輸入數據使用faacEncEncode編碼幀數據寫入編碼數據到輸出文件使用faacEncClose關閉編碼引擎
//  
//  faac example code
//  PCM to ACC  
//  
//  Created by arbboter on 15/1/26.  
//  Copyright (c) 2015年 arbboter. All rights reserved.  
// 
#include "faac.h"
#include 

int main()
{
	// 定義別名
	typedef unsigned char   BYTE;

	unsigned long	nSampleRate = 44100;
	unsigned int	nChannels = 2;
	unsigned int	nPCMBitSize = 16;
	unsigned long	nInputSamples = 0;
	unsigned long	nMaxOutputBytes = 0;
	faacEncHandle	hEncoder = {0};

	// 設置輸入輸出文件
	FILE* fpIn = fopen("Beyond.pcm", "rb");
	FILE* fpOut = fopen("Beyond.aac", "wb");

	if(fpIn==NULL || fpOut==NULL)
	{
		printf("打開文件失敗!\n");
		return -1;
	}

	// 打開faac編碼器引擎
	hEncoder = faacEncOpen(nSampleRate, nChannels, &nInputSamples, &nMaxOutputBytes);
	if(hEncoder == NULL)
	{
		printf("打開faac編碼器引擎失敗!\n");
		return -1;
	}

	// 分配內存信息
	int		nPCMBufferSize = nInputSamples*nPCMBitSize/8;
	BYTE*	pbPCMBuffer = new BYTE[nPCMBufferSize];
	BYTE*	pbAACBuffer = new BYTE[nMaxOutputBytes];

	// 獲取當前編碼器信息
	faacEncConfigurationPtr pConfiguration = {0};
	pConfiguration = faacEncGetCurrentConfiguration(hEncoder);

	// 設置編碼配置信息
	/*
		PCM Sample Input Format
		0	FAAC_INPUT_NULL			invalid, signifies a misconfigured config
		1	FAAC_INPUT_16BIT		native endian 16bit
		2	FAAC_INPUT_24BIT		native endian 24bit in 24 bits		(not implemented)
		3	FAAC_INPUT_32BIT		native endian 24bit in 32 bits		(DEFAULT)
		4	FAAC_INPUT_FLOAT		32bit floating point
    */
	pConfiguration->inputFormat = FAAC_INPUT_16BIT;

	// 0 = Raw; 1 = ADTS
	pConfiguration->outputFormat = 1;

	// AAC object types 
	//#define MAIN 1
	//#define LOW  2
	//#define SSR  3
	//#define LTP  4
	pConfiguration->aacObjectType = LOW;
	pConfiguration->allowMidside = 0;
	pConfiguration->useLfe = 0;
	pConfiguration->bitRate = 48000;
	pConfiguration->bandWidth = 32000;

	// 其他的參數不知道怎麼配置,畢竟對音頻不熟
	// 不過當前的設置可以實現轉換,不過聲音好像有一丟丟怪異
	// 這一塊的配置信息很重要,錯了會導致轉碼失敗,然後你以為代碼其他地方錯了

	// 重置編碼器的配置信息
	faacEncSetConfiguration(hEncoder, pConfiguration);

	size_t nRet = 0;

	printf("數據轉換中:        ");
	int i = 0;
	while( (nRet = fread(pbPCMBuffer, 1, nPCMBufferSize, fpIn)) > 0)
	{
		printf("\b\b\b\b\b\b\b\b%-8d", ++i);
		nInputSamples = nRet / (nPCMBitSize/8);

		// 編碼
		nRet = faacEncEncode(hEncoder, (int*) pbPCMBuffer, nInputSamples, pbAACBuffer, nMaxOutputBytes);

		// 寫入轉碼後的數據
		fwrite(pbAACBuffer, 1, nRet, fpOut);
	}

	// 掃尾工作
	faacEncClose(hEncoder);
	fclose(fpOut);
	fclose(fpIn);

	delete[] pbAACBuffer;
	delete[] pbPCMBuffer;
	
	return 0;
}

編碼器的參數設置,可以找正確的解碼例子照例修改或者問專業人士吧,如果出錯了的話。

 

 

 

 

 

 

 

 

打開FAAC編碼器

m_faacHandle = faacEncOpen(isamplerate, ichannels, &m_uSampleInput, &m_uOutputBytes);

if( 0 == m_faacHandle )
return false ;

faacEncConfigurationPtr faacCfg;

faacCfg = faacEncGetCurrentConfiguration(m_faacHandle);

if (faacCfg->version != FAAC_CFG_VERSION){
return false ;
}

//* 設置配置參數
faacCfg->aacObjectType = LOW; //LC編碼
faacCfg->mpegVersion = MPEG4;//
faacCfg->useTns = 1 ;//時域噪音控制,大概就是消爆音
faacCfg->allowMidside =0 ;//
faacCfg->bitRate = m_nBitRate/m_uChannelNums;
faacCfg->bandWidth = 0 ; //頻寬
faacCfg->outputFormat = isADTS; //輸出是否包含ADTS頭
faacCfg->inputFormat = FAAC_INPUT_16BIT;
//faacCfg->shortctl = 0 ;
faacCfg->quantqual = 50 ;

//* 獲取解碼信息.
//unsigned char* ucBuffer = NULL;
//unsigned long ulDecoderSpecificInfoSize;
//faacEncGetDecoderSpecificInfo(m_faacHandle, &ucBuffer, &ulDecoderSpecificInfoSize);

if (!faacEncSetConfiguration(m_faacHandle, faacCfg)){
return false ;
}

m_uSampleInput這個參數要注意,需要在編碼時使用。是faac所使用的音頻樣片數量

隨後就可以解碼了

int iBytesWritten = faacEncEncode(m_faacHandle, (int32_t*)input, m_uSampleInput , output, outlen );

判斷下iBytesWritten初始編碼的幾幀數據會返回0,0是數據被緩沖,並不是錯誤。

 

解碼相對編碼更簡單。

但是遇到個問題,就是編碼單聲道的數據,解碼會返回雙聲道,這對打開播放設備播放時造成了一定的

困擾。因為前期是將音頻編碼參數優先發送出來,接收端收到參數後會打開播放設備,現在得在數據解碼後再打開

播放設備。

 

我的程序是根據faac 1.28 庫中的frontend目錄下的faac的例子改的。

下面是程序的運行流程:

首先調用faacEncHandle hEncoder=faacEncOpen(samplerate,channels,& samplesInput,

&maxBytesOutput);

1.打開aac編碼引擎,創建aac編碼句柄。

參數 samplerate 為要編碼的音頻pcm流的采樣率,channels為要編碼的音頻pcm流的的頻道數(原有的例子程序是從wav文件中讀出這些信息),sampleInput在編碼時要用到,意思是每次要編碼的采樣數,參數maxBytesOutput為編碼時輸出地最大字節數。

 

2.然後在設置一些編碼參數,如

int version=MPEG4; //設置版本,錄制MP4文件時要用MPEG4

int objecttype=LOW; //編碼類型

int midside=1; //M/S編碼

int usetns=DEFAULT_TNS; //瞬時噪聲定形(temporal noise shaping,TNS)濾波器

int shortctl=SHORTCTL_NORMAL;

int inputformat=FAAC_INPUT_16BIT; //輸入數據類型

int outputformat=RAW_STREAM; //錄制MP4文件時,要用raw流。檢驗編碼是否正確時可設

//置為adts傳輸流,把aac 流寫入.aac文件中,如編碼正確

//用千千靜聽就可以播放。

其他的參數可根據例子程序設置。

設置完參數後就調用faacEncSetConfiguration(hEncoder, aacFormat)設置編碼參數。

3.如編碼完的aac流要寫入MP4文件時,要調用

faacEncGetDecoderSpecificInfo(hEncoder,&(ASC), &(ASCLength));//得到解碼信息

//(mpeg4ip mp4 錄制使用)

此函數支持MPEG4版本,得到的ASC 和ACSLength 數據在錄制MP4(mpegip庫)文件時用。

 

4.然後就是編碼了,每次從實時的pcm音頻隊列中讀出samplesInput* channels*(量化位數/8),

字節數的pcm數據。然後再把得到pcm流轉變一下存儲位數,我是轉化為16位的了,這部分

可以根據例子程序寫一個函數,這是我寫的一個,

size_t read_int16(AACInfo *sndf, int16_t *outbuf, size_t num, unsigned char *inputbuf)

{

size_t i=0,j=0;

unsigned char bufi[8];

while(i

{

memcpy(bufi,inputbuf+j,sndf->samplebytes);

j+=sndf->samplebytes;

int16_t s=((int16_t*)bufi)[0];

outbuf[i]=s;

i++;

}

return i;

}

也可以寫一個read_float32(AACInfo *sndf, float *outbuf, size_t num ,unsigned char *inputbuf),

和size_t read_int24(AACInfo *sndf, int32_t *outbuf, size_t num, unsigned char *inputbuf)。

處理完數據轉換後就調用

bytesWritten = faacEncEncode(hEncoder,

(int *)pcmbuf,

samplesInput,

outbuff,

maxbytesoutput);

進行編碼,pcmbuf為轉換後的pcm流數據,samplesInput為調用faacEncOpen時得到的輸入采樣數,outbuff為編碼後的數據buff,maxbytesoutput為調用faacEncOpen時得到的最大輸出字節數。然後每次從outbuff中得到編碼後的aac數據流,放到數據隊列就行了,如果還要錄制MP4文件,在編碼完samplesInput(一幀)個采樣數時,打上時間戳(mpegip庫用於音視頻同步)後再放到輸出隊列中。如果想測試看編碼的aac流是否正確,設置輸出格式為ADTS_STREAM,把aac數據寫入到.aac文件中,看能否用千千靜聽播放。

5.釋放資源,調用faacEncClose(hEncoder);就行了


  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved