/******************************************************************************** Copyright (C) 2012 Hugh Bailey This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ********************************************************************************/ #include "Main.h" #include "../libfaac/include/faac.h" //AAC is pretty good, I changed my mind class AACEncoder : public AudioEncoder { UINT curBitRate; bool bFirstPacket; faacEncHandle faac; DWORD numReadSamples; DWORD outputSize; List inputBuffer; List aacBuffer; List header; List bufferedTimestamps; QWORD curEncodeTimestamp; bool bFirstFrame; public: AACEncoder(UINT bitRate) { curBitRate = bitRate; faac = faacEncOpen(44100, 2, &numReadSamples, &outputSize); //Log(TEXT("numReadSamples: %d"), numReadSamples); aacBuffer.SetSize(outputSize+2); aacBuffer[0] = 0xaf; aacBuffer[1] = 0x1; faacEncConfigurationPtr config = faacEncGetCurrentConfiguration(faac); config->bitRate = (bitRate*1000)/2; config->quantqual = 100; config->inputFormat = FAAC_INPUT_FLOAT; config->mpegVersion = MPEG4; config->aacObjectType = LOW; config->useLfe = 0; config->outputFormat = 0; int ret = faacEncSetConfiguration(faac, config); if(!ret) CrashError(TEXT("aac configuration failed")); BYTE *tempHeader; DWORD len; header.SetSize(2); header[0] = 0xaf; header[1] = 0x00; faacEncGetDecoderSpecificInfo(faac, &tempHeader, &len); header.AppendArray(tempHeader, len); free(tempHeader); bFirstPacket = true; bFirstFrame = true; Log(TEXT("------------------------------------------")); Log(TEXT("%s"), GetInfoString().Array()); } ~AACEncoder() { faacEncClose(faac); } bool Encode(float *input, UINT numInputFrames, DataPacket &packet, QWORD ×tamp) { if(bFirstFrame) { curEncodeTimestamp = timestamp; bFirstFrame = false; } //------------------------------------------------ QWORD curTimestamp = timestamp; UINT lastSampleSize = inputBuffer.Num(); UINT numInputSamples = numInputFrames*2; inputBuffer.AppendArray(input, numInputSamples); int ret = 0; if(inputBuffer.Num() >= numReadSamples) { //now we have to upscale the floats. fortunately we almost always have SSE UINT floatsLeft = numReadSamples; float *inputTemp = inputBuffer.Array(); if(App->SSE2Available() && (UPARAM(inputTemp) & 0xF) == 0) { UINT alignedFloats = floatsLeft & 0xFFFFFFFC; for(UINT i=0; i 0) { if(bFirstPacket) { bFirstPacket = false; ret = 0; } else { packet.lpPacket = aacBuffer.Array(); packet.size = ret+2; timestamp = bufferedTimestamps[0]; bufferedTimestamps.Remove(0); } } else if(ret < 0) AppWarning(TEXT("aac encode error")); inputBuffer.RemoveRange(0, numReadSamples); bufferedTimestamps << curEncodeTimestamp; curEncodeTimestamp = curTimestamp + (((numReadSamples-lastSampleSize)/2)*10/441); } return ret > 0; } UINT GetFrameSize() const { return 1024; } void GetHeaders(DataPacket &packet) { packet.lpPacket = header.Array(); packet.size = header.Num(); } int GetBitRate() const {return curBitRate;} CTSTR GetCodec() const {return TEXT("AAC");} String GetInfoString() const { String strInfo; strInfo << TEXT("Audio Encoding: AAC") << TEXT("\r\n bitrate: ") << IntString(curBitRate); return strInfo; } }; AudioEncoder* CreateAACEncoder(UINT bitRate) { return new AACEncoder(bitRate); }