Add Fraunhofer AAC encoder with AAC-ELD support.

Change-Id: I6cd499d257d72f50a5b508bed97796a591a51506
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index 30db642..3891809 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -77,6 +77,7 @@
     AUDIO_ENCODER_AAC = 3,
     AUDIO_ENCODER_AAC_PLUS = 4,
     AUDIO_ENCODER_EAAC_PLUS = 5,
+    AUDIO_ENCODER_AAC_ELD = 6,
 
     AUDIO_ENCODER_LIST_END // must be the last - used to validate the audio encoder type
 };
diff --git a/include/media/stagefright/AACWriter.h b/include/media/stagefright/AACWriter.h
index 49397ee..df1b053 100644
--- a/include/media/stagefright/AACWriter.h
+++ b/include/media/stagefright/AACWriter.h
@@ -59,6 +59,7 @@
     int64_t mEstimatedDurationUs;
     int32_t mChannelCount;
     int32_t mSampleRate;
+    int32_t mAACProfile;
     int32_t mFrameDurationUs;
 
     static void *ThreadWrapper(void *);
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 7d7af63..b8d925e 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -182,7 +182,7 @@
     status_t setupAACCodec(
             bool encoder,
             int32_t numChannels, int32_t sampleRate, int32_t bitRate,
-            bool isADTS);
+            int32_t aacProfile, bool isADTS);
 
     status_t selectAudioPortFormat(
             OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE desiredFormat);
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 8a87d83..3c25a14 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -49,6 +49,7 @@
     kKeyFrameRate         = 'frmR',  // int32_t (video frame rate fps)
     kKeyBitRate           = 'brte',  // int32_t (bps)
     kKeyESDS              = 'esds',  // raw data
+    kKeyAACProfile        = 'aacp',  // int32_t
     kKeyAVCC              = 'avcc',  // raw data
     kKeyD263              = 'd263',  // raw data
     kKeyVorbisInfo        = 'vinf',  // raw data
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 055da5d..887ce5d 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -243,7 +243,7 @@
 
     status_t setAACFormat(
             int32_t numChannels, int32_t sampleRate, int32_t bitRate,
-            bool isADTS);
+            int32_t aacProfile, bool isADTS);
 
     void setG711Format(int32_t numChannels);
 
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index c224f06..c08f033 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -41,9 +41,10 @@
 };
 
 const MediaProfiles::NameToTagMap MediaProfiles::sAudioEncoderNameMap[] = {
-    {"amrnb", AUDIO_ENCODER_AMR_NB},
-    {"amrwb", AUDIO_ENCODER_AMR_WB},
-    {"aac",   AUDIO_ENCODER_AAC},
+    {"amrnb",  AUDIO_ENCODER_AMR_NB},
+    {"amrwb",  AUDIO_ENCODER_AMR_WB},
+    {"aac",    AUDIO_ENCODER_AAC},
+    {"aaceld", AUDIO_ENCODER_AAC_ELD},
 };
 
 const MediaProfiles::NameToTagMap MediaProfiles::sFileFormatMap[] = {
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 2c5644f..b676cc7 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -24,6 +24,7 @@
 #include <binder/IServiceManager.h>
 
 #include <media/IMediaPlayerService.h>
+#include <media/openmax/OMX_Audio.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/AudioSource.h>
 #include <media/stagefright/AMRWriter.h>
@@ -817,6 +818,11 @@
             break;
         case AUDIO_ENCODER_AAC:
             mime = MEDIA_MIMETYPE_AUDIO_AAC;
+            encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectLC);
+            break;
+        case AUDIO_ENCODER_AAC_ELD:
+            mime = MEDIA_MIMETYPE_AUDIO_AAC;
+            encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectELD);
             break;
         default:
             ALOGE("Unknown audio encoder: %d", mAudioEncoder);
@@ -852,7 +858,8 @@
     // Add support for OUTPUT_FORMAT_AAC_ADIF
     CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_AAC_ADTS);
 
-    CHECK_EQ(mAudioEncoder, AUDIO_ENCODER_AAC);
+    CHECK(mAudioEncoder == AUDIO_ENCODER_AAC ||
+          mAudioEncoder == AUDIO_ENCODER_AAC_ELD);
     CHECK(mAudioSource != AUDIO_SOURCE_CNT);
 
     mWriter = new AACWriter(mOutputFd);
@@ -1435,6 +1442,7 @@
         case AUDIO_ENCODER_AMR_NB:
         case AUDIO_ENCODER_AMR_WB:
         case AUDIO_ENCODER_AAC:
+        case AUDIO_ENCODER_AAC_ELD:
             break;
 
         default:
diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp
index 9cdb463..21c5428 100644
--- a/media/libstagefright/AACWriter.cpp
+++ b/media/libstagefright/AACWriter.cpp
@@ -18,6 +18,7 @@
 #define LOG_TAG "AACWriter"
 #include <utils/Log.h>
 
+#include <media/openmax/OMX_Audio.h>
 #include <media/stagefright/AACWriter.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -38,7 +39,8 @@
       mPaused(false),
       mResumed(false),
       mChannelCount(-1),
-      mSampleRate(-1) {
+      mSampleRate(-1),
+      mAACProfile(OMX_AUDIO_AACObjectLC) {
 
     ALOGV("AACWriter Constructor");
 
@@ -96,6 +98,7 @@
     CHECK(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC));
     CHECK(meta->findInt32(kKeyChannelCount, &mChannelCount));
     CHECK(meta->findInt32(kKeySampleRate, &mSampleRate));
+    CHECK(meta->findInt32(kKeyAACProfile, &mAACProfile));
     CHECK(mChannelCount >= 1 && mChannelCount <= 2);
 
     mSource = source;
@@ -254,7 +257,7 @@
     data |= kProtectionAbsense;
     write(mFd, &data, 1);
 
-    const uint8_t kProfileCode = 1;  // AAC-LC
+    const uint8_t kProfileCode = mAACProfile - 1;
     uint8_t kSampleFreqIndex;
     CHECK(getSampleRateTableIndex(mSampleRate, &kSampleFreqIndex));
     const uint8_t kPrivateStream = 0;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 5ac34c9..c303146 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -852,13 +852,16 @@
                 || !msg->findInt32("sample-rate", &sampleRate)) {
             err = INVALID_OPERATION;
         } else {
-            int32_t isADTS;
+            int32_t isADTS, aacProfile;
             if (!msg->findInt32("is-adts", &isADTS)) {
                 isADTS = 0;
             }
+            if (!msg->findInt32("aac-profile", &aacProfile)) {
+                aacProfile = OMX_AUDIO_AACObjectNull;
+            }
 
             err = setupAACCodec(
-                    encoder, numChannels, sampleRate, bitRate, isADTS != 0);
+                    encoder, numChannels, sampleRate, bitRate, aacProfile, isADTS != 0);
         }
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) {
         err = setupAMRCodec(encoder, false /* isWAMR */, bitRate);
@@ -960,8 +963,8 @@
 }
 
 status_t ACodec::setupAACCodec(
-        bool encoder,
-        int32_t numChannels, int32_t sampleRate, int32_t bitRate, bool isADTS) {
+        bool encoder, int32_t numChannels, int32_t sampleRate,
+        int32_t bitRate, int32_t aacProfile, bool isADTS) {
     if (encoder && isADTS) {
         return -EINVAL;
     }
@@ -1026,7 +1029,7 @@
         profile.nFrameLength = 0;
         profile.nAACtools = OMX_AUDIO_AACToolAll;
         profile.nAACERtools = OMX_AUDIO_AACERNone;
-        profile.eAACProfile = OMX_AUDIO_AACObjectLC;
+        profile.eAACProfile = (OMX_AUDIO_AACPROFILETYPE) aacProfile;
         profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF;
 
         err = mOMX->setParameter(
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 9385b8a..a572541 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -28,6 +28,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/DataSource.h>
@@ -1824,26 +1825,23 @@
         return ERROR_MALFORMED;
     }
 
-    uint32_t objectType = csd[0] >> 3;
+    ABitReader br(csd, csd_size);
+    uint32_t objectType = br.getBits(5);
 
-    if (objectType == 31) {
-        return ERROR_UNSUPPORTED;
+    if (objectType == 31) {  // AAC-ELD => additional 6 bits
+        objectType = 32 + br.getBits(6);
     }
 
-    uint32_t freqIndex = (csd[0] & 7) << 1 | (csd[1] >> 7);
+    uint32_t freqIndex = br.getBits(4);
+
     int32_t sampleRate = 0;
     int32_t numChannels = 0;
     if (freqIndex == 15) {
         if (csd_size < 5) {
             return ERROR_MALFORMED;
         }
-
-        sampleRate = (csd[1] & 0x7f) << 17
-                        | csd[2] << 9
-                        | csd[3] << 1
-                        | (csd[4] >> 7);
-
-        numChannels = (csd[4] >> 3) & 15;
+        sampleRate = br.getBits(24);
+        numChannels = br.getBits(4);
     } else {
         static uint32_t kSamplingRate[] = {
             96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
@@ -1855,7 +1853,7 @@
         }
 
         sampleRate = kSamplingRate[freqIndex];
-        numChannels = (csd[1] >> 3) & 15;
+        numChannels = br.getBits(4);
     }
 
     if (numChannels == 0) {
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 1d6f927..245d941 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -511,16 +511,20 @@
     } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mMIME)) {
         setAMRFormat(true /* isWAMR */, bitRate);
     } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mMIME)) {
-        int32_t numChannels, sampleRate;
+        int32_t numChannels, sampleRate, aacProfile;
         CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
         CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
 
+        if (!meta->findInt32(kKeyAACProfile, &aacProfile)) {
+            aacProfile = OMX_AUDIO_AACObjectNull;
+        }
+
         int32_t isADTS;
         if (!meta->findInt32(kKeyIsADTS, &isADTS)) {
             isADTS = false;
         }
 
-        status_t err = setAACFormat(numChannels, sampleRate, bitRate, isADTS);
+        status_t err = setAACFormat(numChannels, sampleRate, bitRate, aacProfile, isADTS);
         if (err != OK) {
             CODEC_LOGE("setAACFormat() failed (err = %d)", err);
             return err;
@@ -3395,7 +3399,7 @@
 }
 
 status_t OMXCodec::setAACFormat(
-        int32_t numChannels, int32_t sampleRate, int32_t bitRate, bool isADTS) {
+        int32_t numChannels, int32_t sampleRate, int32_t bitRate, int32_t aacProfile, bool isADTS) {
     if (numChannels > 2) {
         ALOGW("Number of channels: (%d) \n", numChannels);
     }
@@ -3453,7 +3457,7 @@
         profile.nFrameLength = 0;
         profile.nAACtools = OMX_AUDIO_AACToolAll;
         profile.nAACERtools = OMX_AUDIO_AACERNone;
-        profile.eAACProfile = OMX_AUDIO_AACObjectLC;
+        profile.eAACProfile = (OMX_AUDIO_AACPROFILETYPE) aacProfile;
         profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF;
         err = mOMX->setParameter(mNode, OMX_IndexParamAudioAac,
                 &profile, sizeof(profile));
diff --git a/media/libstagefright/codecs/aacenc/Android.mk b/media/libstagefright/codecs/aacenc/Android.mk
index 0ad3f6c..98e702e 100644
--- a/media/libstagefright/codecs/aacenc/Android.mk
+++ b/media/libstagefright/codecs/aacenc/Android.mk
@@ -2,7 +2,7 @@
 include $(CLEAR_VARS)
 include frameworks/av/media/libstagefright/codecs/common/Config.mk
 
-
+AAC_LIBRARY = fraunhofer
 
 LOCAL_SRC_FILES := basic_op/basicop2.c basic_op/oper_32b.c
 
@@ -90,24 +90,57 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := \
-        SoftAACEncoder.cpp
+ifeq ($(AAC_LIBRARY), fraunhofer)
 
-LOCAL_C_INCLUDES := \
-	frameworks/av/media/libstagefright/include \
-	frameworks/av/media/libstagefright/codecs/common/include \
-	frameworks/native/include/media/openmax
+  include $(CLEAR_VARS)
 
-LOCAL_CFLAGS := -DOSCL_IMPORT_REF=
+  LOCAL_SRC_FILES := \
+          SoftAACEncoder2.cpp
 
-LOCAL_STATIC_LIBRARIES := \
-        libstagefright_aacenc
+  LOCAL_C_INCLUDES := \
+          frameworks/av/media/libstagefright/include \
+          frameworks/native/include/media/openmax \
+          external/aac/libAACenc/include \
+          external/aac/libFDK/include \
+          external/aac/libMpegTPEnc/include \
+          external/aac/libSBRenc/include \
+          external/aac/libSYS/include
 
-LOCAL_SHARED_LIBRARIES := \
-        libstagefright_omx libstagefright_foundation libutils \
-        libstagefright_enc_common
+  LOCAL_CFLAGS :=
 
-LOCAL_MODULE := libstagefright_soft_aacenc
-LOCAL_MODULE_TAGS := optional
+  LOCAL_STATIC_LIBRARIES := \
+          libAACenc libMpegTPEnc libSBRenc libFDK libSYS
 
-include $(BUILD_SHARED_LIBRARY)
+  LOCAL_SHARED_LIBRARIES := \
+          libstagefright_omx libstagefright_foundation libutils
+
+  LOCAL_MODULE := libstagefright_soft_aacenc
+  LOCAL_MODULE_TAGS := optional
+
+  include $(BUILD_SHARED_LIBRARY)
+
+else # visualon
+
+  LOCAL_SRC_FILES := \
+          SoftAACEncoder.cpp
+
+  LOCAL_C_INCLUDES := \
+          frameworks/av/media/libstagefright/include \
+          frameworks/av/media/libstagefright/codecs/common/include \
+          frameworks/native/include/media/openmax
+
+  LOCAL_CFLAGS := -DOSCL_IMPORT_REF=
+
+  LOCAL_STATIC_LIBRARIES := \
+          libstagefright_aacenc
+
+  LOCAL_SHARED_LIBRARIES := \
+          libstagefright_omx libstagefright_foundation libutils \
+          libstagefright_enc_common
+
+  LOCAL_MODULE := libstagefright_soft_aacenc
+  LOCAL_MODULE_TAGS := optional
+
+  include $(BUILD_SHARED_LIBRARY)
+
+endif # $(AAC_LIBRARY)
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
new file mode 100644
index 0000000..4947fb2
--- /dev/null
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
@@ -0,0 +1,557 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SoftAACEncoder2"
+#include <utils/Log.h>
+
+#include "SoftAACEncoder2.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/hexdump.h>
+
+namespace android {
+
+template<class T>
+static void InitOMXParams(T *params) {
+    params->nSize = sizeof(T);
+    params->nVersion.s.nVersionMajor = 1;
+    params->nVersion.s.nVersionMinor = 0;
+    params->nVersion.s.nRevision = 0;
+    params->nVersion.s.nStep = 0;
+}
+
+SoftAACEncoder2::SoftAACEncoder2(
+        const char *name,
+        const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData,
+        OMX_COMPONENTTYPE **component)
+    : SimpleSoftOMXComponent(name, callbacks, appData, component),
+      mAACEncoder(NULL),
+      mNumChannels(1),
+      mSampleRate(44100),
+      mBitRate(0),
+      mAACProfile(OMX_AUDIO_AACObjectLC),
+      mSentCodecSpecificData(false),
+      mInputSize(0),
+      mInputFrame(NULL),
+      mInputTimeUs(-1ll),
+      mSawInputEOS(false),
+      mSignalledError(false) {
+    initPorts();
+    CHECK_EQ(initEncoder(), (status_t)OK);
+    setAudioParams();
+}
+
+SoftAACEncoder2::~SoftAACEncoder2() {
+    aacEncClose(&mAACEncoder);
+
+    delete[] mInputFrame;
+    mInputFrame = NULL;
+}
+
+void SoftAACEncoder2::initPorts() {
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    InitOMXParams(&def);
+
+    def.nPortIndex = 0;
+    def.eDir = OMX_DirInput;
+    def.nBufferCountMin = kNumBuffers;
+    def.nBufferCountActual = def.nBufferCountMin;
+    def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t) * 2;
+    def.bEnabled = OMX_TRUE;
+    def.bPopulated = OMX_FALSE;
+    def.eDomain = OMX_PortDomainAudio;
+    def.bBuffersContiguous = OMX_FALSE;
+    def.nBufferAlignment = 1;
+
+    def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
+    def.format.audio.pNativeRender = NULL;
+    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+    def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
+
+    addPort(def);
+
+    def.nPortIndex = 1;
+    def.eDir = OMX_DirOutput;
+    def.nBufferCountMin = kNumBuffers;
+    def.nBufferCountActual = def.nBufferCountMin;
+    def.nBufferSize = 8192;
+    def.bEnabled = OMX_TRUE;
+    def.bPopulated = OMX_FALSE;
+    def.eDomain = OMX_PortDomainAudio;
+    def.bBuffersContiguous = OMX_FALSE;
+    def.nBufferAlignment = 2;
+
+    def.format.audio.cMIMEType = const_cast<char *>("audio/aac");
+    def.format.audio.pNativeRender = NULL;
+    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+    def.format.audio.eEncoding = OMX_AUDIO_CodingAAC;
+
+    addPort(def);
+}
+
+status_t SoftAACEncoder2::initEncoder() {
+    if (AACENC_OK != aacEncOpen(&mAACEncoder, 0, 0)) {
+        ALOGE("Failed to init AAC encoder");
+        return UNKNOWN_ERROR;
+    }
+    return OK;
+}
+
+OMX_ERRORTYPE SoftAACEncoder2::internalGetParameter(
+        OMX_INDEXTYPE index, OMX_PTR params) {
+    switch (index) {
+        case OMX_IndexParamAudioPortFormat:
+        {
+            OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+                (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+            if (formatParams->nPortIndex > 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (formatParams->nIndex > 0) {
+                return OMX_ErrorNoMore;
+            }
+
+            formatParams->eEncoding =
+                (formatParams->nPortIndex == 0)
+                    ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingAAC;
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioAac:
+        {
+            OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams =
+                (OMX_AUDIO_PARAM_AACPROFILETYPE *)params;
+
+            if (aacParams->nPortIndex != 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            aacParams->nBitRate = mBitRate;
+            aacParams->nAudioBandWidth = 0;
+            aacParams->nAACtools = 0;
+            aacParams->nAACERtools = 0;
+            aacParams->eAACProfile = (OMX_AUDIO_AACPROFILETYPE) mAACProfile;
+            aacParams->eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF;
+            aacParams->eChannelMode = OMX_AUDIO_ChannelModeStereo;
+
+            aacParams->nChannels = mNumChannels;
+            aacParams->nSampleRate = mSampleRate;
+            aacParams->nFrameLength = 0;
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioPcm:
+        {
+            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+            if (pcmParams->nPortIndex != 0) {
+                return OMX_ErrorUndefined;
+            }
+
+            pcmParams->eNumData = OMX_NumericalDataSigned;
+            pcmParams->eEndian = OMX_EndianBig;
+            pcmParams->bInterleaved = OMX_TRUE;
+            pcmParams->nBitPerSample = 16;
+            pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
+            pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
+            pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
+
+            pcmParams->nChannels = mNumChannels;
+            pcmParams->nSamplingRate = mSampleRate;
+
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return SimpleSoftOMXComponent::internalGetParameter(index, params);
+    }
+}
+
+OMX_ERRORTYPE SoftAACEncoder2::internalSetParameter(
+        OMX_INDEXTYPE index, const OMX_PTR params) {
+    switch (index) {
+        case OMX_IndexParamStandardComponentRole:
+        {
+            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
+                (const OMX_PARAM_COMPONENTROLETYPE *)params;
+
+            if (strncmp((const char *)roleParams->cRole,
+                        "audio_encoder.aac",
+                        OMX_MAX_STRINGNAME_SIZE - 1)) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioPortFormat:
+        {
+            const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+                (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+            if (formatParams->nPortIndex > 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (formatParams->nIndex > 0) {
+                return OMX_ErrorNoMore;
+            }
+
+            if ((formatParams->nPortIndex == 0
+                        && formatParams->eEncoding != OMX_AUDIO_CodingPCM)
+                || (formatParams->nPortIndex == 1
+                        && formatParams->eEncoding != OMX_AUDIO_CodingAAC)) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioAac:
+        {
+            OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams =
+                (OMX_AUDIO_PARAM_AACPROFILETYPE *)params;
+
+            if (aacParams->nPortIndex != 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            mBitRate = aacParams->nBitRate;
+            mNumChannels = aacParams->nChannels;
+            mSampleRate = aacParams->nSampleRate;
+
+            if (aacParams->eAACProfile != OMX_AUDIO_AACObjectNull) {
+                mAACProfile = aacParams->eAACProfile;
+            }
+
+            if (setAudioParams() != OK) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioPcm:
+        {
+            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+            if (pcmParams->nPortIndex != 0) {
+                return OMX_ErrorUndefined;
+            }
+
+            mNumChannels = pcmParams->nChannels;
+            mSampleRate = pcmParams->nSamplingRate;
+
+            if (setAudioParams() != OK) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return SimpleSoftOMXComponent::internalSetParameter(index, params);
+    }
+}
+
+CHANNEL_MODE getChannelMode(OMX_U32 nChannels) {
+    CHANNEL_MODE chMode = MODE_INVALID;
+    switch (nChannels) {
+        case 1: chMode = MODE_1; break;
+        case 2: chMode = MODE_2; break;
+        case 3: chMode = MODE_1_2; break;
+        case 4: chMode = MODE_1_2_1; break;
+        case 5: chMode = MODE_1_2_2; break;
+        case 6: chMode = MODE_1_2_2_1; break;
+        default: chMode = MODE_INVALID;
+    }
+    return chMode;
+}
+
+status_t SoftAACEncoder2::setAudioParams() {
+    // We call this whenever sample rate, number of channels or bitrate change
+    // in reponse to setParameter calls.
+
+    ALOGV("setAudioParams: %lu Hz, %lu channels, %lu bps",
+         mSampleRate, mNumChannels, mBitRate);
+
+    if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_AOT,
+            mAACProfile == OMX_AUDIO_AACObjectELD ? AOT_ER_AAC_ELD : AOT_AAC_LC)) {
+        ALOGE("Failed to set AAC encoder parameters");
+        return UNKNOWN_ERROR;
+    }
+
+    if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_SAMPLERATE, mSampleRate)) {
+        ALOGE("Failed to set AAC encoder parameters");
+        return UNKNOWN_ERROR;
+    }
+    if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_BITRATE, mBitRate)) {
+        ALOGE("Failed to set AAC encoder parameters");
+        return UNKNOWN_ERROR;
+    }
+    if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_CHANNELMODE,
+            getChannelMode(mNumChannels))) {
+        ALOGE("Failed to set AAC encoder parameters");
+        return UNKNOWN_ERROR;
+    }
+    if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_TRANSMUX, TT_MP4_RAW)) {
+        ALOGE("Failed to set AAC encoder parameters");
+        return UNKNOWN_ERROR;
+    }
+
+    return OK;
+}
+
+void SoftAACEncoder2::onQueueFilled(OMX_U32 portIndex) {
+    if (mSignalledError) {
+        return;
+    }
+
+    List<BufferInfo *> &inQueue = getPortQueue(0);
+    List<BufferInfo *> &outQueue = getPortQueue(1);
+
+    if (!mSentCodecSpecificData) {
+        // The very first thing we want to output is the codec specific
+        // data. It does not require any input data but we will need an
+        // output buffer to store it in.
+
+        if (outQueue.empty()) {
+            return;
+        }
+
+        if (AACENC_OK != aacEncEncode(mAACEncoder, NULL, NULL, NULL, NULL)) {
+            ALOGE("Failed to initialize AAC encoder");
+            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+            mSignalledError = true;
+            return;
+        }
+
+        AACENC_InfoStruct encInfo;
+        if (AACENC_OK != aacEncInfo(mAACEncoder, &encInfo)) {
+            ALOGE("Failed to get AAC encoder info");
+            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+            mSignalledError = true;
+            return;
+        }
+
+        BufferInfo *outInfo = *outQueue.begin();
+        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+        outHeader->nFilledLen = encInfo.confSize;
+        outHeader->nFlags = OMX_BUFFERFLAG_CODECCONFIG;
+
+        uint8_t *out = outHeader->pBuffer + outHeader->nOffset;
+        memcpy(out, encInfo.confBuf, encInfo.confSize);
+
+        outQueue.erase(outQueue.begin());
+        outInfo->mOwnedByUs = false;
+        notifyFillBufferDone(outHeader);
+
+        mSentCodecSpecificData = true;
+    }
+
+    size_t numBytesPerInputFrame =
+        mNumChannels * kNumSamplesPerFrame * sizeof(int16_t);
+
+    // BUGBUG: Fraunhofer's decoder chokes on large chunks of AAC-ELD
+    if (mAACProfile == OMX_AUDIO_AACObjectELD && numBytesPerInputFrame > 512) {
+        numBytesPerInputFrame = 512;
+    }
+
+    for (;;) {
+        // We do the following until we run out of buffers.
+
+        while (mInputSize < numBytesPerInputFrame) {
+            // As long as there's still input data to be read we
+            // will drain "kNumSamplesPerFrame * mNumChannels" samples
+            // into the "mInputFrame" buffer and then encode those
+            // as a unit into an output buffer.
+
+            if (mSawInputEOS || inQueue.empty()) {
+                return;
+            }
+
+            BufferInfo *inInfo = *inQueue.begin();
+            OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+
+            const void *inData = inHeader->pBuffer + inHeader->nOffset;
+
+            size_t copy = numBytesPerInputFrame - mInputSize;
+            if (copy > inHeader->nFilledLen) {
+                copy = inHeader->nFilledLen;
+            }
+
+            if (mInputFrame == NULL) {
+                mInputFrame = new int16_t[kNumSamplesPerFrame * mNumChannels];
+            }
+
+            if (mInputSize == 0) {
+                mInputTimeUs = inHeader->nTimeStamp;
+            }
+
+            memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy);
+            mInputSize += copy;
+
+            inHeader->nOffset += copy;
+            inHeader->nFilledLen -= copy;
+
+            // "Time" on the input buffer has in effect advanced by the
+            // number of audio frames we just advanced nOffset by.
+            inHeader->nTimeStamp +=
+                (copy * 1000000ll / mSampleRate)
+                    / (mNumChannels * sizeof(int16_t));
+
+            if (inHeader->nFilledLen == 0) {
+                if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+                    mSawInputEOS = true;
+
+                    // Pad any remaining data with zeroes.
+                    memset((uint8_t *)mInputFrame + mInputSize,
+                           0,
+                           numBytesPerInputFrame - mInputSize);
+
+                    mInputSize = numBytesPerInputFrame;
+                }
+
+                inQueue.erase(inQueue.begin());
+                inInfo->mOwnedByUs = false;
+                notifyEmptyBufferDone(inHeader);
+
+                inData = NULL;
+                inHeader = NULL;
+                inInfo = NULL;
+            }
+        }
+
+        // At this  point we have all the input data necessary to encode
+        // a single frame, all we need is an output buffer to store the result
+        // in.
+
+        if (outQueue.empty()) {
+            return;
+        }
+
+        BufferInfo *outInfo = *outQueue.begin();
+        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+
+        uint8_t *outPtr = (uint8_t *)outHeader->pBuffer + outHeader->nOffset;
+        size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset;
+
+        AACENC_InArgs inargs;
+        AACENC_OutArgs outargs;
+        memset(&inargs, 0, sizeof(inargs));
+        memset(&outargs, 0, sizeof(outargs));
+        inargs.numInSamples = numBytesPerInputFrame / sizeof(int16_t);
+
+        void* inBuffer[]        = { (unsigned char *)mInputFrame };
+        INT   inBufferIds[]     = { IN_AUDIO_DATA };
+        INT   inBufferSize[]    = { numBytesPerInputFrame };
+        INT   inBufferElSize[]  = { sizeof(int16_t) };
+
+        AACENC_BufDesc inBufDesc;
+        inBufDesc.numBufs           = sizeof(inBuffer) / sizeof(void*);
+        inBufDesc.bufs              = (void**)&inBuffer;
+        inBufDesc.bufferIdentifiers = inBufferIds;
+        inBufDesc.bufSizes          = inBufferSize;
+        inBufDesc.bufElSizes        = inBufferElSize;
+
+        void* outBuffer[]       = { outPtr };
+        INT   outBufferIds[]    = { OUT_BITSTREAM_DATA };
+        INT   outBufferSize[]   = { 0 };
+        INT   outBufferElSize[] = { sizeof(UCHAR) };
+
+        AACENC_BufDesc outBufDesc;
+        outBufDesc.numBufs           = sizeof(outBuffer) / sizeof(void*);
+        outBufDesc.bufs              = (void**)&outBuffer;
+        outBufDesc.bufferIdentifiers = outBufferIds;
+        outBufDesc.bufSizes          = outBufferSize;
+        outBufDesc.bufElSizes        = outBufferElSize;
+
+        // Encode the mInputFrame, which is treated as a modulo buffer
+        AACENC_ERROR encoderErr = AACENC_OK;
+        size_t nOutputBytes = 0;
+        do {
+            memset(&outargs, 0, sizeof(outargs));
+
+            outBuffer[0] = outPtr;
+            outBufferSize[0] = outAvailable - nOutputBytes;
+
+            encoderErr = aacEncEncode(mAACEncoder,
+                                      &inBufDesc,
+                                      &outBufDesc,
+                                      &inargs,
+                                      &outargs);
+
+            if (encoderErr == AACENC_OK) {
+                outPtr += outargs.numOutBytes;
+                nOutputBytes += outargs.numOutBytes;
+
+                if (outargs.numInSamples > 0) {
+                    int numRemainingSamples = inargs.numInSamples - outargs.numInSamples;
+                    if (numRemainingSamples > 0) {
+                        memmove(mInputFrame,
+                                &mInputFrame[outargs.numInSamples],
+                                sizeof(int16_t) * numRemainingSamples);
+                    }
+                    inargs.numInSamples -= outargs.numInSamples;
+                }
+            }
+        } while (encoderErr == AACENC_OK && inargs.numInSamples > 0);
+
+        outHeader->nFilledLen = nOutputBytes;
+
+        outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;
+
+        if (mSawInputEOS) {
+            // We also tag this output buffer with EOS if it corresponds
+            // to the final input buffer.
+            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+        }
+
+        outHeader->nTimeStamp = mInputTimeUs;
+
+#if 0
+        ALOGI("sending %d bytes of data (time = %lld us, flags = 0x%08lx)",
+              nOutputBytes, mInputTimeUs, outHeader->nFlags);
+
+        hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen);
+#endif
+
+        outQueue.erase(outQueue.begin());
+        outInfo->mOwnedByUs = false;
+        notifyFillBufferDone(outHeader);
+
+        outHeader = NULL;
+        outInfo = NULL;
+
+        mInputSize = 0;
+    }
+}
+
+}  // namespace android
+
+android::SoftOMXComponent *createSoftOMXComponent(
+        const char *name, const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
+    return new android::SoftAACEncoder2(name, callbacks, appData, component);
+}
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
new file mode 100644
index 0000000..2603f4f
--- /dev/null
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SOFT_AAC_ENCODER_2_H_
+
+#define SOFT_AAC_ENCODER_2_H_
+
+#include "SimpleSoftOMXComponent.h"
+
+#include "aacenc_lib.h"
+
+namespace android {
+
+struct SoftAACEncoder2 : public SimpleSoftOMXComponent {
+    SoftAACEncoder2(
+            const char *name,
+            const OMX_CALLBACKTYPE *callbacks,
+            OMX_PTR appData,
+            OMX_COMPONENTTYPE **component);
+
+protected:
+    virtual ~SoftAACEncoder2();
+
+    virtual OMX_ERRORTYPE internalGetParameter(
+            OMX_INDEXTYPE index, OMX_PTR params);
+
+    virtual OMX_ERRORTYPE internalSetParameter(
+            OMX_INDEXTYPE index, const OMX_PTR params);
+
+    virtual void onQueueFilled(OMX_U32 portIndex);
+
+private:
+    enum {
+        kNumBuffers             = 4,
+        kNumSamplesPerFrame     = 1024
+    };
+
+    HANDLE_AACENCODER mAACEncoder;
+
+    OMX_U32 mNumChannels;
+    OMX_U32 mSampleRate;
+    OMX_U32 mBitRate;
+    OMX_U32 mAACProfile;
+
+    bool mSentCodecSpecificData;
+    size_t mInputSize;
+    int16_t *mInputFrame;
+    int64_t mInputTimeUs;
+
+    bool mSawInputEOS;
+
+    bool mSignalledError;
+
+    void initPorts();
+    status_t initEncoder();
+
+    status_t setAudioParams();
+
+    DISALLOW_EVIL_CONSTRUCTORS(SoftAACEncoder2);
+};
+
+}  // namespace android
+
+#endif  // SOFT_AAC_ENCODER_2_H_