diff --git a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
index dfe34e870..717dd5fcf 100644
--- a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
+++ b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
@@ -54,6 +54,11 @@ enum {
     kKeyBitRate           = 'brte',  // int32_t (bps)
     kKeyMaxBitRate        = 'mxBr',  // int32_t (bps)
     kKeyStreamHeader      = 'stHd',  // raw data
+    kKeyCodecId           = 'cdid',  // int32_t
+    kKeyCodedSampleBits   = 'cosb',  // int32_t
+    kKeySampleFormat      = 'sfmt',  // int32_t
+    kKeyBitsPerRawSample  = 'sbit',  // int32_t
+    kKeyFileFormat        = 'ffmt',  // cstring
     kKeyESDS              = 'esds',  // raw data
     kKeyAACProfile        = 'aacp',  // int32_t
     kKeyAVCC              = 'avcc',  // raw data
@@ -139,6 +144,23 @@ enum {
 
     kKeyIsUnreadable      = 'unre',  // bool (int32_t)
 
+    kKeyRawCodecSpecificData = 'rcsd',  // raw data - added to support mmParser
+    kKeyDivXVersion       = 'DivX',  // int32_t
+    kKeyDivXDrm           = 'QDrm',  // void *
+    kKeyWMAEncodeOpt      = 'eopt',  // int32_t
+    kKeyWMABlockAlign     = 'blka',  // int32_t
+    kKeyWMAVersion        = 'wmav',  // int32_t
+    kKeyWMAAdvEncOpt1     = 'ade1',  // int16_t
+    kKeyWMAAdvEncOpt2     = 'ade2',  // int32_t
+    kKeyWMAFormatTag      = 'fmtt',  // int64_t
+    kKeyWMABitspersample  = 'bsps',  // int64_t
+    kKeyWMAVirPktSize     = 'vpks',  // int64_t
+    kKeyWMVProfile        = 'wmvp',  // int32_t
+
+    kKeyWMVVersion        = 'wmvv',  // int32_t
+    kKeyRVVersion         = '#rvv',  // int32_t
+    kKeyBlockAlign        = 'ablk',   // int32_t , should be different from kKeyWMABlockAlign
+
     // An indication that a video buffer has been rendered.
     kKeyRendered          = 'rend',  // bool (int32_t)
 
@@ -225,6 +247,8 @@ enum {
     kKeyExifOffset       = 'exof', // int64_t, Exif data offset
     kKeyExifSize         = 'exsz', // int64_t, Exif data size
     kKeyIsExif           = 'exif', // bool (int32_t) buffer contains exif data block
+
+    kKeyArbitraryMode     = 'ArbM',
 };
 
 enum {
@@ -234,6 +258,32 @@ enum {
     kTypeD263        = 'd263',
 };
 
+enum {
+    kTypeDivXVer_3_11,
+    kTypeDivXVer_4,
+    kTypeDivXVer_5,
+    kTypeDivXVer_6,
+};
+
+enum {
+    kTypeWMA,
+    kTypeWMAPro,
+    kTypeWMALossLess,
+};
+
+enum {
+    kTypeWMVVer_7, // WMV1
+    kTypeWMVVer_8, // WMV2
+    kTypeWMVVer_9, // WMV3
+};
+
+// http://en.wikipedia.org/wiki/RealVideo
+enum {
+    kTypeRVVer_G2, // rv20: RealVideo G2
+    kTypeRVVer_8,  // rv30: RealVideo 8
+    kTypeRVVer_9,  // rv40: RealVideo 9
+};
+
 enum {
     kCryptoModeUnencrypted = 0,
     kCryptoModeAesCtr      = 1,
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 69cd82e2d..badd92f47 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -40,6 +40,9 @@
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/SurfaceUtils.h>
+
+#include <media/stagefright/FFMPEGSoftCodec.h>
+
 #include <gui/Surface.h>
 
 #include "ATSParser.h"
@@ -294,8 +297,16 @@ void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) {
     mComponentName.append(" decoder");
     ALOGV("[%s] onConfigure (surface=%p)", mComponentName.c_str(), mSurface.get());
 
-    mCodec = MediaCodec::CreateByType(
-            mCodecLooper, mime.c_str(), false /* encoder */, NULL /* err */, mPid, mUid);
+    FFMPEGSoftCodec::overrideComponentName(0, format, &mComponentName, &mime, false);
+
+    if (!mComponentName.startsWith(mime.c_str())) {
+        mCodec = MediaCodec::CreateByComponentName(
+                mCodecLooper, mComponentName.c_str(), NULL, mPid, mUid);
+    } else {
+        mCodec = MediaCodec::CreateByType(
+                mCodecLooper, mime.c_str(), false /* encoder */, NULL /* err */, mPid, mUid);
+    }
+
     int32_t secure = 0;
     if (format->findInt32("secure", &secure) && secure != 0) {
         if (mCodec != NULL) {
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 7f39d109f..0eaaafe1e 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -37,10 +37,13 @@
 
 #include <media/stagefright/BufferProducerWrapper.h>
 #include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaCodecList.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/OMXClient.h>
 #include <media/stagefright/PersistentSurface.h>
 #include <media/stagefright/SurfaceUtils.h>
+#include <media/stagefright/FFMPEGSoftCodec.h>
+
 #include <media/hardware/HardwareAPI.h>
 #include <media/MediaBufferHolder.h>
 #include <media/OMXBuffer.h>
@@ -607,6 +610,15 @@ ACodec::ACodec()
 ACodec::~ACodec() {
 }
 
+status_t ACodec::setupCustomCodec(status_t err, const char *mime, const sp<AMessage> &msg) {
+     if (!strncmp(mComponentName.c_str(), "OMX.ffmpeg.", 11) && !mIsEncoder) {
+         return FFMPEGSoftCodec::setAudioFormat(
+               msg, mime, mOMX, mOMXNode);
+     }
+
+    return err;
+}
+
 void ACodec::initiateSetup(const sp<AMessage> &msg) {
     msg->setWhat(kWhatSetup);
     msg->setTarget(this);
@@ -2020,7 +2032,8 @@ status_t ACodec::configureCodec(
     if (mIsVideo || mIsImage) {
         // determine need for software renderer
         bool usingSwRenderer = false;
-        if (haveNativeWindow && mComponentName.startsWith("OMX.google.")) {
+        if (haveNativeWindow && (mComponentName.startsWith("OMX.google.") ||
+                                 mComponentName.startsWith("OMX.ffmpeg."))) {
             usingSwRenderer = true;
             haveNativeWindow = false;
             (void)setPortMode(kPortIndexOutput, IOMX::kPortModePresetByteBuffer);
@@ -2099,7 +2112,7 @@ status_t ACodec::configureCodec(
             err = setupRawAudioFormat(
                     encoder ? kPortIndexInput : kPortIndexOutput,
                     sampleRate,
-                    numChannels);
+                    numChannels, pcmEncoding);
         }
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
         int32_t numChannels, sampleRate;
@@ -2216,14 +2229,15 @@ status_t ACodec::configureCodec(
         } else {
             err = setupRawAudioFormat(kPortIndexInput, sampleRate, numChannels, pcmEncoding);
         }
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AC3)) {
+    } else if (!strncmp(mComponentName.c_str(), "OMX.google.", 11)
+            && !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AC3)) {
         int32_t numChannels;
         int32_t sampleRate;
         if (!msg->findInt32("channel-count", &numChannels)
                 || !msg->findInt32("sample-rate", &sampleRate)) {
             err = INVALID_OPERATION;
         } else {
-            err = setupAC3Codec(encoder, numChannels, sampleRate);
+            err = setupAC3Codec(encoder, numChannels, sampleRate, pcmEncoding);
         }
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_EAC3)) {
         int32_t numChannels;
@@ -2232,8 +2246,10 @@ status_t ACodec::configureCodec(
                 || !msg->findInt32("sample-rate", &sampleRate)) {
             err = INVALID_OPERATION;
         } else {
-            err = setupEAC3Codec(encoder, numChannels, sampleRate);
+            err = setupEAC3Codec(encoder, numChannels, sampleRate, pcmEncoding);
         }
+    } else {
+        err = setupCustomCodec(err, mime, msg);
     }
 
     if (err != OK) {
@@ -2827,9 +2843,9 @@ status_t ACodec::setupAACCodec(
 }
 
 status_t ACodec::setupAC3Codec(
-        bool encoder, int32_t numChannels, int32_t sampleRate) {
+        bool encoder, int32_t numChannels, int32_t sampleRate, AudioEncoding encoding) {
     status_t err = setupRawAudioFormat(
-            encoder ? kPortIndexInput : kPortIndexOutput, sampleRate, numChannels);
+            encoder ? kPortIndexInput : kPortIndexOutput, sampleRate, numChannels, encoding);
 
     if (err != OK) {
         return err;
@@ -2859,9 +2875,9 @@ status_t ACodec::setupAC3Codec(
 }
 
 status_t ACodec::setupEAC3Codec(
-        bool encoder, int32_t numChannels, int32_t sampleRate) {
+        bool encoder, int32_t numChannels, int32_t sampleRate, AudioEncoding encoding) {
     status_t err = setupRawAudioFormat(
-            encoder ? kPortIndexInput : kPortIndexOutput, sampleRate, numChannels);
+            encoder ? kPortIndexInput : kPortIndexOutput, sampleRate, numChannels, encoding);
 
     if (err != OK) {
         return err;
@@ -3311,6 +3327,9 @@ status_t ACodec::setupVideoDecoder(
     OMX_VIDEO_CODINGTYPE compressionFormat;
     status_t err = GetVideoCodingTypeFromMime(mime, &compressionFormat);
 
+    err = FFMPEGSoftCodec::setVideoFormat(err,
+                    msg, mime, mOMX, mOMXNode, mIsEncoder, &compressionFormat,
+                    mComponentName.c_str());
     if (err != OK) {
         return err;
     }
@@ -3848,7 +3867,11 @@ status_t ACodec::setupVideoEncoder(
     OMX_VIDEO_CODINGTYPE compressionFormat;
     err = GetVideoCodingTypeFromMime(mime, &compressionFormat);
 
+    err = FFMPEGSoftCodec::setVideoFormat(err,
+                msg, mime, mOMX, mOMXNode, mIsEncoder, &compressionFormat,
+                mComponentName.c_str());
     if (err != OK) {
+        ALOGE("Not a supported video mime type: %s", mime);
         return err;
     }
 
@@ -5023,6 +5046,14 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp<AMessage> &notify) {
 
                 default:
                 {
+                    if (!strncmp(mComponentName.c_str(), "OMX.ffmpeg.", 11)) {
+                        err = FFMPEGSoftCodec::getVideoPortFormat(portIndex,
+                                (int)videoDef->eCompressionFormat, notify, mOMX, mOMXNode);
+                        if (err == OK) {
+                            break;
+                        }
+                    }
+
                     if (mIsEncoder ^ (portIndex == kPortIndexOutput)) {
                         // should be CodingUnused
                         ALOGE("Raw port video compression format is %s(%d)",
@@ -5151,6 +5182,13 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp<AMessage> &notify) {
 
                 case OMX_AUDIO_CodingFLAC:
                 {
+                    if (!strncmp(mComponentName.c_str(), "OMX.ffmpeg.", 11)) {
+                        err = FFMPEGSoftCodec::getAudioPortFormat(portIndex,
+                                (int)audioDef->eEncoding, notify, mOMX, mOMXNode);
+                        if (err != OK) {
+                            return err;
+                        }
+                    } else {
                     OMX_AUDIO_PARAM_FLACTYPE params;
                     InitOMXParams(&params);
                     params.nPortIndex = portIndex;
@@ -5164,6 +5202,7 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp<AMessage> &notify) {
                     notify->setString("mime", MEDIA_MIMETYPE_AUDIO_FLAC);
                     notify->setInt32("channel-count", params.nChannels);
                     notify->setInt32("sample-rate", params.nSampleRate);
+                    }
                     break;
                 }
 
@@ -5306,6 +5345,14 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp<AMessage> &notify) {
                 }
 
                 default:
+                    if (!strncmp(mComponentName.c_str(), "OMX.ffmpeg.", 11)) {
+                        err = FFMPEGSoftCodec::getAudioPortFormat(portIndex,
+                                (int)audioDef->eEncoding, notify, mOMX, mOMXNode);
+                    }
+                    if (err == OK) {
+                        break;
+                    }
+
                     ALOGE("Unsupported audio coding: %s(%d)\n",
                             asString(audioDef->eEncoding), audioDef->eEncoding);
                     return BAD_TYPE;
@@ -6648,8 +6695,79 @@ bool ACodec::LoadedState::onConfigureComponent(
         ALOGE("[%s] configureCodec returning error %d",
               mCodec->mComponentName.c_str(), err);
 
-        mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));
-        return false;
+        int32_t encoder;
+        if (!msg->findInt32("encoder", &encoder)) {
+            encoder = false;
+        }
+
+        if (!encoder && !strncmp(mime.c_str(), "video/", strlen("video/"))) {
+            Vector<AString> matchingCodecs;
+
+            MediaCodecList::findMatchingCodecs(
+                mime.c_str(),
+                encoder, // createEncoder
+                0,     // flags
+                &matchingCodecs);
+
+            err = mCodec->mOMXNode->freeNode();
+
+            if (err != OK) {
+                ALOGE("Failed to freeNode");
+                mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));
+                return false;
+            }
+
+            mCodec->mOMXNode.clear();
+            AString componentName;
+            sp<CodecObserver> observer = new CodecObserver;
+
+            err = NAME_NOT_FOUND;
+            for (size_t matchIndex = 0; matchIndex < matchingCodecs.size();
+                    ++matchIndex) {
+                componentName = matchingCodecs.itemAt(matchIndex);
+                if (!strcmp(mCodec->mComponentName.c_str(), componentName.c_str())) {
+                    continue;
+                }
+
+                pid_t tid = gettid();
+                int prevPriority = androidGetThreadPriority(tid);
+                androidSetThreadPriority(tid, ANDROID_PRIORITY_FOREGROUND);
+                err = mCodec->mOMX->allocateNode(componentName.c_str(), observer,
+                        &mCodec->mOMXNode);
+                androidSetThreadPriority(tid, prevPriority);
+
+                if (err == OK) {
+                    break;
+                } else {
+                    ALOGW("Allocating component '%s' failed, try next one.", componentName.c_str());
+                }
+
+                mCodec->mOMXNode.clear();
+            }
+
+            if (mCodec->mOMXNode.get() == NULL) {
+                if (!mime.empty()) {
+                    ALOGE("Unable to instantiate a %scoder for type '%s' with err %#x.",
+                            encoder ? "en" : "de", mime.c_str(), err);
+                } else {
+                    ALOGE("Unable to instantiate codec '%s' with err %#x.", componentName.c_str(), err);
+                }
+
+                mCodec->signalError((OMX_ERRORTYPE)err, makeNoSideEffectStatus(err));
+                return false;
+            }
+
+            sp<AMessage> notify = new AMessage(kWhatOMXMessageList, mCodec);
+            observer->setNotificationMessage(notify);
+            mCodec->mComponentName = componentName;
+
+            err = mCodec->configureCodec(mime.c_str(), msg);
+        }
+
+        if (err != OK) {
+            mCodec->signalError((OMX_ERRORTYPE)err, makeNoSideEffectStatus(err));
+            return false;
+        }
     }
 
     mCodec->mCallback->onComponentConfigured(mCodec->mInputFormat, mCodec->mOutputFormat);
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 48e351b59..634ea671c 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -105,6 +105,7 @@ cc_library_shared {
         "DataConverter.cpp",
         "DataSourceFactory.cpp",
         "DataURISource.cpp",
+        "FFMPEGSoftCodec.cpp",
         "FileSource.cpp",
         "FrameDecoder.cpp",
         "HTTPBase.cpp",
@@ -189,6 +190,11 @@ cc_library_shared {
         "libFLAC",
     ],
 
+    include_dirs: [
+        // FFMPEG plugin
+        "external/stagefright-plugins/include"
+    ],
+
     export_shared_lib_headers: [
         "libmedia",
         "android.hidl.allocator@1.0",
@@ -235,6 +241,7 @@ cc_library {
         "DataSourceFactory.cpp",
         "DataURISource.cpp",
         "FileSource.cpp",
+        "FFMPEGSoftCodec.cpp",
         "HTTPBase.cpp",
         "HevcUtils.cpp",
         "InterfaceUtils.cpp",
@@ -266,8 +273,17 @@ cc_library {
         "libmedia_helper",
         "libstagefright_foundation",
         "libziparchive",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "android.hardware.media.omx@1.0",
     ],
 
+    include_dirs: [
+        // FFMPEG plugin
+        "external/stagefright-plugins/include"
+    ],
+
+
     static_libs: [
         "libstagefright_esds",
     ],
diff --git a/media/libstagefright/FFMPEGSoftCodec.cpp b/media/libstagefright/FFMPEGSoftCodec.cpp
new file mode 100644
index 000000000..68be3ca50
--- /dev/null
+++ b/media/libstagefright/FFMPEGSoftCodec.cpp
@@ -0,0 +1,1352 @@
+/*
+ * Copyright (C) 2014 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef __LP64__
+#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
+#endif
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "FFMPEGSoftCodec"
+#include <utils/Log.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ABitReader.h>
+
+#include <media/stagefright/FFMPEGSoftCodec.h>
+
+#include <media/stagefright/ACodec.h>
+#include <media/stagefright/MediaCodecList.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+
+#include <cutils/properties.h>
+
+#include <OMX_Component.h>
+#include <OMX_AudioExt.h>
+#include <OMX_IndexExt.h>
+
+#include <OMX_FFMPEG_Extn.h>
+
+#include <cutils/properties.h>
+#include <dlfcn.h>
+
+#ifdef QCOM_HARDWARE
+#include <OMX_QCOMExtns.h>
+#endif
+
+namespace android {
+
+enum MetaKeyType{
+    INT32, INT64, STRING, DATA, CSD
+};
+
+struct MetaKeyEntry{
+    int MetaKey;
+    const char* MsgKey;
+    MetaKeyType KeyType;
+};
+
+static const MetaKeyEntry MetaKeyTable[] {
+   {kKeyAACAOT               , "aac-profile"            , INT32},
+   {kKeyArbitraryMode        , "use-arbitrary-mode"     , INT32},
+   {kKeyBitsPerRawSample     , "bits-per-raw-sample"    , INT32},
+   {kKeyBitRate              , "bitrate"                , INT32},
+   {kKeyBlockAlign           , "block-align"            , INT32},
+   {kKeyChannelCount         , "channel-count"          , INT32},
+   {kKeyCodecId              , "codec-id"               , INT32},
+   {kKeyCodedSampleBits      , "coded-sample-bits"      , INT32},
+   {kKeyFileFormat           , "file-format"            , INT32},
+   {kKeyRawCodecSpecificData , "raw-codec-specific-data", CSD},
+   {kKeyPcmEncoding          , "pcm-encoding"           , INT32},
+   {kKeyRVVersion            , "rv-version"             , INT32},
+   {kKeySampleFormat         , "sample-format"          , INT32},
+   {kKeySampleRate           , "sample-rate"            , INT32},
+   {kKeyWMAVersion           , "wma-version"            , INT32},  // int32_t
+   {kKeyWMVVersion           , "wmv-version"            , INT32},
+   {kKeyDivXVersion          , "divx-version"           , INT32},
+};
+
+const char* FFMPEGSoftCodec::getMsgKey(int key) {
+    static const size_t numMetaKeys =
+                     sizeof(MetaKeyTable) / sizeof(MetaKeyTable[0]);
+    size_t i;
+    for (i = 0; i < numMetaKeys; ++i) {
+        if (key == MetaKeyTable[i].MetaKey) {
+            return MetaKeyTable[i].MsgKey;
+        }
+    }
+    return "unknown";
+}
+
+void FFMPEGSoftCodec::convertMetaDataToMessageFF(
+        const sp<MetaData> &meta, sp<AMessage> *format) {
+    const char * str_val;
+    int32_t int32_val;
+    int64_t int64_val;
+    uint32_t data_type;
+    const void * data;
+    size_t size;
+    static const size_t numMetaKeys =
+                     sizeof(MetaKeyTable) / sizeof(MetaKeyTable[0]);
+    size_t i;
+    for (i = 0; i < numMetaKeys; ++i) {
+        if (MetaKeyTable[i].KeyType == INT32 &&
+            meta->findInt32(MetaKeyTable[i].MetaKey, &int32_val)) {
+            ALOGV("found metakey %s of type int32", MetaKeyTable[i].MsgKey);
+            format->get()->setInt32(MetaKeyTable[i].MsgKey, int32_val);
+        } else if (MetaKeyTable[i].KeyType == INT64 &&
+                 meta->findInt64(MetaKeyTable[i].MetaKey, &int64_val)) {
+            ALOGV("found metakey %s of type int64", MetaKeyTable[i].MsgKey);
+            format->get()->setInt64(MetaKeyTable[i].MsgKey, int64_val);
+        } else if (MetaKeyTable[i].KeyType == STRING &&
+                 meta->findCString(MetaKeyTable[i].MetaKey, &str_val)) {
+            ALOGV("found metakey %s of type string", MetaKeyTable[i].MsgKey);
+            format->get()->setString(MetaKeyTable[i].MsgKey, str_val);
+        } else if ( (MetaKeyTable[i].KeyType == DATA ||
+                   MetaKeyTable[i].KeyType == CSD) &&
+                   meta->findData(MetaKeyTable[i].MetaKey, &data_type, &data, &size)) {
+            ALOGV("found metakey %s of type data", MetaKeyTable[i].MsgKey);
+            if (MetaKeyTable[i].KeyType == CSD) {
+                const char *mime;
+                CHECK(meta->findCString(kKeyMIMEType, &mime));
+                if (strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
+                    sp<ABuffer> buffer = new ABuffer(size);
+                    memcpy(buffer->data(), data, size);
+                    buffer->meta()->setInt32("csd", true);
+                    buffer->meta()->setInt64("timeUs", 0);
+                    format->get()->setBuffer("csd-0", buffer);
+                } else {
+                    const uint8_t *ptr = (const uint8_t *)data;
+                    CHECK(size >= 8);
+                    int seqLength = 0, picLength = 0;
+                    for (size_t i = 4; i < (size - 4); i++)
+                    {
+                        if ((*(ptr + i) == 0) && (*(ptr + i + 1) == 0) &&
+                           (*(ptr + i + 2) == 0) && (*(ptr + i + 3) == 1))
+                            seqLength = i;
+                    }
+                    sp<ABuffer> buffer = new ABuffer(seqLength);
+                    memcpy(buffer->data(), data, seqLength);
+                    buffer->meta()->setInt32("csd", true);
+                    buffer->meta()->setInt64("timeUs", 0);
+                    format->get()->setBuffer("csd-0", buffer);
+                    picLength=size-seqLength;
+                    sp<ABuffer> buffer1 = new ABuffer(picLength);
+                    memcpy(buffer1->data(), (const uint8_t *)data + seqLength, picLength);
+                    buffer1->meta()->setInt32("csd", true);
+                    buffer1->meta()->setInt64("timeUs", 0);
+                    format->get()->setBuffer("csd-1", buffer1);
+                }
+            } else {
+                sp<ABuffer> buffer = new ABuffer(size);
+                memcpy(buffer->data(), data, size);
+                format->get()->setBuffer(MetaKeyTable[i].MsgKey, buffer);
+            }
+        }
+    }
+}
+
+void FFMPEGSoftCodec::convertMessageToMetaDataFF(
+        const sp<AMessage> &msg, sp<MetaData> &meta) {
+    AString str_val;
+    int32_t int32_val;
+    int64_t int64_val;
+    static const size_t numMetaKeys =
+                     sizeof(MetaKeyTable) / sizeof(MetaKeyTable[0]);
+    size_t i;
+    for (i = 0; i < numMetaKeys; ++i) {
+        if (MetaKeyTable[i].KeyType == INT32 &&
+                msg->findInt32(MetaKeyTable[i].MsgKey, &int32_val)) {
+            ALOGV("found metakey %s of type int32", MetaKeyTable[i].MsgKey);
+            meta->setInt32(MetaKeyTable[i].MetaKey, int32_val);
+        } else if (MetaKeyTable[i].KeyType == INT64 &&
+                msg->findInt64(MetaKeyTable[i].MsgKey, &int64_val)) {
+            ALOGV("found metakey %s of type int64", MetaKeyTable[i].MsgKey);
+            meta->setInt64(MetaKeyTable[i].MetaKey, int64_val);
+        } else if (MetaKeyTable[i].KeyType == STRING &&
+                msg->findString(MetaKeyTable[i].MsgKey, &str_val)) {
+            ALOGV("found metakey %s of type string", MetaKeyTable[i].MsgKey);
+            meta->setCString(MetaKeyTable[i].MetaKey, str_val.c_str());
+        }
+    }
+}
+
+
+template<class T>
+static void InitOMXParams(T *params) {
+    params->nSize = sizeof(T);
+    params->nVersion.s.nVersionMajor = 1;
+    params->nVersion.s.nVersionMinor = 0;
+    params->nVersion.s.nRevision = 0;
+    params->nVersion.s.nStep = 0;
+}
+
+const char* FFMPEGSoftCodec::overrideComponentName(
+        uint32_t /*quirks*/, const sp<MetaData> &meta, const char *mime, bool isEncoder) {
+    const char* componentName = NULL;
+
+    int32_t wmvVersion = 0;
+    if (!strncasecmp(mime, MEDIA_MIMETYPE_VIDEO_WMV, strlen(MEDIA_MIMETYPE_VIDEO_WMV)) &&
+            meta->findInt32(kKeyWMVVersion, &wmvVersion)) {
+        ALOGD("Found WMV version key %d", wmvVersion);
+        if (wmvVersion != 2) {
+            ALOGD("Use FFMPEG for unsupported WMV track");
+            componentName = "OMX.ffmpeg.wmv.decoder";
+        }
+    }
+
+    int32_t encodeOptions = 0;
+    if (!isEncoder && !strncasecmp(mime, MEDIA_MIMETYPE_AUDIO_WMA, strlen(MEDIA_MIMETYPE_AUDIO_WMA)) &&
+            !meta->findInt32(kKeyWMAEncodeOpt, &encodeOptions)) {
+        ALOGD("Use FFMPEG for unsupported WMA track");
+        componentName = "OMX.ffmpeg.wma.decoder";
+    }
+
+    // Google's decoder doesn't support MAIN profile
+    int32_t aacProfile = 0;
+    if (!isEncoder && !strncasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC, strlen(MEDIA_MIMETYPE_AUDIO_AAC)) &&
+            meta->findInt32(kKeyAACAOT, &aacProfile)) {
+        if ((aacProfile == OMX_AUDIO_AACObjectMain) || (aacProfile == OMX_AUDIO_AACObjectLTP)) {
+            ALOGD("Use FFMPEG for AAC Main/LTP profile");
+            componentName = "OMX.ffmpeg.aac.decoder";
+        }
+    }
+
+    // Use FFMPEG for high-res formats which other decoders can't handle
+    AudioEncoding encoding = kAudioEncodingPcm16bit;
+    if (!isEncoder && meta->findInt32(kKeyPcmEncoding, (int32_t*)&encoding)) {
+        if (audioEncodingToBits(encoding) > 16) {
+            if (!strncasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC, strlen(MEDIA_MIMETYPE_AUDIO_AAC))) {
+                componentName = "OMX.ffmpeg.aac.decoder";
+                ALOGD("Use FFMPEG for high-res AAC format");
+            } else if (!strncasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC, strlen(MEDIA_MIMETYPE_AUDIO_FLAC))) {
+                componentName = "OMX.ffmpeg.flac.decoder";
+                ALOGD("Use FFMPEG for high-res FLAC format");
+            }
+        }
+    }
+
+    return componentName;
+}
+
+void FFMPEGSoftCodec::overrideComponentName(
+        uint32_t quirks, const sp<AMessage> &msg, AString* componentName, AString* mime, int32_t isEncoder) {
+
+    sp<MetaData> meta = new MetaData;
+    convertMessageToMetaData(msg, meta);
+    const char *updated = overrideComponentName(
+                quirks, meta, mime->c_str(), isEncoder);
+    if (updated != NULL) {
+        componentName->setTo(updated);
+    }
+}
+
+status_t FFMPEGSoftCodec::setVideoFormat(
+        status_t status,
+        const sp<AMessage> &msg, const char* mime, sp<IOMX> OMXhandle,
+        sp<IOMXNode> node, bool isEncoder,
+        OMX_VIDEO_CODINGTYPE *compressionFormat,
+        const char* componentName) {
+    status_t err = OK;
+
+    //ALOGD("setVideoFormat: %s", msg->debugString(0).c_str());
+
+    /* status passed in is the result of the normal codec lookup */
+    if (status != OK) {
+
+        if (isEncoder) {
+            ALOGE("Encoding not supported");
+            err = BAD_VALUE;
+
+        } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_WMV, mime)) {
+            if (strncmp(componentName, "OMX.ffmpeg.", 11) == 0) {
+                err = setWMVFormat(msg, OMXhandle, node);
+                if (err != OK) {
+                    ALOGE("setWMVFormat() failed (err = %d)", err);
+                }
+            }
+            *compressionFormat = OMX_VIDEO_CodingWMV;
+        } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_RV, mime)) {
+            err = setRVFormat(msg, OMXhandle, node);
+            if (err != OK) {
+                ALOGE("setRVFormat() failed (err = %d)", err);
+            } else {
+                *compressionFormat = OMX_VIDEO_CodingRV;
+            }
+        } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_VC1, mime)) {
+            *compressionFormat = (OMX_VIDEO_CODINGTYPE)OMX_VIDEO_CodingVC1;
+        } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_FLV1, mime)) {
+            *compressionFormat = (OMX_VIDEO_CODINGTYPE)OMX_VIDEO_CodingFLV1;
+        } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX, mime)) {
+            *compressionFormat = (OMX_VIDEO_CODINGTYPE)OMX_VIDEO_CodingDIVX;
+#ifdef QCOM_HARDWARE
+        // compressionFormat will be override later
+        } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX4, mime)) {
+            *compressionFormat = (OMX_VIDEO_CODINGTYPE)OMX_VIDEO_CodingDIVX;
+        } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX311, mime)) {
+            *compressionFormat = (OMX_VIDEO_CODINGTYPE)OMX_VIDEO_CodingDIVX;
+#endif
+        } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) {
+            *compressionFormat = (OMX_VIDEO_CODINGTYPE)OMX_VIDEO_CodingHEVC;
+        } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_FFMPEG, mime)) {
+            ALOGV("Setting the OMX_VIDEO_PARAM_FFMPEGTYPE params");
+            err = setFFmpegVideoFormat(msg, OMXhandle, node);
+            if (err != OK) {
+                ALOGE("setFFmpegVideoFormat() failed (err = %d)", err);
+            } else {
+                *compressionFormat = OMX_VIDEO_CodingAutoDetect;
+            }
+        } else {
+            err = BAD_TYPE;
+        }
+    }
+
+#ifdef QCOM_HARDWARE
+    // We need to do a few extra steps if FFMPEGExtractor is in control
+    // and we want to talk to the hardware codecs. This logic is taken
+    // from the CAF L release. It was unfortunately moved to a proprietary
+    // blob and an architecture which is hellish for OEMs who wish to
+    // customize the platform.
+    if (err == OK && (!strncmp(componentName, "OMX.qcom.", 9)
+        || !strncmp(componentName, "OMX.ittiam.", 11))) {
+        status_t xerr = OK;
+
+
+        int32_t mode = 0;
+        OMX_QCOM_PARAM_PORTDEFINITIONTYPE portFmt;
+        InitOMXParams(&portFmt);
+        portFmt.nPortIndex = kPortIndexInput;
+
+        if (msg->findInt32("use-arbitrary-mode", &mode) && mode) {
+            ALOGI("Decoder will be in arbitrary mode");
+            portFmt.nFramePackingFormat = OMX_QCOM_FramePacking_Arbitrary;
+        } else {
+            ALOGI("Decoder will be in frame by frame mode");
+            portFmt.nFramePackingFormat = OMX_QCOM_FramePacking_OnlyOneCompleteFrame;
+        }
+        xerr = node->setParameter(
+                (OMX_INDEXTYPE)OMX_QcomIndexPortDefn,
+                (void *)&portFmt, sizeof(portFmt));
+        if (xerr != OK) {
+            ALOGW("Failed to set frame packing format on component");
+        }
+
+        if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX, mime) ||
+                !strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX4, mime) ||
+                !strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX311, mime)) {
+            // Override with QCOM specific compressionFormat
+            *compressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx;
+            setQCDIVXFormat(msg, mime, OMXhandle, node, kPortIndexOutput);
+        }
+
+        // Enable timestamp reordering for mpeg4 and vc1 codec types, the AVI file
+        // type, and hevc content in the ts container
+        AString container;
+        const char * containerStr = NULL;
+        if (msg->findString("file-format", &container)) {
+            containerStr = container.c_str();
+        }
+
+        bool tsReorder = false;
+        const char* roleVC1 = "OMX.qcom.video.decoder.vc1";
+        const char* roleMPEG4 = "OMX.qcom.video.decoder.mpeg4";
+        const char* roleHEVC = "OMX.qcom.video.decoder.hevc";
+        if (!strncmp(componentName, roleVC1, strlen(roleVC1)) ||
+                !strncmp(componentName, roleMPEG4, strlen(roleMPEG4))) {
+            // The codec requires timestamp reordering
+            tsReorder = true;
+        } else if (containerStr != NULL) {
+            if (!strncmp(containerStr, MEDIA_MIMETYPE_CONTAINER_AVI,
+                    strlen(MEDIA_MIMETYPE_CONTAINER_AVI))) {
+                tsReorder = true;
+            } else if (!strncmp(containerStr, MEDIA_MIMETYPE_CONTAINER_MPEG2TS,
+                        strlen(MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) ||
+                       !strncmp(componentName, roleHEVC, strlen(roleHEVC))) {
+                tsReorder = true;
+            }
+        }
+
+        if (tsReorder) {
+            ALOGI("Enabling timestamp reordering");
+            QOMX_INDEXTIMESTAMPREORDER reorder;
+            InitOMXParams(&reorder);
+            reorder.nPortIndex = kPortIndexOutput;
+            reorder.bEnable = OMX_TRUE;
+            xerr = node->setParameter(
+                           (OMX_INDEXTYPE)OMX_QcomIndexParamEnableTimeStampReorder,
+                           (void *)&reorder, sizeof(reorder));
+
+            if (xerr != OK) {
+                ALOGW("Failed to enable timestamp reordering");
+            }
+        }
+
+        // Enable Sync-frame decode mode for thumbnails
+        char board[PROPERTY_VALUE_MAX];
+        property_get("ro.board.platform", board, NULL);
+        int32_t thumbnailMode = 0;
+        if (msg->findInt32("thumbnail-mode", &thumbnailMode) &&
+                thumbnailMode > 0 &&
+                !(!strcmp(board, "msm8996") || !strcmp(board, "msm8937") ||
+                 !strcmp(board, "msm8953") || !strcmp(board, "msm8976"))) {
+            ALOGV("Enabling thumbnail mode.");
+            QOMX_ENABLETYPE enableType;
+            OMX_INDEXTYPE indexType;
+
+            status_t err = node->getExtensionIndex(
+                    OMX_QCOM_INDEX_PARAM_VIDEO_SYNCFRAMEDECODINGMODE,
+                    &indexType);
+            if (err != OK) {
+                ALOGW("Failed to get extension for SYNCFRAMEDECODINGMODE");
+            } else {
+
+                enableType.bEnable = OMX_TRUE;
+                err = node->setParameter(indexType,
+                           (void *)&enableType, sizeof(enableType));
+                if (err != OK) {
+                    ALOGW("Failed to get extension for SYNCFRAMEDECODINGMODE");
+                } else {
+                    ALOGI("Thumbnail mode enabled.");
+                }
+            }
+        }
+
+        // MediaCodec clients can request decoder extradata by setting
+        // "enable-extradata-<type>" in MediaFormat.
+        // Following <type>s are supported:
+        //    "user" => user-extradata
+        int extraDataRequested = 0;
+        if (msg->findInt32("enable-extradata-user", &extraDataRequested) &&
+                extraDataRequested == 1) {
+            ALOGI("[%s] User-extradata requested", componentName);
+            QOMX_ENABLETYPE enableType;
+            enableType.bEnable = OMX_TRUE;
+
+            xerr = node->setParameter(
+                    (OMX_INDEXTYPE)OMX_QcomIndexEnableExtnUserData,
+                    &enableType, sizeof(enableType));
+            if (xerr != OK) {
+                ALOGW("[%s] Failed to enable user-extradata", componentName);
+            }
+        }
+    }
+#endif
+    return err;
+}
+
+#ifdef QCOM_HARDWARE
+status_t FFMPEGSoftCodec::setQCDIVXFormat(
+        const sp<AMessage> &msg, const char* mime, sp<IOMX> OMXhandle,
+        sp<IOMXNode> node, int port_index) {
+    status_t err = OK;
+    ALOGV("Setting the QOMX_VIDEO_PARAM_DIVXTYPE params ");
+    QOMX_VIDEO_PARAM_DIVXTYPE paramDivX;
+    InitOMXParams(&paramDivX);
+    paramDivX.nPortIndex = port_index;
+    int32_t DivxVersion = 0;
+    if (!msg->findInt32(getMsgKey(kKeyDivXVersion), &DivxVersion)) {
+        // Cannot find the key, the caller is skipping the container
+        // and use codec directly, let determine divx version from
+        // mime type
+        DivxVersion = kTypeDivXVer_4;
+        const char *v;
+        if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX, mime) ||
+                !strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX4, mime)) {
+            DivxVersion = kTypeDivXVer_4;
+            v = "4";
+        } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX311, mime)) {
+            DivxVersion = kTypeDivXVer_3_11;
+            v = "3.11";
+        }
+        ALOGW("Divx version key missing, initializing the version to %s", v);
+    }
+    ALOGV("Divx Version Type %d", DivxVersion);
+
+    if (DivxVersion == kTypeDivXVer_4) {
+        paramDivX.eFormat = QOMX_VIDEO_DIVXFormat4;
+    } else if (DivxVersion == kTypeDivXVer_5) {
+        paramDivX.eFormat = QOMX_VIDEO_DIVXFormat5;
+    } else if (DivxVersion == kTypeDivXVer_6) {
+        paramDivX.eFormat = QOMX_VIDEO_DIVXFormat6;
+    } else if (DivxVersion == kTypeDivXVer_3_11 ) {
+        paramDivX.eFormat = QOMX_VIDEO_DIVXFormat311;
+    } else {
+        paramDivX.eFormat = QOMX_VIDEO_DIVXFormatUnused;
+    }
+    paramDivX.eProfile = (QOMX_VIDEO_DIVXPROFILETYPE)0;    //Not used for now.
+
+    err =  node->setParameter(
+            (OMX_INDEXTYPE)OMX_QcomIndexParamVideoDivx,
+            &paramDivX, sizeof(paramDivX));
+    return err;
+}
+#endif
+
+status_t FFMPEGSoftCodec::getVideoPortFormat(OMX_U32 portIndex, int coding,
+        sp<AMessage> &notify, sp<IOMX> /* OMXHandle */, sp<IOMXNode> node) {
+
+    status_t err = BAD_TYPE;
+    switch (coding) {
+        case OMX_VIDEO_CodingWMV:
+        {
+            OMX_VIDEO_PARAM_WMVTYPE params;
+            InitOMXParams(&params);
+            params.nPortIndex = portIndex;
+
+            err = node->getParameter(
+                    OMX_IndexParamVideoWmv, &params, sizeof(params));
+            if (err != OK) {
+                return err;
+            }
+
+            int32_t version;
+            if (params.eFormat == OMX_VIDEO_WMVFormat7) {
+                version = kTypeWMVVer_7;
+            } else if (params.eFormat == OMX_VIDEO_WMVFormat8) {
+                version = kTypeWMVVer_8;
+            } else {
+                version = kTypeWMVVer_9;
+            }
+            notify->setString("mime", MEDIA_MIMETYPE_VIDEO_WMV);
+            notify->setInt32("wmv-version", version);
+            break;
+        }
+        case OMX_VIDEO_CodingAutoDetect:
+        {
+            OMX_VIDEO_PARAM_FFMPEGTYPE params;
+            InitOMXParams(&params);
+            params.nPortIndex = portIndex;
+
+            err = node->getParameter(
+                    (OMX_INDEXTYPE)OMX_IndexParamVideoFFmpeg, &params, sizeof(params));
+            if (err != OK) {
+                return err;
+            }
+
+            notify->setString("mime", MEDIA_MIMETYPE_VIDEO_FFMPEG);
+            notify->setInt32("codec-id", params.eCodecId);
+            break;
+        }
+        case OMX_VIDEO_CodingRV:
+        {
+            OMX_VIDEO_PARAM_RVTYPE params;
+            InitOMXParams(&params);
+            params.nPortIndex = portIndex;
+
+            err = node->getParameter(
+                    (OMX_INDEXTYPE)OMX_IndexParamVideoRv, &params, sizeof(params));
+            if (err != OK) {
+                return err;
+            }
+
+            int32_t version;
+            if (params.eFormat == OMX_VIDEO_RVFormatG2) {
+                version = kTypeRVVer_G2;
+            } else if (params.eFormat == OMX_VIDEO_RVFormat8) {
+                version = kTypeRVVer_8;
+            } else {
+                version = kTypeRVVer_9;
+            }
+            notify->setString("mime", MEDIA_MIMETYPE_VIDEO_RV);
+            break;
+        }
+    }
+    return err;
+}
+
+status_t FFMPEGSoftCodec::getAudioPortFormat(OMX_U32 portIndex, int coding,
+        sp<AMessage> &notify, sp<IOMX> /* OMXHandle */, sp<IOMXNode> node) {
+
+    status_t err = BAD_TYPE;
+    switch (coding) {
+        case OMX_AUDIO_CodingRA:
+        {
+            OMX_AUDIO_PARAM_RATYPE params;
+            InitOMXParams(&params);
+            params.nPortIndex = portIndex;
+
+            err = node->getParameter(
+                    OMX_IndexParamAudioRa, &params, sizeof(params));
+            if (err != OK) {
+                return err;
+            }
+
+            notify->setString("mime", MEDIA_MIMETYPE_AUDIO_RA);
+            notify->setInt32("channel-count", params.nChannels);
+            notify->setInt32("sample-rate", params.nSamplingRate);
+            break;
+        }
+        case OMX_AUDIO_CodingMP2:
+        {
+            OMX_AUDIO_PARAM_MP2TYPE params;
+            InitOMXParams(&params);
+            params.nPortIndex = portIndex;
+
+            err = node->getParameter(
+                    (OMX_INDEXTYPE)OMX_IndexParamAudioMp2, &params, sizeof(params));
+            if (err != OK) {
+                return err;
+            }
+
+            notify->setString("mime", MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
+            notify->setInt32("channel-count", params.nChannels);
+            notify->setInt32("sample-rate", params.nSampleRate);
+            break;
+        }
+        case OMX_AUDIO_CodingWMA:
+        {
+            OMX_AUDIO_PARAM_WMATYPE params;
+            InitOMXParams(&params);
+            params.nPortIndex = portIndex;
+
+            err = node->getParameter(
+                    OMX_IndexParamAudioWma, &params, sizeof(params));
+            if (err != OK) {
+                return err;
+            }
+
+            notify->setString("mime", MEDIA_MIMETYPE_AUDIO_WMA);
+            notify->setInt32("channel-count", params.nChannels);
+            notify->setInt32("sample-rate", params.nSamplingRate);
+            break;
+        }
+        case OMX_AUDIO_CodingAPE:
+        {
+            OMX_AUDIO_PARAM_APETYPE params;
+            InitOMXParams(&params);
+            params.nPortIndex = portIndex;
+
+            err = node->getParameter(
+                    (OMX_INDEXTYPE)OMX_IndexParamAudioApe, &params, sizeof(params));
+            if (err != OK) {
+                return err;
+            }
+
+            notify->setString("mime", MEDIA_MIMETYPE_AUDIO_APE);
+            notify->setInt32("channel-count", params.nChannels);
+            notify->setInt32("sample-rate", params.nSamplingRate);
+            notify->setInt32("pcm-encoding",
+                    bitsToAudioEncoding(params.nBitsPerSample));
+            break;
+        }
+        case OMX_AUDIO_CodingFLAC:
+        {
+            OMX_AUDIO_PARAM_FLACTYPE params;
+            InitOMXParams(&params);
+            params.nPortIndex = portIndex;
+
+            err = node->getParameter(
+                    (OMX_INDEXTYPE)OMX_IndexParamAudioFlac, &params, sizeof(params));
+            if (err != OK) {
+                return err;
+            }
+
+            notify->setString("mime", MEDIA_MIMETYPE_AUDIO_FLAC);
+            notify->setInt32("channel-count", params.nChannels);
+            notify->setInt32("sample-rate", params.nSampleRate);
+            notify->setInt32("pcm-encoding",
+                    bitsToAudioEncoding(params.nCompressionLevel)); // piggyback
+            break;
+        }
+
+        case OMX_AUDIO_CodingDTS:
+        {
+            OMX_AUDIO_PARAM_DTSTYPE params;
+            InitOMXParams(&params);
+            params.nPortIndex = portIndex;
+
+            err = node->getParameter(
+                    (OMX_INDEXTYPE)OMX_IndexParamAudioDts, &params, sizeof(params));
+            if (err != OK) {
+                return err;
+            }
+
+            notify->setString("mime", MEDIA_MIMETYPE_AUDIO_DTS);
+            notify->setInt32("channel-count", params.nChannels);
+            notify->setInt32("sample-rate", params.nSamplingRate);
+            break;
+        }
+        case OMX_AUDIO_CodingAC3:
+        {
+            OMX_AUDIO_PARAM_ANDROID_AC3TYPE params;
+            InitOMXParams(&params);
+            params.nPortIndex = portIndex;
+
+            err = node->getParameter(
+                    (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3, &params, sizeof(params));
+            if (err != OK) {
+                return err;
+            }
+
+            notify->setString("mime", MEDIA_MIMETYPE_AUDIO_AC3);
+            notify->setInt32("channel-count", params.nChannels);
+            notify->setInt32("sample-rate", params.nSampleRate);
+            break;
+        }
+
+        case OMX_AUDIO_CodingAutoDetect:
+        {
+            OMX_AUDIO_PARAM_FFMPEGTYPE params;
+            InitOMXParams(&params);
+            params.nPortIndex = portIndex;
+
+            err = node->getParameter(
+                    (OMX_INDEXTYPE)OMX_IndexParamAudioFFmpeg, &params, sizeof(params));
+            if (err != OK) {
+                return err;
+            }
+
+            notify->setString("mime", MEDIA_MIMETYPE_AUDIO_FFMPEG);
+            notify->setInt32("channel-count", params.nChannels);
+            notify->setInt32("sample-rate", params.nSampleRate);
+            break;
+        }
+    }
+    return err;
+}
+
+status_t FFMPEGSoftCodec::setAudioFormat(
+        const sp<AMessage> &msg, const char* mime, sp<IOMX> OMXhandle,
+        sp<IOMXNode> node) {
+    ALOGV("setAudioFormat called");
+    status_t err = OK;
+
+    ALOGV("setAudioFormat: %s", msg->debugString(0).c_str());
+
+    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_WMA, mime))  {
+        err = setWMAFormat(msg, OMXhandle, node);
+        if (err != OK) {
+            ALOGE("setWMAFormat() failed (err = %d)", err);
+        }
+    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_VORBIS, mime))  {
+        err = setVORBISFormat(msg, OMXhandle, node);
+        if (err != OK) {
+            ALOGE("setVORBISFormat() failed (err = %d)", err);
+        }
+    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_RA, mime))  {
+        err = setRAFormat(msg, OMXhandle, node);
+        if (err != OK) {
+            ALOGE("setRAFormat() failed (err = %d)", err);
+        }
+    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_FLAC, mime))  {
+        err = setFLACFormat(msg, OMXhandle, node);
+        if (err != OK) {
+            ALOGE("setFLACFormat() failed (err = %d)", err);
+        }
+    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II, mime))  {
+        err = setMP2Format(msg, OMXhandle, node);
+        if (err != OK) {
+            ALOGE("setMP2Format() failed (err = %d)", err);
+        }
+    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AC3, mime)) {
+        err = setAC3Format(msg, OMXhandle, node);
+        if (err != OK) {
+            ALOGE("setAC3Format() failed (err = %d)", err);
+        }
+    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_APE, mime))  {
+        err = setAPEFormat(msg, OMXhandle, node);
+        if (err != OK) {
+            ALOGE("setAPEFormat() failed (err = %d)", err);
+        }
+    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_DTS, mime))  {
+        err = setDTSFormat(msg, OMXhandle, node);
+        if (err != OK) {
+            ALOGE("setDTSFormat() failed (err = %d)", err);
+        }
+    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_FFMPEG, mime))  {
+        err = setFFmpegAudioFormat(msg, OMXhandle, node);
+        if (err != OK) {
+            ALOGE("setFFmpegAudioFormat() failed (err = %d)", err);
+        }
+    }
+
+    return err;
+}
+
+//video
+status_t FFMPEGSoftCodec::setWMVFormat(
+        const sp<AMessage> &msg, sp<IOMX> /* OMXhandle */, sp<IOMXNode> node)
+{
+    int32_t version = -1;
+    OMX_VIDEO_PARAM_WMVTYPE paramWMV;
+
+    if (!msg->findInt32(getMsgKey(kKeyWMVVersion), &version)) {
+        ALOGE("WMV version not detected");
+    }
+
+    InitOMXParams(&paramWMV);
+    paramWMV.nPortIndex = kPortIndexInput;
+
+    status_t err = node->getParameter(
+            OMX_IndexParamVideoWmv, &paramWMV, sizeof(paramWMV));
+    if (err != OK) {
+        return err;
+    }
+
+    if (version == kTypeWMVVer_7) {
+        paramWMV.eFormat = OMX_VIDEO_WMVFormat7;
+    } else if (version == kTypeWMVVer_8) {
+        paramWMV.eFormat = OMX_VIDEO_WMVFormat8;
+    } else if (version == kTypeWMVVer_9) {
+        paramWMV.eFormat = OMX_VIDEO_WMVFormat9;
+    }
+
+    err = node->setParameter(
+            OMX_IndexParamVideoWmv, &paramWMV, sizeof(paramWMV));
+    return err;
+}
+
+status_t FFMPEGSoftCodec::setRVFormat(
+        const sp<AMessage> &msg, sp<IOMX> /* OMXhandle */, sp<IOMXNode> node)
+{
+    int32_t version = kTypeRVVer_G2;
+    OMX_VIDEO_PARAM_RVTYPE paramRV;
+
+    if (!msg->findInt32(getMsgKey(kKeyRVVersion), &version)) {
+        ALOGE("RV version not detected");
+    }
+
+    InitOMXParams(&paramRV);
+    paramRV.nPortIndex = kPortIndexInput;
+
+    status_t err = node->getParameter(
+            OMX_IndexParamVideoRv, &paramRV, sizeof(paramRV));
+    if (err != OK)
+        return err;
+
+    if (version == kTypeRVVer_G2) {
+        paramRV.eFormat = OMX_VIDEO_RVFormatG2;
+    } else if (version == kTypeRVVer_8) {
+        paramRV.eFormat = OMX_VIDEO_RVFormat8;
+    } else if (version == kTypeRVVer_9) {
+        paramRV.eFormat = OMX_VIDEO_RVFormat9;
+    }
+
+    err = node->setParameter(
+            OMX_IndexParamVideoRv, &paramRV, sizeof(paramRV));
+    return err;
+}
+
+status_t FFMPEGSoftCodec::setFFmpegVideoFormat(
+        const sp<AMessage> &msg, sp<IOMX> /* OMXhandle */, sp<IOMXNode> node)
+{
+    int32_t codec_id = 0;
+    int32_t width = 0;
+    int32_t height = 0;
+    OMX_VIDEO_PARAM_FFMPEGTYPE param;
+
+    ALOGD("setFFmpegVideoFormat");
+
+    if (msg->findInt32(getMsgKey(kKeyWidth), &width)) {
+        ALOGE("No video width specified");
+    }
+    if (msg->findInt32(getMsgKey(kKeyHeight), &height)) {
+        ALOGE("No video height specified");
+    }
+    if (!msg->findInt32(getMsgKey(kKeyCodecId), &codec_id)) {
+        ALOGE("No codec id sent for FFMPEG catch-all codec!");
+    }
+
+    InitOMXParams(&param);
+    param.nPortIndex = kPortIndexInput;
+
+    status_t err = node->getParameter(
+            (OMX_INDEXTYPE)OMX_IndexParamVideoFFmpeg, &param, sizeof(param));
+    if (err != OK)
+        return err;
+
+    param.eCodecId = codec_id;
+    param.nWidth   = width;
+    param.nHeight  = height;
+
+    err = node->setParameter(
+            (OMX_INDEXTYPE)OMX_IndexParamVideoFFmpeg, &param, sizeof(param));
+    return err;
+}
+
+//audio
+status_t FFMPEGSoftCodec::setRawAudioFormat(
+        const sp<AMessage> &msg, sp<IOMX> /* OMXhandle */, sp<IOMXNode> node)
+{
+    int32_t numChannels = 0;
+    int32_t sampleRate = 0;
+    AudioEncoding encoding = kAudioEncodingPcm16bit;
+
+    CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels));
+    CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate));
+    if (!msg->findInt32(getMsgKey(kKeyPcmEncoding), (int32_t*)&encoding)) {
+        ALOGD("No PCM format specified, using 16 bit");
+    }
+
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    InitOMXParams(&def);
+    def.nPortIndex = kPortIndexOutput;
+
+    status_t err = node->getParameter(
+            OMX_IndexParamPortDefinition, &def, sizeof(def));
+
+    if (err != OK) {
+        return err;
+    }
+
+    def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
+
+    err = node->setParameter(
+            OMX_IndexParamPortDefinition, &def, sizeof(def));
+
+    if (err != OK) {
+        return err;
+    }
+
+    OMX_AUDIO_PARAM_PCMMODETYPE pcmParams;
+    InitOMXParams(&pcmParams);
+    pcmParams.nPortIndex = kPortIndexOutput;
+
+    err = node->getParameter(
+            OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
+
+    if (err != OK) {
+        return err;
+    }
+
+    pcmParams.nChannels = numChannels;
+    switch (encoding) {
+        case kAudioEncodingPcm8bit:
+            pcmParams.eNumData = OMX_NumericalDataUnsigned;
+            pcmParams.nBitPerSample = 8;
+            break;
+        case kAudioEncodingPcmFloat:
+            pcmParams.eNumData = OMX_NumericalDataFloat;
+            pcmParams.nBitPerSample = 32;
+            break;
+        case kAudioEncodingPcm16bit:
+            pcmParams.eNumData = OMX_NumericalDataSigned;
+            pcmParams.nBitPerSample = 16;
+            break;
+        default:
+            return BAD_VALUE;
+	}
+    pcmParams.bInterleaved = OMX_TRUE;
+    pcmParams.nSamplingRate = sampleRate;
+    pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear;
+
+    if (ACodec::getOMXChannelMapping(numChannels, pcmParams.eChannelMapping) != OK) {
+        return OMX_ErrorNone;
+    }
+
+    err = node->setParameter(
+            OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
+    // if we could not set up raw format to non-16-bit, try with 16-bit
+    // NOTE: we will also verify this via readback, in case codec ignores these fields
+    if (err != OK && encoding != kAudioEncodingPcm16bit) {
+        pcmParams.eNumData = OMX_NumericalDataSigned;
+        pcmParams.nBitPerSample = 16;
+        err = node->setParameter(
+                OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
+    }
+    return err;
+}
+
+status_t FFMPEGSoftCodec::setWMAFormat(
+        const sp<AMessage> &msg, sp<IOMX> OMXhandle, sp<IOMXNode> node)
+{
+    int32_t version = 0;
+    int32_t numChannels = 0;
+    int32_t bitRate = 0;
+    int32_t sampleRate = 0;
+    int32_t blockAlign = 0;
+    int32_t bitsPerSample = 0;
+
+    OMX_AUDIO_PARAM_WMATYPE paramWMA;
+
+    CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels));
+    CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate));
+    CHECK(msg->findInt32(getMsgKey(kKeyBitRate), &bitRate));
+    if (!msg->findInt32(getMsgKey(kKeyBlockAlign), &blockAlign)) {
+        // we should be last on the codec list, but another sniffer may
+        // have handled it and there is no hardware codec.
+        if (!msg->findInt32(getMsgKey(kKeyWMABlockAlign), &blockAlign)) {
+            return ERROR_UNSUPPORTED;
+        }
+    }
+
+    // mm-parser may want a different bit depth
+    if (msg->findInt32(getMsgKey(kKeyWMABitspersample), &bitsPerSample)) {
+        msg->setInt32(getMsgKey(kKeyPcmEncoding), (int32_t)bitsToAudioEncoding(bitsPerSample));
+    }
+
+    ALOGV("Channels: %d, SampleRate: %d, BitRate: %d, blockAlign: %d",
+            numChannels, sampleRate, bitRate, blockAlign);
+
+    CHECK(msg->findInt32(getMsgKey(kKeyWMAVersion), &version));
+
+    status_t err = setRawAudioFormat(msg, OMXhandle, node);
+    if (err != OK)
+        return err;
+
+    InitOMXParams(&paramWMA);
+    paramWMA.nPortIndex = kPortIndexInput;
+
+    err = node->getParameter(
+            OMX_IndexParamAudioWma, &paramWMA, sizeof(paramWMA));
+    if (err != OK)
+        return err;
+
+    paramWMA.nChannels = numChannels;
+    paramWMA.nSamplingRate = sampleRate;
+    paramWMA.nBitRate = bitRate;
+    paramWMA.nBlockAlign = blockAlign;
+
+    // http://msdn.microsoft.com/en-us/library/ff819498(v=vs.85).aspx
+    if (version == kTypeWMA) {
+        paramWMA.eFormat = OMX_AUDIO_WMAFormat7;
+    } else if (version == kTypeWMAPro) {
+        paramWMA.eFormat = OMX_AUDIO_WMAFormat8;
+    } else if (version == kTypeWMALossLess) {
+        paramWMA.eFormat = OMX_AUDIO_WMAFormat9;
+    }
+
+    return node->setParameter(
+            OMX_IndexParamAudioWma, &paramWMA, sizeof(paramWMA));
+}
+
+status_t FFMPEGSoftCodec::setVORBISFormat(
+        const sp<AMessage> &msg, sp<IOMX> OMXhandle, sp<IOMXNode> node)
+{
+    int32_t numChannels = 0;
+    int32_t sampleRate = 0;
+    OMX_AUDIO_PARAM_VORBISTYPE param;
+
+    CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels));
+    CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate));
+
+    ALOGV("Channels: %d, SampleRate: %d",
+            numChannels, sampleRate);
+
+    status_t err = setRawAudioFormat(msg, OMXhandle, node);
+    if (err != OK)
+        return err;
+
+    InitOMXParams(&param);
+    param.nPortIndex = kPortIndexInput;
+
+    err = node->getParameter(
+            OMX_IndexParamAudioVorbis, &param, sizeof(param));
+    if (err != OK)
+        return err;
+
+    param.nChannels = numChannels;
+    param.nSampleRate = sampleRate;
+
+    return node->setParameter(
+            OMX_IndexParamAudioVorbis, &param, sizeof(param));
+}
+
+status_t FFMPEGSoftCodec::setRAFormat(
+        const sp<AMessage> &msg, sp<IOMX> OMXhandle, sp<IOMXNode> node)
+{
+    int32_t numChannels = 0;
+    int32_t bitRate = 0;
+    int32_t sampleRate = 0;
+    int32_t blockAlign = 0;
+    OMX_AUDIO_PARAM_RATYPE paramRA;
+
+    CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels));
+    CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate));
+    msg->findInt32(getMsgKey(kKeyBitRate), &bitRate);
+    CHECK(msg->findInt32(getMsgKey(kKeyBlockAlign), &blockAlign));
+
+    ALOGV("Channels: %d, SampleRate: %d, BitRate: %d, blockAlign: %d",
+            numChannels, sampleRate, bitRate, blockAlign);
+
+    status_t err = setRawAudioFormat(msg, OMXhandle, node);
+    if (err != OK)
+        return err;
+
+    InitOMXParams(&paramRA);
+    paramRA.nPortIndex = kPortIndexInput;
+
+    err = node->getParameter(
+            OMX_IndexParamAudioRa, &paramRA, sizeof(paramRA));
+    if (err != OK)
+        return err;
+
+    paramRA.eFormat = OMX_AUDIO_RAFormatUnused; // FIXME, cook only???
+    paramRA.nChannels = numChannels;
+    paramRA.nSamplingRate = sampleRate;
+    // FIXME, HACK!!!, I use the nNumRegions parameter pass blockAlign!!!
+    // the cook audio codec need blockAlign!
+    paramRA.nNumRegions = blockAlign;
+
+    return node->setParameter(
+            OMX_IndexParamAudioRa, &paramRA, sizeof(paramRA));
+}
+
+status_t FFMPEGSoftCodec::setFLACFormat(
+        const sp<AMessage> &msg, sp<IOMX> OMXhandle, sp<IOMXNode> node)
+{
+    int32_t numChannels = 0;
+    int32_t sampleRate = 0;
+    AudioEncoding encoding = kAudioEncodingPcm16bit;
+    OMX_AUDIO_PARAM_FLACTYPE param;
+
+    CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels));
+    CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate));
+    msg->findInt32(getMsgKey(kKeyPcmEncoding), (int32_t*)&encoding);
+
+    ALOGV("Channels: %d, SampleRate: %d Encoding: %d",
+            numChannels, sampleRate, encoding);
+
+    status_t err = setRawAudioFormat(msg, OMXhandle, node);
+    if (err != OK)
+        return err;
+
+    InitOMXParams(&param);
+    param.nPortIndex = kPortIndexInput;
+
+    err = node->getParameter(
+            OMX_IndexParamAudioFlac, &param, sizeof(param));
+    if (err != OK)
+        return err;
+
+    param.nChannels = numChannels;
+    param.nSampleRate = sampleRate;
+    param.nCompressionLevel = encoding; // piggyback hax!
+
+    return node->setParameter(
+            OMX_IndexParamAudioFlac, &param, sizeof(param));
+}
+
+status_t FFMPEGSoftCodec::setMP2Format(
+        const sp<AMessage> &msg, sp<IOMX> OMXhandle, sp<IOMXNode> node)
+{
+    int32_t numChannels = 0;
+    int32_t sampleRate = 0;
+    OMX_AUDIO_PARAM_MP2TYPE param;
+
+    CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels));
+    CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate));
+
+    ALOGV("Channels: %d, SampleRate: %d",
+            numChannels, sampleRate);
+
+    status_t err = setRawAudioFormat(msg, OMXhandle, node);
+    if (err != OK)
+        return err;
+
+    InitOMXParams(&param);
+    param.nPortIndex = kPortIndexInput;
+
+    err = node->getParameter(
+            (OMX_INDEXTYPE)OMX_IndexParamAudioMp2, &param, sizeof(param));
+    if (err != OK)
+        return err;
+
+    param.nChannels = numChannels;
+    param.nSampleRate = sampleRate;
+
+    return node->setParameter(
+            (OMX_INDEXTYPE)OMX_IndexParamAudioMp2, &param, sizeof(param));
+}
+
+status_t FFMPEGSoftCodec::setAC3Format(
+        const sp<AMessage> &msg, sp<IOMX> OMXhandle, sp<IOMXNode> node)
+{
+    int32_t numChannels = 0;
+    int32_t sampleRate = 0;
+    OMX_AUDIO_PARAM_ANDROID_AC3TYPE param;
+
+    CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels));
+    CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate));
+
+    ALOGV("Channels: %d, SampleRate: %d",
+            numChannels, sampleRate);
+
+    status_t err = setRawAudioFormat(msg, OMXhandle, node);
+    if (err != OK)
+        return err;
+
+    InitOMXParams(&param);
+    param.nPortIndex = kPortIndexInput;
+
+    err = node->getParameter(
+            (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3, &param, sizeof(param));
+    if (err != OK)
+        return err;
+
+    param.nChannels = numChannels;
+    param.nSampleRate = sampleRate;
+
+    return node->setParameter(
+            (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3, &param, sizeof(param));
+}
+
+status_t FFMPEGSoftCodec::setAPEFormat(
+        const sp<AMessage> &msg, sp<IOMX> OMXhandle, sp<IOMXNode> node)
+{
+    int32_t numChannels = 0;
+    int32_t sampleRate = 0;
+    AudioEncoding encoding = kAudioEncodingPcm16bit;
+    OMX_AUDIO_PARAM_APETYPE param;
+
+    CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels));
+    CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate));
+    CHECK(msg->findInt32(getMsgKey(kKeyPcmEncoding), (int32_t*)&encoding));
+
+    ALOGV("Channels:%d, SampleRate:%d, Encoding:%d",
+            numChannels, sampleRate, encoding);
+
+    status_t err = setRawAudioFormat(msg, OMXhandle, node);
+    if (err != OK)
+        return err;
+
+    InitOMXParams(&param);
+    param.nPortIndex = kPortIndexInput;
+
+    err = node->getParameter(
+            (OMX_INDEXTYPE)OMX_IndexParamAudioApe, &param, sizeof(param));
+    if (err != OK)
+        return err;
+
+    param.nChannels = numChannels;
+    param.nSamplingRate = sampleRate;
+    param.nBitsPerSample = audioEncodingToBits(encoding);
+
+    return node->setParameter(
+            (OMX_INDEXTYPE)OMX_IndexParamAudioApe, &param, sizeof(param));
+}
+
+status_t FFMPEGSoftCodec::setDTSFormat(
+        const sp<AMessage> &msg, sp<IOMX> OMXhandle, sp<IOMXNode> node)
+{
+    int32_t numChannels = 0;
+    int32_t sampleRate = 0;
+    OMX_AUDIO_PARAM_DTSTYPE param;
+
+    CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels));
+    CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate));
+
+    ALOGV("Channels: %d, SampleRate: %d",
+            numChannels, sampleRate);
+
+    status_t err = setRawAudioFormat(msg, OMXhandle, node);
+    if (err != OK)
+        return err;
+
+    InitOMXParams(&param);
+    param.nPortIndex = kPortIndexInput;
+
+    err = node->getParameter(
+            (OMX_INDEXTYPE)OMX_IndexParamAudioDts, &param, sizeof(param));
+    if (err != OK)
+        return err;
+
+    param.nChannels = numChannels;
+    param.nSamplingRate = sampleRate;
+
+    return node->setParameter(
+            (OMX_INDEXTYPE)OMX_IndexParamAudioDts, &param, sizeof(param));
+}
+
+status_t FFMPEGSoftCodec::setFFmpegAudioFormat(
+        const sp<AMessage> &msg, sp<IOMX> OMXhandle, sp<IOMXNode> node)
+{
+    int32_t codec_id = 0;
+    int32_t numChannels = 0;
+    int32_t bitRate = 0;
+    int32_t sampleRate = 0;
+    int32_t blockAlign = 0;
+    int32_t sampleFormat = 0;
+    int32_t codedSampleBits = 0;
+	AudioEncoding encoding = kAudioEncodingPcm16bit;
+    OMX_AUDIO_PARAM_FFMPEGTYPE param;
+
+    ALOGD("setFFmpegAudioFormat");
+
+    CHECK(msg->findInt32(getMsgKey(kKeyCodecId), &codec_id));
+    CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels));
+    CHECK(msg->findInt32(getMsgKey(kKeySampleFormat), &sampleFormat));
+    msg->findInt32(getMsgKey(kKeyBitRate), &bitRate);
+    msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate);
+    msg->findInt32(getMsgKey(kKeyBlockAlign), &blockAlign);
+    msg->findInt32(getMsgKey(kKeyCodedSampleBits), &codedSampleBits);
+    msg->findInt32(getMsgKey(kKeyPcmEncoding), (int32_t*)&encoding);
+
+    status_t err = setRawAudioFormat(msg, OMXhandle, node);
+    if (err != OK)
+        return err;
+
+    InitOMXParams(&param);
+    param.nPortIndex = kPortIndexInput;
+
+    err = node->getParameter(
+            (OMX_INDEXTYPE)OMX_IndexParamAudioFFmpeg, &param, sizeof(param));
+    if (err != OK)
+        return err;
+
+    param.eCodecId       = codec_id;
+    param.nChannels      = numChannels;
+    param.nBitRate       = bitRate;
+    param.nBitsPerSample = codedSampleBits;
+    param.nSampleRate    = sampleRate;
+    param.nBlockAlign    = blockAlign;
+    param.eSampleFormat  = sampleFormat;
+
+    return node->setParameter(
+            (OMX_INDEXTYPE)OMX_IndexParamAudioFFmpeg, &param, sizeof(param));
+}
+
+void* FFMPEGSoftCodec::sLibHandle = NULL;
+
+void FFMPEGSoftCodec::loadPlugin() {
+    char lib[PROPERTY_VALUE_MAX];
+    if (!sLibHandle && property_get("media.sf.extractor-plugin", lib, NULL)) {
+        if ((sLibHandle = ::dlopen(lib, RTLD_LAZY)) != NULL) {
+            sSnifferFunc = (MediaExtractor::SnifferFunc)dlsym(sLibHandle, "SniffFFMPEG");
+            sExtractorFunc = (CreateExtractorFunc)dlsym(sLibHandle, "CreateFFMPEGExtractor");
+        }
+        if (dlerror()) {
+            sSnifferFunc = NULL;
+            sExtractorFunc = NULL;
+            dlclose(sLibHandle);
+            ALOGE("Failed to load FFMPEG plugin: %s", dlerror());
+        }
+    }
+}
+
+MediaExtractor::SnifferFunc FFMPEGSoftCodec::sSnifferFunc = NULL;
+
+MediaExtractor::SnifferFunc FFMPEGSoftCodec::getSniffer() {
+    loadPlugin();
+    return sSnifferFunc;
+}
+
+FFMPEGSoftCodec::CreateExtractorFunc FFMPEGSoftCodec::sExtractorFunc = NULL;
+
+MediaExtractor* FFMPEGSoftCodec::createExtractor(const sp<DataSource> &source,
+        const char *mime, const sp<AMessage> &meta) {
+    loadPlugin();
+    if (sLibHandle == NULL) {
+        return NULL;
+    }
+    return sExtractorFunc(source, mime, meta);
+}
+
+}
diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp
index eef5314e0..455d38484 100644
--- a/media/libstagefright/FileSource.cpp
+++ b/media/libstagefright/FileSource.cpp
@@ -32,6 +32,7 @@ namespace android {
 
 FileSource::FileSource(const char *filename)
     : mFd(-1),
+      mUri(filename),
       mOffset(0),
       mLength(-1),
       mName("<null>"),
@@ -98,6 +99,7 @@ FileSource::FileSource(int fd, int64_t offset, int64_t length)
             (long long) mOffset,
             (long long) mLength);
 
+    fetchUriFromFd(fd);
 }
 
 FileSource::~FileSource() {
@@ -237,4 +239,18 @@ bool FileSource::requiresDrm(int fd, int64_t offset, int64_t length, const char
     return requiresDrm;
 }
 
+void FileSource::fetchUriFromFd(int fd) {
+    ssize_t len = 0;
+    char path[PATH_MAX] = {0};
+    char link[PATH_MAX] = {0};
+
+    mUri.clear();
+
+    snprintf(path, PATH_MAX, "/proc/%d/fd/%d", getpid(), fd);
+    if ((len = readlink(path, link, sizeof(link)-1)) != -1) {
+        link[len] = '\0';
+        mUri.setTo(link);
+    }
+}
+
 }  // namespace android
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 353e40702..8df959002 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1944,7 +1944,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                     }
 
                     const char *owner = mCodecInfo->getOwnerName();
-                    if (mComponentName.startsWith("OMX.google.")
+                    if ((mComponentName.startsWith("OMX.google.") || mComponentName.startsWith("OMX.ffmpeg."))
                             && (owner == nullptr || strncmp(owner, "default", 8) == 0)) {
                         mFlags |= kFlagUsesSoftwareRenderer;
                     } else {
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index e010b3e75..6f19c2932 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -41,7 +41,11 @@ static bool FileHasAcceptableExtension(const char *extension) {
         ".wav", ".amr", ".midi", ".xmf", ".rtttl", ".rtx", ".ota",
         ".mkv", ".mka", ".webm", ".ts", ".fl", ".flac", ".mxmf",
         ".avi", ".mpeg", ".mpg", ".awb", ".mpga", ".mov",
-        ".m4v", ".oga"
+        ".m4v", ".oga", ".adts",
+        ".dm", ".m2ts", ".mp3d", ".wmv", ".asf", ".flv", ".ra",
+        ".rm", ".rmvb", ".ac3", ".ape", ".dts", ".mp1", ".mp2",
+        ".f4v", "hlv", "nrg", "m2v", ".swf", ".vc1", ".vob",
+        ".divx", ".qcp", ".ec3"
     };
     static const size_t kNumValidExtensions =
         sizeof(kValidExtensions) / sizeof(kValidExtensions[0]);
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index e80ec3bd7..34c28015d 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -28,6 +28,7 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/DataSourceFactory.h>
+#include <media/stagefright/FFMPEGSoftCodec.h>
 #include <media/stagefright/FileSource.h>
 #include <media/stagefright/MediaCodecList.h>
 #include <media/stagefright/MediaDefs.h>
@@ -333,7 +334,16 @@ status_t StagefrightMetadataRetriever::getFrameInternal(
             &matchingCodecs);
 
     for (size_t i = 0; i < matchingCodecs.size(); ++i) {
-        const AString &componentName = matchingCodecs[i];
+        AString componentName;
+        const char* ffmpegComponentName =
+            FFMPEGSoftCodec::overrideComponentName(0, trackMeta, mime, false);
+        if (ffmpegComponentName != NULL) {
+            ALOGV("override compoent %s to %s for video frame extraction.",
+                    matchingCodecs[i].c_str(), ffmpegComponentName);
+            componentName.setTo(ffmpegComponentName);
+        } else {
+            componentName = matchingCodecs[i];
+        }
         VideoFrameDecoder decoder(componentName, trackMeta, source);
         if (decoder.init(timeUs, numFrames, option, colorFormat) == OK) {
             if (outFrame != NULL) {
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index cf5e91e61..6cfcbe582 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -45,6 +45,8 @@
 #include <media/AudioParameter.h>
 #include <system/audio.h>
 
+#include <media/stagefright/FFMPEGSoftCodec.h>
+
 namespace android {
 
 static status_t copyNALUToABuffer(sp<ABuffer> *buffer, const uint8_t *ptr, size_t length) {
@@ -1094,8 +1096,15 @@ status_t convertMetaDataToMessage(
         memcpy(buffer->data(), data, size);
     }
 
+    FFMPEGSoftCodec::convertMetaDataToMessageFF(meta, &msg);
     *format = msg;
 
+#if 0
+    ALOGI("convertMetaDataToMessage from:");
+    meta->dumpToLog();
+    ALOGI("  to: %s", msg->debugString(0).c_str());
+#endif
+
     return OK;
 }
 
@@ -1506,8 +1515,10 @@ void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) {
 
     // XXX TODO add whatever other keys there are
 
+    FFMPEGSoftCodec::convertMessageToMetaDataFF(msg, meta);
+
 #if 0
-    ALOGI("converted %s to:", msg->debugString(0).c_str());
+    ALOGI("convertMessageToMetaData from %s to:", msg->debugString(0).c_str());
     meta->dumpToLog();
 #endif
 }
diff --git a/media/libstagefright/foundation/MediaDefs.cpp b/media/libstagefright/foundation/MediaDefs.cpp
index 1695c75bd..38671eba2 100644
--- a/media/libstagefright/foundation/MediaDefs.cpp
+++ b/media/libstagefright/foundation/MediaDefs.cpp
@@ -68,4 +68,41 @@ const char *MEDIA_MIMETYPE_TEXT_CEA_608 = "text/cea-608";
 const char *MEDIA_MIMETYPE_TEXT_CEA_708 = "text/cea-708";
 const char *MEDIA_MIMETYPE_DATA_TIMED_ID3 = "application/x-id3v4";
 
+const char *MEDIA_MIMETYPE_VIDEO_DIVX = "video/divx";
+const char *MEDIA_MIMETYPE_VIDEO_DIVX311 = "video/divx311";
+const char *MEDIA_MIMETYPE_VIDEO_DIVX4 = "video/divx4";
+const char *MEDIA_MIMETYPE_VIDEO_FLV1 = "video/x-flv";
+const char *MEDIA_MIMETYPE_VIDEO_MJPEG = "video/x-jpeg";
+const char *MEDIA_MIMETYPE_VIDEO_RV = "video/vnd.rn-realvideo";
+const char *MEDIA_MIMETYPE_VIDEO_VC1 = "video/vc1";
+const char *MEDIA_MIMETYPE_VIDEO_WMV = "video/x-ms-wmv";
+const char *MEDIA_MIMETYPE_VIDEO_FFMPEG = "video/ffmpeg";
+
+const char *MEDIA_MIMETYPE_AUDIO_ALAC = "audio/alac";
+const char *MEDIA_MIMETYPE_AUDIO_APE = "audio/x-ape";
+const char *MEDIA_MIMETYPE_AUDIO_DTS = "audio/dts";
+const char *MEDIA_MIMETYPE_AUDIO_PCM = "audio/x-pcm";
+const char *MEDIA_MIMETYPE_AUDIO_RA = "audio/vnd.rn-realaudio";
+const char *MEDIA_MIMETYPE_AUDIO_WMA = "audio/x-ms-wma";
+const char *MEDIA_MIMETYPE_AUDIO_FFMPEG = "audio/ffmpeg";
+
+const char *MEDIA_MIMETYPE_CONTAINER_APE = "audio/x-ape";
+const char *MEDIA_MIMETYPE_CONTAINER_ASF = "video/x-ms-asf";
+const char *MEDIA_MIMETYPE_CONTAINER_DIVX = "video/divx";
+const char *MEDIA_MIMETYPE_CONTAINER_DTS = "audio/vnd.dts";
+const char *MEDIA_MIMETYPE_CONTAINER_FLAC = "audio/flac";
+const char *MEDIA_MIMETYPE_CONTAINER_FLV = "video/x-flv";
+const char *MEDIA_MIMETYPE_CONTAINER_MOV = "video/quicktime";
+const char *MEDIA_MIMETYPE_CONTAINER_MP2 = "audio/mpeg2";
+const char *MEDIA_MIMETYPE_CONTAINER_MPG = "video/mpeg";
+const char *MEDIA_MIMETYPE_CONTAINER_RA = "audio/vnd.rn-realaudio";
+const char *MEDIA_MIMETYPE_CONTAINER_RM = "video/vnd.rn-realvideo";
+const char *MEDIA_MIMETYPE_CONTAINER_TS = "video/mp2t";
+const char *MEDIA_MIMETYPE_CONTAINER_WEBM = "video/webm";
+const char *MEDIA_MIMETYPE_CONTAINER_WMA = "audio/x-ms-wma";
+const char *MEDIA_MIMETYPE_CONTAINER_WMV = "video/x-ms-wmv";
+const char *MEDIA_MIMETYPE_CONTAINER_VC1 = "video/vc1";
+const char *MEDIA_MIMETYPE_CONTAINER_HEVC = "video/hevc";
+const char *MEDIA_MIMETYPE_CONTAINER_FFMPEG = "video/ffmpeg";
+
 }  // namespace android
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
index 25be89f4c..7a8d97232 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
@@ -18,6 +18,8 @@
 
 #define MEDIA_DEFS_H_
 
+#include <stdint.h>
+
 namespace android {
 
 extern const char *MEDIA_MIMETYPE_IMAGE_JPEG;
@@ -70,15 +72,84 @@ extern const char *MEDIA_MIMETYPE_TEXT_CEA_608;
 extern const char *MEDIA_MIMETYPE_TEXT_CEA_708;
 extern const char *MEDIA_MIMETYPE_DATA_TIMED_ID3;
 
+extern const char *MEDIA_MIMETYPE_AUDIO_EAC3_JOC;
+extern const char *MEDIA_MIMETYPE_AUDIO_EAC3;
+
+extern const char *MEDIA_MIMETYPE_VIDEO_DIVX;
+extern const char *MEDIA_MIMETYPE_VIDEO_DIVX311;
+extern const char *MEDIA_MIMETYPE_VIDEO_DIVX4;
+extern const char *MEDIA_MIMETYPE_VIDEO_FLV1;
+extern const char *MEDIA_MIMETYPE_VIDEO_MJPEG;
+extern const char *MEDIA_MIMETYPE_VIDEO_RV;
+extern const char *MEDIA_MIMETYPE_VIDEO_VC1;
+extern const char *MEDIA_MIMETYPE_VIDEO_WMV;
+extern const char *MEDIA_MIMETYPE_VIDEO_HEVC;
+extern const char *MEDIA_MIMETYPE_VIDEO_FFMPEG;
+
+extern const char *MEDIA_MIMETYPE_AUDIO_AC3;
+extern const char *MEDIA_MIMETYPE_AUDIO_ALAC;
+extern const char *MEDIA_MIMETYPE_AUDIO_APE;
+extern const char *MEDIA_MIMETYPE_AUDIO_DTS;
+extern const char *MEDIA_MIMETYPE_AUDIO_PCM;
+extern const char *MEDIA_MIMETYPE_AUDIO_RA;
+extern const char *MEDIA_MIMETYPE_AUDIO_WMA;
+extern const char *MEDIA_MIMETYPE_AUDIO_FFMPEG;
+
+extern const char *MEDIA_MIMETYPE_CONTAINER_APE;
+extern const char *MEDIA_MIMETYPE_CONTAINER_ASF;
+extern const char *MEDIA_MIMETYPE_CONTAINER_DIVX;
+extern const char *MEDIA_MIMETYPE_CONTAINER_DTS;
+extern const char *MEDIA_MIMETYPE_CONTAINER_FLAC;
+extern const char *MEDIA_MIMETYPE_CONTAINER_FLV;
+extern const char *MEDIA_MIMETYPE_CONTAINER_MOV;
+extern const char *MEDIA_MIMETYPE_CONTAINER_MP2;
+extern const char *MEDIA_MIMETYPE_CONTAINER_MPG;
+extern const char *MEDIA_MIMETYPE_CONTAINER_RA;
+extern const char *MEDIA_MIMETYPE_CONTAINER_RM;
+extern const char *MEDIA_MIMETYPE_CONTAINER_TS;
+extern const char *MEDIA_MIMETYPE_CONTAINER_WEBM;
+extern const char *MEDIA_MIMETYPE_CONTAINER_VC1;
+extern const char *MEDIA_MIMETYPE_CONTAINER_HEVC;
+extern const char *MEDIA_MIMETYPE_CONTAINER_WMA;
+extern const char *MEDIA_MIMETYPE_CONTAINER_WMV;
+extern const char *MEDIA_MIMETYPE_CONTAINER_FFMPEG;
+
 // These are values exported to JAVA API that need to be in sync with
 // frameworks/base/media/java/android/media/AudioFormat.java. Unfortunately,
 // they are not defined in frameworks/av, so defining them here.
 enum AudioEncoding {
+    kAudioEncodingInvalid = 0,
     kAudioEncodingPcm16bit = 2,
     kAudioEncodingPcm8bit = 3,
     kAudioEncodingPcmFloat = 4,
 };
 
+static inline AudioEncoding bitsToAudioEncoding(int32_t bits) {
+    switch (bits) {
+        case 8:
+            return kAudioEncodingPcm8bit;
+        case 16:
+            return kAudioEncodingPcm16bit;
+        case 32:
+            return kAudioEncodingPcmFloat;
+    }
+    return kAudioEncodingInvalid;
+}
+
+static inline int32_t audioEncodingToBits(AudioEncoding encoding) {
+    switch (encoding) {
+        case kAudioEncodingInvalid:
+            return 0;
+        case kAudioEncodingPcm8bit:
+            return 8;
+        case kAudioEncodingPcm16bit:
+            return 16;
+        case kAudioEncodingPcmFloat:
+            return 32;
+    }
+    return 0;
+}
+
 }  // namespace android
 
 #endif  // MEDIA_DEFS_H_
diff --git a/media/libstagefright/include/media/stagefright/ACodec.h b/media/libstagefright/include/media/stagefright/ACodec.h
index 97d15a71f..ea8d38308 100644
--- a/media/libstagefright/include/media/stagefright/ACodec.h
+++ b/media/libstagefright/include/media/stagefright/ACodec.h
@@ -34,6 +34,8 @@
 #include <android/hidl/allocator/1.0/IAllocator.h>
 #include <android/hidl/memory/1.0/IMemory.h>
 
+#include <system/audio.h>
+
 #define TRACK_BUFFER_TIMING     0
 
 namespace android {
@@ -97,6 +99,8 @@ struct ACodec : public AHierarchicalStateMachine, public CodecBase {
 
 protected:
     virtual ~ACodec();
+    virtual status_t setupCustomCodec(
+            status_t err, const char *mime, const sp<AMessage> &msg);
 
 private:
     struct BaseState;
@@ -456,9 +460,11 @@ private:
             int32_t maxOutputChannelCount, const drcParams_t& drc,
             int32_t pcmLimiterEnable);
 
-    status_t setupAC3Codec(bool encoder, int32_t numChannels, int32_t sampleRate);
+    status_t setupAC3Codec(bool encoder, int32_t numChannels, int32_t sampleRate,
+            AudioEncoding encoding = kAudioEncodingPcm16bit);
 
-    status_t setupEAC3Codec(bool encoder, int32_t numChannels, int32_t sampleRate);
+    status_t setupEAC3Codec(bool encoder, int32_t numChannels, int32_t sampleRate,
+            AudioEncoding encoding = kAudioEncodingPcm16bit);
 
     status_t selectAudioPortFormat(
             OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE desiredFormat);
diff --git a/media/libstagefright/include/media/stagefright/FFMPEGSoftCodec.h b/media/libstagefright/include/media/stagefright/FFMPEGSoftCodec.h
new file mode 100644
index 000000000..8d2e94a3c
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/FFMPEGSoftCodec.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2014 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef FFMPEG_SOFT_CODEC_H_
+#define FFMPEG_SOFT_CODEC_H_
+
+#include <media/DataSource.h>
+#include <media/IOMX.h>
+#include <media/MediaCodecInfo.h>
+#include <media/MediaExtractor.h>
+
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/AString.h>
+
+#include <media/stagefright/MetaData.h>
+
+#include <OMX_Audio.h>
+#include <OMX_Video.h>
+
+namespace android {
+
+struct FFMPEGSoftCodec {
+
+    enum {
+        kPortIndexInput  = 0,
+        kPortIndexOutput = 1
+    };
+
+    typedef MediaExtractor *(*CreateExtractorFunc)(const sp<DataSource> &source,
+            const char *mime, const sp<AMessage> &meta);
+
+    static void convertMessageToMetaDataFF(
+            const sp<AMessage> &msg, sp<MetaData> &meta);
+
+    static void convertMetaDataToMessageFF(
+        const sp<MetaData> &meta, sp<AMessage> *format);
+
+    static const char* overrideComponentName(
+            uint32_t quirks, const sp<MetaData> &meta,
+            const char *mime, bool isEncoder);
+
+    static void overrideComponentName(
+            uint32_t quirks, const sp<AMessage> &msg,
+            AString* componentName, AString* mime,
+            int32_t isEncoder);
+
+    static status_t setAudioFormat(
+            const sp<AMessage> &msg, const char* mime,
+            sp<IOMX> OMXhandle, sp<IOMXNode> node);
+
+    static status_t setVideoFormat(
+            status_t status,
+            const sp<AMessage> &msg, const char* mime,
+            sp<IOMX> OMXhandle,sp<IOMXNode> node,
+            bool isEncoder, OMX_VIDEO_CODINGTYPE *compressionFormat,
+            const char* componentName);
+
+    static status_t getAudioPortFormat(
+            OMX_U32 portIndex, int coding,
+            sp<AMessage> &notify, sp<IOMX> OMXhandle, sp<IOMXNode> node);
+
+    static status_t getVideoPortFormat(
+            OMX_U32 portIndex, int coding,
+            sp<AMessage> &notify, sp<IOMX> OMXhandle, sp<IOMXNode> node);
+
+    static MediaExtractor::SnifferFunc getSniffer();
+
+    static MediaExtractor* createExtractor(const sp<DataSource> &source,
+            const char *mime, const sp<AMessage> &meta);
+
+private:
+    static const char* getMsgKey(int key);
+
+    static status_t setWMVFormat(
+            const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+            sp<IOMXNode> node);
+
+    static status_t setRVFormat(
+            const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+            sp<IOMXNode> node);
+
+    static status_t setFFmpegVideoFormat(
+            const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+            sp<IOMXNode> node);
+
+    static status_t setRawAudioFormat(
+            const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+            sp<IOMXNode> node);
+
+    static status_t setWMAFormat(
+            const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+            sp<IOMXNode> node);
+
+    static status_t setVORBISFormat(
+            const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+            sp<IOMXNode> node);
+
+    static status_t setRAFormat(
+            const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+            sp<IOMXNode> node);
+
+    static status_t setFLACFormat(
+            const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+            sp<IOMXNode> node);
+
+    static status_t setMP2Format(
+            const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+            sp<IOMXNode> node);
+
+    static status_t setAC3Format(
+            const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+            sp<IOMXNode> node);
+
+    static status_t setAPEFormat(
+            const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+            sp<IOMXNode> node);
+
+    static status_t setDTSFormat(
+            const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+            sp<IOMXNode> node);
+
+    static status_t setFFmpegAudioFormat(
+            const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+            sp<IOMXNode> node);
+
+#ifdef QCOM_HARDWARE
+    static status_t setQCDIVXFormat(
+            const sp<AMessage> &msg, const char* mime,
+            sp<IOMX> OMXhandle, sp<IOMXNode> node, int port_index);
+#endif
+
+    static void loadPlugin();
+
+    static void* sLibHandle;
+    static MediaExtractor::SnifferFunc sSnifferFunc;
+    static CreateExtractorFunc sExtractorFunc;
+};
+
+}
+#endif
diff --git a/media/libstagefright/include/media/stagefright/FileSource.h b/media/libstagefright/include/media/stagefright/FileSource.h
index 8604890b4..873978ec0 100644
--- a/media/libstagefright/include/media/stagefright/FileSource.h
+++ b/media/libstagefright/include/media/stagefright/FileSource.h
@@ -51,11 +51,16 @@ public:
 
     static bool requiresDrm(int fd, int64_t offset, int64_t length, const char *mime);
 
+    virtual String8 getUri() {
+        return mUri;
+    }
+
 protected:
     virtual ~FileSource();
 
 private:
     int mFd;
+    String8 mUri;
     int64_t mOffset;
     int64_t mLength;
     Mutex mLock;
@@ -69,6 +74,7 @@ private:
     unsigned char *mDrmBuf;
 
     ssize_t readAtDRM(off64_t offset, void *data, size_t size);
+    void fetchUriFromFd(int fd);
 
     FileSource(const FileSource &);
     FileSource &operator=(const FileSource &);
diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp
index 0967b5fa6..75443bdf0 100644
--- a/media/libstagefright/omx/OMXMaster.cpp
+++ b/media/libstagefright/omx/OMXMaster.cpp
@@ -53,6 +53,7 @@ OMXMaster::OMXMaster()
 
     addVendorPlugin();
     addPlugin(new SoftOMXPlugin);
+    addPlugin("libffmpeg_omx.so");
 }
 
 OMXMaster::~OMXMaster() {
diff --git a/media/libstagefright/omx/OMXUtils.cpp b/media/libstagefright/omx/OMXUtils.cpp
index f7b569dff..4adf5a44b 100644
--- a/media/libstagefright/omx/OMXUtils.cpp
+++ b/media/libstagefright/omx/OMXUtils.cpp
@@ -165,6 +165,50 @@ const char *GetComponentRole(bool isEncoder, const char *mime) {
             "audio_decoder.eac3", "audio_encoder.eac3" },
         { MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC,
             "image_decoder.heic", "image_encoder.heic" },
+
+        // FFMPEG extensions
+        { MEDIA_MIMETYPE_AUDIO_AAC,
+            "audio_decoder.aac", NULL },
+        { MEDIA_MIMETYPE_AUDIO_MPEG,
+            "audio_decoder.mp3", NULL },
+        { MEDIA_MIMETYPE_AUDIO_VORBIS,
+            "audio_decoder.vorbis", NULL },
+        { MEDIA_MIMETYPE_AUDIO_WMA,
+            "audio_decoder.wma", NULL },
+        { MEDIA_MIMETYPE_AUDIO_RA,
+            "audio_decoder.ra" , NULL },
+        { MEDIA_MIMETYPE_AUDIO_FLAC,
+            "audio_decoder.flac", NULL },
+        { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II,
+            "audio_decoder.mp2", NULL },
+        { MEDIA_MIMETYPE_AUDIO_AC3,
+            "audio_decoder.ac3", NULL },
+        { MEDIA_MIMETYPE_AUDIO_APE,
+            "audio_decoder.ape", NULL },
+        { MEDIA_MIMETYPE_AUDIO_DTS,
+            "audio_decoder.dts", NULL },
+        { MEDIA_MIMETYPE_VIDEO_MPEG2,
+            "video_decoder.mpeg2", NULL },
+        { MEDIA_MIMETYPE_VIDEO_DIVX,
+            "video_decoder.divx", NULL },
+        { MEDIA_MIMETYPE_VIDEO_DIVX4,
+            "video_decoder.divx", NULL },
+        { MEDIA_MIMETYPE_VIDEO_DIVX311,
+            "video_decoder.divx", NULL },
+        { MEDIA_MIMETYPE_VIDEO_WMV,
+            "video_decoder.vc1",  NULL }, // so we can still talk to hardware codec
+        { MEDIA_MIMETYPE_VIDEO_VC1,
+            "video_decoder.vc1", NULL },
+        { MEDIA_MIMETYPE_VIDEO_RV,
+            "video_decoder.rv", NULL },
+        { MEDIA_MIMETYPE_VIDEO_FLV1,
+            "video_decoder.flv1", NULL },
+        { MEDIA_MIMETYPE_VIDEO_HEVC,
+            "video_decoder.hevc", NULL },
+        { MEDIA_MIMETYPE_AUDIO_FFMPEG,
+            "audio_decoder.trial", NULL },
+        { MEDIA_MIMETYPE_VIDEO_FFMPEG,
+            "video_decoder.trial", NULL },
     };
 
     static const size_t kNumMimeToRole =
diff --git a/services/mediaextractor/Android.mk b/services/mediaextractor/Android.mk
index 7c6527f13..f6642a0d7 100644
--- a/services/mediaextractor/Android.mk
+++ b/services/mediaextractor/Android.mk
@@ -34,7 +34,7 @@ LOCAL_REQUIRED_MODULES += \
     libwavextractor \
 
 LOCAL_SRC_FILES := main_extractorservice.cpp
-LOCAL_SHARED_LIBRARIES := libmedia libmediaextractorservice libbinder libutils \
+LOCAL_SHARED_LIBRARIES := libmedia libmediaextractorservice libstagefright libbinder libutils \
     liblog libbase libicuuc libavservices_minijail
 LOCAL_STATIC_LIBRARIES := libicuandroid_utils
 LOCAL_MODULE:= mediaextractor
diff --git a/services/mediaextractor/main_extractorservice.cpp b/services/mediaextractor/main_extractorservice.cpp
index 8d3359a04..6fb6d132b 100644
--- a/services/mediaextractor/main_extractorservice.cpp
+++ b/services/mediaextractor/main_extractorservice.cpp
@@ -28,6 +28,8 @@
 #include <android-base/properties.h>
 #include <utils/misc.h>
 
+#include <media/stagefright/FFMPEGSoftCodec.h>
+
 // from LOCAL_C_INCLUDES
 #include "IcuUtils.h"
 #include "MediaExtractorService.h"
@@ -56,6 +58,7 @@ int main(int argc __unused, char** argv)
     //as pread64 are used by linker but aren't allowed in the minijail. By
     //calling the function before entering minijail, we can force dlopen.
     android::report_sysprop_change();
+    FFMPEGSoftCodec::getSniffer();
 
     SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath);
 
