obs源码之libaac编码。
#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<float> inputBuffer;
List<BYTE> aacBuffer;
List<BYTE> header;
List<DWORD> bufferedTimestamps;
DWORD 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, DWORD ×tamp)
{
if(bFirstFrame)
{
curEncodeTimestamp = timestamp;
bFirstFrame = false;
}
//------------------------------------------------
DWORD 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<alignedFloats; i += 4)
{
float *pos = inputTemp+i;
_mm_store_ps(pos, _mm_mul_ps(_mm_load_ps(pos), _mm_set_ps1(32767.0f)));
}
floatsLeft &= 0x3;
inputTemp += alignedFloats;
}
if(floatsLeft)
{
for(UINT i=0; i<floatsLeft; i++)
inputTemp[i] *= 32767.0f;
}
ret = faacEncEncode(faac, (int32_t*)inputBuffer.Array(), numReadSamples, aacBuffer.Array()+2, outputSize);
if(ret > 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);
}