Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8d30b2d2 authored by James Dong's avatar James Dong Committed by Android (Google) Code Review
Browse files

Merge "Support AAC recording" into kraken

parents ce0bd717 abed93a5
Loading
Loading
Loading
Loading
+200 −30
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@
#include <utils/Errors.h>
#include <sys/types.h>
#include <unistd.h>
#include <ctype.h>

namespace android {

@@ -149,9 +150,149 @@ status_t StagefrightRecorder::setOutputFile(int fd, int64_t offset, int64_t leng
    return OK;
}

status_t StagefrightRecorder::setParameters(const String8 &params) {
    mParams = params;
// Attempt to parse an int64 literal optionally surrounded by whitespace,
// returns true on success, false otherwise.
static bool safe_strtoi64(const char *s, int32_t *val) {
    char *end;
    *val = static_cast<int32_t>(strtoll(s, &end, 10));

    if (end == s || errno == ERANGE) {
        return false;
    }

    // Skip trailing whitespace
    while (isspace(*end)) {
        ++end;
    }

    // For a successful return, the string must contain nothing but a valid
    // int64 literal optionally surrounded by whitespace.

    return *end == '\0';
}

// Trim both leading and trailing whitespace from the given string.
static void TrimString(String8 *s) {
    size_t num_bytes = s->bytes();
    const char *data = s->string();

    size_t leading_space = 0;
    while (leading_space < num_bytes && isspace(data[leading_space])) {
        ++leading_space;
    }

    size_t i = num_bytes;
    while (i > leading_space && isspace(data[i - 1])) {
        --i;
    }

    s->setTo(String8(&data[leading_space], i - leading_space));
}

status_t StagefrightRecorder::setParamAudioSamplingRate(int32_t sampleRate) {
    LOGV("setParamAudioSamplingRate: %d", sampleRate);
    mSampleRate = sampleRate;
    return OK;
}

status_t StagefrightRecorder::setParamAudioNumberOfChannels(int32_t channels) {
    LOGV("setParamAudioNumberOfChannels: %d", channels);
    mAudioChannels = channels;
    return OK;
}

status_t StagefrightRecorder::setParamAudioEncodingBitRate(int32_t bitRate) {
    LOGV("setParamAudioEncodingBitRate: %d", bitRate);
    mAudioBitRate = bitRate;
    return OK;
}

status_t StagefrightRecorder::setParamVideoEncodingBitRate(int32_t bitRate) {
    LOGV("setParamVideoEncodingBitRate: %d", bitRate);
    mVideoBitRate = bitRate;
    return OK;
}

status_t StagefrightRecorder::setMaxDurationOrFileSize(int32_t limit, bool limit_is_duration) {
    LOGV("setMaxDurationOrFileSize: limit (%d) for %s",
            limit, limit_is_duration?"duration":"size");
    return OK;
}

status_t StagefrightRecorder::setParameter(
        const String8 &key, const String8 &value) {
    LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string());
    if (key == "max-duration") {
        int32_t max_duration_ms;
        if (safe_strtoi64(value.string(), &max_duration_ms)) {
            return setMaxDurationOrFileSize(
                    max_duration_ms, true /* limit_is_duration */);
        }
    } else if (key == "max-filesize") {
        int32_t max_filesize_bytes;
        if (safe_strtoi64(value.string(), &max_filesize_bytes)) {
            return setMaxDurationOrFileSize(
                    max_filesize_bytes, false /* limit is filesize */);
        }
    } else if (key == "audio-param-sampling-rate") {
        int32_t sampling_rate;
        if (safe_strtoi64(value.string(), &sampling_rate)) {
            return setParamAudioSamplingRate(sampling_rate);
        }
    } else if (key == "audio-param-number-of-channels") {
        int32_t number_of_channels;
        if (safe_strtoi64(value.string(), &number_of_channels)) {
            return setParamAudioNumberOfChannels(number_of_channels);
        }
    } else if (key == "audio-param-encoding-bitrate") {
        int32_t audio_bitrate;
        if (safe_strtoi64(value.string(), &audio_bitrate)) {
            return setParamAudioEncodingBitRate(audio_bitrate);
        }
    } else if (key == "video-param-encoding-bitrate") {
        int32_t video_bitrate;
        if (safe_strtoi64(value.string(), &video_bitrate)) {
            return setParamVideoEncodingBitRate(video_bitrate);
        }
    } else {
        LOGE("setParameter: failed to find key %s", key.string());
        return BAD_VALUE;
    }
    return OK;
}

status_t StagefrightRecorder::setParameters(const String8 &params) {
    LOGV("setParameters: %s", params.string());
    const char *cparams = params.string();
    const char *key_start = cparams;
    for (;;) {
        const char *equal_pos = strchr(key_start, '=');
        if (equal_pos == NULL) {
            LOGE("Parameters %s miss a value", cparams);
            return BAD_VALUE;
        }
        String8 key(key_start, equal_pos - key_start);
        TrimString(&key);
        if (key.length() == 0) {
            LOGE("Parameters %s contains an empty key", cparams);
            return BAD_VALUE;
        }
        const char *value_start = equal_pos + 1;
        const char *semicolon_pos = strchr(value_start, ';');
        String8 value;
        if (semicolon_pos == NULL) {
            value.setTo(value_start);
        } else {
            value.setTo(value_start, semicolon_pos - value_start);
        }
        if (setParameter(key, value) != OK) {
            return BAD_VALUE;
        }
        if (semicolon_pos == NULL) {
            break;  // Reaches the end
        }
        key_start = semicolon_pos + 1;
    }
    return OK;
}

@@ -185,35 +326,46 @@ status_t StagefrightRecorder::start() {
    }
}

sp<MediaSource> StagefrightRecorder::createAMRAudioSource() {
    uint32_t sampleRate =
        mAudioEncoder == AUDIO_ENCODER_AMR_NB ? 8000 : 16000;

sp<MediaSource> StagefrightRecorder::createAudioSource() {
    sp<AudioSource> audioSource =
        new AudioSource(
                mAudioSource,
                sampleRate,
                mSampleRate,
                AudioSystem::CHANNEL_IN_MONO);

    status_t err = audioSource->initCheck();

    if (err != OK) {
        LOGE("audio source is not initialized");
        return NULL;
    }

    sp<MetaData> encMeta = new MetaData;
    encMeta->setCString(
            kKeyMIMEType,
            mAudioEncoder == AUDIO_ENCODER_AMR_NB
                ? MEDIA_MIMETYPE_AUDIO_AMR_NB : MEDIA_MIMETYPE_AUDIO_AMR_WB);
    const char *mime;
    switch (mAudioEncoder) {
        case AUDIO_ENCODER_AMR_NB:
        case AUDIO_ENCODER_DEFAULT:
            mime = MEDIA_MIMETYPE_AUDIO_AMR_NB;
            break;
        case AUDIO_ENCODER_AMR_WB:
            mime = MEDIA_MIMETYPE_AUDIO_AMR_WB;
            break;
        case AUDIO_ENCODER_AAC:
            mime = MEDIA_MIMETYPE_AUDIO_AAC;
            break;
        default:
            LOGE("Unknown audio encoder: %d", mAudioEncoder);
            return NULL;
    }
    encMeta->setCString(kKeyMIMEType, mime);

    int32_t maxInputSize;
    CHECK(audioSource->getFormat()->findInt32(
                kKeyMaxInputSize, &maxInputSize));

    encMeta->setInt32(kKeyMaxInputSize, maxInputSize);
    encMeta->setInt32(kKeyChannelCount, 1);
    encMeta->setInt32(kKeySampleRate, sampleRate);
    encMeta->setInt32(kKeyChannelCount, mAudioChannels);
    encMeta->setInt32(kKeySampleRate, mSampleRate);

    OMXClient client;
    CHECK_EQ(client.connect(), OK);
@@ -240,7 +392,7 @@ status_t StagefrightRecorder::startAMRRecording() {
        return UNKNOWN_ERROR;
    }

    sp<MediaSource> audioEncoder = createAMRAudioSource();
    sp<MediaSource> audioEncoder = createAudioSource();

    if (audioEncoder == NULL) {
        return UNKNOWN_ERROR;
@@ -257,6 +409,26 @@ status_t StagefrightRecorder::startAMRRecording() {
status_t StagefrightRecorder::startMPEG4Recording() {
    mWriter = new MPEG4Writer(dup(mOutputFd));

    // Add audio source first if it exists
    if (mAudioSource != AUDIO_SOURCE_LIST_END) {
        sp<MediaSource> audioEncoder;
        switch(mAudioEncoder) {
            case AUDIO_ENCODER_AMR_NB:
            case AUDIO_ENCODER_AMR_WB:
            case AUDIO_ENCODER_AAC:
                audioEncoder = createAudioSource();
                break;
            default:
                LOGE("Unsupported audio encoder: %d", mAudioEncoder);
                return UNKNOWN_ERROR;
        }

        if (audioEncoder == NULL) {
            return UNKNOWN_ERROR;
        }

        mWriter->addSource(audioEncoder);
    }
    if (mVideoSource == VIDEO_SOURCE_DEFAULT
            || mVideoSource == VIDEO_SOURCE_CAMERA) {
        CHECK(mCamera != NULL);
@@ -308,16 +480,6 @@ status_t StagefrightRecorder::startMPEG4Recording() {
        mWriter->addSource(encoder);
    }

    if (mAudioSource != AUDIO_SOURCE_LIST_END) {
        sp<MediaSource> audioEncoder = createAMRAudioSource();

        if (audioEncoder == NULL) {
            return UNKNOWN_ERROR;
        }

        mWriter->addSource(audioEncoder);
    }

    mWriter->start();
    return OK;
}
@@ -353,14 +515,22 @@ status_t StagefrightRecorder::close() {
status_t StagefrightRecorder::reset() {
    stop();

    // No audio or video source by default
    mAudioSource = AUDIO_SOURCE_LIST_END;
    mVideoSource = VIDEO_SOURCE_LIST_END;
    mOutputFormat = OUTPUT_FORMAT_LIST_END;
    mAudioEncoder = AUDIO_ENCODER_LIST_END;
    mVideoEncoder = VIDEO_ENCODER_LIST_END;
    mVideoWidth = -1;
    mVideoHeight = -1;
    mFrameRate = -1;

    // Default parameters
    mOutputFormat  = OUTPUT_FORMAT_THREE_GPP;
    mAudioEncoder  = AUDIO_ENCODER_AMR_NB;
    mVideoEncoder  = VIDEO_ENCODER_H263;
    mVideoWidth    = 176;
    mVideoHeight   = 144;
    mFrameRate     = 20;
    mVideoBitRate  = 192000;
    mSampleRate    = 8000;
    mAudioChannels = 1;
    mAudioBitRate  = 12200;

    mOutputFd = -1;
    mFlags = 0;

+14 −3
Original line number Diff line number Diff line
@@ -68,15 +68,26 @@ private:
    output_format mOutputFormat;
    audio_encoder mAudioEncoder;
    video_encoder mVideoEncoder;
    int mVideoWidth, mVideoHeight;
    int mFrameRate;
    int32_t mVideoWidth, mVideoHeight;
    int32_t mFrameRate;
    int32_t mVideoBitRate;
    int32_t mAudioBitRate;
    int32_t mAudioChannels;
    int32_t mSampleRate;

    String8 mParams;
    int mOutputFd;
    int32_t mFlags;

    status_t startMPEG4Recording();
    status_t startAMRRecording();
    sp<MediaSource> createAMRAudioSource();
    sp<MediaSource> createAudioSource();
    status_t setParameter(const String8 &key, const String8 &value);
    status_t setParamVideoEncodingBitRate(int32_t bitRate);
    status_t setParamAudioEncodingBitRate(int32_t bitRate);
    status_t setParamAudioNumberOfChannels(int32_t channles);
    status_t setParamAudioSamplingRate(int32_t sampleRate);
    status_t setMaxDurationOrFileSize(int32_t limit, bool limit_is_duration);

    StagefrightRecorder(const StagefrightRecorder &);
    StagefrightRecorder &operator=(const StagefrightRecorder &);
+4 −0
Original line number Diff line number Diff line
@@ -14,6 +14,10 @@
 * limitations under the License.
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "AudioSource"
#include <utils/Log.h>

#include <media/stagefright/AudioSource.h>

#include <media/AudioRecord.h>
+85 −22
Original line number Diff line number Diff line
@@ -14,6 +14,10 @@
 * limitations under the License.
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "MPEG4Writer"
#include <utils/Log.h>

#include <arpa/inet.h>

#include <ctype.h>
@@ -58,6 +62,8 @@ private:
    };
    List<SampleInfo> mSampleInfos;

    List<int32_t> mStssTableEntries;

    void *mCodecSpecificData;
    size_t mCodecSpecificDataSize;
    bool mGotAllCodecSpecificData;
@@ -522,7 +528,8 @@ void MPEG4Writer::Track::threadEntry() {
    sp<MetaData> meta = mSource->getFormat();
    const char *mime;
    meta->findCString(kKeyMIMEType, &mime);
    bool is_mpeg4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4);
    bool is_mpeg4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
                    !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);
    bool is_avc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
    int32_t count = 0;

@@ -668,6 +675,9 @@ void MPEG4Writer::Track::threadEntry() {

        info.offset = offset;


        bool is_audio = !strncasecmp(mime, "audio/", 6);

        int64_t timestampUs;
        CHECK(buffer->meta_data()->findInt64(kKeyTime, &timestampUs));

@@ -680,6 +690,12 @@ void MPEG4Writer::Track::threadEntry() {

        mSampleInfos.push_back(info);

        int32_t isSync = false;
        buffer->meta_data()->findInt32(kKeyIsSyncFrame, &isSync);
        if (isSync) {
            mStssTableEntries.push_back(mSampleInfos.size());
        }
        // Our timestamp is in ms.
        buffer->release();
        buffer = NULL;
    }
@@ -735,8 +751,8 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
            success = success && mMeta->findInt32(kKeyHeight, &height);
            CHECK(success);

            mOwner->writeInt32(width);
            mOwner->writeInt32(height);
            mOwner->writeInt32(width << 16);   // 32-bit fixed-point value
            mOwner->writeInt32(height << 16);  // 32-bit fixed-point value
        }
      mOwner->endBox();  // tkhd

@@ -754,26 +770,15 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {

        mOwner->beginBox("hdlr");
          mOwner->writeInt32(0);             // version=0, flags=0
          mOwner->writeInt32(0);             // predefined
          mOwner->writeFourcc(is_audio ? "soun" : "vide");
          mOwner->writeInt32(0);             // component type: should be mhlr
          mOwner->writeFourcc(is_audio ? "soun" : "vide");  // component subtype
          mOwner->writeInt32(0);             // reserved
          mOwner->writeInt32(0);             // reserved
          mOwner->writeInt32(0);             // reserved
          mOwner->writeCString("");          // name
          mOwner->writeCString("SoundHandler");          // name
        mOwner->endBox();

        mOwner->beginBox("minf");

          mOwner->beginBox("dinf");
            mOwner->beginBox("dref");
              mOwner->writeInt32(0);  // version=0, flags=0
              mOwner->writeInt32(1);
              mOwner->beginBox("url ");
                mOwner->writeInt32(1);  // version=0, flags=1
              mOwner->endBox();  // url
            mOwner->endBox();  // dref
          mOwner->endBox();  // dinf

          if (is_audio) {
              mOwner->beginBox("smhd");
              mOwner->writeInt32(0);           // version=0, flags=0
@@ -789,6 +794,17 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
              mOwner->writeInt16(0);
              mOwner->endBox();
          }

          mOwner->beginBox("dinf");
            mOwner->beginBox("dref");
              mOwner->writeInt32(0);  // version=0, flags=0
              mOwner->writeInt32(1);
              mOwner->beginBox("url ");
                mOwner->writeInt32(1);  // version=0, flags=1
              mOwner->endBox();  // url
            mOwner->endBox();  // dref
          mOwner->endBox();  // dinf

       mOwner->endBox();  // minf

        mOwner->beginBox("stbl");
@@ -802,6 +818,8 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
                    fourcc = "samr";
                } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
                    fourcc = "sawb";
                } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
                    fourcc = "mp4a";
                } else {
                    LOGE("Unknown mime type '%s'.", mime);
                    CHECK(!"should not be here, unknown mime type.");
@@ -810,10 +828,12 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
                mOwner->beginBox(fourcc);          // audio format
                  mOwner->writeInt32(0);           // reserved
                  mOwner->writeInt16(0);           // reserved
                  mOwner->writeInt16(0);           // data ref index
                  mOwner->writeInt16(0x1);         // data ref index
                  mOwner->writeInt32(0);           // reserved
                  mOwner->writeInt32(0);           // reserved
                  mOwner->writeInt16(2);           // channel count
                  int32_t nChannels;
                  CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels));
                  mOwner->writeInt16(nChannels);   // channel count
                  mOwner->writeInt16(16);          // sample size
                  mOwner->writeInt16(0);           // predefined
                  mOwner->writeInt16(0);           // reserved
@@ -823,6 +843,38 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
                  CHECK(success);

                  mOwner->writeInt32(samplerate << 16);
                  if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
                    mOwner->beginBox("esds");

                        mOwner->writeInt32(0);     // version=0, flags=0
                        mOwner->writeInt8(0x03);   // ES_DescrTag
                        mOwner->writeInt8(23 + mCodecSpecificDataSize);
                        mOwner->writeInt16(0x0000);// ES_ID
                        mOwner->writeInt8(0x00);

                        mOwner->writeInt8(0x04);   // DecoderConfigDescrTag
                        mOwner->writeInt8(15 + mCodecSpecificDataSize);
                        mOwner->writeInt8(0x40);   // objectTypeIndication ISO/IEC 14492-2
                        mOwner->writeInt8(0x15);   // streamType AudioStream

                        mOwner->writeInt16(0x03);  // XXX
                        mOwner->writeInt8(0x00);   // buffer size 24-bit
                        mOwner->writeInt32(96000); // max bit rate
                        mOwner->writeInt32(96000); // avg bit rate

                        mOwner->writeInt8(0x05);   // DecoderSpecificInfoTag
                        mOwner->writeInt8(mCodecSpecificDataSize);
                        mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);

                        static const uint8_t kData2[] = {
                            0x06,  // SLConfigDescriptorTag
                            0x01,
                            0x02
                        };
                        mOwner->write(kData2, sizeof(kData2));

                    mOwner->endBox();  // esds
                  }
                mOwner->endBox();
            } else {
                if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
@@ -943,6 +995,17 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {

          mOwner->endBox();  // stts

          if (!is_audio) {
            mOwner->beginBox("stss");
              mOwner->writeInt32(0);  // version=0, flags=0
              mOwner->writeInt32(mStssTableEntries.size());  // number of sync frames
              for (List<int32_t>::iterator it = mStssTableEntries.begin();
                   it != mStssTableEntries.end(); ++it) {
                  mOwner->writeInt32(*it);
              }
            mOwner->endBox();  // stss
          }

          mOwner->beginBox("stsz");
            mOwner->writeInt32(0);  // version=0, flags=0
            mOwner->writeInt32(0);  // default sample size
@@ -969,7 +1032,7 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
            mOwner->writeInt32(0);  // version=0, flags=0
            mOwner->writeInt32(mSampleInfos.size());
            for (List<SampleInfo>::iterator it = mSampleInfos.begin();
                 it != mSampleInfos.end(); ++it, ++n) {
                 it != mSampleInfos.end(); ++it) {
                mOwner->writeInt64((*it).offset);
            }
          mOwner->endBox();  // co64
+77 −3
Original line number Diff line number Diff line
@@ -520,6 +520,7 @@ status_t OMXCodec::configureCodec(const sp<MetaData> &meta) {

        setAACFormat(numChannels, sampleRate);
    }

    if (!strncasecmp(mMIME, "video/", 6)) {
        int32_t width, height;
        bool success = meta->findInt32(kKeyWidth, &width);
@@ -567,7 +568,8 @@ status_t OMXCodec::configureCodec(const sp<MetaData> &meta) {
    }

    if (!strcmp(mComponentName, "OMX.TI.AMR.encode")
        || !strcmp(mComponentName, "OMX.TI.WBAMR.encode")) {
        || !strcmp(mComponentName, "OMX.TI.WBAMR.encode")
        || !strcmp(mComponentName, "OMX.TI.AAC.encode")) {
        setMinBufferSize(kPortIndexOutput, 8192);  // XXX
    }

@@ -708,7 +710,7 @@ void OMXCodec::setVideoInputFormat(

    OMX_COLOR_FORMATTYPE colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
    if (!strcasecmp("OMX.TI.Video.encoder", mComponentName)) {
        colorFormat = OMX_COLOR_FormatYUV420Planar;
        colorFormat = OMX_COLOR_FormatYCbYCr;
    }


@@ -2127,11 +2129,24 @@ void OMXCodec::setState(State newState) {

void OMXCodec::setRawAudioFormat(
        OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels) {

    // port definition
    OMX_PARAM_PORTDEFINITIONTYPE def;
    InitOMXParams(&def);
    def.nPortIndex = portIndex;
    status_t err = mOMX->getParameter(
            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
    CHECK_EQ(err, OK);
    def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
    CHECK_EQ(mOMX->setParameter(mNode, OMX_IndexParamPortDefinition,
            &def, sizeof(def)), OK);

    // pcm param
    OMX_AUDIO_PARAM_PCMMODETYPE pcmParams;
    InitOMXParams(&pcmParams);
    pcmParams.nPortIndex = portIndex;

    status_t err = mOMX->getParameter(
    err = mOMX->getParameter(
            mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));

    CHECK_EQ(err, OK);
@@ -2171,6 +2186,8 @@ void OMXCodec::setAMRFormat(bool isWAMR) {
    CHECK_EQ(err, OK);

    def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;

    // XXX: Select bandmode based on bit rate
    def.eAMRBandMode =
        isWAMR ? OMX_AUDIO_AMRBandModeWB0 : OMX_AUDIO_AMRBandModeNB0;

@@ -2191,8 +2208,60 @@ void OMXCodec::setAMRFormat(bool isWAMR) {
}

void OMXCodec::setAACFormat(int32_t numChannels, int32_t sampleRate) {
    CHECK(numChannels == 1 || numChannels == 2);
    if (mIsEncoder) {
        //////////////// input port ////////////////////
        setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);

        //////////////// output port ////////////////////
        // format
        OMX_AUDIO_PARAM_PORTFORMATTYPE format;
        format.nPortIndex = kPortIndexOutput;
        format.nIndex = 0;
        status_t err = OMX_ErrorNone;
        while (OMX_ErrorNone == err) {
            CHECK_EQ(mOMX->getParameter(mNode, OMX_IndexParamAudioPortFormat,
                    &format, sizeof(format)), OK);
            if (format.eEncoding == OMX_AUDIO_CodingAAC) {
                break;
            }
            format.nIndex++;
        }
        CHECK_EQ(OK, err);
        CHECK_EQ(mOMX->setParameter(mNode, OMX_IndexParamAudioPortFormat,
                &format, sizeof(format)), OK);

        // port definition
        OMX_PARAM_PORTDEFINITIONTYPE def;
        InitOMXParams(&def);
        def.nPortIndex = kPortIndexOutput;
        CHECK_EQ(mOMX->getParameter(mNode, OMX_IndexParamPortDefinition,
                &def, sizeof(def)), OK);
        def.format.audio.bFlagErrorConcealment = OMX_TRUE;
        def.format.audio.eEncoding = OMX_AUDIO_CodingAAC;
        CHECK_EQ(mOMX->setParameter(mNode, OMX_IndexParamPortDefinition,
                &def, sizeof(def)), OK);

        // profile
        OMX_AUDIO_PARAM_AACPROFILETYPE profile;
        InitOMXParams(&profile);
        profile.nPortIndex = kPortIndexOutput;
        CHECK_EQ(mOMX->getParameter(mNode, OMX_IndexParamAudioAac,
                &profile, sizeof(profile)), OK);
        profile.nChannels = numChannels;
        profile.eChannelMode = (numChannels == 1?
                OMX_AUDIO_ChannelModeMono: OMX_AUDIO_ChannelModeStereo);
        profile.nSampleRate = sampleRate;
        profile.nBitRate = 96000;   // XXX
        profile.nAudioBandWidth = 0;
        profile.nFrameLength = 0;
        profile.nAACtools = OMX_AUDIO_AACToolAll;
        profile.nAACERtools = OMX_AUDIO_AACERNone;
        profile.eAACProfile = OMX_AUDIO_AACObjectLC;
        profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF;
        CHECK_EQ(mOMX->setParameter(mNode, OMX_IndexParamAudioAac,
                &profile, sizeof(profile)), OK);

    } else {
        OMX_AUDIO_PARAM_AACPROFILETYPE profile;
        InitOMXParams(&profile);
@@ -2961,6 +3030,11 @@ void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) {
            } else if (audio_def->eEncoding == OMX_AUDIO_CodingAAC) {
                mOutputFormat->setCString(
                        kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
                int32_t numChannels, sampleRate;
                inputFormat->findInt32(kKeyChannelCount, &numChannels);
                inputFormat->findInt32(kKeySampleRate, &sampleRate);
                mOutputFormat->setInt32(kKeyChannelCount, numChannels);
                mOutputFormat->setInt32(kKeySampleRate, sampleRate);
            } else {
                CHECK(!"Should not be here. Unknown audio encoding.");
            }