OSDN Git Service

add HEVC(H.265) decoder. plz sync:
[android-x86/external-stagefright-plugins.git] / libstagefright / codecs / ffmpegdec / adec / SoftFFmpegAudio.cpp
index beaccaa..304f794 100644 (file)
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MediaDefs.h>
 
-#include "utils/common_utils.h"
 #include "utils/ffmpeg_utils.h"
 
-//#undef realloc
-//#include <stdlib.h>
-
 #define DEBUG_PKT 0
 #define DEBUG_FRM 0
 
-/**
- * Note: DECLARE_ALIGNED should move from "*.h" to here, otherwise
- * "Fatal signal 7 (SIGBUS)"!!! SIGBUS is because of an alignment exception
- */
-DECLARE_ALIGNED(16, uint8_t, mAudioBuf2)[AVCODEC_MAX_AUDIO_FRAME_SIZE * 4];
-
 namespace android {
 
 template<class T>
@@ -50,113 +40,119 @@ static void InitOMXParams(T *params) {
     params->nVersion.s.nStep = 0;
 }
 
+void SoftFFmpegAudio::setMode(const char *name) {
+    if (!strcmp(name, "OMX.ffmpeg.aac.decoder")) {
+        mMode = MODE_AAC;
+       } else if (!strcmp(name, "OMX.ffmpeg.mp3.decoder")) {
+        mMode = MODE_MPEG;
+        mIgnoreExtradata = true;
+    } else if (!strcmp(name, "OMX.ffmpeg.vorbis.decoder")) {
+        mMode = MODE_VORBIS;
+    } else if (!strcmp(name, "OMX.ffmpeg.wma.decoder")) {
+        mMode = MODE_WMA;
+    } else if (!strcmp(name, "OMX.ffmpeg.ra.decoder")) {
+        mMode = MODE_RA;
+    } else if (!strcmp(name, "OMX.ffmpeg.flac.decoder")) {
+        mMode = MODE_FLAC;
+    } else if (!strcmp(name, "OMX.ffmpeg.mp2.decoder")) {
+        mMode = MODE_MPEGL2;
+    } else if (!strcmp(name, "OMX.ffmpeg.ac3.decoder")) {
+        mMode = MODE_AC3;
+    } else if (!strcmp(name, "OMX.ffmpeg.ape.decoder")) {
+        mMode = MODE_APE;
+    } else if (!strcmp(name, "OMX.ffmpeg.dts.decoder")) {
+        mMode = MODE_DTS;
+    } else if (!strcmp(name, "OMX.ffmpeg.atrial.decoder")) {
+        mMode = MODE_TRIAL;
+    } else {
+        TRESPASS();
+    }
+}
+
 SoftFFmpegAudio::SoftFFmpegAudio(
         const char *name,
         const OMX_CALLBACKTYPE *callbacks,
         OMX_PTR appData,
         OMX_COMPONENTTYPE **component)
     : SimpleSoftOMXComponent(name, callbacks, appData, component),
-      mMode(MODE_MPEG),
-      mCtx(NULL),
-      mSwrCtx(NULL),
-      mCodecOpened(false),
+      mMode(MODE_NONE),
+      mFFmpegAlreadyInited(false),
+      mCodecAlreadyOpened(false),
       mExtradataReady(false),
       mIgnoreExtradata(false),
-      mFlushComplete(false),
-      mSignalledError(false),
-      mReceivedEOS(false),
+      mCtx(NULL),
+      mSwrCtx(NULL),
       mFrame(NULL),
-      mAnchorTimeUs(0),
-      mNumFramesOutput(0),
+      mEOSStatus(INPUT_DATA_AVAILABLE),
+      mSignalledError(false),
+      mAudioClock(0),
       mInputBufferSize(0),
-      mAudioBufferSize(0),
-      mNumChannels(2),
-      mSamplingRate(44100),
-      mBitRate(0),
-      mBlockAlign(0),
-      mSamplingFmt(AV_SAMPLE_FMT_S16),
-      mAudioConfigChanged(false),
+      mResampledData(NULL),
+      mResampledDataSize(0),
       mOutputPortSettingsChange(NONE) {
-    if (!strcmp(name, "OMX.ffmpeg.mp3.decoder")) {
-        mMode = MODE_MPEG;
-        mIgnoreExtradata = true;
-    } else if (!strcmp(name, "OMX.ffmpeg.mp1.decoder")) {
-        mMode = MODE_MPEGL1;
-    } else if (!strcmp(name, "OMX.ffmpeg.mp2.decoder")) {
-        mMode = MODE_MPEGL2;
-    } else if (!strcmp(name, "OMX.ffmpeg.aac.decoder")) {
-        mMode = MODE_AAC;
-    } else if (!strcmp(name, "OMX.ffmpeg.ape.decoder")) {
-        mMode = MODE_APE;
-    } else if (!strcmp(name, "OMX.ffmpeg.wma.decoder")) {
-        mMode = MODE_WMA;
-    } else if (!strcmp(name, "OMX.ffmpeg.dts.decoder")) {
-        mMode = MODE_DTS;
-    } else if (!strcmp(name, "OMX.ffmpeg.ra.decoder")) {
-        mMode = MODE_RA;
-    } else {
-        CHECK(!strcmp(name, "OMX.ffmpeg.ac3.decoder"));
-        mMode = MODE_AC3;
-    }
 
-    LOGV("SoftFFmpegAudio component: %s", name);
+    setMode(name);
+
+    ALOGD("SoftFFmpegAudio component: %s mMode: %d", name, mMode);
 
     initPorts();
     CHECK_EQ(initDecoder(), (status_t)OK);
 }
 
 SoftFFmpegAudio::~SoftFFmpegAudio() {
-    av_freep(&mFrame);
-    LOGV("~SoftFFmpegAudio");
+    ALOGV("~SoftFFmpegAudio");
     deInitDecoder();
-    deInitFFmpeg();
+    if (mFFmpegAlreadyInited) {
+        deInitFFmpeg();
+    }
 }
 
-void SoftFFmpegAudio::initPorts() {
-    OMX_PARAM_PORTDEFINITIONTYPE def;
-    InitOMXParams(&def);
-
-    def.nPortIndex = 0;
-    def.eDir = OMX_DirInput;
-    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 = 1;
-
-    switch (mMode) {
+void SoftFFmpegAudio::initInputFormat(uint32_t mode,
+        OMX_PARAM_PORTDEFINITIONTYPE &def) {
+    switch (mode) {
+    case MODE_AAC:
+        def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_AAC);
+        def.format.audio.eEncoding = OMX_AUDIO_CodingAAC;
+        break;
     case MODE_MPEG:
         def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_MPEG);
         def.format.audio.eEncoding = OMX_AUDIO_CodingMP3;
         break;
-    case MODE_MPEGL1:
-        def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I);
-        def.format.audio.eEncoding = OMX_AUDIO_CodingMP3;
+    case MODE_VORBIS:
+        def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_VORBIS);
+        def.format.audio.eEncoding = OMX_AUDIO_CodingVORBIS;
+        break;
+    case MODE_WMA:
+        def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_WMA);
+        def.format.audio.eEncoding = OMX_AUDIO_CodingWMA;
+        break;
+    case MODE_RA:
+        def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_RA);
+        def.format.audio.eEncoding = OMX_AUDIO_CodingRA;
+        break;
+    case MODE_FLAC:
+        def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_FLAC);
+        def.format.audio.eEncoding = OMX_AUDIO_CodingFLAC;
         break;
     case MODE_MPEGL2:
         def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
         def.format.audio.eEncoding = OMX_AUDIO_CodingMP3;
         break;
-    case MODE_AAC:
-        def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_AAC);
-        def.format.audio.eEncoding = OMX_AUDIO_CodingAAC;
-        break;
     case MODE_AC3:
         def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_AC3);
-        // TODO
-        //def.format.audio.eEncoding = OMX_AUDIO_CodingAC3;
-        def.format.audio.eEncoding = OMX_AUDIO_CodingAutoDetect; // right?? orz
+        def.format.audio.eEncoding = OMX_AUDIO_CodingAC3;
         break;
-    case MODE_WMA:
-        def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_WMA);
-        def.format.audio.eEncoding = OMX_AUDIO_CodingWMA;
+    case MODE_APE:
+        def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_APE);
+        def.format.audio.eEncoding = OMX_AUDIO_CodingAPE;
         break;
-    case MODE_RA:
-        def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_RA);
-        def.format.audio.eEncoding = OMX_AUDIO_CodingRA;
+    case MODE_DTS:
+        def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_DTS);
+        def.format.audio.eEncoding = OMX_AUDIO_CodingDTS;
+        break;
+    case MODE_TRIAL:
+        def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_FFMPEG);
+        def.format.audio.eEncoding = OMX_AUDIO_CodingAutoDetect;
         break;
     default:
         CHECK(!"Should not be here. Unsupported mime type and compression format");
@@ -165,12 +161,36 @@ void SoftFFmpegAudio::initPorts() {
 
     def.format.audio.pNativeRender = NULL;
     def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+}
+
+void SoftFFmpegAudio::initPorts() {
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    InitOMXParams(&def);
+
+    def.nPortIndex = 0;
+    def.eDir = OMX_DirInput;
+    def.nBufferCountMin = kNumInputBuffers;
+    def.nBufferCountActual = def.nBufferCountMin;
+    if (mMode == MODE_APE) {
+        def.nBufferSize = 1000000; // ape!
+    } else if (mMode == MODE_DTS) {
+        def.nBufferSize = 1000000; // dts!
+    } else {
+        def.nBufferSize = 20480; // 8192 is too small
+    }
+    def.bEnabled = OMX_TRUE;
+    def.bPopulated = OMX_FALSE;
+    def.eDomain = OMX_PortDomainAudio;
+    def.bBuffersContiguous = OMX_FALSE;
+    def.nBufferAlignment = 1;
+
+    initInputFormat(mMode, def);
 
     addPort(def);
 
     def.nPortIndex = 1;
     def.eDir = OMX_DirOutput;
-    def.nBufferCountMin = kNumBuffers;
+    def.nBufferCountMin = kNumOutputBuffers;
     def.nBufferCountActual = def.nBufferCountMin;
     def.nBufferSize = kOutputBufferSize;
     def.bEnabled = OMX_TRUE;
@@ -187,13 +207,13 @@ void SoftFFmpegAudio::initPorts() {
     addPort(def);
 }
 
-void SoftFFmpegAudio::setAVCtxToDefault(AVCodecContext *avctx, const AVCodec *codec) {
+void SoftFFmpegAudio::setDefaultCtx(AVCodecContext *avctx, const AVCodec *codec) {
     int fast = 0;
 
     avctx->workaround_bugs   = 1;
     avctx->lowres            = 0;
     if(avctx->lowres > codec->max_lowres){
-        LOGW("The maximum value for lowres supported by the decoder is %d",
+        ALOGW("The maximum value for lowres supported by the decoder is %d",
                 codec->max_lowres);
         avctx->lowres= codec->max_lowres;
     }
@@ -209,67 +229,82 @@ void SoftFFmpegAudio::setAVCtxToDefault(AVCodecContext *avctx, const AVCodec *co
         avctx->flags |= CODEC_FLAG_EMU_EDGE;
 }
 
+bool SoftFFmpegAudio::isConfigured() {
+       return mAudioSrcChannels != -1;
+}
+
+void SoftFFmpegAudio::resetCtx() {
+    mCtx->channels = -1;
+    mCtx->sample_rate = -1;
+    mCtx->bit_rate = -1;
+    mCtx->sample_fmt = AV_SAMPLE_FMT_NONE;
+
+    mAudioSrcChannels = mAudioTgtChannels = -1;
+    mAudioSrcFreq = mAudioTgtFreq = -1;
+    mAudioSrcFmt = mAudioTgtFmt = AV_SAMPLE_FMT_NONE;
+    mAudioSrcChannelLayout = mAudioTgtChannelLayout = 0;
+}
+
 status_t SoftFFmpegAudio::initDecoder() {
     status_t status;
 
     status = initFFmpeg();
-    if (status != OK)
+    if (status != OK) {
         return NO_INIT;
+    }
+    mFFmpegAlreadyInited = true;
 
     mCtx = avcodec_alloc_context3(NULL);
-    if (!mCtx)
-    {
-        LOGE("avcodec_alloc_context failed.");
+    if (!mCtx) {
+        ALOGE("avcodec_alloc_context failed.");
         return NO_MEMORY;
     }
 
     mCtx->codec_type = AVMEDIA_TYPE_AUDIO;
     switch (mMode) {
+    case MODE_AAC:
+        mCtx->codec_id = AV_CODEC_ID_AAC;
+        break;
     case MODE_MPEG:
-        mCtx->codec_id = CODEC_ID_MP3;
+        mCtx->codec_id = AV_CODEC_ID_MP3;
         break;
-    case MODE_MPEGL1:
-        mCtx->codec_id = CODEC_ID_MP1;
+    case MODE_VORBIS:
+        mCtx->codec_id = AV_CODEC_ID_VORBIS;
         break;
-    case MODE_MPEGL2:
-        mCtx->codec_id = CODEC_ID_MP2;
+    case MODE_WMA:
+        mCtx->codec_id = AV_CODEC_ID_WMAV2; //should be adjusted later
         break;
-    case MODE_AAC:
-        mCtx->codec_id = CODEC_ID_AAC;
+    case MODE_RA:
+        mCtx->codec_id = AV_CODEC_ID_COOK;
+        break;
+    case MODE_FLAC:
+        mCtx->codec_id = AV_CODEC_ID_FLAC;
+        break;
+    case MODE_MPEGL2:
+        mCtx->codec_id = AV_CODEC_ID_MP2;
         break;
     case MODE_AC3:
-        mCtx->codec_id = CODEC_ID_AC3;
+        mCtx->codec_id = AV_CODEC_ID_AC3;
         break;
-    case MODE_WMA:
-        mCtx->codec_id = CODEC_ID_WMAV2; // FIXME, CODEC_ID_WMAV1 or CODEC_ID_WMAV2?
+    case MODE_APE:
+        mCtx->codec_id = AV_CODEC_ID_APE;
         break;
-    case MODE_RA:
-        mCtx->codec_id = CODEC_ID_COOK; // FIXME
+    case MODE_DTS:
+        mCtx->codec_id = AV_CODEC_ID_DTS;
+        break;
+    case MODE_TRIAL:
+        mCtx->codec_id = AV_CODEC_ID_NONE;
         break;
     default:
         CHECK(!"Should not be here. Unsupported codec");
         break;
     }
 
-    mCtx->codec = avcodec_find_decoder(mCtx->codec_id);
-    if (!mCtx->codec)
-    {
-        LOGE("find codec failed");
-        return BAD_TYPE;
-    }
-
-    setAVCtxToDefault(mCtx, mCtx->codec);
+    //invalid ctx
+    resetCtx();
 
-    mCtx->channels = mNumChannels;
-    mCtx->sample_rate = mSamplingRate;
-    mCtx->bit_rate = mBitRate;
-    mCtx->sample_fmt = mSamplingFmt;
-
-    mAudioSrcFmt = mAudioTgtFmt = AV_SAMPLE_FMT_S16;
-    mAudioSrcFreq = mAudioTgtFreq = mSamplingRate;
-    mAudioSrcChannels = mAudioTgtChannels = mNumChannels;
-    mAudioSrcChannelLayout = mAudioTgtChannelLayout = 
-        av_get_default_channel_layout(mNumChannels);
+    mCtx->extradata = NULL;
+    mCtx->extradata_size = 0;
 
     memset(mSilenceBuffer, 0, kOutputBufferSize);
 
@@ -278,663 +313,1200 @@ status_t SoftFFmpegAudio::initDecoder() {
 
 void SoftFFmpegAudio::deInitDecoder() {
     if (mCtx) {
-        //avcodec_flush_buffers(mCtx); // is it necessary? crash sometimes if call it
         if (!mCtx->extradata) {
             av_free(mCtx->extradata);
             mCtx->extradata = NULL;
             mCtx->extradata_size = 0;
         }
-        avcodec_close(mCtx);
-        av_free(mCtx);
-        mCtx = NULL;
+        if (mCodecAlreadyOpened) {
+            avcodec_close(mCtx);
+            av_free(mCtx);
+            mCtx = NULL;
+        }
+    }
+    if (mFrame) {
+        av_freep(&mFrame);
+        mFrame = NULL;
     }
-
     if (mSwrCtx) {
         swr_free(&mSwrCtx);
         mSwrCtx = NULL;
     }
-
 }
 
 OMX_ERRORTYPE SoftFFmpegAudio::internalGetParameter(
         OMX_INDEXTYPE index, OMX_PTR params) {
-    int32_t channels = 0;
-    int32_t sampling_rate = 0;
-
+    //ALOGV("internalGetParameter index:0x%x", index);
     switch (index) {
-        case OMX_IndexParamAudioAac:
+        case OMX_IndexParamAudioPcm:
         {
-            OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams =
-                (OMX_AUDIO_PARAM_AACPROFILETYPE *)params;
+            OMX_AUDIO_PARAM_PCMMODETYPE *profile =
+                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
 
-            if (aacParams->nPortIndex != 0) {
+            if (profile->nPortIndex > kOutputPortIndex) {
                 return OMX_ErrorUndefined;
             }
 
-            aacParams->nBitRate = 0;
-            aacParams->nAudioBandWidth = 0;
-            aacParams->nAACtools = 0;
-            aacParams->nAACERtools = 0;
-            aacParams->eAACProfile = OMX_AUDIO_AACObjectMain;
-            aacParams->eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF;
-            aacParams->eChannelMode = OMX_AUDIO_ChannelModeStereo;
+            profile->eNumData = OMX_NumericalDataSigned;
+            profile->eEndian = OMX_EndianBig;
+            profile->bInterleaved = OMX_TRUE;
+            profile->nBitPerSample = 16;
+            profile->ePCMMode = OMX_AUDIO_PCMModeLinear;
+            profile->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
+            profile->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
+
+            CHECK(isConfigured());
 
-            aacParams->nChannels = mNumChannels;
-            aacParams->nSampleRate = mSamplingRate;
+            profile->nChannels = mAudioSrcChannels;
+            profile->nSamplingRate = mAudioSrcFreq;
+
+            //mCtx has been updated(adjustAudioParams)!
+            ALOGV("get pcm params, nChannels:%lu, nSamplingRate:%lu",
+                   profile->nChannels, profile->nSamplingRate);
 
             return OMX_ErrorNone;
         }
-        case OMX_IndexParamAudioWma:
+
+        case OMX_IndexParamAudioAac:
         {
-            OMX_AUDIO_PARAM_WMATYPE *wmaParams =
-                (OMX_AUDIO_PARAM_WMATYPE *)params;
+            OMX_AUDIO_PARAM_AACPROFILETYPE *profile =
+                (OMX_AUDIO_PARAM_AACPROFILETYPE *)params;
 
-            if (wmaParams->nPortIndex != 0) {
+            if (profile->nPortIndex != kInputPortIndex) {
                 return OMX_ErrorUndefined;
             }
 
-            wmaParams->nChannels = 0;
-            wmaParams->nSamplingRate = 0;
-            wmaParams->nBitRate = 0;
-            wmaParams->eFormat = OMX_AUDIO_WMAFormatUnused;
+            CHECK(!isConfigured());
+
+            profile->nBitRate = 0;
+            profile->nAudioBandWidth = 0;
+            profile->nAACtools = 0;
+            profile->nAACERtools = 0;
+            profile->eAACProfile = OMX_AUDIO_AACObjectMain;
+            profile->eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF;
+            profile->eChannelMode = OMX_AUDIO_ChannelModeStereo;
+
+            profile->nChannels = 0;
+            profile->nSampleRate = 0;
 
             return OMX_ErrorNone;
         }
-        case OMX_IndexParamAudioRa:
+
+        case OMX_IndexParamAudioMp3:
         {
-            OMX_AUDIO_PARAM_RATYPE *raParams =
-                (OMX_AUDIO_PARAM_RATYPE *)params;
+            OMX_AUDIO_PARAM_MP3TYPE *profile =
+                (OMX_AUDIO_PARAM_MP3TYPE *)params;
 
-            if (raParams->nPortIndex != 0) {
+            if (profile->nPortIndex != kInputPortIndex) {
                 return OMX_ErrorUndefined;
             }
 
-            raParams->nChannels = 0;
-            raParams->nSamplingRate = 0;
-            raParams->eFormat = OMX_AUDIO_RAFormatUnused;
+            CHECK(!isConfigured());
+
+            profile->nChannels = 0;
+            profile->nSampleRate = 0;
+            profile->nBitRate = 0;
+            profile->nAudioBandWidth = 0;
+            profile->eChannelMode = OMX_AUDIO_ChannelModeStereo;
+            profile->eFormat = OMX_AUDIO_MP3StreamFormatMP1Layer3;
 
             return OMX_ErrorNone;
         }
-        case OMX_IndexParamAudioPcm:
+        case OMX_IndexParamAudioVorbis:
         {
-            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
-                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+            OMX_AUDIO_PARAM_VORBISTYPE *profile =
+                (OMX_AUDIO_PARAM_VORBISTYPE *)params;
 
-            if (pcmParams->nPortIndex > 1) {
+            if (profile->nPortIndex != kInputPortIndex) {
                 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;
-
-            LOGV("audio config change");
-
-            channels = mNumChannels >= 2 ? 2 : 1;
-            sampling_rate = mSamplingRate;
-            // 4000 <= nSamplingRate <= 48000
-            if (mSamplingRate < 4000) {
-                sampling_rate = 4000;
-            } else if (mSamplingRate > 48000) {
-                sampling_rate = 48000;
-            }
+            CHECK(!isConfigured());
 
-            // update src and target(except aac), only once!
-            mAudioSrcChannels = mAudioTgtChannels =  channels;
-            mAudioSrcFreq = mAudioTgtFreq = sampling_rate;
-            mAudioSrcFmt = mAudioTgtFmt = AV_SAMPLE_FMT_S16;
-            mAudioSrcChannelLayout = mAudioTgtChannelLayout = av_get_default_channel_layout(channels);
+            profile->nBitRate = 0;
+            profile->nMinBitRate = 0;
+            profile->nMaxBitRate = 0;
+            profile->nAudioBandWidth = 0;
+            profile->nQuality = 3;
+            profile->bManaged = OMX_FALSE;
+            profile->bDownmix = OMX_FALSE;
 
-            pcmParams->nChannels = channels;
-            pcmParams->nSamplingRate = sampling_rate;
+            profile->nChannels = 0;
+            profile->nSampleRate = 0;
 
             return OMX_ErrorNone;
         }
 
-        default:
-            return SimpleSoftOMXComponent::internalGetParameter(index, params);
-    }
-}
-
-OMX_ERRORTYPE SoftFFmpegAudio::internalSetParameter(
-        OMX_INDEXTYPE index, const OMX_PTR params) {
-    int32_t channels = 0;
-    int32_t sampling_rate = 0;
-
-    switch (index) {
-        case OMX_IndexParamStandardComponentRole:
+        case OMX_IndexParamAudioWma:
         {
-            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
-                (const OMX_PARAM_COMPONENTROLETYPE *)params;
+            OMX_AUDIO_PARAM_WMATYPE *profile =
+                (OMX_AUDIO_PARAM_WMATYPE *)params;
 
-            bool supported = true;
-            switch (mMode) {
-            case MODE_MPEG:
-                if (strncmp((const char *)roleParams->cRole,
-                        "audio_decoder.mp3", OMX_MAX_STRINGNAME_SIZE - 1))
-                    supported =  false;
-                break;
-            case MODE_MPEGL1:
-                if (strncmp((const char *)roleParams->cRole,
-                        "audio_decoder.mp1", OMX_MAX_STRINGNAME_SIZE - 1))
-                    supported =  false;
-                break;
-            case MODE_MPEGL2:
-                if (strncmp((const char *)roleParams->cRole,
-                        "audio_decoder.mp2", OMX_MAX_STRINGNAME_SIZE - 1))
-                    supported =  false;
-                break;
-            case MODE_AAC:
-                if (strncmp((const char *)roleParams->cRole,
-                        "audio_decoder.aac", OMX_MAX_STRINGNAME_SIZE - 1))
-                    supported =  false;
-                break;
-            case MODE_AC3:
-                if (strncmp((const char *)roleParams->cRole,
-                        "audio_decoder.ac3", OMX_MAX_STRINGNAME_SIZE - 1))
-                    supported =  false;
-                break;
-            case MODE_WMA:
-                if (strncmp((const char *)roleParams->cRole,
-                        "audio_decoder.wma", OMX_MAX_STRINGNAME_SIZE - 1))
-                    supported =  false;
-                break;
-            case MODE_RA:
-                if (strncmp((const char *)roleParams->cRole,
-                        "audio_decoder.ra", OMX_MAX_STRINGNAME_SIZE - 1))
-                    supported =  false;
-                break;
-            default:
-                CHECK(!"Should not be here. Unsupported role.");
-                break;
-            }
-            if (!supported) {
-                LOGE("unsupported role: %s", (const char *)roleParams->cRole);
+            if (profile->nPortIndex != kInputPortIndex) {
                 return OMX_ErrorUndefined;
             }
 
+            CHECK(!isConfigured());
+
+            profile->nChannels = 0;
+            profile->nSamplingRate = 0;
+            profile->nBitRate = 0;
+            profile->eFormat = OMX_AUDIO_WMAFormatUnused;
+
             return OMX_ErrorNone;
         }
-        case OMX_IndexParamAudioAac:
+
+        case OMX_IndexParamAudioRa:
         {
-            const OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams =
-                (const OMX_AUDIO_PARAM_AACPROFILETYPE *)params;
+            OMX_AUDIO_PARAM_RATYPE *profile =
+                (OMX_AUDIO_PARAM_RATYPE *)params;
 
-            if (aacParams->nPortIndex != 0) {
+            if (profile->nPortIndex != kInputPortIndex) {
                 return OMX_ErrorUndefined;
             }
 
-            mNumChannels = aacParams->nChannels;
-            mSamplingRate = aacParams->nSampleRate;
-
-            channels = mNumChannels >= 2 ? 2 : 1;
-            sampling_rate = mSamplingRate;
-            // 4000 <= nSamplingRate <= 48000
-            if (mSamplingRate < 4000) {
-                sampling_rate = 4000;
-            } else if (mSamplingRate > 48000) {
-                sampling_rate = 48000;
-            }
-
-            // update src and target(only aac), only once!
-            mAudioSrcChannels = mAudioTgtChannels = channels;
-            mAudioSrcFreq = mAudioTgtFreq = sampling_rate;
-            mAudioSrcFmt = mAudioTgtFmt = AV_SAMPLE_FMT_S16;
-            mAudioSrcChannelLayout = mAudioTgtChannelLayout = av_get_default_channel_layout(channels);
+            CHECK(!isConfigured());
 
-            LOGV("got OMX_IndexParamAudioAac, mNumChannels: %d, mSamplingRate: %d",
-                mNumChannels, mSamplingRate);
+            profile->nChannels = 0;
+            profile->nSamplingRate = 0;
+            profile->eFormat = OMX_AUDIO_RAFormatUnused;
 
             return OMX_ErrorNone;
         }
-        case OMX_IndexParamAudioWma:
+
+        case OMX_IndexParamAudioFlac:
         {
-            OMX_AUDIO_PARAM_WMATYPE *wmaParams =
-                (OMX_AUDIO_PARAM_WMATYPE *)params;
+            OMX_AUDIO_PARAM_FLACTYPE *profile =
+                (OMX_AUDIO_PARAM_FLACTYPE *)params;
 
-            if (wmaParams->nPortIndex != 0) {
+            if (profile->nPortIndex != kInputPortIndex) {
                 return OMX_ErrorUndefined;
             }
 
-            if (wmaParams->eFormat == OMX_AUDIO_WMAFormat7) {
-               mCtx->codec_id = CODEC_ID_WMAV2;
-            } else if (wmaParams->eFormat == OMX_AUDIO_WMAFormat8) {
-               mCtx->codec_id = CODEC_ID_WMAPRO;
-            } else if (wmaParams->eFormat == OMX_AUDIO_WMAFormat9) {
-               mCtx->codec_id = CODEC_ID_WMALOSSLESS;
-            } else {
-                LOGE("unsupported wma codec: 0x%x", wmaParams->eFormat);
-                return OMX_ErrorUndefined;
-            }
+            CHECK(!isConfigured());
 
-            mNumChannels = wmaParams->nChannels;
-            mSamplingRate = wmaParams->nSamplingRate;
-            mBitRate = wmaParams->nBitRate;
+            profile->nChannels = 0;
+            profile->nSampleRate = 0;
+
+            return OMX_ErrorNone;
+        }
 
-            // wma need bitrate
-            mCtx->bit_rate = mBitRate;
+        case OMX_IndexParamAudioMp2:
+        {
+            OMX_AUDIO_PARAM_MP2TYPE *profile =
+                (OMX_AUDIO_PARAM_MP2TYPE *)params;
 
-            channels = mNumChannels >= 2 ? 2 : 1;
-            sampling_rate = mSamplingRate;
-            // 4000 <= nSamplingRate <= 48000
-            if (mSamplingRate < 4000) {
-                sampling_rate = 4000;
-            } else if (mSamplingRate > 48000) {
-                sampling_rate = 48000;
+            if (profile->nPortIndex != kInputPortIndex) {
+                return OMX_ErrorUndefined;
             }
 
-            // update src and target(only wma), only once!
-            mAudioSrcChannels = mAudioTgtChannels = channels;
-            mAudioSrcFreq = mAudioTgtFreq = sampling_rate;
-            mAudioSrcFmt = mAudioTgtFmt = AV_SAMPLE_FMT_S16;
-            mAudioSrcChannelLayout = mAudioTgtChannelLayout = av_get_default_channel_layout(channels);
+            CHECK(!isConfigured());
 
-            LOGV("got OMX_IndexParamAudioWma, mNumChannels: %d, mSamplingRate: %d, mBitRate: %d",
-                mNumChannels, mSamplingRate, mBitRate);
+            profile->nChannels = 0;
+            profile->nSampleRate = 0;
 
             return OMX_ErrorNone;
         }
-        case OMX_IndexParamAudioRa:
+
+        case OMX_IndexParamAudioAc3:
         {
-            OMX_AUDIO_PARAM_RATYPE *raParams =
-                (OMX_AUDIO_PARAM_RATYPE *)params;
+            OMX_AUDIO_PARAM_AC3TYPE *profile =
+                (OMX_AUDIO_PARAM_AC3TYPE *)params;
 
-            if (raParams->nPortIndex != 0) {
+            if (profile->nPortIndex != kInputPortIndex) {
                 return OMX_ErrorUndefined;
             }
 
-            mCtx->codec_id = CODEC_ID_COOK;
-
-            mNumChannels = raParams->nChannels;
-            mSamplingRate = raParams->nSamplingRate;
-            // FIXME, HACK!!!, I use the nNumRegions parameter pass blockAlign!!!
-            // the cook audio codec need blockAlign!
-            mBlockAlign = raParams->nNumRegions;
-
-            // cook decoder need block_align
-            mCtx->block_align = mBlockAlign;
-
-            channels = mNumChannels >= 2 ? 2 : 1;
-            sampling_rate = mSamplingRate;
-            // 4000 <= nSamplingRate <= 48000
-            if (mSamplingRate < 4000) {
-                sampling_rate = 4000;
-            } else if (mSamplingRate > 48000) {
-                sampling_rate = 48000;
-            }
-
-            // update src and target(only wma), only once!
-            mAudioSrcChannels = mAudioTgtChannels = channels;
-            mAudioSrcFreq = mAudioTgtFreq = sampling_rate;
-            mAudioSrcFmt = mAudioTgtFmt = AV_SAMPLE_FMT_S16;
-            mAudioSrcChannelLayout = mAudioTgtChannelLayout = av_get_default_channel_layout(channels);
+            CHECK(!isConfigured());
 
-            LOGV("got OMX_IndexParamAudioRa, mNumChannels: %d, mSamplingRate: %d, mBlockAlign: %d",
-                mNumChannels, mSamplingRate, mBlockAlign);
+            profile->nChannels = 0;
+            profile->nSamplingRate = 0;
 
             return OMX_ErrorNone;
         }
-        default:
-            LOGI("internalSetParameter, index: 0x%x", index);
-            return SimpleSoftOMXComponent::internalSetParameter(index, params);
-    }
-}
-
-void SoftFFmpegAudio::onQueueFilled(OMX_U32 portIndex) {
-    int len = 0;
-    int err = 0;
-    size_t dataSize = 0;
-    int64_t decChannelLayout;
-    int32_t inputBufferUsedLength = 0;
-    BufferInfo *inInfo = NULL;
-    OMX_BUFFERHEADERTYPE *inHeader = NULL;
 
-    if (mSignalledError || mOutputPortSettingsChange != NONE) {
-        return;
-    }
+        case OMX_IndexParamAudioApe:
+        {
+            OMX_AUDIO_PARAM_APETYPE *profile =
+                (OMX_AUDIO_PARAM_APETYPE *)params;
 
-    List<BufferInfo *> &inQueue = getPortQueue(0);
-    List<BufferInfo *> &outQueue = getPortQueue(1);
+            if (profile->nPortIndex != kInputPortIndex) {
+                return OMX_ErrorUndefined;
+            }
 
-    while ((!inQueue.empty() || mInputBufferSize > 0 ||
-            mAudioBufferSize > 0 || mFlushComplete) && !outQueue.empty()) {
-        if (!inQueue.empty() || mInputBufferSize > 0) {
-            inInfo = *inQueue.begin();
-            inHeader = inInfo->mHeader;
-        } else {
-            inInfo = NULL;
-            inHeader = NULL;
-        }
+            CHECK(!isConfigured());
 
-        BufferInfo *outInfo = *outQueue.begin();
-        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+            profile->nChannels = 0;
+            profile->nSamplingRate = 0;
 
-        if (inHeader && inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
-            inQueue.erase(inQueue.begin());
-            inInfo->mOwnedByUs = false;
-            notifyEmptyBufferDone(inHeader);
-            mReceivedEOS = true;
+            return OMX_ErrorNone;
         }
 
-        if (mReceivedEOS && (mFlushComplete || !(mCtx->codec->capabilities & CODEC_CAP_DELAY))) {
-            outHeader->nFilledLen = 0;
-            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+        case OMX_IndexParamAudioDts:
+        {
+            OMX_AUDIO_PARAM_DTSTYPE *profile =
+                (OMX_AUDIO_PARAM_DTSTYPE *)params;
 
-            outQueue.erase(outQueue.begin());
-            outInfo->mOwnedByUs = false;
-            notifyFillBufferDone(outHeader);
-            return;
-        }
+            if (profile->nPortIndex != kInputPortIndex) {
+                return OMX_ErrorUndefined;
+            }
 
-        if (inHeader && inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
-            LOGI("got extradata, ignore: %d, size: %lu", mIgnoreExtradata, inHeader->nFilledLen);
-            hexdump(inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen);
-            if (!mExtradataReady && !mIgnoreExtradata) {
-                int orig_extradata_size = mCtx->extradata_size;
-                mCtx->extradata_size += inHeader->nFilledLen;
-                mCtx->extradata = (uint8_t *)av_realloc(mCtx->extradata,
-                        mCtx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
-                if (!mCtx->extradata) {
-                    LOGE("ffmpeg audio decoder failed to alloc extradata memory.");
-                    notify(OMX_EventError, OMX_ErrorInsufficientResources, 0, NULL);
-                    mSignalledError = true;
-                    return;
-                }
-
-                memcpy(mCtx->extradata + orig_extradata_size,
-                        inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen);
-                memset(mCtx->extradata + mCtx->extradata_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
-
-                inInfo->mOwnedByUs = false;
-                inQueue.erase(inQueue.begin());
-                inInfo = NULL;
-                notifyEmptyBufferDone(inHeader);
-                inHeader = NULL;
+            CHECK(!isConfigured());
 
-                continue;
-            }
-            if (mIgnoreExtradata) {
-                LOGI("got extradata, size: %lu, but ignore it", inHeader->nFilledLen);
-                inInfo->mOwnedByUs = false;
-                inQueue.erase(inQueue.begin());
-                inInfo = NULL;
-                notifyEmptyBufferDone(inHeader);
-                inHeader = NULL;
+            profile->nChannels = 0;
+            profile->nSamplingRate = 0;
 
-                continue;
-            }
+            return OMX_ErrorNone;
         }
 
-        if (!mCodecOpened) {
-            if (!mExtradataReady && !mIgnoreExtradata) {
-                LOGI("extradata is ready");
-                hexdump(mCtx->extradata, mCtx->extradata_size);
-                mExtradataReady = true;
-            }
+        case OMX_IndexParamAudioFFmpeg:
+        {
+            OMX_AUDIO_PARAM_FFMPEGTYPE *profile =
+                (OMX_AUDIO_PARAM_FFMPEGTYPE *)params;
 
-            // find decoder again as codec_id may have changed
-            mCtx->codec = avcodec_find_decoder(mCtx->codec_id);
-            if (!mCtx->codec) {
-                LOGE("ffmpeg audio decoder failed to find codec");
-                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
-                mSignalledError = true;
-                return;
+            if (profile->nPortIndex != kInputPortIndex) {
+                return OMX_ErrorUndefined;
             }
 
-            setAVCtxToDefault(mCtx, mCtx->codec);
+            CHECK(!isConfigured());
 
-            LOGI("open ffmpeg decoder now");
-            err = avcodec_open2(mCtx, mCtx->codec, NULL);
-            if (err < 0) {
-                LOGE("ffmpeg audio decoder failed to initialize. (%d)", err);
-                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
-                mSignalledError = true;
-                return;
-            }
-            mCodecOpened = true;
-            LOGI("open ffmpeg audio decoder, mCtx sample_rate: %d, channels: %d, channel_layout: %llu, sample_fmt: %s",
-                mCtx->sample_rate, mCtx->channels, mCtx->channel_layout, av_get_sample_fmt_name(mCtx->sample_fmt));
-        }
+            profile->eCodecId = 0;
+            profile->nChannels = 0;
+            profile->nBitRate = 0;
+            profile->nBitsPerSample = 0;
+            profile->nSampleRate = 0;
+            profile->nBlockAlign = 0;
+            profile->eSampleFormat = 0;
 
-        /* update the audio clock with the pts */
-        if (inHeader && inHeader->nOffset == 0) {
-            mAnchorTimeUs = inHeader->nTimeStamp;
-            mInputBufferSize = inHeader->nFilledLen;
+            return OMX_ErrorNone;
         }
 
-        if (inHeader && mAudioBufferSize == 0 && !mFlushComplete) {
-            AVPacket pkt;
-            memset(&pkt, 0, sizeof(pkt));
-            av_init_packet(&pkt);
-            if (!mFlushComplete) {
-                pkt.data = (uint8_t *)inHeader->pBuffer + inHeader->nOffset;
-                pkt.size = inHeader->nFilledLen;
-                pkt.pts = inHeader->nTimeStamp; // ingore it, we will compute it
-            } else {
-                pkt.data = NULL;
-                pkt.size = 0;
-                pkt.pts = AV_NOPTS_VALUE;
-            }
-#if DEBUG_PKT
-            LOGV("pkt size: %d, pts: %lld", pkt.size, pkt.pts);
-#endif
-            if (!mFrame) {
-                if (!(mFrame = avcodec_alloc_frame())) {
-                    LOGE("ffmpeg audio decoder failed to alloc memory.");
-                    notify(OMX_EventError, OMX_ErrorInsufficientResources, 0, NULL);
-                    mSignalledError = true;
-                    return;
-                }
-            } else {
-                avcodec_get_frame_defaults(mFrame);
-            }
+        default:
 
-            int gotFrm = false;
-            inputBufferUsedLength = 0;
-            len = avcodec_decode_audio4(mCtx, mFrame, &gotFrm, &pkt);
-           if (len < 0) {
-                LOGE("ffmpeg audio decoder failed to decode frame. consume pkt len: %d", len);
-
-                /* if !mAudioConfigChanged, Don't fill the out buffer */
-                if (!mAudioConfigChanged) {
-                    inInfo->mOwnedByUs = false;
-                    inQueue.erase(inQueue.begin());
-                    inInfo = NULL;
-                    notifyEmptyBufferDone(inHeader);
-                    inHeader = NULL;
-
-                    mInputBufferSize = 0; // need?
-                    continue;
-                }
-
-                //inputBufferUsedLength = inHeader->nFilledLen;
-                /* if error, we skip the frame and play silence instead */
-                mPAudioBuffer = mSilenceBuffer;
-                mAudioBufferSize = kOutputBufferSize;
-            }
+            return SimpleSoftOMXComponent::internalGetParameter(index, params);
+    }
+}
 
-#if DEBUG_PKT
-            LOGV("ffmpeg audio decoder, consume pkt len: %d", len);
-#endif
+OMX_ERRORTYPE SoftFFmpegAudio::isRoleSupported(
+        const OMX_PARAM_COMPONENTROLETYPE *roleParams) {
+    bool supported = true;
+
+    switch (mMode) {
+    case MODE_AAC:
+        if (strncmp((const char *)roleParams->cRole,
+                "audio_decoder.aac", OMX_MAX_STRINGNAME_SIZE - 1))
+        supported = false;
+        break;
+    case MODE_MPEG:
+        if (strncmp((const char *)roleParams->cRole,
+                "audio_decoder.mp3", OMX_MAX_STRINGNAME_SIZE - 1))
+            supported = false;
+        break;
+    case MODE_VORBIS:
+        if (strncmp((const char *)roleParams->cRole,
+                "audio_decoder.vorbis", OMX_MAX_STRINGNAME_SIZE - 1))
+        supported = false;
+        break;
+    case MODE_WMA:
+        if (strncmp((const char *)roleParams->cRole,
+                "audio_decoder.wma", OMX_MAX_STRINGNAME_SIZE - 1))
+        supported = false;
+        break;
+    case MODE_RA:
+        if (strncmp((const char *)roleParams->cRole,
+                "audio_decoder.ra", OMX_MAX_STRINGNAME_SIZE - 1))
+        supported = false;
+        break;
+    case MODE_FLAC:
+        if (strncmp((const char *)roleParams->cRole,
+                "audio_decoder.flac", OMX_MAX_STRINGNAME_SIZE - 1))
+        supported = false;
+        break;
+    case MODE_MPEGL2:
+        if (strncmp((const char *)roleParams->cRole,
+                "audio_decoder.mp2", OMX_MAX_STRINGNAME_SIZE - 1))
+            supported = false;
+        break;
+    case MODE_AC3:
+        if (strncmp((const char *)roleParams->cRole,
+                "audio_decoder.ac3", OMX_MAX_STRINGNAME_SIZE - 1))
+            supported = false;
+        break;
+    case MODE_APE:
+        if (strncmp((const char *)roleParams->cRole,
+                "audio_decoder.ape", OMX_MAX_STRINGNAME_SIZE - 1))
+        supported = false;
+        break;
+    case MODE_DTS:
+        if (strncmp((const char *)roleParams->cRole,
+                "audio_decoder.dts", OMX_MAX_STRINGNAME_SIZE - 1))
+        supported = false;
+        break;
+    case MODE_TRIAL:
+        if (strncmp((const char *)roleParams->cRole,
+                "audio_decoder.trial", OMX_MAX_STRINGNAME_SIZE - 1))
+        supported = false;
+        break;
+    default:
+        CHECK(!"Should not be here. Unsupported role.");
+        break;
+    }
+
+    if (!supported) {
+        ALOGE("unsupported role: %s", (const char *)roleParams->cRole);
+        return OMX_ErrorUndefined;
+    }
+
+    return OMX_ErrorNone;
+}
+
+void SoftFFmpegAudio::adjustAudioParams() {
+    int32_t channels = 0;
+    int32_t sampling_rate = 0;
+
+    CHECK(!isConfigured());
 
-            if (len < 0)
-                inputBufferUsedLength = inHeader->nFilledLen;
-            else
-                inputBufferUsedLength = len;
-
-            CHECK_GE(inHeader->nFilledLen, inputBufferUsedLength);
-            inHeader->nOffset += inputBufferUsedLength;
-            inHeader->nFilledLen -= inputBufferUsedLength;
-            mInputBufferSize -= inputBufferUsedLength;
-            if (inHeader->nFilledLen == 0) {
-                inInfo->mOwnedByUs = false;
-                inQueue.erase(inQueue.begin());
-                inInfo = NULL;
-                notifyEmptyBufferDone(inHeader);
-                inHeader = NULL;
-
-                mInputBufferSize = 0;
+    sampling_rate = mCtx->sample_rate;
+
+    //channels support 1 or 2 only
+    channels = mCtx->channels >= 2 ? 2 : 1;
+
+    //4000 <= sampling rate <= 48000
+    if (sampling_rate < 4000) {
+        sampling_rate = 4000;
+    } else if (sampling_rate > 48000) {
+        sampling_rate = 48000;
+    }
+
+    mAudioSrcChannels = mAudioTgtChannels = channels;
+    mAudioSrcFreq = mAudioTgtFreq = sampling_rate;
+    mAudioSrcFmt = mAudioTgtFmt = AV_SAMPLE_FMT_S16;
+    mAudioSrcChannelLayout = mAudioTgtChannelLayout =
+        av_get_default_channel_layout(channels);
+}
+
+OMX_ERRORTYPE SoftFFmpegAudio::internalSetParameter(
+        OMX_INDEXTYPE index, const OMX_PTR params) {
+    //ALOGV("internalSetParameter index:0x%x", index);
+    switch (index) {
+        case OMX_IndexParamStandardComponentRole:
+        {
+            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
+                (const OMX_PARAM_COMPONENTROLETYPE *)params;
+                       return isRoleSupported(roleParams);
+        }
+
+        case OMX_IndexParamAudioPcm:
+        {
+            const OMX_AUDIO_PARAM_PCMMODETYPE *profile =
+                (const OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+            if (profile->nPortIndex != kOutputPortIndex) {
+                return OMX_ErrorUndefined;
             }
 
-            if (!gotFrm) {
-                LOGI("ffmpeg audio decoder failed to get frame.");
-                /* stop sending empty packets if the decoder is finished */
-                if (!pkt.data && mCtx->codec->capabilities & CODEC_CAP_DELAY)
-                    mFlushComplete = true;
-                continue;
+            CHECK(!isConfigured());
+
+            mCtx->channels = profile->nChannels;
+            mCtx->sample_rate = profile->nSamplingRate;
+            mCtx->bits_per_coded_sample = profile->nBitPerSample;
+
+            ALOGV("set OMX_IndexParamAudioPcm, nChannels:%lu, "
+                    "nSampleRate:%lu, nBitsPerSample:%lu",
+                profile->nChannels, profile->nSamplingRate,
+                profile->nBitPerSample);
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioAac:
+        {
+            const OMX_AUDIO_PARAM_AACPROFILETYPE *profile =
+                (const OMX_AUDIO_PARAM_AACPROFILETYPE *)params;
+
+            if (profile->nPortIndex != kInputPortIndex) {
+                return OMX_ErrorUndefined;
             }
 
-            /**
-             * FIXME, check mAudioConfigChanged when the first time you call the audio4!
-             * mCtx->sample_rate and mCtx->channels may be changed by audio decoder later, why???
-             */
-            if (!mAudioConfigChanged) {
-                //if (mCtx->channels != mNumChannels || mCtx->sample_rate != mSamplingRate || mCtx->sample_fmt != mSamplingFmt) {
-                if (mCtx->channels != mNumChannels || mCtx->sample_rate != mSamplingRate) {
-                    LOGI("audio OMX_EventPortSettingsChanged, mCtx->channels: %d, mNumChannels: %d, mCtx->sample_rate: %d, mSamplingRate: %d, mCtx->sample_fmt: %s, mSamplingFmt: %s",
-                            mCtx->channels, mNumChannels, mCtx->sample_rate, mSamplingRate,
-                            av_get_sample_fmt_name(mCtx->sample_fmt), av_get_sample_fmt_name(mSamplingFmt));
-                    mNumChannels = mCtx->channels;
-                    mSamplingRate = mCtx->sample_rate;
-                    mSamplingFmt = mCtx->sample_fmt;
-                    mAudioConfigChanged = true;
-                    notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
-                    mOutputPortSettingsChange = AWAITING_DISABLED;
-                    return;
-                } else {
-                    // match with the default, set mAudioConfigChanged true anyway!
-                    mAudioConfigChanged = true;
-                    mSamplingFmt = mCtx->sample_fmt;
-                }
+            CHECK(!isConfigured());
+
+            mCtx->channels = profile->nChannels;
+            mCtx->sample_rate = profile->nSampleRate;
+
+            adjustAudioParams();
+
+            ALOGV("set OMX_IndexParamAudioAac, nChannels:%lu, nSampleRate:%lu",
+                profile->nChannels, profile->nSampleRate);
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioMp3:
+        {
+            const OMX_AUDIO_PARAM_MP3TYPE *profile =
+                (const OMX_AUDIO_PARAM_MP3TYPE *)params;
+
+            if (profile->nPortIndex != kInputPortIndex) {
+                return OMX_ErrorUndefined;
             }
 
-            dataSize = av_samples_get_buffer_size(NULL, mNumChannels, mFrame->nb_samples, mSamplingFmt, 1);
+            CHECK(!isConfigured());
 
-#if DEBUG_FRM
-            LOGV("audio decoder, nb_samples: %d, get buffer size: %d", mFrame->nb_samples, dataSize);
-            LOGV("audio decoder: mCtx channel_layout: %llu, channels: %d, channels_from_layout: %d\n",
-                mCtx->channel_layout,  mCtx->channels, av_get_channel_layout_nb_channels(mCtx->channel_layout));
-#endif
+            mCtx->channels = profile->nChannels;
+            mCtx->sample_rate = profile->nSampleRate;
+
+            adjustAudioParams();
+
+            ALOGV("set OMX_IndexParamAudioMp3, nChannels:%lu, nSampleRate:%lu",
+                profile->nChannels, profile->nSampleRate);
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioVorbis:
+        {
+            const OMX_AUDIO_PARAM_VORBISTYPE *profile =
+                (const OMX_AUDIO_PARAM_VORBISTYPE *)params;
 
-            decChannelLayout = av_get_default_channel_layout(mNumChannels);
-            if (mSamplingFmt != mAudioSrcFmt ||
-                    decChannelLayout != mAudioSrcChannelLayout ||
-                    mSamplingRate != mAudioSrcFreq ) {
-                if (mSwrCtx)
-                    swr_free(&mSwrCtx);
-                mSwrCtx = swr_alloc_set_opts(NULL,
-                                             mAudioTgtChannelLayout, mAudioTgtFmt, mAudioTgtFreq,
-                                             decChannelLayout,       mSamplingFmt, mSamplingRate,
-                                             0, NULL);
-                if (!mSwrCtx || swr_init(mSwrCtx) < 0) {
-                    LOGE("Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!",
-                            mSamplingRate,
-                            av_get_sample_fmt_name(mSamplingFmt),
-                            mNumChannels,
-                            mAudioTgtFreq,
-                            av_get_sample_fmt_name(mAudioTgtFmt),
-                            mAudioTgtChannels);
-                    notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
-                    mSignalledError = true;
-                    return;
-                }
-
-                LOGI("Create sample rate converter for conversion of %d Hz %s %d channels(%lld channel_layout) to %d Hz %s %d channels(%lld channel_layout)!",
-                        mSamplingRate,
-                        av_get_sample_fmt_name(mSamplingFmt),
-                        mNumChannels,
-                        mAudioTgtChannelLayout,
-                        mAudioTgtFreq,
-                        av_get_sample_fmt_name(mAudioTgtFmt),
-                        mAudioTgtChannels,
-                        decChannelLayout);
-
-                mAudioSrcChannelLayout = decChannelLayout;
-                mAudioSrcChannels = mNumChannels;
-                mAudioSrcFreq = mSamplingRate;
-                mAudioSrcFmt = mSamplingFmt;
+            if (profile->nPortIndex != kInputPortIndex) {
+                return OMX_ErrorUndefined;
             }
 
-            if (mSwrCtx) {
-                //const uint8_t *in[] = { mFrame->data[0] };
-                const uint8_t **in = (const uint8_t **)mFrame->extended_data;
-                uint8_t *out[] = {mAudioBuf2};
-                int out_count = sizeof(mAudioBuf2) / mAudioTgtChannels / av_get_bytes_per_sample(mAudioTgtFmt);
-#if DEBUG_FRM
-                LOGV("swr_convert 1, out_count: %d, mFrame->nb_samples: %d, src frm: %s, tgt frm: %s",
-                    out_count, mFrame->nb_samples, av_get_sample_fmt_name(mCtx->sample_fmt), av_get_sample_fmt_name(mAudioTgtFmt));
-#endif
-                int len2 = swr_convert(mSwrCtx, out, out_count, in, mFrame->nb_samples);
-                if (len2 < 0) {
-                    LOGE("audio_resample() failed");
-                    break;
-                }
-                if (len2 == out_count) {
-                    LOGE("warning: audio buffer is probably too small");
-                    swr_init(mSwrCtx);
-                }
-                mPAudioBuffer = mAudioBuf2;
-                mAudioBufferSize = len2 * mAudioTgtChannels * av_get_bytes_per_sample(mAudioTgtFmt);
+            CHECK(!isConfigured());
+
+            mCtx->channels = profile->nChannels;
+            mCtx->sample_rate = profile->nSampleRate;
+
+            adjustAudioParams();
+
+            ALOGD("set OMX_IndexParamAudioVorbis, "
+                    "nChannels=%lu, nSampleRate=%lu, nBitRate=%lu, "
+                    "nMinBitRate=%lu, nMaxBitRate=%lu",
+                profile->nChannels, profile->nSampleRate,
+                profile->nBitRate, profile->nMinBitRate,
+                profile->nMaxBitRate);
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioWma:
+        {
+            OMX_AUDIO_PARAM_WMATYPE *profile =
+                (OMX_AUDIO_PARAM_WMATYPE *)params;
+
+            if (profile->nPortIndex != kInputPortIndex) {
+                return OMX_ErrorUndefined;
+            }
+
+            CHECK(!isConfigured());
+
+            if (profile->eFormat == OMX_AUDIO_WMAFormat7) {
+               mCtx->codec_id = AV_CODEC_ID_WMAV2;
+            } else if (profile->eFormat == OMX_AUDIO_WMAFormat8) {
+               mCtx->codec_id = AV_CODEC_ID_WMAPRO;
+            } else if (profile->eFormat == OMX_AUDIO_WMAFormat9) {
+               mCtx->codec_id = AV_CODEC_ID_WMALOSSLESS;
             } else {
-                mPAudioBuffer = mFrame->data[0];
-                mAudioBufferSize = dataSize;
+                ALOGE("unsupported wma codec: 0x%x", profile->eFormat);
+                return OMX_ErrorUndefined;
+            }
+
+            mCtx->channels = profile->nChannels;
+            mCtx->sample_rate = profile->nSamplingRate;
+
+            // wmadec needs bitrate, block_align
+            mCtx->bit_rate = profile->nBitRate;
+            mCtx->block_align = profile->nBlockAlign;
+
+            adjustAudioParams();
+
+            ALOGV("set OMX_IndexParamAudioWma, nChannels:%u, "
+                    "nSampleRate:%lu, nBitRate:%lu, nBlockAlign:%u",
+                profile->nChannels, profile->nSamplingRate,
+                profile->nBitRate, profile->nBlockAlign);
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioRa:
+        {
+            OMX_AUDIO_PARAM_RATYPE *profile =
+                (OMX_AUDIO_PARAM_RATYPE *)params;
+
+            if (profile->nPortIndex != kInputPortIndex) {
+                return OMX_ErrorUndefined;
+            }
+
+            CHECK(!isConfigured());
+
+            mCtx->channels = profile->nChannels;
+            mCtx->sample_rate = profile->nSamplingRate;
+
+            // FIXME, HACK!!!, I use the nNumRegions parameter pass blockAlign!!!
+            // the cook audio codec need blockAlign!
+            mCtx->block_align = profile->nNumRegions;
+
+            adjustAudioParams();
+
+            ALOGV("set OMX_IndexParamAudioRa, nChannels:%lu, "
+                    "nSampleRate:%lu, nBlockAlign:%d",
+                profile->nChannels, profile->nSamplingRate, mCtx->block_align);
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioFlac:
+        {
+            OMX_AUDIO_PARAM_FLACTYPE *profile =
+                (OMX_AUDIO_PARAM_FLACTYPE *)params;
+
+            if (profile->nPortIndex != kInputPortIndex) {
+                return OMX_ErrorUndefined;
+            }
+
+            CHECK(!isConfigured());
+
+            mCtx->channels = profile->nChannels;
+            mCtx->sample_rate = profile->nSampleRate;
+
+            adjustAudioParams();
+
+            ALOGV("set OMX_IndexParamAudioFlac, nChannels:%lu, nSampleRate:%lu",
+                profile->nChannels, profile->nSampleRate);
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioMp2:
+        {
+            OMX_AUDIO_PARAM_MP2TYPE *profile =
+                (OMX_AUDIO_PARAM_MP2TYPE *)params;
+
+            if (profile->nPortIndex != kInputPortIndex) {
+                return OMX_ErrorUndefined;
+            }
+
+            CHECK(!isConfigured());
+
+            mCtx->channels = profile->nChannels;
+            mCtx->sample_rate = profile->nSampleRate;
+
+            adjustAudioParams();
+
+            ALOGV("set OMX_IndexParamAudioMp2, nChannels:%lu, nSampleRate:%lu",
+                profile->nChannels, profile->nSampleRate);
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioAc3:
+        {
+            OMX_AUDIO_PARAM_AC3TYPE *profile =
+                (OMX_AUDIO_PARAM_AC3TYPE *)params;
+
+            if (profile->nPortIndex != kInputPortIndex) {
+                return OMX_ErrorUndefined;
+            }
+
+            CHECK(!isConfigured());
+
+            mCtx->channels = profile->nChannels;
+            mCtx->sample_rate = profile->nSamplingRate;
+
+            adjustAudioParams();
+
+            ALOGV("set OMX_IndexParamAudioFlac, nChannels:%lu, nSampleRate:%lu",
+                profile->nChannels, profile->nSamplingRate);
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioApe:
+        {
+            OMX_AUDIO_PARAM_APETYPE *profile =
+                (OMX_AUDIO_PARAM_APETYPE *)params;
+
+            if (profile->nPortIndex != kInputPortIndex) {
+                return OMX_ErrorUndefined;
+            }
+
+            CHECK(!isConfigured());
+
+            mCtx->channels = profile->nChannels;
+            mCtx->sample_rate = profile->nSamplingRate;
+
+            //ape decoder need bits_per_coded_sample
+            mCtx->bits_per_coded_sample = profile->nBitsPerSample;
+
+            adjustAudioParams();
+
+            ALOGV("set OMX_IndexParamAudioApe, nChannels:%lu, "
+                    "nSampleRate:%lu, nBitsPerSample:%lu",
+                profile->nChannels, profile->nSamplingRate,
+                profile->nBitsPerSample);
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioDts:
+        {
+            OMX_AUDIO_PARAM_DTSTYPE *profile =
+                (OMX_AUDIO_PARAM_DTSTYPE *)params;
+
+            if (profile->nPortIndex != kInputPortIndex) {
+                return OMX_ErrorUndefined;
+            }
+
+            CHECK(!isConfigured());
+
+            mCtx->channels = profile->nChannels;
+            mCtx->sample_rate = profile->nSamplingRate;
+
+            adjustAudioParams();
+
+            ALOGV("set OMX_IndexParamAudioDts, nChannels:%lu, nSampleRate:%lu",
+                profile->nChannels, profile->nSamplingRate);
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioFFmpeg:
+        {
+            OMX_AUDIO_PARAM_FFMPEGTYPE *profile =
+                (OMX_AUDIO_PARAM_FFMPEGTYPE *)params;
+
+            if (profile->nPortIndex != kInputPortIndex) {
+                return OMX_ErrorUndefined;
+            }
+
+            CHECK(!isConfigured());
+
+
+            mCtx->codec_id = (enum AVCodecID)profile->eCodecId;
+            mCtx->channels = profile->nChannels;
+            mCtx->bit_rate = profile->nBitRate;
+            mCtx->bits_per_coded_sample = profile->nBitsPerSample;
+            mCtx->sample_rate = profile->nSampleRate;
+            mCtx->block_align = profile->nBlockAlign;
+            mCtx->sample_fmt = (AVSampleFormat)profile->eSampleFormat;
+
+            adjustAudioParams();
+
+            ALOGD("set OMX_IndexParamAudioFFmpeg, "
+                "eCodecId:%ld(%s), nChannels:%lu, nBitRate:%lu, "
+                "nBitsPerSample:%lu, nSampleRate:%lu, "
+                "nBlockAlign:%lu, eSampleFormat:%lu(%s)",
+                profile->eCodecId, avcodec_get_name(mCtx->codec_id),
+                profile->nChannels, profile->nBitRate,
+                profile->nBitsPerSample, profile->nSampleRate,
+                profile->nBlockAlign, profile->eSampleFormat,
+                av_get_sample_fmt_name(mCtx->sample_fmt));
+            return OMX_ErrorNone;
+        }
+
+        default:
+
+            return SimpleSoftOMXComponent::internalSetParameter(index, params);
+    }
+}
+
+int32_t SoftFFmpegAudio::handleExtradata() {
+    List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
+    BufferInfo *inInfo = *inQueue.begin();
+    OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+
+    ALOGI("got extradata, ignore: %d, size: %lu",
+            mIgnoreExtradata, inHeader->nFilledLen);
+    hexdump(inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen);
+
+    if (mIgnoreExtradata) {
+        ALOGI("got extradata, size: %lu, but ignore it", inHeader->nFilledLen);
+    } else {
+        if (!mExtradataReady) {
+            int orig_extradata_size = mCtx->extradata_size;
+            mCtx->extradata_size += inHeader->nFilledLen;
+            mCtx->extradata = (uint8_t *)av_realloc(mCtx->extradata,
+                    mCtx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
+            if (!mCtx->extradata) {
+                ALOGE("ffmpeg audio decoder failed to alloc extradata memory.");
+                return ERR_OOM;
             }
 
+            memcpy(mCtx->extradata + orig_extradata_size,
+                    inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen);
+            memset(mCtx->extradata + mCtx->extradata_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+        }
+    }
+
+    inInfo->mOwnedByUs = false;
+    inQueue.erase(inQueue.begin());
+    inInfo = NULL;
+    notifyEmptyBufferDone(inHeader);
+    inHeader = NULL;
+
+    return ERR_OK;
+}
+
+int32_t SoftFFmpegAudio::openDecoder() {
+    if (mCodecAlreadyOpened) {
+        return ERR_OK;
+    }
+
+    if (!mExtradataReady && !mIgnoreExtradata) {
+        ALOGI("extradata is ready, size: %d", mCtx->extradata_size);
+        hexdump(mCtx->extradata, mCtx->extradata_size);
+        mExtradataReady = true;
+    }
+
+    //find decoder
+    mCtx->codec = avcodec_find_decoder(mCtx->codec_id);
+    if (!mCtx->codec) {
+        ALOGE("ffmpeg audio decoder failed to find codec");
+        return ERR_CODEC_NOT_FOUND;
+    }
+
+    CHECK(isConfigured());
+
+    setDefaultCtx(mCtx, mCtx->codec);
+
+    ALOGD("begin to open ffmpeg audio decoder(%s), mCtx sample_rate: %d, "
+           "channels: %d, , sample_fmt: %s",
+           avcodec_get_name(mCtx->codec_id),
+           mCtx->sample_rate, mCtx->channels,
+           av_get_sample_fmt_name(mCtx->sample_fmt));
+
+    int err = avcodec_open2(mCtx, mCtx->codec, NULL);
+    if (err < 0) {
+        ALOGE("ffmpeg audio decoder failed to initialize.(%s)", av_err2str(err));
+        return ERR_DECODER_OPEN_FAILED;
+    }
+    mCodecAlreadyOpened = true;
+
+    ALOGD("open ffmpeg audio decoder(%s) success, mCtx sample_rate: %d, "
+            "channels: %d, sample_fmt: %s",
+            avcodec_get_name(mCtx->codec_id),
+            mCtx->sample_rate, mCtx->channels,
+            av_get_sample_fmt_name(mCtx->sample_fmt));
+
+    mFrame = avcodec_alloc_frame();
+    if (!mFrame) {
+        ALOGE("oom for video frame");
+        return ERR_OOM;
+    }
+
+       return ERR_OK;
+}
+
+void SoftFFmpegAudio::updateTimeStamp(OMX_BUFFERHEADERTYPE *inHeader) {
+    CHECK_EQ(mInputBufferSize, 0);
+
+    //XXX reset to AV_NOPTS_VALUE if the pts is invalid
+    if (inHeader->nTimeStamp == SF_NOPTS_VALUE) {
+        inHeader->nTimeStamp = AV_NOPTS_VALUE;
+    }
+
+    //update the audio clock if the pts is valid
+    if (inHeader->nTimeStamp != AV_NOPTS_VALUE) {
+        mAudioClock = inHeader->nTimeStamp;
+    }
+}
+
+void SoftFFmpegAudio::initPacket(AVPacket *pkt,
+        OMX_BUFFERHEADERTYPE *inHeader) {
+    memset(pkt, 0, sizeof(AVPacket));
+    av_init_packet(pkt);
+
+    if (inHeader) {
+        pkt->data = (uint8_t *)inHeader->pBuffer + inHeader->nOffset;
+        pkt->size = inHeader->nFilledLen;
+        pkt->pts = inHeader->nTimeStamp; //ingore it, we will compute it
+    } else {
+        pkt->data = NULL;
+        pkt->size = 0;
+        pkt->pts = AV_NOPTS_VALUE;
+    }
+
+#if DEBUG_PKT
+    if (pkt->pts != AV_NOPTS_VALUE)
+    {
+        ALOGV("pkt size:%d, pts:%lld", pkt->size, pkt->pts);
+    } else {
+        ALOGV("pkt size:%d, pts:N/A", pkt->size);
+    }
+#endif
+}
+
+int32_t SoftFFmpegAudio::decodeAudio() {
+    int len = 0;
+    int gotFrm = false;
+       int32_t ret = ERR_OK;
+    int32_t inputBufferUsedLength = 0;
+       bool is_flush = (mEOSStatus != INPUT_DATA_AVAILABLE);
+    List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
+    BufferInfo *inInfo = NULL;
+    OMX_BUFFERHEADERTYPE *inHeader = NULL;
+
+    CHECK_EQ(mResampledDataSize, 0);
+
+    if (!is_flush) {
+        inInfo = *inQueue.begin();
+        CHECK(inInfo != NULL);
+        inHeader = inInfo->mHeader;
+
+               if (mInputBufferSize == 0) {
+                   updateTimeStamp(inHeader);
+            mInputBufferSize = inHeader->nFilledLen;
+        }
+    }
+
+    AVPacket pkt;
+    initPacket(&pkt, inHeader);
+    av_frame_unref(mFrame);
+    avcodec_get_frame_defaults(mFrame);
+
+    len = avcodec_decode_audio4(mCtx, mFrame, &gotFrm, &pkt);
+    //a negative error code is returned if an error occurred during decoding
+    if (len < 0) {
+        ALOGW("ffmpeg audio decoder err, we skip the frame and play silence instead");
+        mResampledData = mSilenceBuffer;
+        mResampledDataSize = kOutputBufferSize;
+        ret = ERR_OK;
+    } else {
+#if DEBUG_PKT
+        ALOGV("ffmpeg audio decoder, consume pkt len: %d", len);
+#endif
+        if (!gotFrm) {
+            ALOGI("ffmpeg audio decoder failed to get frame.");
+            //stop sending empty packets if the decoder is finished
+            if (is_flush && mCtx->codec->capabilities & CODEC_CAP_DELAY) {
+                           ret = ERR_FLUSHED;
+                   } else {
+                       ret = ERR_NO_FRM;
+                   }
+        } else {
+            ret = resampleAudio();
+               }
+    }
+
+       if (!is_flush) {
+        if (len < 0) {
+            //if error, we skip the frame 
+            inputBufferUsedLength = mInputBufferSize;
+        } else {
+            inputBufferUsedLength = len;
+        }
+
+        CHECK_GE(inHeader->nFilledLen, inputBufferUsedLength);
+        inHeader->nOffset += inputBufferUsedLength;
+        inHeader->nFilledLen -= inputBufferUsedLength;
+        mInputBufferSize -= inputBufferUsedLength;
+
+        if (inHeader->nFilledLen == 0) {
+            CHECK_EQ(mInputBufferSize, 0);
+            inQueue.erase(inQueue.begin());
+            inInfo->mOwnedByUs = false;
+            notifyEmptyBufferDone(inHeader);
+        }
+       }
+
+    return ret;
+}
+
+int32_t SoftFFmpegAudio::resampleAudio() {
+       int channels = 0;
+    int64_t channelLayout = 0;
+    size_t dataSize = 0;
+
+    dataSize = av_samples_get_buffer_size(NULL, av_frame_get_channels(mFrame),
+            mFrame->nb_samples, (enum AVSampleFormat)mFrame->format, 1);
+
 #if DEBUG_FRM
-            LOGV("ffmpeg audio decoder get frame. consume pkt len: %d, nb_samples(before resample): %d, mAudioBufferSize: %d",
-                    len, mFrame->nb_samples, mAudioBufferSize);
+    ALOGV("ffmpeg audio decoder, nb_samples:%d, get buffer size:%d",
+            mFrame->nb_samples, dataSize);
 #endif
-        } // if (inHeader && mAudioBufferSize == 0 && !mFlushComplete)
 
-        size_t copyToOutputBufferLen = mAudioBufferSize;
-        if (mAudioBufferSize > kOutputBufferSize)
-            copyToOutputBufferLen = kOutputBufferSize;
+       channels = av_get_channel_layout_nb_channels(mFrame->channel_layout);
+    channelLayout =
+        (mFrame->channel_layout && av_frame_get_channels(mFrame) == channels) ?
+        mFrame->channel_layout : av_get_default_channel_layout(av_frame_get_channels(mFrame));
 
-        outHeader->nOffset = 0;
-        outHeader->nFilledLen = copyToOutputBufferLen;
-        outHeader->nTimeStamp = mAnchorTimeUs + (mNumFramesOutput * 1000000ll) / mSamplingRate;
-        memcpy(outHeader->pBuffer, mPAudioBuffer, copyToOutputBufferLen);
-        outHeader->nFlags = 0;
+    if (mFrame->format != mAudioSrcFmt
+            || channelLayout != mAudioSrcChannelLayout
+            || mFrame->sample_rate != mAudioSrcFreq) {
+        if (mSwrCtx) {
+            swr_free(&mSwrCtx);
+        }
+        mSwrCtx = swr_alloc_set_opts(NULL,
+                mAudioTgtChannelLayout, mAudioTgtFmt,                     mAudioTgtFreq,
+                channelLayout,       (enum AVSampleFormat)mFrame->format, mFrame->sample_rate,
+                0, NULL);
+        if (!mSwrCtx || swr_init(mSwrCtx) < 0) {
+            ALOGE("Cannot create sample rate converter for conversion "
+                    "of %d Hz %s %d channels to %d Hz %s %d channels!",
+                    mFrame->sample_rate,
+                    av_get_sample_fmt_name((enum AVSampleFormat)mFrame->format),
+                    av_frame_get_channels(mFrame),
+                    mAudioTgtFreq,
+                    av_get_sample_fmt_name(mAudioTgtFmt),
+                    mAudioTgtChannels);
+            return ERR_SWR_INIT_FAILED;
+        }
+
+        char src_layout_name[1024] = {0};
+        char tgt_layout_name[1024] = {0};
+        av_get_channel_layout_string(src_layout_name, sizeof(src_layout_name),
+                mCtx->channels, channelLayout);
+        av_get_channel_layout_string(tgt_layout_name, sizeof(tgt_layout_name),
+                mAudioTgtChannels, mAudioTgtChannelLayout);
+        ALOGI("Create sample rate converter for conversion "
+                "of %d Hz %s %d channels(%s) "
+                "to %d Hz %s %d channels(%s)!",
+                mFrame->sample_rate,
+                av_get_sample_fmt_name((enum AVSampleFormat)mFrame->format),
+                av_frame_get_channels(mFrame),
+                src_layout_name,
+                mAudioTgtFreq,
+                av_get_sample_fmt_name(mAudioTgtFmt),
+                mAudioTgtChannels,
+                tgt_layout_name);
+
+        mAudioSrcChannelLayout = channelLayout;
+        mAudioSrcChannels = av_frame_get_channels(mFrame);
+        mAudioSrcFreq = mFrame->sample_rate;
+        mAudioSrcFmt = (enum AVSampleFormat)mFrame->format;
+    }
+
+    if (mSwrCtx) {
+        const uint8_t **in = (const uint8_t **)mFrame->extended_data;
+        uint8_t *out[] = {mAudioBuffer};
+        int out_count = sizeof(mAudioBuffer) / mAudioTgtChannels / av_get_bytes_per_sample(mAudioTgtFmt);
+        int out_size  = av_samples_get_buffer_size(NULL, mAudioTgtChannels, out_count, mAudioTgtFmt, 0);
+        int len2 = 0;
+        if (out_size < 0) {
+            ALOGE("av_samples_get_buffer_size() failed");
+            return ERR_INVALID_PARAM;
+        }
+
+        len2 = swr_convert(mSwrCtx, out, out_count, in, mFrame->nb_samples);
+        if (len2 < 0) {
+            ALOGE("audio_resample() failed");
+            return ERR_RESAMPLE_FAILED;
+        }
+        if (len2 == out_count) {
+            ALOGE("warning: audio buffer is probably too small");
+            swr_init(mSwrCtx);
+        }
+        mResampledData = mAudioBuffer;
+        mResampledDataSize = len2 * mAudioTgtChannels * av_get_bytes_per_sample(mAudioTgtFmt);
 
 #if DEBUG_FRM
-        LOGV("ffmpeg audio decoder, fill out buffer, pts: %lld, mNumFramesOutput: %lld", outHeader->nTimeStamp, mNumFramesOutput);
+        ALOGV("ffmpeg audio decoder(resample), mFrame->nb_samples:%d, len2:%d, mResampledDataSize:%d, "
+                "src channel:%u, src fmt:%s, tgt channel:%u, tgt fmt:%s",
+                mFrame->nb_samples, len2, mResampledDataSize,
+                av_frame_get_channels(mFrame),
+                av_get_sample_fmt_name((enum AVSampleFormat)mFrame->format),
+                mAudioTgtChannels,
+                av_get_sample_fmt_name(mAudioTgtFmt));
 #endif
+    } else {
+        mResampledData = mFrame->data[0];
+        mResampledDataSize = dataSize;
+
+#if DEBUG_FRM
+    ALOGV("ffmpeg audio decoder(no resample),"
+            "nb_samples(before resample):%d, mResampledDataSize:%d",
+            mFrame->nb_samples, mResampledDataSize);
+#endif
+    }
+
+       return ERR_OK;
+}
 
-        mPAudioBuffer += copyToOutputBufferLen;
-        mAudioBufferSize -= copyToOutputBufferLen;
-        mNumFramesOutput += copyToOutputBufferLen / (av_get_bytes_per_sample(mAudioTgtFmt) * mNumChannels);
+void SoftFFmpegAudio::drainOneOutputBuffer() {
+    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
+       BufferInfo *outInfo = *outQueue.begin();
+       CHECK(outInfo != NULL);
+       OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+
+       CHECK_GT(mResampledDataSize, 0);
+
+    size_t copy = mResampledDataSize;
+    if (mResampledDataSize > kOutputBufferSize) {
+        copy = kOutputBufferSize;
+       }
+
+    outHeader->nOffset = 0;
+    outHeader->nFilledLen = copy;
+    outHeader->nTimeStamp = mAudioClock; 
+    memcpy(outHeader->pBuffer, mResampledData, copy);
+    outHeader->nFlags = 0;
+
+    //update mResampledSize
+    mResampledData += copy;
+    mResampledDataSize -= copy;
+
+    //update audio pts
+    size_t frames = copy / (av_get_bytes_per_sample(mAudioTgtFmt) * mAudioTgtChannels);
+    mAudioClock += (frames * 1000000ll) / mAudioTgtFreq;
 
-        // reset mNumFramesOutput
-        if (mAudioBufferSize == 0) {
 #if DEBUG_FRM
-            LOGV("~~~~ mAudioBufferSize, set mNumFramesOutput = 0");
+    ALOGV("ffmpeg audio decoder, fill out buffer, copy:%u, pts: %lld",
+            copy, outHeader->nTimeStamp);
 #endif
-            mNumFramesOutput = 0;
+
+    outQueue.erase(outQueue.begin());
+    outInfo->mOwnedByUs = false;
+    notifyFillBufferDone(outHeader);
+}
+
+void SoftFFmpegAudio::drainEOSOutputBuffer() {
+    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
+       BufferInfo *outInfo = *outQueue.begin();
+       CHECK(outInfo != NULL);
+       OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+
+       CHECK_EQ(mResampledDataSize, 0);
+
+    ALOGD("ffmpeg audio decoder fill eos outbuf");
+
+    outHeader->nTimeStamp = 0;
+    outHeader->nFilledLen = 0;
+    outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+
+    outQueue.erase(outQueue.begin());
+    outInfo->mOwnedByUs = false;
+    notifyFillBufferDone(outHeader);
+
+    mEOSStatus = OUTPUT_FRAMES_FLUSHED;
+}
+
+void SoftFFmpegAudio::drainAllOutputBuffers() {
+    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
+
+    if (!mCodecAlreadyOpened) {
+        drainEOSOutputBuffer();
+        mEOSStatus = OUTPUT_FRAMES_FLUSHED;
+        return;
+    }
+
+    if(!(mCtx->codec->capabilities & CODEC_CAP_DELAY)) {
+        drainEOSOutputBuffer();
+        mEOSStatus = OUTPUT_FRAMES_FLUSHED;
+        return;
+    }
+
+    while (!outQueue.empty()) {
+        if (mResampledDataSize == 0) {
+            int32_t err = decodeAudio();
+            if (err < ERR_OK) {
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                mSignalledError = true;
+                           return;
+            } else if (err == ERR_FLUSHED) {
+                drainEOSOutputBuffer();
+                return;
+                       } else {
+                CHECK_EQ(err, ERR_OK);
+                       }
         }
 
-        outInfo->mOwnedByUs = false;
-        outQueue.erase(outQueue.begin());
-        outInfo = NULL;
-        notifyFillBufferDone(outHeader);
-        outHeader = NULL;
+               if (mResampledDataSize > 0) {
+            drainOneOutputBuffer();
+        }
     }
 }
 
-void SoftFFmpegAudio::onPortFlushCompleted(OMX_U32 portIndex) {
-    if (portIndex == 0 && mCtx) {
-        // Make sure that the next buffer output does not still
-        // depend on fragments from the last one decoded.
-        avcodec_flush_buffers(mCtx);
+void SoftFFmpegAudio::onQueueFilled(OMX_U32 portIndex) {
+    BufferInfo *inInfo = NULL;
+    OMX_BUFFERHEADERTYPE *inHeader = NULL;
+
+    if (mSignalledError || mOutputPortSettingsChange != NONE) {
+        return;
     }
 
+    if (mEOSStatus == OUTPUT_FRAMES_FLUSHED) {
+        return;
+    }
+
+    List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
+    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
+
+    while (((mEOSStatus != INPUT_DATA_AVAILABLE) || !inQueue.empty())
+            && !outQueue.empty()) {
+
+        if (mEOSStatus == INPUT_EOS_SEEN) {
+            drainAllOutputBuffers();
+            return;
+        }
+
+        inInfo   = *inQueue.begin();
+        inHeader = inInfo->mHeader;
+
+        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+            ALOGD("ffmpeg audio decoder empty eos inbuf");
+            inQueue.erase(inQueue.begin());
+            inInfo->mOwnedByUs = false;
+            notifyEmptyBufferDone(inHeader);
+            mEOSStatus = INPUT_EOS_SEEN;
+            continue;
+        }
+
+        if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
+                   if (handleExtradata() != ERR_OK) {
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                mSignalledError = true;
+                return;
+            }
+            continue;
+        }
+
+        if (!mCodecAlreadyOpened) {
+            if (openDecoder() != ERR_OK) {
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                mSignalledError = true;
+                   return;
+            }
+        }
+
+               if (mResampledDataSize == 0) {
+                       int32_t err = decodeAudio();
+            if (err < ERR_OK) {
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                mSignalledError = true;
+                           return;
+            } else if (err == ERR_NO_FRM) {
+                CHECK_EQ(mResampledDataSize, 0);
+                continue;
+                       } else {
+                CHECK_EQ(err, ERR_OK);
+                       }
+               }
+
+               if (mResampledDataSize > 0) {
+                       drainOneOutputBuffer();
+               }
+    }
+}
+
+void SoftFFmpegAudio::onPortFlushCompleted(OMX_U32 portIndex) {
+    ALOGV("ffmpeg audio decoder flush port(%lu)", portIndex);
+    if (portIndex == kInputPortIndex) {
+        if (mCtx) {
+            //Make sure that the next buffer output does not still
+            //depend on fragments from the last one decoded.
+            avcodec_flush_buffers(mCtx);
+        }
+
+           mAudioClock = 0;
+           mInputBufferSize = 0;
+           mResampledDataSize = 0;
+           mResampledData = NULL;
+        mEOSStatus = INPUT_DATA_AVAILABLE;
+    }
 }
 
 void SoftFFmpegAudio::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
-    if (portIndex != 1) {
+    if (portIndex != kOutputPortIndex) {
         return;
     }