編輯:關於Android編程
使用FAAC轉換PCM為AAC
FAAC是一個MPEG-4和MPEG-2的AAC編碼器,其特性是:可移植性好,快速,支持LC/Main/LTP,通過Dream支持DRM,代碼小相對於FFMPEG的AAC轉碼,FAAC實在是微乎其微,而且可以直接把代碼加到工程裡面編譯,也可使用靜態庫,而沒有巨大的動態庫的煩惱。
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 : 版權信息
// // faac example code // PCM to ACC // // Created by arbboter on 15/1/26. // Copyright (c) 2015年 arbboter. All rights reserved. // #include "faac.h" #includeint 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);就行了
游戲中攝像頭的原理介紹 在游戲開發中更新攝像頭的位置可以決定屏幕顯示的內容,尤其是RPG類游戲攝像頭有著非常重要的作用,我
效果圖: .java文件有MainActivity.java、FileService.java、FileServiceTest.java, .xml文
· ·點此進入上篇: Android 學習(三)上: UI 控件 · · · · ·AnalogClock和DigitalClock // 獲得當前的時間,獲得小時和分鐘
前言:本文主要是針對沒有接觸過Dragonboard 410c開發板的朋友,教大家如何從裸板搭建平台以及通過這個平台如何去操作Light、Gesture、Color這三個