Merge "Work around lack of pitch adjustment in Timestretcher"
diff --git a/include/media/AudioPolicy.h b/include/media/AudioPolicy.h
index a755e1e..800b27b 100644
--- a/include/media/AudioPolicy.h
+++ b/include/media/AudioPolicy.h
@@ -38,9 +38,15 @@
 #define MIX_TYPE_PLAYERS 0
 #define MIX_TYPE_RECORDERS 1
 
+#define MIX_STATE_DISABLED -1
+#define MIX_STATE_IDLE 0
+#define MIX_STATE_MIXING 1
+
 #define ROUTE_FLAG_RENDER 0x1
 #define ROUTE_FLAG_LOOP_BACK (0x1 << 1)
 
+#define MIX_FLAG_NOTIFY_ACTIVITY 0x1
+
 #define MAX_MIXES_PER_POLICY 10
 #define MAX_CRITERIA_PER_MIX 20
 
@@ -63,9 +69,9 @@
 public:
     AudioMix() {}
     AudioMix(Vector<AttributeMatchCriterion> criteria, uint32_t mixType, audio_config_t format,
-             uint32_t routeFlags, String8 registrationId) :
+             uint32_t routeFlags, String8 registrationId, uint32_t flags) :
         mCriteria(criteria), mMixType(mixType), mFormat(format),
-        mRouteFlags(routeFlags), mRegistrationId(registrationId) {}
+        mRouteFlags(routeFlags), mRegistrationId(registrationId), mFlags(flags){}
 
     status_t readFromParcel(Parcel *parcel);
     status_t writeToParcel(Parcel *parcel) const;
@@ -75,6 +81,7 @@
     audio_config_t  mFormat;
     uint32_t        mRouteFlags;
     String8         mRegistrationId;
+    uint32_t        mFlags;
 };
 
 }; // namespace android
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 3b6db8c..182133c 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -332,6 +332,12 @@
 
     static status_t registerPolicyMixes(Vector<AudioMix> mixes, bool registration);
 
+    static status_t startAudioSource(const struct audio_port_config *source,
+                                      const audio_attributes_t *attributes,
+                                      audio_io_handle_t *handle);
+    static status_t stopAudioSource(audio_io_handle_t handle);
+
+
     // ----------------------------------------------------------------------------
 
     class AudioPortCallback : public RefBase
@@ -384,6 +390,7 @@
         // IAudioPolicyServiceClient
         virtual void onAudioPortListUpdate();
         virtual void onAudioPatchListUpdate();
+        virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
 
     private:
         Mutex                               mLock;
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index 7506153..413267b 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -155,6 +155,11 @@
     virtual audio_mode_t getPhoneState() = 0;
 
     virtual status_t registerPolicyMixes(Vector<AudioMix> mixes, bool registration) = 0;
+
+    virtual status_t startAudioSource(const struct audio_port_config *source,
+                                      const audio_attributes_t *attributes,
+                                      audio_io_handle_t *handle) = 0;
+    virtual status_t stopAudioSource(audio_io_handle_t handle) = 0;
 };
 
 
diff --git a/include/media/IAudioPolicyServiceClient.h b/include/media/IAudioPolicyServiceClient.h
index 59df046..a7f2cc3 100644
--- a/include/media/IAudioPolicyServiceClient.h
+++ b/include/media/IAudioPolicyServiceClient.h
@@ -35,6 +35,8 @@
     virtual void onAudioPortListUpdate() = 0;
     // Notifies a change of audio patch configuration.
     virtual void onAudioPatchListUpdate() = 0;
+    // Notifies a change in the mixing state of a specific mix in a dynamic audio policy
+    virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state) = 0;
 };
 
 
diff --git a/include/media/IDataSource.h b/include/media/IDataSource.h
new file mode 100644
index 0000000..07e46f7
--- /dev/null
+++ b/include/media/IDataSource.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_IDATASOURCE_H
+#define ANDROID_IDATASOURCE_H
+
+#include <binder/IInterface.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+class IMemory;
+
+// A binder interface for implementing a stagefright DataSource remotely.
+class IDataSource : public IInterface {
+public:
+    DECLARE_META_INTERFACE(DataSource);
+
+    // Get the memory that readAt writes into.
+    virtual sp<IMemory> getIMemory() = 0;
+    // Read up to |size| bytes into the memory returned by getIMemory(). Returns
+    // the number of bytes read, or -1 on error. |size| must not be larger than
+    // the buffer.
+    virtual ssize_t readAt(off64_t offset, size_t size) = 0;
+    // Get the size, or -1 if the size is unknown.
+    virtual status_t getSize(off64_t* size) = 0;
+    // This should be called before deleting |this|. The other methods may
+    // return errors if they're called after calling close().
+    virtual void close() = 0;
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(IDataSource);
+};
+
+// ----------------------------------------------------------------------------
+
+class BnDataSource : public BnInterface<IDataSource> {
+public:
+    virtual status_t onTransact(uint32_t code,
+                                const Parcel& data,
+                                Parcel* reply,
+                                uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif // ANDROID_IDATASOURCE_H
diff --git a/include/media/IMediaMetadataRetriever.h b/include/media/IMediaMetadataRetriever.h
index 2529800..95851fd 100644
--- a/include/media/IMediaMetadataRetriever.h
+++ b/include/media/IMediaMetadataRetriever.h
@@ -26,7 +26,8 @@
 
 namespace android {
 
-struct IMediaHTTPService;
+class IDataSource;
+class IMediaHTTPService;
 
 class IMediaMetadataRetriever: public IInterface
 {
@@ -40,6 +41,7 @@
             const KeyedVector<String8, String8> *headers = NULL) = 0;
 
     virtual status_t        setDataSource(int fd, int64_t offset, int64_t length) = 0;
+    virtual status_t        setDataSource(const sp<IDataSource>& dataSource) = 0;
     virtual sp<IMemory>     getFrameAtTime(int64_t timeUs, int option) = 0;
     virtual sp<IMemory>     extractAlbumArt() = 0;
     virtual const char*     extractMetadata(int keyCode) = 0;
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index 4153c25..17ef489 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -31,6 +31,7 @@
 
 class Parcel;
 class Surface;
+class IDataSource;
 class IStreamSource;
 class IGraphicBufferProducer;
 struct IMediaHTTPService;
@@ -49,6 +50,7 @@
 
     virtual status_t        setDataSource(int fd, int64_t offset, int64_t length) = 0;
     virtual status_t        setDataSource(const sp<IStreamSource>& source) = 0;
+    virtual status_t        setDataSource(const sp<IDataSource>& source) = 0;
     virtual status_t        setVideoSurfaceTexture(
                                     const sp<IGraphicBufferProducer>& bufferProducer) = 0;
     virtual status_t        prepareAsync() = 0;
diff --git a/include/media/MediaMetadataRetrieverInterface.h b/include/media/MediaMetadataRetrieverInterface.h
index 38dbb20..df6c7d6 100644
--- a/include/media/MediaMetadataRetrieverInterface.h
+++ b/include/media/MediaMetadataRetrieverInterface.h
@@ -25,7 +25,8 @@
 
 namespace android {
 
-struct IMediaHTTPService;
+class DataSource;
+class IMediaHTTPService;
 
 // Abstract base class
 class MediaMetadataRetrieverBase : public RefBase
@@ -40,6 +41,7 @@
             const KeyedVector<String8, String8> *headers = NULL) = 0;
 
     virtual status_t    setDataSource(int fd, int64_t offset, int64_t length) = 0;
+    virtual status_t setDataSource(const sp<DataSource>& source) = 0;
     virtual VideoFrame* getFrameAtTime(int64_t timeUs, int option) = 0;
     virtual MediaAlbumArt* extractAlbumArt() = 0;
     virtual const char* extractMetadata(int keyCode) = 0;
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index d6fe390..90211b1 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -36,6 +36,7 @@
 
 namespace android {
 
+class DataSource;
 class Parcel;
 class Surface;
 class IGraphicBufferProducer;
@@ -158,6 +159,10 @@
         return INVALID_OPERATION;
     }
 
+    virtual status_t    setDataSource(const sp<DataSource> &source) {
+        return INVALID_OPERATION;
+    }
+
     // pass the buffered IGraphicBufferProducer to the media player service
     virtual status_t    setVideoSurfaceTexture(
                                 const sp<IGraphicBufferProducer>& bufferProducer) = 0;
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
index 7191965..08049c4 100644
--- a/include/media/mediametadataretriever.h
+++ b/include/media/mediametadataretriever.h
@@ -25,7 +25,8 @@
 
 namespace android {
 
-struct IMediaHTTPService;
+class IDataSource;
+class IMediaHTTPService;
 class IMediaPlayerService;
 class IMediaMetadataRetriever;
 
@@ -75,6 +76,7 @@
             const KeyedVector<String8, String8> *headers = NULL);
 
     status_t setDataSource(int fd, int64_t offset, int64_t length);
+    status_t setDataSource(const sp<IDataSource>& dataSource);
     sp<IMemory> getFrameAtTime(int64_t timeUs, int option);
     sp<IMemory> extractAlbumArt();
     const char* extractMetadata(int keyCode);
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 808e893..269a2d7 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -211,6 +211,7 @@
 
             status_t        setDataSource(int fd, int64_t offset, int64_t length);
             status_t        setDataSource(const sp<IStreamSource> &source);
+            status_t        setDataSource(const sp<IDataSource> &source);
             status_t        setVideoSurfaceTexture(
                                     const sp<IGraphicBufferProducer>& bufferProducer);
             status_t        setListener(const sp<MediaPlayerListener>& listener);
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index 3630263..997fe95 100644
--- a/include/media/stagefright/DataSource.h
+++ b/include/media/stagefright/DataSource.h
@@ -32,6 +32,7 @@
 
 struct AMessage;
 struct AString;
+struct IDataSource;
 struct IMediaHTTPService;
 class String8;
 struct HTTPBase;
@@ -53,11 +54,15 @@
             HTTPBase *httpSource = NULL);
 
     static sp<DataSource> CreateMediaHTTP(const sp<IMediaHTTPService> &httpService);
+    static sp<DataSource> CreateFromIDataSource(const sp<IDataSource> &source);
 
     DataSource() {}
 
     virtual status_t initCheck() const = 0;
 
+    // Returns the number of bytes read, or -1 on failure. It's not an error if
+    // this returns zero; it just means the given offset is equal to, or
+    // beyond, the end of the source.
     virtual ssize_t readAt(off64_t offset, void *data, size_t size) = 0;
 
     // Convenience methods:
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 3b260d6..78baa43 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -19,6 +19,7 @@
     IAudioTrack.cpp \
     IAudioRecord.cpp \
     ICrypto.cpp \
+    IDataSource.cpp \
     IDrm.cpp \
     IDrmClient.cpp \
     IHDCP.cpp \
diff --git a/media/libmedia/AudioPolicy.cpp b/media/libmedia/AudioPolicy.cpp
index c7dafcb..786eb63 100644
--- a/media/libmedia/AudioPolicy.cpp
+++ b/media/libmedia/AudioPolicy.cpp
@@ -68,6 +68,7 @@
     mFormat.format = (audio_format_t)parcel->readInt32();
     mRouteFlags = parcel->readInt32();
     mRegistrationId = parcel->readString8();
+    mFlags = (uint32_t)parcel->readInt32();
     size_t size = (size_t)parcel->readInt32();
     if (size > MAX_CRITERIA_PER_MIX) {
         size = MAX_CRITERIA_PER_MIX;
@@ -89,6 +90,7 @@
     parcel->writeInt32(mFormat.format);
     parcel->writeInt32(mRouteFlags);
     parcel->writeString8(mRegistrationId);
+    parcel->writeInt32(mFlags);
     size_t size = mCriteria.size();
     if (size > MAX_CRITERIA_PER_MIX) {
         size = MAX_CRITERIA_PER_MIX;
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 8db72ee..e9ee169 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -985,6 +985,22 @@
     return aps->registerPolicyMixes(mixes, registration);
 }
 
+status_t AudioSystem::startAudioSource(const struct audio_port_config *source,
+                                       const audio_attributes_t *attributes,
+                                       audio_io_handle_t *handle)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->startAudioSource(source, attributes, handle);
+}
+
+status_t AudioSystem::stopAudioSource(audio_io_handle_t handle)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->stopAudioSource(handle);
+}
+
 // ---------------------------------------------------------------------------
 
 status_t AudioSystem::AudioPolicyServiceClient::addAudioPortCallback(
@@ -1033,6 +1049,12 @@
     }
 }
 
+void AudioSystem::AudioPolicyServiceClient::onDynamicPolicyMixStateUpdate(
+        String8 regId, int32_t state)
+{
+    ALOGV("TODO propagate onDynamicPolicyMixStateUpdate(%s, %d)", regId.string(), state);
+}
+
 void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who __unused)
 {
     {
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index 4b86532..afae7f5 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -71,6 +71,8 @@
     RELEASE_SOUNDTRIGGER_SESSION,
     GET_PHONE_STATE,
     REGISTER_POLICY_MIXES,
+    START_AUDIO_SOURCE,
+    STOP_AUDIO_SOURCE
 };
 
 #define MAX_ITEMS_PER_LIST 1024
@@ -714,6 +716,42 @@
         }
         return status;
     }
+
+    virtual status_t startAudioSource(const struct audio_port_config *source,
+                                      const audio_attributes_t *attributes,
+                                      audio_io_handle_t *handle)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        if (source == NULL || attributes == NULL || handle == NULL) {
+            return BAD_VALUE;
+        }
+        data.write(source, sizeof(struct audio_port_config));
+        data.write(attributes, sizeof(audio_attributes_t));
+        status_t status = remote()->transact(START_AUDIO_SOURCE, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        status = (status_t)reply.readInt32();
+        if (status != NO_ERROR) {
+            return status;
+        }
+        *handle = (audio_io_handle_t)reply.readInt32();
+        return status;
+    }
+
+    virtual status_t stopAudioSource(audio_io_handle_t handle)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(handle);
+        status_t status = remote()->transact(STOP_AUDIO_SOURCE, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        status = (status_t)reply.readInt32();
+        return status;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
@@ -1224,6 +1262,27 @@
             return NO_ERROR;
         } break;
 
+        case START_AUDIO_SOURCE: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            struct audio_port_config source;
+            data.read(&source, sizeof(struct audio_port_config));
+            audio_attributes_t attributes;
+            data.read(&attributes, sizeof(audio_attributes_t));
+            audio_io_handle_t handle;
+            status_t status = startAudioSource(&source, &attributes, &handle);
+            reply->writeInt32(status);
+            reply->writeInt32(handle);
+            return NO_ERROR;
+        } break;
+
+        case STOP_AUDIO_SOURCE: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            audio_io_handle_t handle = (audio_io_handle_t)data.readInt32();
+            status_t status = stopAudioSource(handle);
+            reply->writeInt32(status);
+            return NO_ERROR;
+        } break;
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/IAudioPolicyServiceClient.cpp b/media/libmedia/IAudioPolicyServiceClient.cpp
index 7c65878..65cc7d6 100644
--- a/media/libmedia/IAudioPolicyServiceClient.cpp
+++ b/media/libmedia/IAudioPolicyServiceClient.cpp
@@ -29,7 +29,8 @@
 
 enum {
     PORT_LIST_UPDATE = IBinder::FIRST_CALL_TRANSACTION,
-    PATCH_LIST_UPDATE
+    PATCH_LIST_UPDATE,
+    MIX_STATE_UPDATE
 };
 
 class BpAudioPolicyServiceClient : public BpInterface<IAudioPolicyServiceClient>
@@ -53,6 +54,15 @@
         data.writeInterfaceToken(IAudioPolicyServiceClient::getInterfaceDescriptor());
         remote()->transact(PATCH_LIST_UPDATE, data, &reply, IBinder::FLAG_ONEWAY);
     }
+
+    void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyServiceClient::getInterfaceDescriptor());
+        data.writeString8(regId);
+        data.writeInt32(state);
+        remote()->transact(MIX_STATE_UPDATE, data, &reply, IBinder::FLAG_ONEWAY);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioPolicyServiceClient, "android.media.IAudioPolicyServiceClient");
@@ -73,6 +83,13 @@
             onAudioPatchListUpdate();
             return NO_ERROR;
         } break;
+    case MIX_STATE_UPDATE: {
+            CHECK_INTERFACE(IAudioPolicyServiceClient, data, reply);
+            String8 regId = data.readString8();
+            int32_t state = data.readInt32();
+            onDynamicPolicyMixStateUpdate(regId, state);
+            return NO_ERROR;
+    }
     default:
         return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/IDataSource.cpp b/media/libmedia/IDataSource.cpp
new file mode 100644
index 0000000..76d1d68
--- /dev/null
+++ b/media/libmedia/IDataSource.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "IDataSource"
+#include <utils/Log.h>
+#include <utils/Timers.h>
+
+#include <media/IDataSource.h>
+
+#include <binder/IMemory.h>
+#include <binder/Parcel.h>
+#include <media/stagefright/foundation/ADebug.h>
+
+namespace android {
+
+enum {
+    GET_IMEMORY = IBinder::FIRST_CALL_TRANSACTION,
+    READ_AT,
+    GET_SIZE,
+    CLOSE,
+};
+
+struct BpDataSource : public BpInterface<IDataSource> {
+    BpDataSource(const sp<IBinder>& impl) : BpInterface<IDataSource>(impl) {}
+
+    virtual sp<IMemory> getIMemory() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IDataSource::getInterfaceDescriptor());
+        remote()->transact(GET_IMEMORY, data, &reply);
+        sp<IBinder> binder = reply.readStrongBinder();
+        return interface_cast<IMemory>(binder);
+    }
+
+    virtual ssize_t readAt(off64_t offset, size_t size) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IDataSource::getInterfaceDescriptor());
+        data.writeInt64(offset);
+        data.writeInt64(size);
+        remote()->transact(READ_AT, data, &reply);
+        return reply.readInt64();
+    }
+
+    virtual status_t getSize(off64_t* size) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IDataSource::getInterfaceDescriptor());
+        remote()->transact(GET_SIZE, data, &reply);
+        status_t err = reply.readInt32();
+        *size = reply.readInt64();
+        return err;
+    }
+
+    virtual void close() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IDataSource::getInterfaceDescriptor());
+        remote()->transact(CLOSE, data, &reply);
+    }
+};
+
+IMPLEMENT_META_INTERFACE(DataSource, "android.media.IDataSource");
+
+status_t BnDataSource::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+    switch (code) {
+        case GET_IMEMORY: {
+            CHECK_INTERFACE(IDataSource, data, reply);
+            reply->writeStrongBinder(IInterface::asBinder(getIMemory()));
+            return NO_ERROR;
+        } break;
+        case READ_AT: {
+            CHECK_INTERFACE(IDataSource, data, reply);
+            off64_t offset = (off64_t) data.readInt64();
+            size_t size = (size_t) data.readInt64();
+            reply->writeInt64(readAt(offset, size));
+            return NO_ERROR;
+        } break;
+        case GET_SIZE: {
+            CHECK_INTERFACE(IDataSource, data, reply);
+            off64_t size;
+            status_t err = getSize(&size);
+            reply->writeInt32(err);
+            reply->writeInt64(size);
+            return NO_ERROR;
+        } break;
+        case CLOSE: {
+            CHECK_INTERFACE(IDataSource, data, reply);
+            close();
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+}  // namespace android
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index 551cffe..9765f0d 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -20,6 +20,7 @@
 #include <sys/types.h>
 
 #include <binder/Parcel.h>
+#include <media/IDataSource.h>
 #include <media/IMediaHTTPService.h>
 #include <media/IMediaMetadataRetriever.h>
 #include <utils/String8.h>
@@ -65,6 +66,7 @@
     DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
     SET_DATA_SOURCE_URL,
     SET_DATA_SOURCE_FD,
+    SET_DATA_SOURCE_CALLBACK,
     GET_FRAME_AT_TIME,
     EXTRACT_ALBUM_ART,
     EXTRACT_METADATA,
@@ -125,6 +127,15 @@
         return reply.readInt32();
     }
 
+    status_t setDataSource(const sp<IDataSource>& source)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+        data.writeStrongBinder(IInterface::asBinder(source));
+        remote()->transact(SET_DATA_SOURCE_CALLBACK, data, &reply);
+        return reply.readInt32();
+    }
+
     sp<IMemory> getFrameAtTime(int64_t timeUs, int option)
     {
         ALOGV("getTimeAtTime: time(%" PRId64 " us) and option(%d)", timeUs, option);
@@ -235,6 +246,13 @@
             reply->writeInt32(setDataSource(fd, offset, length));
             return NO_ERROR;
         } break;
+        case SET_DATA_SOURCE_CALLBACK: {
+            CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+            sp<IDataSource> source =
+                interface_cast<IDataSource>(data.readStrongBinder());
+            reply->writeInt32(setDataSource(source));
+            return NO_ERROR;
+        } break;
         case GET_FRAME_AT_TIME: {
             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
             int64_t timeUs = data.readInt64();
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index ce3009a..0091078 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -21,6 +21,7 @@
 
 #include <binder/Parcel.h>
 
+#include <media/IDataSource.h>
 #include <media/IMediaHTTPService.h>
 #include <media/IMediaPlayer.h>
 #include <media/IStreamSource.h>
@@ -35,6 +36,7 @@
     SET_DATA_SOURCE_URL,
     SET_DATA_SOURCE_FD,
     SET_DATA_SOURCE_STREAM,
+    SET_DATA_SOURCE_CALLBACK,
     PREPARE_ASYNC,
     START,
     STOP,
@@ -121,6 +123,14 @@
         return reply.readInt32();
     }
 
+    status_t setDataSource(const sp<IDataSource> &source) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        data.writeStrongBinder(IInterface::asBinder(source));
+        remote()->transact(SET_DATA_SOURCE_CALLBACK, data, &reply);
+        return reply.readInt32();
+    }
+
     // pass the buffered IGraphicBufferProducer to the media player service
     status_t setVideoSurfaceTexture(const sp<IGraphicBufferProducer>& bufferProducer)
     {
@@ -406,6 +416,13 @@
             reply->writeInt32(setDataSource(source));
             return NO_ERROR;
         }
+        case SET_DATA_SOURCE_CALLBACK: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            sp<IDataSource> source =
+                interface_cast<IDataSource>(data.readStrongBinder());
+            reply->writeInt32(setDataSource(source));
+            return NO_ERROR;
+        }
         case SET_VIDEO_SURFACETEXTURE: {
             CHECK_INTERFACE(IMediaPlayer, data, reply);
             sp<IGraphicBufferProducer> bufferProducer =
diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp
index 873808a..9a76f58 100644
--- a/media/libmedia/mediametadataretriever.cpp
+++ b/media/libmedia/mediametadataretriever.cpp
@@ -129,6 +129,18 @@
     return mRetriever->setDataSource(fd, offset, length);
 }
 
+status_t MediaMetadataRetriever::setDataSource(
+    const sp<IDataSource>& dataSource)
+{
+    ALOGV("setDataSource(IDataSource)");
+    Mutex::Autolock _l(mLock);
+    if (mRetriever == 0) {
+        ALOGE("retriever is not initialized");
+        return INVALID_OPERATION;
+    }
+    return mRetriever->setDataSource(dataSource);
+}
+
 sp<IMemory> MediaMetadataRetriever::getFrameAtTime(int64_t timeUs, int option)
 {
     ALOGV("getFrameAtTime: time(%" PRId64 " us) option(%d)", timeUs, option);
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 5dd8c02..6eddcb6 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -33,6 +33,7 @@
 
 #include <media/mediaplayer.h>
 #include <media/AudioSystem.h>
+#include <media/IDataSource.h>
 
 #include <binder/MemoryBase.h>
 
@@ -195,6 +196,22 @@
     return err;
 }
 
+status_t MediaPlayer::setDataSource(const sp<IDataSource> &source)
+{
+    ALOGV("setDataSource(IDataSource)");
+    status_t err = UNKNOWN_ERROR;
+    const sp<IMediaPlayerService>& service(getMediaPlayerService());
+    if (service != 0) {
+        sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
+        if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
+            (NO_ERROR != player->setDataSource(source))) {
+            player.clear();
+        }
+        err = attachNewPlayer(player);
+    }
+    return err;
+}
+
 status_t MediaPlayer::invoke(const Parcel& request, Parcel *reply)
 {
     Mutex::Autolock _l(mLock);
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index 48884b9..ca33aed 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -131,6 +131,11 @@
     GET_PLAYER_TYPE_IMPL(client, source);
 }
 
+player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client,
+                                              const sp<DataSource> &source) {
+    GET_PLAYER_TYPE_IMPL(client, source);
+}
+
 #undef GET_PLAYER_TYPE_IMPL
 
 sp<MediaPlayerBase> MediaPlayerFactory::createPlayer(
@@ -273,6 +278,13 @@
         return 1.0;
     }
 
+    virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
+                               const sp<DataSource>& /*source*/,
+                               float /*curScore*/) {
+        // Only NuPlayer supports setting a DataSource source directly.
+        return 1.0;
+    }
+
     virtual sp<MediaPlayerBase> createPlayer() {
         ALOGV(" create NuPlayer");
         return new NuPlayerDriver;
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.h b/media/libmediaplayerservice/MediaPlayerFactory.h
index 55ff918..7f9b3b5 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.h
+++ b/media/libmediaplayerservice/MediaPlayerFactory.h
@@ -43,6 +43,10 @@
                                    const sp<IStreamSource> &/*source*/,
                                    float /*curScore*/) { return 0.0; }
 
+        virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
+                                   const sp<DataSource> &/*source*/,
+                                   float /*curScore*/) { return 0.0; }
+
         virtual sp<MediaPlayerBase> createPlayer() = 0;
     };
 
@@ -57,6 +61,8 @@
                                      int64_t length);
     static player_type getPlayerType(const sp<IMediaPlayer>& client,
                                      const sp<IStreamSource> &source);
+    static player_type getPlayerType(const sp<IMediaPlayer>& client,
+                                     const sp<DataSource> &source);
 
     static sp<MediaPlayerBase> createPlayer(player_type playerType,
                                             void* cookie,
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index f113e21..8e2e214 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -790,6 +790,19 @@
     return mStatus;
 }
 
+status_t MediaPlayerService::Client::setDataSource(
+        const sp<IDataSource> &source) {
+    sp<DataSource> dataSource = DataSource::CreateFromIDataSource(source);
+    player_type playerType = MediaPlayerFactory::getPlayerType(this, dataSource);
+    sp<MediaPlayerBase> p = setDataSource_pre(playerType);
+    if (p == NULL) {
+        return NO_INIT;
+    }
+    // now set data source
+    setDataSource_post(p, p->setDataSource(dataSource));
+    return mStatus;
+}
+
 void MediaPlayerService::Client::disconnectNativeWindow() {
     if (mConnectedWindow != NULL) {
         status_t err = native_window_api_disconnect(mConnectedWindow.get(),
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 4ce4b81..2a95ce1 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -35,6 +35,7 @@
 namespace android {
 
 class AudioTrack;
+class IDataSource;
 class IMediaRecorder;
 class IMediaMetadataRetriever;
 class IOMX;
@@ -292,6 +293,8 @@
         virtual status_t        setDataSource(int fd, int64_t offset, int64_t length);
 
         virtual status_t        setDataSource(const sp<IStreamSource> &source);
+        virtual status_t        setDataSource(const sp<IDataSource> &source);
+
 
         sp<MediaPlayerBase>     setDataSource_pre(player_type playerType);
         void                    setDataSource_post(const sp<MediaPlayerBase>& p,
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index 715cc0c..80804a7 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -34,6 +34,7 @@
 #include <media/IMediaHTTPService.h>
 #include <media/MediaMetadataRetrieverInterface.h>
 #include <media/MediaPlayerInterface.h>
+#include <media/stagefright/DataSource.h>
 #include <private/media/VideoFrame.h>
 #include "MetadataRetrieverClient.h"
 #include "StagefrightMetadataRetriever.h"
@@ -173,6 +174,23 @@
     return status;
 }
 
+status_t MetadataRetrieverClient::setDataSource(
+        const sp<IDataSource>& source)
+{
+    ALOGV("setDataSource(IDataSource)");
+    Mutex::Autolock lock(mLock);
+
+    sp<DataSource> dataSource = DataSource::CreateFromIDataSource(source);
+    player_type playerType =
+        MediaPlayerFactory::getPlayerType(NULL /* client */, dataSource);
+    ALOGV("player type = %d", playerType);
+    sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
+    if (p == NULL) return NO_INIT;
+    status_t ret = p->setDataSource(dataSource);
+    if (ret == NO_ERROR) mRetriever = p;
+    return ret;
+}
+
 sp<IMemory> MetadataRetrieverClient::getFrameAtTime(int64_t timeUs, int option)
 {
     ALOGV("getFrameAtTime: time(%lld us) option(%d)", timeUs, option);
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h
index 9d3fbe9..ce52b91 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.h
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.h
@@ -49,6 +49,7 @@
             const KeyedVector<String8, String8> *headers);
 
     virtual status_t                setDataSource(int fd, int64_t offset, int64_t length);
+    virtual status_t                setDataSource(const sp<IDataSource>& source);
     virtual sp<IMemory>             getFrameAtTime(int64_t timeUs, int option);
     virtual sp<IMemory>             extractAlbumArt();
     virtual const char*             extractMetadata(int keyCode);
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 5a31b74..8f1cd57 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -124,6 +124,12 @@
     return OK;
 }
 
+status_t NuPlayer::GenericSource::setDataSource(const sp<DataSource>& source) {
+    resetDataSource();
+    mDataSource = source;
+    return OK;
+}
+
 sp<MetaData> NuPlayer::GenericSource::getFileFormatMeta() const {
     return mFileMeta;
 }
@@ -377,20 +383,20 @@
             notifyPreparedAndCleanup(UNKNOWN_ERROR);
             return;
         }
-
-        if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
-            mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
-        }
-
-        // For widevine or other cached streaming cases, we need to wait for
-        // enough buffering before reporting prepared.
-        // Note that even when URL doesn't start with widevine://, mIsWidevine
-        // could still be set to true later, if the streaming or file source
-        // is sniffed to be widevine. We don't want to buffer for file source
-        // in that case, so must check the flag now.
-        mIsStreaming = (mIsWidevine || mCachedSource != NULL);
     }
 
+    if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
+        mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
+    }
+
+    // For widevine or other cached streaming cases, we need to wait for
+    // enough buffering before reporting prepared.
+    // Note that even when URL doesn't start with widevine://, mIsWidevine
+    // could still be set to true later, if the streaming or file source
+    // is sniffed to be widevine. We don't want to buffer for file source
+    // in that case, so must check the flag now.
+    mIsStreaming = (mIsWidevine || mCachedSource != NULL);
+
     // init extractor from data source
     status_t err = initFromDataSource();
 
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 862ee5f..2f6e78e 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -32,6 +32,7 @@
 struct AnotherPacketSource;
 struct ARTSPController;
 struct DataSource;
+struct IDataSource;
 struct IMediaHTTPService;
 struct MediaSource;
 class MediaBuffer;
@@ -48,6 +49,8 @@
 
     status_t setDataSource(int fd, int64_t offset, int64_t length);
 
+    status_t setDataSource(const sp<DataSource>& dataSource);
+
     virtual void prepareAsync();
 
     virtual void start();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 02d9f32..db73784 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -285,6 +285,22 @@
     msg->post();
 }
 
+void NuPlayer::setDataSourceAsync(const sp<DataSource> &dataSource) {
+    sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
+    sp<AMessage> notify = new AMessage(kWhatSourceNotify, this);
+
+    sp<GenericSource> source = new GenericSource(notify, mUIDValid, mUID);
+    status_t err = source->setDataSource(dataSource);
+
+    if (err != OK) {
+        ALOGE("Failed to set data source!");
+        source = NULL;
+    }
+
+    msg->setObject("source", source);
+    msg->post();
+}
+
 void NuPlayer::prepareAsync() {
     (new AMessage(kWhatPrepare, this))->post();
 }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 2bc20d7..623b0ce 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -26,6 +26,7 @@
 
 struct ABuffer;
 struct AMessage;
+struct IDataSource;
 class MetaData;
 struct NuPlayerDriver;
 
@@ -45,6 +46,8 @@
 
     void setDataSourceAsync(int fd, int64_t offset, int64_t length);
 
+    void setDataSourceAsync(const sp<DataSource> &source);
+
     void prepareAsync();
 
     void setVideoSurfaceTextureAsync(
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 3fff1e6..d521c64 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -463,10 +463,6 @@
         size_t size,
         int64_t timeUs,
         int32_t flags) {
-    if (mFormatChangePending) {
-        return false;
-    }
-
 //    CHECK_LT(bufferIx, mOutputBuffers.size());
     sp<ABuffer> buffer;
     mCodec->getOutputBuffer(index, &buffer);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 1fa9cef..bb1255f 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -135,6 +135,25 @@
     return mAsyncResult;
 }
 
+status_t NuPlayerDriver::setDataSource(const sp<DataSource> &source) {
+    ALOGV("setDataSource(%p) callback source", this);
+    Mutex::Autolock autoLock(mLock);
+
+    if (mState != STATE_IDLE) {
+        return INVALID_OPERATION;
+    }
+
+    mState = STATE_SET_DATASOURCE_PENDING;
+
+    mPlayer->setDataSourceAsync(source);
+
+    while (mState == STATE_SET_DATASOURCE_PENDING) {
+        mCondition.wait(mLock);
+    }
+
+    return mAsyncResult;
+}
+
 status_t NuPlayerDriver::setVideoSurfaceTexture(
         const sp<IGraphicBufferProducer> &bufferProducer) {
     ALOGV("setVideoSurfaceTexture(%p)", this);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index e53abcd..65f170e 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -39,6 +39,8 @@
 
     virtual status_t setDataSource(const sp<IStreamSource> &source);
 
+    virtual status_t setDataSource(const sp<DataSource>& dataSource);
+
     virtual status_t setVideoSurfaceTexture(
             const sp<IGraphicBufferProducer> &bufferProducer);
     virtual status_t prepare();
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index b0eeb7f..0ba6743 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -12,6 +12,7 @@
         AudioPlayer.cpp                   \
         AudioSource.cpp                   \
         AwesomePlayer.cpp                 \
+        CallbackDataSource.cpp            \
         CameraSource.cpp                  \
         CameraSourceTimeLapse.cpp         \
         ClockEstimator.cpp                \
diff --git a/media/libstagefright/CallbackDataSource.cpp b/media/libstagefright/CallbackDataSource.cpp
new file mode 100644
index 0000000..e16cef7
--- /dev/null
+++ b/media/libstagefright/CallbackDataSource.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "CallbackDataSource"
+#include <utils/Log.h>
+
+#include "include/CallbackDataSource.h"
+
+#include <binder/IMemory.h>
+#include <media/IDataSource.h>
+#include <media/stagefright/foundation/ADebug.h>
+
+#include <algorithm>
+
+namespace android {
+
+CallbackDataSource::CallbackDataSource(
+    const sp<IDataSource>& binderDataSource)
+    : mIDataSource(binderDataSource) {
+    // Set up the buffer to read into.
+    mMemory = mIDataSource->getIMemory();
+}
+
+CallbackDataSource::~CallbackDataSource() {
+    ALOGV("~CallbackDataSource");
+    mIDataSource->close();
+}
+
+status_t CallbackDataSource::initCheck() const {
+    if (mMemory == NULL) {
+        return UNKNOWN_ERROR;
+    }
+    return OK;
+}
+
+ssize_t CallbackDataSource::readAt(off64_t offset, void* data, size_t size) {
+    if (mMemory == NULL) {
+        return -1;
+    }
+
+    // IDataSource can only read up to mMemory->size() bytes at a time, but this
+    // method should be able to read any number of bytes, so read in a loop.
+    size_t totalNumRead = 0;
+    size_t numLeft = size;
+    const size_t bufferSize = mMemory->size();
+
+    while (numLeft > 0) {
+        size_t numToRead = std::min(numLeft, bufferSize);
+        ssize_t numRead =
+            mIDataSource->readAt(offset + totalNumRead, numToRead);
+        // A negative return value represents an error. Pass it on.
+        if (numRead < 0) {
+            return numRead;
+        }
+        // A zero return value signals EOS. Return the bytes read so far.
+        if (numRead == 0) {
+            return totalNumRead;
+        }
+        // Sanity check.
+        CHECK((size_t)numRead <= numToRead && numRead >= 0 &&
+              numRead <= bufferSize);
+        memcpy(((uint8_t*)data) + totalNumRead, mMemory->pointer(), numRead);
+        numLeft -= numRead;
+        totalNumRead += numRead;
+    }
+
+    return totalNumRead;
+}
+
+status_t CallbackDataSource::getSize(off64_t *size) {
+    status_t err = mIDataSource->getSize(size);
+    if (err != OK) {
+        return err;
+    }
+    if (*size < 0) {
+        // IDataSource will set size to -1 to indicate unknown size, but
+        // DataSource returns ERROR_UNSUPPORTED for that.
+        return ERROR_UNSUPPORTED;
+    }
+    return OK;
+}
+
+} // namespace android
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index f7dcf35..6a89154 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -19,6 +19,7 @@
 #include "include/AMRExtractor.h"
 
 #include "include/AACExtractor.h"
+#include "include/CallbackDataSource.h"
 #include "include/DRMExtractor.h"
 #include "include/FLACExtractor.h"
 #include "include/HTTPBase.h"
@@ -281,6 +282,10 @@
     }
 }
 
+sp<DataSource> DataSource::CreateFromIDataSource(const sp<IDataSource> &source) {
+    return new CallbackDataSource(source);
+}
+
 String8 DataSource::getMIMEType() const {
     return String8("application/octet-stream");
 }
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 297a186..28a9ed9 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -745,7 +745,8 @@
             && path[1] == FOURCC('m', 'e', 't', 'a')
             && (depth == 2
             || (depth == 3
-                    && (path[2] == FOURCC('i', 'l', 's', 't')
+                    && (path[2] == FOURCC('h', 'd', 'l', 'r')
+                    ||  path[2] == FOURCC('i', 'l', 's', 't')
                     ||  path[2] == FOURCC('k', 'e', 'y', 's'))));
 }
 
@@ -1914,6 +1915,10 @@
         {
             *offset += chunk_size;
 
+            if (underQTMetaPath(mPath, 3)) {
+                break;
+            }
+
             uint32_t buffer;
             if (mDataSource->readAt(
                         data_offset + 8, &buffer, 4) < 4) {
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 6f6e362..3d83e83 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -841,6 +841,8 @@
     mFd = -1;
     mInitCheck = NO_INIT;
     mStarted = false;
+    free(mMoovBoxBuffer);
+    mMoovBoxBuffer = NULL;
 }
 
 status_t MPEG4Writer::reset() {
@@ -2839,8 +2841,10 @@
 
     mOwner->writeInt16(0x03);  // XXX
     mOwner->writeInt8(0x00);   // buffer size 24-bit
-    mOwner->writeInt32(96000); // max bit rate
-    mOwner->writeInt32(96000); // avg bit rate
+    int32_t bitRate;
+    bool success = mMeta->findInt32(kKeyBitRate, &bitRate);
+    mOwner->writeInt32(success ? bitRate : 96000); // max bit rate
+    mOwner->writeInt32(success ? bitRate : 96000); // avg bit rate
 
     mOwner->writeInt8(0x05);   // DecoderSpecificInfoTag
     mOwner->writeInt8(mCodecSpecificDataSize);
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 820b2fc..e9566f2 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -47,10 +47,7 @@
 
 StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
     ALOGV("~StagefrightMetadataRetriever()");
-
-    delete mAlbumArt;
-    mAlbumArt = NULL;
-
+    clearMetadata();
     mClient.disconnect();
 }
 
@@ -60,11 +57,7 @@
         const KeyedVector<String8, String8> *headers) {
     ALOGV("setDataSource(%s)", uri);
 
-    mParsedMetaData = false;
-    mMetaData.clear();
-    delete mAlbumArt;
-    mAlbumArt = NULL;
-
+    clearMetadata();
     mSource = DataSource::CreateFromURI(httpService, uri, headers);
 
     if (mSource == NULL) {
@@ -92,11 +85,7 @@
 
     ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
 
-    mParsedMetaData = false;
-    mMetaData.clear();
-    delete mAlbumArt;
-    mAlbumArt = NULL;
-
+    clearMetadata();
     mSource = new FileSource(fd, offset, length);
 
     status_t err;
@@ -117,6 +106,23 @@
     return OK;
 }
 
+status_t StagefrightMetadataRetriever::setDataSource(
+        const sp<DataSource>& source) {
+    ALOGV("setDataSource(DataSource)");
+
+    clearMetadata();
+    mSource = source;
+    mExtractor = MediaExtractor::Create(mSource);
+
+    if (mExtractor == NULL) {
+        ALOGE("Failed to instantiate a MediaExtractor.");
+        mSource.clear();
+        return UNKNOWN_ERROR;
+    }
+
+    return OK;
+}
+
 static bool isYUV420PlanarSupported(
             OMXClient *client,
             const sp<MetaData> &trackMeta) {
@@ -635,4 +641,11 @@
     }
 }
 
+void StagefrightMetadataRetriever::clearMetadata() {
+    mParsedMetaData = false;
+    mMetaData.clear();
+    delete mAlbumArt;
+    mAlbumArt = NULL;
+}
+
 }  // namespace android
diff --git a/media/libstagefright/codecs/avcdec/Android.mk b/media/libstagefright/codecs/avcdec/Android.mk
new file mode 100644
index 0000000..902ab57
--- /dev/null
+++ b/media/libstagefright/codecs/avcdec/Android.mk
@@ -0,0 +1,27 @@
+#ifeq ($(if $(wildcard external/libh264),1,0),1)
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE            := libstagefright_soft_avcdec
+LOCAL_MODULE_TAGS       := optional
+
+LOCAL_STATIC_LIBRARIES  := libavcdec
+LOCAL_SRC_FILES         := SoftAVCDec.cpp
+
+LOCAL_C_INCLUDES := $(TOP)/external/libavc/decoder
+LOCAL_C_INCLUDES += $(TOP)/external/libavc/common
+LOCAL_C_INCLUDES += $(TOP)/frameworks/av/media/libstagefright/include
+LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/media/openmax
+
+LOCAL_SHARED_LIBRARIES  := libstagefright
+LOCAL_SHARED_LIBRARIES  += libstagefright_omx
+LOCAL_SHARED_LIBRARIES  += libstagefright_foundation
+LOCAL_SHARED_LIBRARIES  += libutils
+LOCAL_SHARED_LIBRARIES  += liblog
+
+LOCAL_LDFLAGS := -Wl,-Bsymbolic
+
+include $(BUILD_SHARED_LIBRARY)
+
+#endif
diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
new file mode 100644
index 0000000..8388472
--- /dev/null
+++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
@@ -0,0 +1,808 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SoftAVCDec"
+#include <utils/Log.h>
+
+#include "ih264_typedefs.h"
+#include "iv.h"
+#include "ivd.h"
+#include "ithread.h"
+#include "ih264d.h"
+#include "SoftAVCDec.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <OMX_VideoExt.h>
+
+namespace android {
+
+#define PRINT_TIME  ALOGV
+
+#define componentName                   "video_decoder.avc"
+#define codingType                      OMX_VIDEO_CodingAVC
+#define CODEC_MIME_TYPE                 MEDIA_MIMETYPE_VIDEO_AVC
+
+/** Function and structure definitions to keep code similar for each codec */
+#define ivdec_api_function              ih264d_api_function
+#define ivdext_init_ip_t                ih264d_init_ip_t
+#define ivdext_init_op_t                ih264d_init_op_t
+#define ivdext_fill_mem_rec_ip_t        ih264d_fill_mem_rec_ip_t
+#define ivdext_fill_mem_rec_op_t        ih264d_fill_mem_rec_op_t
+#define ivdext_ctl_set_num_cores_ip_t   ih264d_ctl_set_num_cores_ip_t
+#define ivdext_ctl_set_num_cores_op_t   ih264d_ctl_set_num_cores_op_t
+
+#define IVDEXT_CMD_CTL_SET_NUM_CORES    \
+        (IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_SET_NUM_CORES
+
+static const CodecProfileLevel kProfileLevels[] = {
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1  },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1b },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel11 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel12 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel13 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel2  },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel21 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel22 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel3  },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel31 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel32 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel4  },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel41 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel42 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel5  },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel51 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel52 },
+
+    { OMX_VIDEO_AVCProfileMain,     OMX_VIDEO_AVCLevel1  },
+    { OMX_VIDEO_AVCProfileMain,     OMX_VIDEO_AVCLevel1b },
+    { OMX_VIDEO_AVCProfileMain,     OMX_VIDEO_AVCLevel11 },
+    { OMX_VIDEO_AVCProfileMain,     OMX_VIDEO_AVCLevel12 },
+    { OMX_VIDEO_AVCProfileMain,     OMX_VIDEO_AVCLevel13 },
+    { OMX_VIDEO_AVCProfileMain,     OMX_VIDEO_AVCLevel2  },
+    { OMX_VIDEO_AVCProfileMain,     OMX_VIDEO_AVCLevel21 },
+    { OMX_VIDEO_AVCProfileMain,     OMX_VIDEO_AVCLevel22 },
+    { OMX_VIDEO_AVCProfileMain,     OMX_VIDEO_AVCLevel3  },
+    { OMX_VIDEO_AVCProfileMain,     OMX_VIDEO_AVCLevel31 },
+    { OMX_VIDEO_AVCProfileMain,     OMX_VIDEO_AVCLevel32 },
+    { OMX_VIDEO_AVCProfileMain,     OMX_VIDEO_AVCLevel4  },
+    { OMX_VIDEO_AVCProfileMain,     OMX_VIDEO_AVCLevel41 },
+    { OMX_VIDEO_AVCProfileMain,     OMX_VIDEO_AVCLevel42 },
+    { OMX_VIDEO_AVCProfileMain,     OMX_VIDEO_AVCLevel5  },
+    { OMX_VIDEO_AVCProfileMain,     OMX_VIDEO_AVCLevel51 },
+    { OMX_VIDEO_AVCProfileMain,     OMX_VIDEO_AVCLevel52 },
+
+    { OMX_VIDEO_AVCProfileHigh,     OMX_VIDEO_AVCLevel1  },
+    { OMX_VIDEO_AVCProfileHigh,     OMX_VIDEO_AVCLevel1b },
+    { OMX_VIDEO_AVCProfileHigh,     OMX_VIDEO_AVCLevel11 },
+    { OMX_VIDEO_AVCProfileHigh,     OMX_VIDEO_AVCLevel12 },
+    { OMX_VIDEO_AVCProfileHigh,     OMX_VIDEO_AVCLevel13 },
+    { OMX_VIDEO_AVCProfileHigh,     OMX_VIDEO_AVCLevel2  },
+    { OMX_VIDEO_AVCProfileHigh,     OMX_VIDEO_AVCLevel21 },
+    { OMX_VIDEO_AVCProfileHigh,     OMX_VIDEO_AVCLevel22 },
+    { OMX_VIDEO_AVCProfileHigh,     OMX_VIDEO_AVCLevel3  },
+    { OMX_VIDEO_AVCProfileHigh,     OMX_VIDEO_AVCLevel31 },
+    { OMX_VIDEO_AVCProfileHigh,     OMX_VIDEO_AVCLevel32 },
+    { OMX_VIDEO_AVCProfileHigh,     OMX_VIDEO_AVCLevel4  },
+    { OMX_VIDEO_AVCProfileHigh,     OMX_VIDEO_AVCLevel41 },
+    { OMX_VIDEO_AVCProfileHigh,     OMX_VIDEO_AVCLevel42 },
+    { OMX_VIDEO_AVCProfileHigh,     OMX_VIDEO_AVCLevel5  },
+    { OMX_VIDEO_AVCProfileHigh,     OMX_VIDEO_AVCLevel51 },
+    { OMX_VIDEO_AVCProfileHigh,     OMX_VIDEO_AVCLevel52 },
+};
+
+SoftAVC::SoftAVC(
+        const char *name,
+        const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData,
+        OMX_COMPONENTTYPE **component)
+    : SoftVideoDecoderOMXComponent(
+            name, componentName, codingType,
+            kProfileLevels, ARRAY_SIZE(kProfileLevels),
+            320 /* width */, 240 /* height */, callbacks,
+            appData, component),
+      mMemRecords(NULL),
+      mFlushOutBuffer(NULL),
+      mOmxColorFormat(OMX_COLOR_FormatYUV420Planar),
+      mIvColorFormat(IV_YUV_420P),
+      mNewWidth(mWidth),
+      mNewHeight(mHeight),
+      mChangingResolution(false) {
+    initPorts(
+            kNumBuffers, INPUT_BUF_SIZE, kNumBuffers, CODEC_MIME_TYPE);
+
+    GETTIME(&mTimeStart, NULL);
+
+    // If input dump is enabled, then open create an empty file
+    GENERATE_FILE_NAMES();
+    CREATE_DUMP_FILE(mInFile);
+
+    CHECK_EQ(initDecoder(), (status_t)OK);
+}
+
+SoftAVC::~SoftAVC() {
+    CHECK_EQ(deInitDecoder(), (status_t)OK);
+}
+
+static size_t GetCPUCoreCount() {
+    long cpuCoreCount = 1;
+#if defined(_SC_NPROCESSORS_ONLN)
+    cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
+#else
+    // _SC_NPROC_ONLN must be defined...
+    cpuCoreCount = sysconf(_SC_NPROC_ONLN);
+#endif
+    CHECK(cpuCoreCount >= 1);
+    ALOGD("Number of CPU cores: %ld", cpuCoreCount);
+    return (size_t)cpuCoreCount;
+}
+
+void SoftAVC::logVersion() {
+    ivd_ctl_getversioninfo_ip_t s_ctl_ip;
+    ivd_ctl_getversioninfo_op_t s_ctl_op;
+    UWORD8 au1_buf[512];
+    IV_API_CALL_STATUS_T status;
+
+    s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION;
+    s_ctl_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t);
+    s_ctl_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t);
+    s_ctl_ip.pv_version_buffer = au1_buf;
+    s_ctl_ip.u4_version_buffer_size = sizeof(au1_buf);
+
+    status =
+        ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, (void *)&s_ctl_op);
+
+    if (status != IV_SUCCESS) {
+        ALOGE("Error in getting version number: 0x%x",
+                s_ctl_op.u4_error_code);
+    } else {
+        ALOGV("Ittiam decoder version number: %s",
+                (char *)s_ctl_ip.pv_version_buffer);
+    }
+    return;
+}
+
+status_t SoftAVC::setParams(size_t stride) {
+    ivd_ctl_set_config_ip_t s_ctl_ip;
+    ivd_ctl_set_config_op_t s_ctl_op;
+    IV_API_CALL_STATUS_T status;
+    s_ctl_ip.u4_disp_wd = (UWORD32)stride;
+    s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE;
+
+    s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
+    s_ctl_ip.e_vid_dec_mode = IVD_DECODE_FRAME;
+    s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
+    s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
+    s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
+
+    ALOGV("Set the run-time (dynamic) parameters stride = %u", stride);
+    status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, (void *)&s_ctl_op);
+
+    if (status != IV_SUCCESS) {
+        ALOGE("Error in setting the run-time parameters: 0x%x",
+                s_ctl_op.u4_error_code);
+
+        return UNKNOWN_ERROR;
+    }
+    return OK;
+}
+
+status_t SoftAVC::resetPlugin() {
+    mIsInFlush = false;
+    mReceivedEOS = false;
+    memset(mTimeStamps, 0, sizeof(mTimeStamps));
+    memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid));
+
+    /* Initialize both start and end times */
+    gettimeofday(&mTimeStart, NULL);
+    gettimeofday(&mTimeEnd, NULL);
+
+    return OK;
+}
+
+status_t SoftAVC::resetDecoder() {
+    ivd_ctl_reset_ip_t s_ctl_ip;
+    ivd_ctl_reset_op_t s_ctl_op;
+    IV_API_CALL_STATUS_T status;
+
+    s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
+    s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
+    s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t);
+
+    status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, (void *)&s_ctl_op);
+    if (IV_SUCCESS != status) {
+        ALOGE("Error in reset: 0x%x", s_ctl_op.u4_error_code);
+        return UNKNOWN_ERROR;
+    }
+
+    /* Set the run-time (dynamic) parameters */
+    setParams(outputBufferWidth());
+
+    /* Set number of cores/threads to be used by the codec */
+    setNumCores();
+
+    return OK;
+}
+
+status_t SoftAVC::setNumCores() {
+    ivdext_ctl_set_num_cores_ip_t s_set_cores_ip;
+    ivdext_ctl_set_num_cores_op_t s_set_cores_op;
+    IV_API_CALL_STATUS_T status;
+    s_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_set_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES;
+    s_set_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_NUM_CORES);
+    s_set_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t);
+    s_set_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t);
+    status = ivdec_api_function(
+            mCodecCtx, (void *)&s_set_cores_ip, (void *)&s_set_cores_op);
+    if (IV_SUCCESS != status) {
+        ALOGE("Error in setting number of cores: 0x%x",
+                s_set_cores_op.u4_error_code);
+        return UNKNOWN_ERROR;
+    }
+    return OK;
+}
+
+status_t SoftAVC::setFlushMode() {
+    IV_API_CALL_STATUS_T status;
+    ivd_ctl_flush_ip_t s_video_flush_ip;
+    ivd_ctl_flush_op_t s_video_flush_op;
+
+    s_video_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_video_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH;
+    s_video_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t);
+    s_video_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t);
+
+    /* Set the decoder in Flush mode, subsequent decode() calls will flush */
+    status = ivdec_api_function(
+            mCodecCtx, (void *)&s_video_flush_ip, (void *)&s_video_flush_op);
+
+    if (status != IV_SUCCESS) {
+        ALOGE("Error in setting the decoder in flush mode: (%d) 0x%x", status,
+                s_video_flush_op.u4_error_code);
+        return UNKNOWN_ERROR;
+    }
+
+    mIsInFlush = true;
+    return OK;
+}
+
+status_t SoftAVC::initDecoder() {
+    IV_API_CALL_STATUS_T status;
+
+    UWORD32 u4_num_reorder_frames;
+    UWORD32 u4_num_ref_frames;
+    UWORD32 u4_share_disp_buf;
+    WORD32 i4_level;
+
+    mNumCores = GetCPUCoreCount();
+
+    /* Initialize number of ref and reorder modes (for H264) */
+    u4_num_reorder_frames = 16;
+    u4_num_ref_frames = 16;
+    u4_share_disp_buf = 0;
+
+    uint32_t displayStride = outputBufferWidth();
+    uint32_t displayHeight = outputBufferHeight();
+    uint32_t displaySizeY = displayStride * displayHeight;
+
+    if (displaySizeY > (1920 * 1088)) {
+        i4_level = 50;
+    } else if (displaySizeY > (1280 * 720)) {
+        i4_level = 40;
+    } else if (displaySizeY > (720 * 576)) {
+        i4_level = 31;
+    } else if (displaySizeY > (624 * 320)) {
+        i4_level = 30;
+    } else if (displaySizeY > (352 * 288)) {
+        i4_level = 21;
+    } else {
+        i4_level = 20;
+    }
+
+    {
+        iv_num_mem_rec_ip_t s_num_mem_rec_ip;
+        iv_num_mem_rec_op_t s_num_mem_rec_op;
+
+        s_num_mem_rec_ip.u4_size = sizeof(s_num_mem_rec_ip);
+        s_num_mem_rec_op.u4_size = sizeof(s_num_mem_rec_op);
+        s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC;
+
+        ALOGV("Get number of mem records");
+        status = ivdec_api_function(
+                mCodecCtx, (void *)&s_num_mem_rec_ip, (void *)&s_num_mem_rec_op);
+        if (IV_SUCCESS != status) {
+            ALOGE("Error in getting mem records: 0x%x",
+                    s_num_mem_rec_op.u4_error_code);
+            return UNKNOWN_ERROR;
+        }
+
+        mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec;
+    }
+
+    mMemRecords = (iv_mem_rec_t *)ivd_aligned_malloc(
+            128, mNumMemRecords * sizeof(iv_mem_rec_t));
+    if (mMemRecords == NULL) {
+        ALOGE("Allocation failure");
+        return NO_MEMORY;
+    }
+
+    memset(mMemRecords, 0, mNumMemRecords * sizeof(iv_mem_rec_t));
+
+    {
+        size_t i;
+        ivdext_fill_mem_rec_ip_t s_fill_mem_ip;
+        ivdext_fill_mem_rec_op_t s_fill_mem_op;
+        iv_mem_rec_t *ps_mem_rec;
+
+        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size =
+            sizeof(ivdext_fill_mem_rec_ip_t);
+        s_fill_mem_ip.i4_level = i4_level;
+        s_fill_mem_ip.u4_num_reorder_frames = u4_num_reorder_frames;
+        s_fill_mem_ip.u4_num_ref_frames = u4_num_ref_frames;
+        s_fill_mem_ip.u4_share_disp_buf = u4_share_disp_buf;
+        s_fill_mem_ip.u4_num_extra_disp_buf = 0;
+        s_fill_mem_ip.e_output_format = mIvColorFormat;
+
+        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC;
+        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location = mMemRecords;
+        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = displayStride;
+        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = displayHeight;
+        s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size =
+            sizeof(ivdext_fill_mem_rec_op_t);
+
+        ps_mem_rec = mMemRecords;
+        for (i = 0; i < mNumMemRecords; i++) {
+            ps_mem_rec[i].u4_size = sizeof(iv_mem_rec_t);
+        }
+
+        status = ivdec_api_function(
+                mCodecCtx, (void *)&s_fill_mem_ip, (void *)&s_fill_mem_op);
+
+        if (IV_SUCCESS != status) {
+            ALOGE("Error in filling mem records: 0x%x",
+                    s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_error_code);
+            return UNKNOWN_ERROR;
+        }
+        mNumMemRecords =
+            s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_num_mem_rec_filled;
+
+        ps_mem_rec = mMemRecords;
+
+        for (i = 0; i < mNumMemRecords; i++) {
+            ps_mem_rec->pv_base = ivd_aligned_malloc(
+                    ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size);
+            if (ps_mem_rec->pv_base == NULL) {
+                ALOGE("Allocation failure for memory record #%zu of size %u",
+                        i, ps_mem_rec->u4_mem_size);
+                status = IV_FAIL;
+                return NO_MEMORY;
+            }
+
+            ps_mem_rec++;
+        }
+    }
+
+    /* Initialize the decoder */
+    {
+        ivdext_init_ip_t s_init_ip;
+        ivdext_init_op_t s_init_op;
+
+        void *dec_fxns = (void *)ivdec_api_function;
+
+        s_init_ip.s_ivd_init_ip_t.u4_size = sizeof(ivdext_init_ip_t);
+        s_init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT;
+        s_init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords;
+        s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = displayStride;
+        s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = displayHeight;
+
+        s_init_ip.i4_level = i4_level;
+        s_init_ip.u4_num_reorder_frames = u4_num_reorder_frames;
+        s_init_ip.u4_num_ref_frames = u4_num_ref_frames;
+        s_init_ip.u4_share_disp_buf = u4_share_disp_buf;
+        s_init_ip.u4_num_extra_disp_buf = 0;
+
+        s_init_op.s_ivd_init_op_t.u4_size = sizeof(s_init_op);
+
+        s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = mNumMemRecords;
+        s_init_ip.s_ivd_init_ip_t.e_output_format = mIvColorFormat;
+
+        mCodecCtx = (iv_obj_t *)mMemRecords[0].pv_base;
+        mCodecCtx->pv_fxns = dec_fxns;
+        mCodecCtx->u4_size = sizeof(iv_obj_t);
+
+        status = ivdec_api_function(mCodecCtx, (void *)&s_init_ip, (void *)&s_init_op);
+        if (status != IV_SUCCESS) {
+            ALOGE("Error in init: 0x%x",
+                    s_init_op.s_ivd_init_op_t.u4_error_code);
+            return UNKNOWN_ERROR;
+        }
+    }
+
+    /* Reset the plugin state */
+    resetPlugin();
+
+    /* Set the run time (dynamic) parameters */
+    setParams(displayStride);
+
+    /* Set number of cores/threads to be used by the codec */
+    setNumCores();
+
+    /* Get codec version */
+    logVersion();
+
+    /* Allocate internal picture buffer */
+    uint32_t bufferSize = displaySizeY * 3 / 2;
+    mFlushOutBuffer = (uint8_t *)ivd_aligned_malloc(128, bufferSize);
+    if (NULL == mFlushOutBuffer) {
+        ALOGE("Could not allocate flushOutputBuffer of size %zu", bufferSize);
+        return NO_MEMORY;
+    }
+
+    mInitNeeded = false;
+    mFlushNeeded = false;
+    return OK;
+}
+
+status_t SoftAVC::deInitDecoder() {
+    size_t i;
+
+    if (mMemRecords) {
+        iv_mem_rec_t *ps_mem_rec;
+
+        ps_mem_rec = mMemRecords;
+        for (i = 0; i < mNumMemRecords; i++) {
+            if (ps_mem_rec->pv_base) {
+                ivd_aligned_free(ps_mem_rec->pv_base);
+            }
+            ps_mem_rec++;
+        }
+        ivd_aligned_free(mMemRecords);
+        mMemRecords = NULL;
+    }
+
+    if (mFlushOutBuffer) {
+        ivd_aligned_free(mFlushOutBuffer);
+        mFlushOutBuffer = NULL;
+    }
+
+    mInitNeeded = true;
+    mChangingResolution = false;
+
+    return OK;
+}
+
+status_t SoftAVC::reInitDecoder() {
+    status_t ret;
+
+    deInitDecoder();
+
+    ret = initDecoder();
+    if (OK != ret) {
+        ALOGE("Create failure");
+        deInitDecoder();
+        return NO_MEMORY;
+    }
+    return OK;
+}
+
+void SoftAVC::onReset() {
+    SoftVideoDecoderOMXComponent::onReset();
+
+    resetDecoder();
+    resetPlugin();
+}
+
+OMX_ERRORTYPE SoftAVC::internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params) {
+    const uint32_t oldWidth = mWidth;
+    const uint32_t oldHeight = mHeight;
+    OMX_ERRORTYPE ret = SoftVideoDecoderOMXComponent::internalSetParameter(index, params);
+    if (mWidth != oldWidth || mHeight != oldHeight) {
+        reInitDecoder();
+    }
+    return ret;
+}
+
+void SoftAVC::setDecodeArgs(
+        ivd_video_decode_ip_t *ps_dec_ip,
+        ivd_video_decode_op_t *ps_dec_op,
+        OMX_BUFFERHEADERTYPE *inHeader,
+        OMX_BUFFERHEADERTYPE *outHeader,
+        size_t timeStampIx) {
+    size_t sizeY = outputBufferWidth() * outputBufferHeight();
+    size_t sizeUV;
+    uint8_t *pBuf;
+
+    ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t);
+    ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t);
+
+    ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
+
+    /* When in flush and after EOS with zero byte input,
+     * inHeader is set to zero. Hence check for non-null */
+    if (inHeader) {
+        ps_dec_ip->u4_ts = timeStampIx;
+        ps_dec_ip->pv_stream_buffer =
+            inHeader->pBuffer + inHeader->nOffset;
+        ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen;
+    } else {
+        ps_dec_ip->u4_ts = 0;
+        ps_dec_ip->pv_stream_buffer = NULL;
+        ps_dec_ip->u4_num_Bytes = 0;
+    }
+
+    if (outHeader) {
+        pBuf = outHeader->pBuffer;
+    } else {
+        pBuf = mFlushOutBuffer;
+    }
+
+    sizeUV = sizeY / 4;
+    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[0] = sizeY;
+    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[1] = sizeUV;
+    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[2] = sizeUV;
+
+    ps_dec_ip->s_out_buffer.pu1_bufs[0] = pBuf;
+    ps_dec_ip->s_out_buffer.pu1_bufs[1] = pBuf + sizeY;
+    ps_dec_ip->s_out_buffer.pu1_bufs[2] = pBuf + sizeY + sizeUV;
+    ps_dec_ip->s_out_buffer.u4_num_bufs = 3;
+    return;
+}
+void SoftAVC::onPortFlushCompleted(OMX_U32 portIndex) {
+    /* Once the output buffers are flushed, ignore any buffers that are held in decoder */
+    if (kOutputPortIndex == portIndex) {
+        setFlushMode();
+
+        while (true) {
+            ivd_video_decode_ip_t s_dec_ip;
+            ivd_video_decode_op_t s_dec_op;
+            IV_API_CALL_STATUS_T status;
+            size_t sizeY, sizeUV;
+
+            setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, 0);
+
+            status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
+            if (0 == s_dec_op.u4_output_present) {
+                resetPlugin();
+                break;
+            }
+        }
+    }
+}
+
+void SoftAVC::onQueueFilled(OMX_U32 portIndex) {
+    UNUSED(portIndex);
+
+    if (mOutputPortSettingsChange != NONE) {
+        return;
+    }
+
+    List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
+    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
+
+    /* If input EOS is seen and decoder is not in flush mode,
+     * set the decoder in flush mode.
+     * There can be a case where EOS is sent along with last picture data
+     * In that case, only after decoding that input data, decoder has to be
+     * put in flush. This case is handled here  */
+
+    if (mReceivedEOS && !mIsInFlush) {
+        setFlushMode();
+    }
+
+    while (!outQueue.empty()) {
+        BufferInfo *inInfo;
+        OMX_BUFFERHEADERTYPE *inHeader;
+
+        BufferInfo *outInfo;
+        OMX_BUFFERHEADERTYPE *outHeader;
+        size_t timeStampIx;
+
+        inInfo = NULL;
+        inHeader = NULL;
+
+        if (!mIsInFlush) {
+            if (!inQueue.empty()) {
+                inInfo = *inQueue.begin();
+                inHeader = inInfo->mHeader;
+            } else {
+                break;
+            }
+        }
+
+        outInfo = *outQueue.begin();
+        outHeader = outInfo->mHeader;
+        outHeader->nFlags = 0;
+        outHeader->nTimeStamp = 0;
+        outHeader->nOffset = 0;
+
+        if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
+            mReceivedEOS = true;
+            if (inHeader->nFilledLen == 0) {
+                inQueue.erase(inQueue.begin());
+                inInfo->mOwnedByUs = false;
+                notifyEmptyBufferDone(inHeader);
+                inHeader = NULL;
+                setFlushMode();
+            }
+        }
+
+        // When there is an init required and the decoder is not in flush mode,
+        // update output port's definition and reinitialize decoder.
+        if (mInitNeeded && !mIsInFlush) {
+            bool portWillReset = false;
+            handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight);
+
+            CHECK_EQ(reInitDecoder(), (status_t)OK);
+            return;
+        }
+
+        /* Get a free slot in timestamp array to hold input timestamp */
+        {
+            size_t i;
+            timeStampIx = 0;
+            for (i = 0; i < MAX_TIME_STAMPS; i++) {
+                if (!mTimeStampsValid[i]) {
+                    timeStampIx = i;
+                    break;
+                }
+            }
+            if (inHeader != NULL) {
+                mTimeStampsValid[timeStampIx] = true;
+                mTimeStamps[timeStampIx] = inHeader->nTimeStamp;
+            }
+        }
+
+        {
+            ivd_video_decode_ip_t s_dec_ip;
+            ivd_video_decode_op_t s_dec_op;
+            WORD32 timeDelay, timeTaken;
+            size_t sizeY, sizeUV;
+
+            setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx);
+            // If input dump is enabled, then write to file
+            DUMP_TO_FILE(mInFile, s_dec_ip.pv_stream_buffer, s_dec_ip.u4_num_Bytes);
+
+            GETTIME(&mTimeStart, NULL);
+            /* Compute time elapsed between end of previous decode()
+             * to start of current decode() */
+            TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);
+
+            IV_API_CALL_STATUS_T status;
+            status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
+
+            bool unsupportedDimensions =
+                (IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED == (s_dec_op.u4_error_code & 0xFF));
+            bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF));
+
+            GETTIME(&mTimeEnd, NULL);
+            /* Compute time taken for decode() */
+            TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
+
+            PRINT_TIME("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay,
+                   s_dec_op.u4_num_bytes_consumed);
+            if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) {
+                mFlushNeeded = true;
+            }
+
+            if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) {
+                /* If the input did not contain picture data, then ignore
+                 * the associated timestamp */
+                mTimeStampsValid[timeStampIx] = false;
+            }
+
+            // This is needed to handle CTS DecoderTest testCodecResetsH264WithoutSurface,
+            // which is not sending SPS/PPS after port reconfiguration and flush to the codec.
+            if (unsupportedDimensions && !mFlushNeeded) {
+                bool portWillReset = false;
+                handlePortSettingsChange(&portWillReset, s_dec_op.u4_pic_wd, s_dec_op.u4_pic_ht);
+
+                CHECK_EQ(reInitDecoder(), (status_t)OK);
+
+                setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx);
+
+                ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
+                return;
+            }
+
+            // If the decoder is in the changing resolution mode and there is no output present,
+            // that means the switching is done and it's ready to reset the decoder and the plugin.
+            if (mChangingResolution && !s_dec_op.u4_output_present) {
+                mChangingResolution = false;
+                resetDecoder();
+                resetPlugin();
+                continue;
+            }
+
+            if (unsupportedDimensions || resChanged) {
+                mChangingResolution = true;
+                if (mFlushNeeded) {
+                    setFlushMode();
+                }
+
+                if (unsupportedDimensions) {
+                    mNewWidth = s_dec_op.u4_pic_wd;
+                    mNewHeight = s_dec_op.u4_pic_ht;
+                    mInitNeeded = true;
+                }
+                continue;
+            }
+
+            if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) {
+                uint32_t width = s_dec_op.u4_pic_wd;
+                uint32_t height = s_dec_op.u4_pic_ht;
+                bool portWillReset = false;
+                handlePortSettingsChange(&portWillReset, width, height);
+
+                if (portWillReset) {
+                    resetDecoder();
+                    return;
+                }
+            }
+
+            if (s_dec_op.u4_output_present) {
+                outHeader->nFilledLen = (mWidth * mHeight * 3) / 2;
+
+                outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts];
+                mTimeStampsValid[s_dec_op.u4_ts] = false;
+
+                outInfo->mOwnedByUs = false;
+                outQueue.erase(outQueue.begin());
+                outInfo = NULL;
+                notifyFillBufferDone(outHeader);
+                outHeader = NULL;
+            } else {
+                /* If in flush mode and no output is returned by the codec,
+                 * then come out of flush mode */
+                mIsInFlush = false;
+
+                /* If EOS was recieved on input port and there is no output
+                 * from the codec, then signal EOS on output port */
+                if (mReceivedEOS) {
+                    outHeader->nFilledLen = 0;
+                    outHeader->nFlags |= OMX_BUFFERFLAG_EOS;
+
+                    outInfo->mOwnedByUs = false;
+                    outQueue.erase(outQueue.begin());
+                    outInfo = NULL;
+                    notifyFillBufferDone(outHeader);
+                    outHeader = NULL;
+                    resetPlugin();
+                }
+            }
+        }
+
+        if (inHeader != NULL) {
+            inInfo->mOwnedByUs = false;
+            inQueue.erase(inQueue.begin());
+            inInfo = NULL;
+            notifyEmptyBufferDone(inHeader);
+            inHeader = NULL;
+        }
+    }
+}
+
+}  // namespace android
+
+android::SoftOMXComponent *createSoftOMXComponent(
+        const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData,
+        OMX_COMPONENTTYPE **component) {
+    return new android::SoftAVC(name, callbacks, appData, component);
+}
diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.h b/media/libstagefright/codecs/avcdec/SoftAVCDec.h
new file mode 100644
index 0000000..191a71d
--- /dev/null
+++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SOFT_H264_DEC_H_
+
+#define SOFT_H264_DEC_H_
+
+#include "SoftVideoDecoderOMXComponent.h"
+#include <sys/time.h>
+
+namespace android {
+
+#define ivd_aligned_malloc(alignment, size) memalign(alignment, size)
+#define ivd_aligned_free(buf) free(buf)
+
+/** Number of entries in the time-stamp array */
+#define MAX_TIME_STAMPS 64
+
+/** Maximum number of cores supported by the codec */
+#define CODEC_MAX_NUM_CORES 4
+
+#define CODEC_MAX_WIDTH     1920
+
+#define CODEC_MAX_HEIGHT    1088
+
+/** Input buffer size */
+#define INPUT_BUF_SIZE (1024 * 1024)
+
+#define MIN(a, b) ((a) < (b)) ? (a) : (b)
+
+/** Used to remove warnings about unused parameters */
+#define UNUSED(x) ((void)(x))
+
+/** Get time */
+#define GETTIME(a, b) gettimeofday(a, b);
+
+/** Compute difference between start and end */
+#define TIME_DIFF(start, end, diff) \
+    diff = ((end.tv_sec - start.tv_sec) * 1000000) + \
+            (end.tv_usec - start.tv_usec);
+
+struct SoftAVC : public SoftVideoDecoderOMXComponent {
+    SoftAVC(const char *name, const OMX_CALLBACKTYPE *callbacks,
+            OMX_PTR appData, OMX_COMPONENTTYPE **component);
+
+protected:
+    virtual ~SoftAVC();
+
+    virtual void onQueueFilled(OMX_U32 portIndex);
+    virtual void onPortFlushCompleted(OMX_U32 portIndex);
+    virtual void onReset();
+    virtual OMX_ERRORTYPE internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params);
+private:
+    // Number of input and output buffers
+    enum {
+        kNumBuffers = 8
+    };
+
+    iv_obj_t *mCodecCtx;         // Codec context
+    iv_mem_rec_t *mMemRecords;   // Memory records requested by the codec
+    size_t mNumMemRecords;       // Number of memory records requested by the codec
+
+    size_t mNumCores;            // Number of cores to be uesd by the codec
+
+    struct timeval mTimeStart;   // Time at the start of decode()
+    struct timeval mTimeEnd;     // Time at the end of decode()
+
+    // Internal buffer to be used to flush out the buffers from decoder
+    uint8_t *mFlushOutBuffer;
+
+    // Status of entries in the timestamp array
+    bool mTimeStampsValid[MAX_TIME_STAMPS];
+
+    // Timestamp array - Since codec does not take 64 bit timestamps,
+    // they are maintained in the plugin
+    OMX_S64 mTimeStamps[MAX_TIME_STAMPS];
+
+#ifdef FILE_DUMP_ENABLE
+    char mInFile[200];
+#endif /* FILE_DUMP_ENABLE */
+
+    OMX_COLOR_FORMATTYPE mOmxColorFormat;    // OMX Color format
+    IV_COLOR_FORMAT_T mIvColorFormat;        // Ittiam Color format
+
+    bool mIsInFlush;        // codec is flush mode
+    bool mReceivedEOS;      // EOS is receieved on input port
+    bool mInitNeeded;
+    uint32_t mNewWidth;
+    uint32_t mNewHeight;
+    // The input stream has changed to a different resolution, which is still supported by the
+    // codec. So the codec is switching to decode the new resolution.
+    bool mChangingResolution;
+    bool mFlushNeeded;
+
+    status_t initDecoder();
+    status_t deInitDecoder();
+    status_t setFlushMode();
+    status_t setParams(size_t stride);
+    void logVersion();
+    status_t setNumCores();
+    status_t resetDecoder();
+    status_t resetPlugin();
+    status_t reInitDecoder();
+
+    void setDecodeArgs(
+            ivd_video_decode_ip_t *ps_dec_ip,
+            ivd_video_decode_op_t *ps_dec_op,
+            OMX_BUFFERHEADERTYPE *inHeader,
+            OMX_BUFFERHEADERTYPE *outHeader,
+            size_t timeStampIx);
+
+    DISALLOW_EVIL_CONSTRUCTORS(SoftAVC);
+};
+
+#ifdef FILE_DUMP_ENABLE
+
+#define INPUT_DUMP_PATH     "/sdcard/media/avcd_input"
+#define INPUT_DUMP_EXT      "h264"
+
+#define GENERATE_FILE_NAMES() {                         \
+    GETTIME(&mTimeStart, NULL);                         \
+    strcpy(mInFile, "");                                \
+    sprintf(mInFile, "%s_%ld.%ld.%s", INPUT_DUMP_PATH,  \
+            mTimeStart.tv_sec, mTimeStart.tv_usec,      \
+            INPUT_DUMP_EXT);                            \
+}
+
+#define CREATE_DUMP_FILE(m_filename) {                  \
+    FILE *fp = fopen(m_filename, "wb");                 \
+    if (fp != NULL) {                                   \
+        fclose(fp);                                     \
+    } else {                                            \
+        ALOGD("Could not open file %s", m_filename);    \
+    }                                                   \
+}
+#define DUMP_TO_FILE(m_filename, m_buf, m_size)         \
+{                                                       \
+    FILE *fp = fopen(m_filename, "ab");                 \
+    if (fp != NULL && m_buf != NULL) {                  \
+        int i;                                          \
+        i = fwrite(m_buf, 1, m_size, fp);               \
+        ALOGD("fwrite ret %d to write %d", i, m_size);  \
+        if (i != (int) m_size) {                        \
+            ALOGD("Error in fwrite, returned %d", i);   \
+            perror("Error in write to file");           \
+        }                                               \
+        fclose(fp);                                     \
+    } else {                                            \
+        ALOGD("Could not write to file %s", m_filename);\
+    }                                                   \
+}
+#else /* FILE_DUMP_ENABLE */
+#define INPUT_DUMP_PATH
+#define INPUT_DUMP_EXT
+#define OUTPUT_DUMP_PATH
+#define OUTPUT_DUMP_EXT
+#define GENERATE_FILE_NAMES()
+#define CREATE_DUMP_FILE(m_filename)
+#define DUMP_TO_FILE(m_filename, m_buf, m_size)
+#endif /* FILE_DUMP_ENABLE */
+
+} // namespace android
+
+#endif  // SOFT_H264_DEC_H_
diff --git a/media/libstagefright/codecs/avcenc/Android.mk b/media/libstagefright/codecs/avcenc/Android.mk
new file mode 100644
index 0000000..24a4db9
--- /dev/null
+++ b/media/libstagefright/codecs/avcenc/Android.mk
@@ -0,0 +1,30 @@
+#ifeq ($(if $(wildcard external/libh264),1,0),1)
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE            := libstagefright_soft_avcenc
+LOCAL_MODULE_TAGS       := optional
+
+LOCAL_STATIC_LIBRARIES  := libavcenc
+LOCAL_SRC_FILES         := SoftAVCEnc.cpp
+
+LOCAL_C_INCLUDES := $(TOP)/external/libavc/encoder
+LOCAL_C_INCLUDES += $(TOP)/external/libavc/common
+LOCAL_C_INCLUDES += $(TOP)/frameworks/av/media/libstagefright/include
+LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/media/openmax
+LOCAL_C_INCLUDES += $(TOP)/frameworks/av/media/libstagefright/include
+LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/media/hardware
+LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/media/openmax
+
+LOCAL_SHARED_LIBRARIES  := libstagefright
+LOCAL_SHARED_LIBRARIES  += libstagefright_omx
+LOCAL_SHARED_LIBRARIES  += libstagefright_foundation
+LOCAL_SHARED_LIBRARIES  += libutils
+LOCAL_SHARED_LIBRARIES  += liblog
+
+LOCAL_LDFLAGS := -Wl,-Bsymbolic
+
+include $(BUILD_SHARED_LIBRARY)
+
+#endif
diff --git a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
new file mode 100644
index 0000000..bf5e353
--- /dev/null
+++ b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
@@ -0,0 +1,1335 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SoftAVCEnc"
+#include <utils/Log.h>
+#include <utils/misc.h>
+
+#include "OMX_Video.h"
+
+#include <HardwareAPI.h>
+#include <MetadataBufferType.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+#include <ui/Rect.h>
+
+#include "ih264_typedefs.h"
+#include "iv2.h"
+#include "ive2.h"
+#include "ih264e.h"
+#include "SoftAVCEnc.h"
+
+namespace android {
+
+    #define ive_api_function ih264e_api_function
+
+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;
+}
+
+typedef struct LevelConversion {
+    OMX_VIDEO_AVCLEVELTYPE omxLevel;
+    WORD32 avcLevel;
+} LevelConcersion;
+
+static LevelConversion ConversionTable[] = {
+    { OMX_VIDEO_AVCLevel1,  10 },
+    { OMX_VIDEO_AVCLevel1b, 9  },
+    { OMX_VIDEO_AVCLevel11, 11 },
+    { OMX_VIDEO_AVCLevel12, 12 },
+    { OMX_VIDEO_AVCLevel13, 13 },
+    { OMX_VIDEO_AVCLevel2,  20 },
+    { OMX_VIDEO_AVCLevel21, 21 },
+    { OMX_VIDEO_AVCLevel22, 22 },
+    { OMX_VIDEO_AVCLevel3,  30 },
+    { OMX_VIDEO_AVCLevel31, 31 },
+    { OMX_VIDEO_AVCLevel32, 32 },
+    { OMX_VIDEO_AVCLevel4,  40 },
+    { OMX_VIDEO_AVCLevel41, 41 },
+    { OMX_VIDEO_AVCLevel42, 42 },
+    { OMX_VIDEO_AVCLevel5,  50 },
+    { OMX_VIDEO_AVCLevel51, 51 },
+};
+
+static const CodecProfileLevel kProfileLevels[] = {
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1  },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1b },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel11 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel12 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel13 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel2  },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel21 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel22 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel3  },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel31 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel32 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel4  },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel41 },
+};
+
+
+static size_t GetCPUCoreCount() {
+    long cpuCoreCount = 1;
+#if defined(_SC_NPROCESSORS_ONLN)
+    cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
+#else
+    // _SC_NPROC_ONLN must be defined...
+    cpuCoreCount = sysconf(_SC_NPROC_ONLN);
+#endif
+    CHECK(cpuCoreCount >= 1);
+    ALOGD("Number of CPU cores: %ld", cpuCoreCount);
+    return (size_t)cpuCoreCount;
+}
+
+static status_t ConvertOmxAvcLevelToAvcSpecLevel(
+        OMX_VIDEO_AVCLEVELTYPE omxLevel, WORD32 *avcLevel) {
+    for (size_t i = 0; i < NELEM(ConversionTable); ++i) {
+        if (omxLevel == ConversionTable[i].omxLevel) {
+            *avcLevel = ConversionTable[i].avcLevel;
+            return OK;
+        }
+    }
+
+    ALOGE("ConvertOmxAvcLevelToAvcSpecLevel: %d level not supported",
+            (int32_t)omxLevel);
+
+    return BAD_VALUE;
+}
+
+static status_t ConvertAvcSpecLevelToOmxAvcLevel(
+        WORD32 avcLevel, OMX_VIDEO_AVCLEVELTYPE *omxLevel) {
+    for (size_t i = 0; i < NELEM(ConversionTable); ++i) {
+        if (avcLevel == ConversionTable[i].avcLevel) {
+            *omxLevel = ConversionTable[i].omxLevel;
+            return OK;
+        }
+    }
+
+    ALOGE("ConvertAvcSpecLevelToOmxAvcLevel: %d level not supported",
+            (int32_t)avcLevel);
+
+    return BAD_VALUE;
+}
+
+
+SoftAVC::SoftAVC(
+        const char *name,
+        const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData,
+        OMX_COMPONENTTYPE **component)
+    : SoftVideoEncoderOMXComponent(
+            name, "video_encoder.avc", OMX_VIDEO_CodingAVC,
+            kProfileLevels, NELEM(kProfileLevels),
+            176 /* width */, 144 /* height */,
+            callbacks, appData, component),
+      mIvVideoColorFormat(IV_YUV_420P),
+      mIDRFrameRefreshIntervalInSec(1),
+      mAVCEncProfile(IV_PROFILE_BASE),
+      mAVCEncLevel(31),
+      mPrevTimestampUs(-1),
+      mStarted(false),
+      mSawInputEOS(false),
+      mSignalledError(false),
+      mConversionBuffer(NULL),
+      mCodecCtx(NULL) {
+
+    initPorts(kNumBuffers, kNumBuffers, ((mWidth * mHeight * 3) >> 1),
+            MEDIA_MIMETYPE_VIDEO_AVC, 2);
+
+    // If dump is enabled, then open create an empty file
+    GENERATE_FILE_NAMES();
+    CREATE_DUMP_FILE(mInFile);
+    CREATE_DUMP_FILE(mOutFile);
+
+}
+
+SoftAVC::~SoftAVC() {
+    releaseEncoder();
+    List<BufferInfo *> &outQueue = getPortQueue(1);
+    List<BufferInfo *> &inQueue = getPortQueue(0);
+    CHECK(outQueue.empty());
+    CHECK(inQueue.empty());
+}
+
+OMX_ERRORTYPE SoftAVC::initEncParams() {
+    mCodecCtx = NULL;
+    mMemRecords = NULL;
+    mNumMemRecords = DEFAULT_MEM_REC_CNT;
+    mHeaderGenerated = 0;
+    mNumCores = GetCPUCoreCount();
+    mArch = DEFAULT_ARCH;
+    mSliceMode = DEFAULT_SLICE_MODE;
+    mSliceParam = DEFAULT_SLICE_PARAM;
+    mHalfPelEnable = DEFAULT_HPEL;
+    mIInterval = DEFAULT_I_INTERVAL;
+    mIDRInterval = DEFAULT_IDR_INTERVAL;
+    mDisableDeblkLevel = DEFAULT_DISABLE_DEBLK_LEVEL;
+    mFrameRate = DEFAULT_SRC_FRAME_RATE;
+    mEnableFastSad = DEFAULT_ENABLE_FAST_SAD;
+    mEnableAltRef = DEFAULT_ENABLE_ALT_REF;
+    mEncSpeed = DEFAULT_ENC_SPEED;
+    mIntra4x4 = DEFAULT_INTRA4x4;
+    mAIRMode = DEFAULT_AIR;
+    mAIRRefreshPeriod = DEFAULT_AIR_REFRESH_PERIOD;
+    mPSNREnable = DEFAULT_PSNR_ENABLE;
+    mReconEnable = DEFAULT_RECON_ENABLE;
+
+    gettimeofday(&mTimeStart, NULL);
+    gettimeofday(&mTimeEnd, NULL);
+
+    return OMX_ErrorNone;
+}
+
+
+OMX_ERRORTYPE SoftAVC::setDimensions() {
+    ive_ctl_set_dimensions_ip_t s_dimensions_ip;
+    ive_ctl_set_dimensions_op_t s_dimensions_op;
+    IV_STATUS_T status;
+
+    s_dimensions_ip.e_cmd = IVE_CMD_VIDEO_CTL;
+    s_dimensions_ip.e_sub_cmd = IVE_CMD_CTL_SET_DIMENSIONS;
+    s_dimensions_ip.u4_ht = mHeight;
+    s_dimensions_ip.u4_wd = mWidth;
+    s_dimensions_ip.u4_strd = mStride;
+
+    s_dimensions_ip.u4_timestamp_high = -1;
+    s_dimensions_ip.u4_timestamp_low = -1;
+
+    s_dimensions_ip.u4_size = sizeof(ive_ctl_set_dimensions_ip_t);
+    s_dimensions_op.u4_size = sizeof(ive_ctl_set_dimensions_op_t);
+
+    status = ive_api_function(mCodecCtx, &s_dimensions_ip, &s_dimensions_op);
+    if (status != IV_SUCCESS) {
+        ALOGE("Unable to set frame dimensions = 0x%x\n",
+                s_dimensions_op.u4_error_code);
+        return OMX_ErrorUndefined;
+    }
+    return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SoftAVC::setNumCores() {
+    IV_STATUS_T status;
+    ive_ctl_set_num_cores_ip_t s_num_cores_ip;
+    ive_ctl_set_num_cores_op_t s_num_cores_op;
+    s_num_cores_ip.e_cmd = IVE_CMD_VIDEO_CTL;
+    s_num_cores_ip.e_sub_cmd = IVE_CMD_CTL_SET_NUM_CORES;
+    s_num_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_CORES);
+    s_num_cores_ip.u4_timestamp_high = -1;
+    s_num_cores_ip.u4_timestamp_low = -1;
+    s_num_cores_ip.u4_size = sizeof(ive_ctl_set_num_cores_ip_t);
+
+    s_num_cores_op.u4_size = sizeof(ive_ctl_set_num_cores_op_t);
+
+    status = ive_api_function(
+            mCodecCtx, (void *) &s_num_cores_ip, (void *) &s_num_cores_op);
+    if (status != IV_SUCCESS) {
+        ALOGE("Unable to set processor params = 0x%x\n",
+                s_num_cores_op.u4_error_code);
+        return OMX_ErrorUndefined;
+    }
+    return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SoftAVC::setFrameRate() {
+    ive_ctl_set_frame_rate_ip_t s_frame_rate_ip;
+    ive_ctl_set_frame_rate_op_t s_frame_rate_op;
+    IV_STATUS_T status;
+
+    s_frame_rate_ip.e_cmd = IVE_CMD_VIDEO_CTL;
+    s_frame_rate_ip.e_sub_cmd = IVE_CMD_CTL_SET_FRAMERATE;
+
+    s_frame_rate_ip.u4_src_frame_rate = mFrameRate;
+    s_frame_rate_ip.u4_tgt_frame_rate = mFrameRate;
+
+    s_frame_rate_ip.u4_timestamp_high = -1;
+    s_frame_rate_ip.u4_timestamp_low = -1;
+
+    s_frame_rate_ip.u4_size = sizeof(ive_ctl_set_frame_rate_ip_t);
+    s_frame_rate_op.u4_size = sizeof(ive_ctl_set_frame_rate_op_t);
+
+    status = ive_api_function(mCodecCtx, &s_frame_rate_ip, &s_frame_rate_op);
+    if (status != IV_SUCCESS) {
+        ALOGE("Unable to set frame rate = 0x%x\n",
+                s_frame_rate_op.u4_error_code);
+        return OMX_ErrorUndefined;
+    }
+    return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SoftAVC::setIpeParams() {
+    ive_ctl_set_ipe_params_ip_t s_ipe_params_ip;
+    ive_ctl_set_ipe_params_op_t s_ipe_params_op;
+    IV_STATUS_T status;
+
+    s_ipe_params_ip.e_cmd = IVE_CMD_VIDEO_CTL;
+    s_ipe_params_ip.e_sub_cmd = IVE_CMD_CTL_SET_IPE_PARAMS;
+
+    s_ipe_params_ip.u4_enable_intra_4x4 = mIntra4x4;
+    s_ipe_params_ip.u4_enc_speed_preset = mEncSpeed;
+
+    s_ipe_params_ip.u4_timestamp_high = -1;
+    s_ipe_params_ip.u4_timestamp_low = -1;
+
+    s_ipe_params_ip.u4_size = sizeof(ive_ctl_set_ipe_params_ip_t);
+    s_ipe_params_op.u4_size = sizeof(ive_ctl_set_ipe_params_op_t);
+
+    status = ive_api_function(mCodecCtx, &s_ipe_params_ip, &s_ipe_params_op);
+    if (status != IV_SUCCESS) {
+        ALOGE("Unable to set ipe params = 0x%x\n",
+                s_ipe_params_op.u4_error_code);
+        return OMX_ErrorUndefined;
+    }
+    return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SoftAVC::setBitRate() {
+    ive_ctl_set_bitrate_ip_t s_bitrate_ip;
+    ive_ctl_set_bitrate_op_t s_bitrate_op;
+    IV_STATUS_T status;
+
+    s_bitrate_ip.e_cmd = IVE_CMD_VIDEO_CTL;
+    s_bitrate_ip.e_sub_cmd = IVE_CMD_CTL_SET_BITRATE;
+
+    s_bitrate_ip.u4_target_bitrate = mBitrate;
+
+    s_bitrate_ip.u4_timestamp_high = -1;
+    s_bitrate_ip.u4_timestamp_low = -1;
+
+    s_bitrate_ip.u4_size = sizeof(ive_ctl_set_bitrate_ip_t);
+    s_bitrate_op.u4_size = sizeof(ive_ctl_set_bitrate_op_t);
+
+    status = ive_api_function(mCodecCtx, &s_bitrate_ip, &s_bitrate_op);
+    if (status != IV_SUCCESS) {
+        ALOGE("Unable to set bit rate = 0x%x\n", s_bitrate_op.u4_error_code);
+        return OMX_ErrorUndefined;
+    }
+    return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SoftAVC::setFrameType(IV_PICTURE_CODING_TYPE_T e_frame_type) {
+    ive_ctl_set_frame_type_ip_t s_frame_type_ip;
+    ive_ctl_set_frame_type_op_t s_frame_type_op;
+    IV_STATUS_T status;
+
+    s_frame_type_ip.e_cmd = IVE_CMD_VIDEO_CTL;
+    s_frame_type_ip.e_sub_cmd = IVE_CMD_CTL_SET_FRAMETYPE;
+
+    s_frame_type_ip.e_frame_type = e_frame_type;
+
+    s_frame_type_ip.u4_timestamp_high = -1;
+    s_frame_type_ip.u4_timestamp_low = -1;
+
+    s_frame_type_ip.u4_size = sizeof(ive_ctl_set_frame_type_ip_t);
+    s_frame_type_op.u4_size = sizeof(ive_ctl_set_frame_type_op_t);
+
+    status = ive_api_function(mCodecCtx, &s_frame_type_ip, &s_frame_type_op);
+    if (status != IV_SUCCESS) {
+        ALOGE("Unable to set frame type = 0x%x\n",
+                s_frame_type_op.u4_error_code);
+        return OMX_ErrorUndefined;
+    }
+    return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SoftAVC::setQp() {
+    ive_ctl_set_qp_ip_t s_qp_ip;
+    ive_ctl_set_qp_op_t s_qp_op;
+    IV_STATUS_T status;
+
+    s_qp_ip.e_cmd = IVE_CMD_VIDEO_CTL;
+    s_qp_ip.e_sub_cmd = IVE_CMD_CTL_SET_QP;
+
+    s_qp_ip.u4_i_qp = DEFAULT_I_QP;
+    s_qp_ip.u4_i_qp_max = DEFAULT_QP_MAX;
+    s_qp_ip.u4_i_qp_min = DEFAULT_QP_MIN;
+
+    s_qp_ip.u4_p_qp = DEFAULT_P_QP;
+    s_qp_ip.u4_p_qp_max = DEFAULT_QP_MAX;
+    s_qp_ip.u4_p_qp_min = DEFAULT_QP_MIN;
+
+    s_qp_ip.u4_b_qp = DEFAULT_P_QP;
+    s_qp_ip.u4_b_qp_max = DEFAULT_QP_MAX;
+    s_qp_ip.u4_b_qp_min = DEFAULT_QP_MIN;
+
+    s_qp_ip.u4_timestamp_high = -1;
+    s_qp_ip.u4_timestamp_low = -1;
+
+    s_qp_ip.u4_size = sizeof(ive_ctl_set_qp_ip_t);
+    s_qp_op.u4_size = sizeof(ive_ctl_set_qp_op_t);
+
+    status = ive_api_function(mCodecCtx, &s_qp_ip, &s_qp_op);
+    if (status != IV_SUCCESS) {
+        ALOGE("Unable to set qp 0x%x\n", s_qp_op.u4_error_code);
+        return OMX_ErrorUndefined;
+    }
+    return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SoftAVC::setEncMode(IVE_ENC_MODE_T e_enc_mode) {
+    IV_STATUS_T status;
+    ive_ctl_set_enc_mode_ip_t s_enc_mode_ip;
+    ive_ctl_set_enc_mode_op_t s_enc_mode_op;
+
+    s_enc_mode_ip.e_cmd = IVE_CMD_VIDEO_CTL;
+    s_enc_mode_ip.e_sub_cmd = IVE_CMD_CTL_SET_ENC_MODE;
+
+    s_enc_mode_ip.e_enc_mode = e_enc_mode;
+
+    s_enc_mode_ip.u4_timestamp_high = -1;
+    s_enc_mode_ip.u4_timestamp_low = -1;
+
+    s_enc_mode_ip.u4_size = sizeof(ive_ctl_set_enc_mode_ip_t);
+    s_enc_mode_op.u4_size = sizeof(ive_ctl_set_enc_mode_op_t);
+
+    status = ive_api_function(mCodecCtx, &s_enc_mode_ip, &s_enc_mode_op);
+    if (status != IV_SUCCESS) {
+        ALOGE("Unable to set in header encode mode = 0x%x\n",
+                s_enc_mode_op.u4_error_code);
+        return OMX_ErrorUndefined;
+    }
+    return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SoftAVC::setVbvParams() {
+    ive_ctl_set_vbv_params_ip_t s_vbv_ip;
+    ive_ctl_set_vbv_params_op_t s_vbv_op;
+    IV_STATUS_T status;
+
+    s_vbv_ip.e_cmd = IVE_CMD_VIDEO_CTL;
+    s_vbv_ip.e_sub_cmd = IVE_CMD_CTL_SET_VBV_PARAMS;
+
+    s_vbv_ip.u4_vbv_buf_size = 0;
+    s_vbv_ip.u4_vbv_buffer_delay = 1000;
+
+    s_vbv_ip.u4_timestamp_high = -1;
+    s_vbv_ip.u4_timestamp_low = -1;
+
+    s_vbv_ip.u4_size = sizeof(ive_ctl_set_vbv_params_ip_t);
+    s_vbv_op.u4_size = sizeof(ive_ctl_set_vbv_params_op_t);
+
+    status = ive_api_function(mCodecCtx, &s_vbv_ip, &s_vbv_op);
+    if (status != IV_SUCCESS) {
+        ALOGE("Unable to set VBC params = 0x%x\n", s_vbv_op.u4_error_code);
+        return OMX_ErrorUndefined;
+    }
+    return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SoftAVC::setAirParams() {
+    ive_ctl_set_air_params_ip_t s_air_ip;
+    ive_ctl_set_air_params_op_t s_air_op;
+    IV_STATUS_T status;
+
+    s_air_ip.e_cmd = IVE_CMD_VIDEO_CTL;
+    s_air_ip.e_sub_cmd = IVE_CMD_CTL_SET_AIR_PARAMS;
+
+    s_air_ip.e_air_mode = mAIRMode;
+    s_air_ip.u4_air_refresh_period = mAIRRefreshPeriod;
+
+    s_air_ip.u4_timestamp_high = -1;
+    s_air_ip.u4_timestamp_low = -1;
+
+    s_air_ip.u4_size = sizeof(ive_ctl_set_air_params_ip_t);
+    s_air_op.u4_size = sizeof(ive_ctl_set_air_params_op_t);
+
+    status = ive_api_function(mCodecCtx, &s_air_ip, &s_air_op);
+    if (status != IV_SUCCESS) {
+        ALOGE("Unable to set air params = 0x%x\n", s_air_op.u4_error_code);
+        return OMX_ErrorUndefined;
+    }
+    return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SoftAVC::setMeParams() {
+    IV_STATUS_T status;
+    ive_ctl_set_me_params_ip_t s_me_params_ip;
+    ive_ctl_set_me_params_op_t s_me_params_op;
+
+    s_me_params_ip.e_cmd = IVE_CMD_VIDEO_CTL;
+    s_me_params_ip.e_sub_cmd = IVE_CMD_CTL_SET_ME_PARAMS;
+
+    s_me_params_ip.u4_enable_fast_sad = mEnableFastSad;
+    s_me_params_ip.u4_enable_alt_ref = mEnableAltRef;
+
+    s_me_params_ip.u4_enable_hpel = mHalfPelEnable;
+    s_me_params_ip.u4_enable_qpel = DEFAULT_QPEL;
+    s_me_params_ip.u4_me_speed_preset = DEFAULT_ME_SPEED;
+    s_me_params_ip.u4_srch_rng_x = DEFAULT_SRCH_RNG_X;
+    s_me_params_ip.u4_srch_rng_y = DEFAULT_SRCH_RNG_Y;
+
+    s_me_params_ip.u4_timestamp_high = -1;
+    s_me_params_ip.u4_timestamp_low = -1;
+
+    s_me_params_ip.u4_size = sizeof(ive_ctl_set_me_params_ip_t);
+    s_me_params_op.u4_size = sizeof(ive_ctl_set_me_params_op_t);
+
+    status = ive_api_function(mCodecCtx, &s_me_params_ip, &s_me_params_op);
+    if (status != IV_SUCCESS) {
+        ALOGE("Unable to set me params = 0x%x\n", s_me_params_op.u4_error_code);
+        return OMX_ErrorUndefined;
+    }
+    return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SoftAVC::setGopParams() {
+    IV_STATUS_T status;
+    ive_ctl_set_gop_params_ip_t s_gop_params_ip;
+    ive_ctl_set_gop_params_op_t s_gop_params_op;
+
+    s_gop_params_ip.e_cmd = IVE_CMD_VIDEO_CTL;
+    s_gop_params_ip.e_sub_cmd = IVE_CMD_CTL_SET_GOP_PARAMS;
+
+    s_gop_params_ip.u4_i_frm_interval = mIInterval;
+    s_gop_params_ip.u4_idr_frm_interval = mIDRInterval;
+    s_gop_params_ip.u4_num_b_frames = DEFAULT_B_FRAMES;
+
+    s_gop_params_ip.u4_timestamp_high = -1;
+    s_gop_params_ip.u4_timestamp_low = -1;
+
+    s_gop_params_ip.u4_size = sizeof(ive_ctl_set_gop_params_ip_t);
+    s_gop_params_op.u4_size = sizeof(ive_ctl_set_gop_params_op_t);
+
+    status = ive_api_function(mCodecCtx, &s_gop_params_ip, &s_gop_params_op);
+    if (status != IV_SUCCESS) {
+        ALOGE("Unable to set ME params = 0x%x\n",
+                s_gop_params_op.u4_error_code);
+        return OMX_ErrorUndefined;
+    }
+    return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SoftAVC::setProfileParams() {
+    IV_STATUS_T status;
+    ive_ctl_set_profile_params_ip_t s_profile_params_ip;
+    ive_ctl_set_profile_params_op_t s_profile_params_op;
+
+    s_profile_params_ip.e_cmd = IVE_CMD_VIDEO_CTL;
+    s_profile_params_ip.e_sub_cmd = IVE_CMD_CTL_SET_PROFILE_PARAMS;
+
+    s_profile_params_ip.e_profile = DEFAULT_EPROFILE;
+
+    s_profile_params_ip.u4_timestamp_high = -1;
+    s_profile_params_ip.u4_timestamp_low = -1;
+
+    s_profile_params_ip.u4_size = sizeof(ive_ctl_set_profile_params_ip_t);
+    s_profile_params_op.u4_size = sizeof(ive_ctl_set_profile_params_op_t);
+
+    status = ive_api_function(mCodecCtx, &s_profile_params_ip, &s_profile_params_op);
+    if (status != IV_SUCCESS) {
+        ALOGE("Unable to set profile params = 0x%x\n",
+                s_profile_params_op.u4_error_code);
+        return OMX_ErrorUndefined;
+    }
+    return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SoftAVC::setDeblockParams() {
+    IV_STATUS_T status;
+    ive_ctl_set_deblock_params_ip_t s_deblock_params_ip;
+    ive_ctl_set_deblock_params_op_t s_deblock_params_op;
+
+    s_deblock_params_ip.e_cmd = IVE_CMD_VIDEO_CTL;
+    s_deblock_params_ip.e_sub_cmd = IVE_CMD_CTL_SET_DEBLOCK_PARAMS;
+
+    s_deblock_params_ip.u4_disable_deblock_level = mDisableDeblkLevel;
+
+    s_deblock_params_ip.u4_timestamp_high = -1;
+    s_deblock_params_ip.u4_timestamp_low = -1;
+
+    s_deblock_params_ip.u4_size = sizeof(ive_ctl_set_deblock_params_ip_t);
+    s_deblock_params_op.u4_size = sizeof(ive_ctl_set_deblock_params_op_t);
+
+    status = ive_api_function(mCodecCtx, &s_deblock_params_ip, &s_deblock_params_op);
+    if (status != IV_SUCCESS) {
+        ALOGE("Unable to enable/disable deblock params = 0x%x\n",
+                s_deblock_params_op.u4_error_code);
+        return OMX_ErrorUndefined;
+    }
+    return OMX_ErrorNone;
+}
+
+void SoftAVC::logVersion() {
+    ive_ctl_getversioninfo_ip_t s_ctl_ip;
+    ive_ctl_getversioninfo_op_t s_ctl_op;
+    UWORD8 au1_buf[512];
+    IV_STATUS_T status;
+
+    s_ctl_ip.e_cmd = IVE_CMD_VIDEO_CTL;
+    s_ctl_ip.e_sub_cmd = IVE_CMD_CTL_GETVERSION;
+    s_ctl_ip.u4_size = sizeof(ive_ctl_getversioninfo_ip_t);
+    s_ctl_op.u4_size = sizeof(ive_ctl_getversioninfo_op_t);
+    s_ctl_ip.pu1_version = au1_buf;
+    s_ctl_ip.u4_version_bufsize = sizeof(au1_buf);
+
+    status = ive_api_function(mCodecCtx, (void *) &s_ctl_ip, (void *) &s_ctl_op);
+
+    if (status != IV_SUCCESS) {
+        ALOGE("Error in getting version: 0x%x", s_ctl_op.u4_error_code);
+    } else {
+        ALOGV("Ittiam encoder version: %s", (char *)s_ctl_ip.pu1_version);
+    }
+    return;
+}
+
+OMX_ERRORTYPE SoftAVC::initEncoder() {
+    IV_STATUS_T status;
+    size_t i;
+    WORD32 level;
+    uint32_t displaySizeY;
+    CHECK(!mStarted);
+
+    OMX_ERRORTYPE errType = OMX_ErrorNone;
+
+    displaySizeY = mWidth * mHeight;
+    if (displaySizeY > (1920 * 1088)) {
+        level = 50;
+    } else if (displaySizeY > (1280 * 720)) {
+        level = 40;
+    } else if (displaySizeY > (720 * 576)) {
+        level = 31;
+    } else if (displaySizeY > (624 * 320)) {
+        level = 30;
+    } else if (displaySizeY > (352 * 288)) {
+        level = 21;
+    } else {
+        level = 20;
+    }
+    mAVCEncLevel = MAX(level, mAVCEncLevel);
+
+    if (OMX_ErrorNone != (errType = initEncParams())) {
+        ALOGE("Failed to initialize encoder params");
+        mSignalledError = true;
+        notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
+        return errType;
+    }
+
+    mStride = ALIGN16(mWidth);
+
+    if (mInputDataIsMeta) {
+        if (mConversionBuffer) {
+            free(mConversionBuffer);
+            mConversionBuffer = NULL;
+        }
+
+        if (mConversionBuffer == NULL) {
+            mConversionBuffer = (uint8_t *)malloc(mStride * mHeight * 3 / 2);
+            if (mConversionBuffer == NULL) {
+                ALOGE("Allocating conversion buffer failed.");
+                return OMX_ErrorUndefined;
+            }
+        }
+    }
+
+    switch (mColorFormat) {
+        case OMX_COLOR_FormatYUV420SemiPlanar:
+            mIvVideoColorFormat = IV_YUV_420SP_UV;
+            ALOGV("colorFormat YUV_420SP");
+            break;
+        default:
+        case OMX_COLOR_FormatYUV420Planar:
+            mIvVideoColorFormat = IV_YUV_420P;
+            ALOGV("colorFormat YUV_420P");
+            break;
+    }
+
+    ALOGV("Params width %d height %d level %d colorFormat %d", mWidth,
+            mHeight, mAVCEncLevel, mIvVideoColorFormat);
+
+    /* Getting Number of MemRecords */
+    {
+        iv_num_mem_rec_ip_t s_num_mem_rec_ip;
+        iv_num_mem_rec_op_t s_num_mem_rec_op;
+
+        s_num_mem_rec_ip.u4_size = sizeof(iv_num_mem_rec_ip_t);
+        s_num_mem_rec_op.u4_size = sizeof(iv_num_mem_rec_op_t);
+
+        s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC;
+
+        status = ive_api_function(0, &s_num_mem_rec_ip, &s_num_mem_rec_op);
+
+        if (status != IV_SUCCESS) {
+            ALOGE("Get number of memory records failed = 0x%x\n",
+                    s_num_mem_rec_op.u4_error_code);
+            return OMX_ErrorUndefined;
+        }
+
+        mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec;
+    }
+
+    /* Allocate array to hold memory records */
+    mMemRecords = (iv_mem_rec_t *)malloc(mNumMemRecords * sizeof(iv_mem_rec_t));
+    if (NULL == mMemRecords) {
+        ALOGE("Unable to allocate memory for hold memory records: Size %d",
+                mNumMemRecords * sizeof(iv_mem_rec_t));
+        mSignalledError = true;
+        notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
+        return OMX_ErrorUndefined;
+    }
+
+    {
+        iv_mem_rec_t *ps_mem_rec;
+        ps_mem_rec = mMemRecords;
+        for (i = 0; i < mNumMemRecords; i++) {
+            ps_mem_rec->u4_size = sizeof(iv_mem_rec_t);
+            ps_mem_rec->pv_base = NULL;
+            ps_mem_rec->u4_mem_size = 0;
+            ps_mem_rec->u4_mem_alignment = 0;
+            ps_mem_rec->e_mem_type = IV_NA_MEM_TYPE;
+
+            ps_mem_rec++;
+        }
+    }
+
+    /* Getting MemRecords Attributes */
+    {
+        iv_fill_mem_rec_ip_t s_fill_mem_rec_ip;
+        iv_fill_mem_rec_op_t s_fill_mem_rec_op;
+
+        s_fill_mem_rec_ip.u4_size = sizeof(iv_fill_mem_rec_ip_t);
+        s_fill_mem_rec_op.u4_size = sizeof(iv_fill_mem_rec_op_t);
+
+        s_fill_mem_rec_ip.e_cmd = IV_CMD_FILL_NUM_MEM_REC;
+        s_fill_mem_rec_ip.ps_mem_rec = mMemRecords;
+        s_fill_mem_rec_ip.u4_num_mem_rec = mNumMemRecords;
+        s_fill_mem_rec_ip.u4_max_wd = mWidth;
+        s_fill_mem_rec_ip.u4_max_ht = mHeight;
+        s_fill_mem_rec_ip.u4_max_level = mAVCEncLevel;
+        s_fill_mem_rec_ip.e_color_format = DEFAULT_INP_COLOR_FORMAT;
+        s_fill_mem_rec_ip.u4_max_ref_cnt = DEFAULT_MAX_REF_FRM;
+        s_fill_mem_rec_ip.u4_max_reorder_cnt = DEFAULT_MAX_REORDER_FRM;
+        s_fill_mem_rec_ip.u4_max_srch_rng_x = DEFAULT_MAX_SRCH_RANGE_X;
+        s_fill_mem_rec_ip.u4_max_srch_rng_y = DEFAULT_MAX_SRCH_RANGE_Y;
+
+        status = ive_api_function(0, &s_fill_mem_rec_ip, &s_fill_mem_rec_op);
+
+        if (status != IV_SUCCESS) {
+            ALOGE("Fill memory records failed = 0x%x\n",
+                    s_fill_mem_rec_op.u4_error_code);
+            mSignalledError = true;
+            notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
+            return OMX_ErrorUndefined;
+        }
+    }
+
+    /* Allocating Memory for Mem Records */
+    {
+        WORD32 total_size;
+        iv_mem_rec_t *ps_mem_rec;
+        total_size = 0;
+
+        ps_mem_rec = mMemRecords;
+        for (i = 0; i < mNumMemRecords; i++) {
+            ps_mem_rec->pv_base = ive_aligned_malloc(
+                    ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size);
+            if (ps_mem_rec->pv_base == NULL) {
+                ALOGE("Allocation failure for mem record id %d size %d\n", i,
+                        ps_mem_rec->u4_mem_size);
+                mSignalledError = true;
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
+                return OMX_ErrorUndefined;
+
+            }
+            total_size += ps_mem_rec->u4_mem_size;
+
+            ps_mem_rec++;
+        }
+        printf("\nTotal memory for codec %d\n", total_size);
+    }
+
+    /* Codec Instance Creation */
+    {
+        ive_init_ip_t s_init_ip;
+        ive_init_op_t s_init_op;
+
+        mCodecCtx = (iv_obj_t *)mMemRecords[0].pv_base;
+        mCodecCtx->u4_size = sizeof(iv_obj_t);
+        mCodecCtx->pv_fxns = (void *)ive_api_function;
+
+        s_init_ip.u4_size = sizeof(ive_init_ip_t);
+        s_init_op.u4_size = sizeof(ive_init_op_t);
+
+        s_init_ip.e_cmd = IV_CMD_INIT;
+        s_init_ip.u4_num_mem_rec = mNumMemRecords;
+        s_init_ip.ps_mem_rec = mMemRecords;
+        s_init_ip.u4_max_wd = mWidth;
+        s_init_ip.u4_max_ht = mHeight;
+        s_init_ip.u4_max_ref_cnt = DEFAULT_MAX_REF_FRM;
+        s_init_ip.u4_max_reorder_cnt = DEFAULT_MAX_REORDER_FRM;
+        s_init_ip.u4_max_level = mAVCEncLevel;
+        s_init_ip.e_inp_color_fmt = mIvVideoColorFormat;
+
+        if (mReconEnable || mPSNREnable) {
+            s_init_ip.u4_enable_recon = 1;
+        } else {
+            s_init_ip.u4_enable_recon = 0;
+        }
+        s_init_ip.e_recon_color_fmt = DEFAULT_RECON_COLOR_FORMAT;
+        s_init_ip.e_rc_mode = DEFAULT_RC_MODE;
+        s_init_ip.u4_max_framerate = DEFAULT_MAX_FRAMERATE;
+        s_init_ip.u4_max_bitrate = DEFAULT_MAX_BITRATE;
+        s_init_ip.u4_max_num_bframes = DEFAULT_B_FRAMES;
+        s_init_ip.e_content_type = IV_PROGRESSIVE;
+        s_init_ip.u4_max_srch_rng_x = DEFAULT_MAX_SRCH_RANGE_X;
+        s_init_ip.u4_max_srch_rng_y = DEFAULT_MAX_SRCH_RANGE_Y;
+        s_init_ip.e_slice_mode = mSliceMode;
+        s_init_ip.u4_slice_param = mSliceParam;
+        s_init_ip.e_arch = mArch;
+        s_init_ip.e_soc = DEFAULT_SOC;
+
+        status = ive_api_function(mCodecCtx, &s_init_ip, &s_init_op);
+
+        if (status != IV_SUCCESS) {
+            ALOGE("Init memory records failed = 0x%x\n",
+                    s_init_op.u4_error_code);
+            mSignalledError = true;
+            notify(OMX_EventError, OMX_ErrorUndefined, 0 /* arg2 */, NULL /* data */);
+            return OMX_ErrorUndefined;
+        }
+    }
+
+    /* Get Codec Version */
+    logVersion();
+
+    /* set processor details */
+    setNumCores();
+
+    /* Video control Set Frame dimensions */
+    setDimensions();
+
+    /* Video control Set Frame rates */
+    setFrameRate();
+
+    /* Video control Set IPE Params */
+    setIpeParams();
+
+    /* Video control Set Bitrate */
+    setBitRate();
+
+    /* Video control Set QP */
+    setQp();
+
+    /* Video control Set AIR params */
+    setAirParams();
+
+    /* Video control Set VBV params */
+    setVbvParams();
+
+    /* Video control Set Motion estimation params */
+    setMeParams();
+
+    /* Video control Set GOP params */
+    setGopParams();
+
+    /* Video control Set Deblock params */
+    setDeblockParams();
+
+    /* Video control Set Profile params */
+    setProfileParams();
+
+    /* Video control Set in Encode header mode */
+    setEncMode(IVE_ENC_MODE_HEADER);
+
+    ALOGV("init_codec successfull");
+
+    mSpsPpsHeaderReceived = false;
+    mStarted = true;
+
+    return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SoftAVC::releaseEncoder() {
+    IV_STATUS_T status = IV_SUCCESS;
+    iv_retrieve_mem_rec_ip_t s_retrieve_mem_ip;
+    iv_retrieve_mem_rec_op_t s_retrieve_mem_op;
+    iv_mem_rec_t *ps_mem_rec;
+    UWORD32 i;
+
+    if (!mStarted) {
+        return OMX_ErrorNone;
+    }
+
+    s_retrieve_mem_ip.u4_size = sizeof(iv_retrieve_mem_rec_ip_t);
+    s_retrieve_mem_op.u4_size = sizeof(iv_retrieve_mem_rec_op_t);
+    s_retrieve_mem_ip.e_cmd = IV_CMD_RETRIEVE_MEMREC;
+    s_retrieve_mem_ip.ps_mem_rec = mMemRecords;
+
+    status = ive_api_function(mCodecCtx, &s_retrieve_mem_ip, &s_retrieve_mem_op);
+
+    if (status != IV_SUCCESS) {
+        ALOGE("Unable to retrieve memory records = 0x%x\n",
+                s_retrieve_mem_op.u4_error_code);
+        return OMX_ErrorUndefined;
+    }
+
+    /* Free memory records */
+    ps_mem_rec = mMemRecords;
+    for (i = 0; i < s_retrieve_mem_op.u4_num_mem_rec_filled; i++) {
+        ive_aligned_free(ps_mem_rec->pv_base);
+        ps_mem_rec++;
+    }
+
+    free(mMemRecords);
+
+    if (mConversionBuffer != NULL) {
+        free(mConversionBuffer);
+        mConversionBuffer = NULL;
+    }
+
+    mStarted = false;
+
+    return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SoftAVC::internalGetParameter(OMX_INDEXTYPE index, OMX_PTR params) {
+    switch (index) {
+        case OMX_IndexParamVideoBitrate:
+        {
+            OMX_VIDEO_PARAM_BITRATETYPE *bitRate =
+                (OMX_VIDEO_PARAM_BITRATETYPE *)params;
+
+            if (bitRate->nPortIndex != 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            bitRate->eControlRate = OMX_Video_ControlRateVariable;
+            bitRate->nTargetBitrate = mBitrate;
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamVideoAvc:
+        {
+            OMX_VIDEO_PARAM_AVCTYPE *avcParams = (OMX_VIDEO_PARAM_AVCTYPE *)params;
+
+            if (avcParams->nPortIndex != 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            avcParams->eProfile = OMX_VIDEO_AVCProfileBaseline;
+            OMX_VIDEO_AVCLEVELTYPE omxLevel = OMX_VIDEO_AVCLevel31;
+            if (OMX_ErrorNone
+                    != ConvertAvcSpecLevelToOmxAvcLevel(mAVCEncLevel, &omxLevel)) {
+                return OMX_ErrorUndefined;
+            }
+
+            avcParams->eLevel = omxLevel;
+            avcParams->nRefFrames = 1;
+            avcParams->nBFrames = 0;
+            avcParams->bUseHadamard = OMX_TRUE;
+            avcParams->nAllowedPictureTypes = (OMX_VIDEO_PictureTypeI
+                    | OMX_VIDEO_PictureTypeP);
+            avcParams->nRefIdx10ActiveMinus1 = 0;
+            avcParams->nRefIdx11ActiveMinus1 = 0;
+            avcParams->bWeightedPPrediction = OMX_FALSE;
+            avcParams->bEntropyCodingCABAC = OMX_FALSE;
+            avcParams->bconstIpred = OMX_FALSE;
+            avcParams->bDirect8x8Inference = OMX_FALSE;
+            avcParams->bDirectSpatialTemporal = OMX_FALSE;
+            avcParams->nCabacInitIdc = 0;
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return SoftVideoEncoderOMXComponent::internalGetParameter(index, params);
+    }
+}
+
+OMX_ERRORTYPE SoftAVC::internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params) {
+    int32_t indexFull = index;
+
+    switch (indexFull) {
+        case OMX_IndexParamVideoBitrate:
+        {
+            return internalSetBitrateParams(
+                    (const OMX_VIDEO_PARAM_BITRATETYPE *)params);
+        }
+
+        case OMX_IndexParamVideoAvc:
+        {
+            OMX_VIDEO_PARAM_AVCTYPE *avcType = (OMX_VIDEO_PARAM_AVCTYPE *)params;
+
+            if (avcType->nPortIndex != 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (avcType->eProfile != OMX_VIDEO_AVCProfileBaseline
+                    || avcType->nRefFrames != 1 || avcType->nBFrames != 0
+                    || avcType->bUseHadamard != OMX_TRUE
+                    || (avcType->nAllowedPictureTypes & OMX_VIDEO_PictureTypeB) != 0
+                    || avcType->nRefIdx10ActiveMinus1 != 0
+                    || avcType->nRefIdx11ActiveMinus1 != 0
+                    || avcType->bWeightedPPrediction != OMX_FALSE
+                    || avcType->bEntropyCodingCABAC != OMX_FALSE
+                    || avcType->bconstIpred != OMX_FALSE
+                    || avcType->bDirect8x8Inference != OMX_FALSE
+                    || avcType->bDirectSpatialTemporal != OMX_FALSE
+                    || avcType->nCabacInitIdc != 0) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (OK != ConvertOmxAvcLevelToAvcSpecLevel(avcType->eLevel, &mAVCEncLevel)) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return SoftVideoEncoderOMXComponent::internalSetParameter(index, params);
+    }
+}
+
+OMX_ERRORTYPE SoftAVC::setConfig(
+        OMX_INDEXTYPE index, const OMX_PTR _params) {
+    switch (index) {
+        case OMX_IndexConfigVideoIntraVOPRefresh:
+        {
+            OMX_CONFIG_INTRAREFRESHVOPTYPE *params =
+                (OMX_CONFIG_INTRAREFRESHVOPTYPE *)_params;
+
+            if (params->nPortIndex != kOutputPortIndex) {
+                return OMX_ErrorBadPortIndex;
+            }
+
+            mKeyFrameRequested = params->IntraRefreshVOP;
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexConfigVideoBitrate:
+        {
+            OMX_VIDEO_CONFIG_BITRATETYPE *params =
+                (OMX_VIDEO_CONFIG_BITRATETYPE *)_params;
+
+            if (params->nPortIndex != kOutputPortIndex) {
+                return OMX_ErrorBadPortIndex;
+            }
+
+            if (mBitrate != params->nEncodeBitrate) {
+                mBitrate = params->nEncodeBitrate;
+                mBitrateUpdated = true;
+            }
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return SimpleSoftOMXComponent::setConfig(index, _params);
+    }
+}
+
+OMX_ERRORTYPE SoftAVC::internalSetBitrateParams(
+        const OMX_VIDEO_PARAM_BITRATETYPE *bitrate) {
+    if (bitrate->nPortIndex != kOutputPortIndex) {
+        return OMX_ErrorUnsupportedIndex;
+    }
+
+    mBitrate = bitrate->nTargetBitrate;
+    mBitrateUpdated = true;
+
+    return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SoftAVC::setEncodeArgs(
+        ive_video_encode_ip_t *ps_encode_ip,
+        ive_video_encode_op_t *ps_encode_op,
+        OMX_BUFFERHEADERTYPE *inputBufferHeader,
+        OMX_BUFFERHEADERTYPE *outputBufferHeader) {
+    iv_raw_buf_t *ps_inp_raw_buf;
+    const uint8_t *source;
+    UWORD8 *pu1_buf;
+
+    ps_inp_raw_buf = &ps_encode_ip->s_inp_buf;
+    ps_encode_ip->s_out_buf.pv_buf = outputBufferHeader->pBuffer;
+    ps_encode_ip->s_out_buf.u4_bytes = 0;
+    ps_encode_ip->s_out_buf.u4_bufsize = outputBufferHeader->nAllocLen;
+    ps_encode_ip->u4_size = sizeof(ive_video_encode_ip_t);
+    ps_encode_op->u4_size = sizeof(ive_video_encode_op_t);
+
+    ps_encode_ip->e_cmd = IVE_CMD_VIDEO_ENCODE;
+    ps_encode_ip->pv_bufs = NULL;
+    ps_encode_ip->pv_mb_info = NULL;
+    ps_encode_ip->pv_pic_info = NULL;
+    ps_encode_ip->u4_mb_info_type = 0;
+    ps_encode_ip->u4_pic_info_type = 0;
+    ps_encode_op->s_out_buf.pv_buf = NULL;
+
+    /* Initialize color formats */
+    ps_inp_raw_buf->e_color_fmt = mIvVideoColorFormat;
+
+    source = NULL;
+    if (inputBufferHeader) {
+        source = inputBufferHeader->pBuffer + inputBufferHeader->nOffset;
+
+        if (mInputDataIsMeta) {
+            source = extractGraphicBuffer(
+                    mConversionBuffer, (mWidth * mHeight * 3 / 2), source,
+                    inputBufferHeader->nFilledLen, mWidth, mHeight);
+
+            if (source == NULL) {
+                ALOGE("Error in extractGraphicBuffer");
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
+                return OMX_ErrorUndefined;
+            }
+        }
+    }
+
+    pu1_buf = (UWORD8 *)source;
+    switch (mIvVideoColorFormat) {
+        case IV_YUV_420P:
+        {
+            ps_inp_raw_buf->apv_bufs[0] = pu1_buf;
+            pu1_buf += (mStride) * mHeight;
+            ps_inp_raw_buf->apv_bufs[1] = pu1_buf;
+            pu1_buf += (mStride / 2) * mHeight / 2;
+            ps_inp_raw_buf->apv_bufs[2] = pu1_buf;
+
+            ps_inp_raw_buf->au4_wd[0] = mWidth;
+            ps_inp_raw_buf->au4_wd[1] = mWidth / 2;
+            ps_inp_raw_buf->au4_wd[2] = mWidth / 2;
+
+            ps_inp_raw_buf->au4_ht[0] = mHeight;
+            ps_inp_raw_buf->au4_ht[1] = mHeight / 2;
+            ps_inp_raw_buf->au4_ht[2] = mHeight / 2;
+
+            ps_inp_raw_buf->au4_strd[0] = mStride;
+            ps_inp_raw_buf->au4_strd[1] = (mStride / 2);
+            ps_inp_raw_buf->au4_strd[2] = (mStride / 2);
+            break;
+        }
+
+        case IV_YUV_422ILE:
+        {
+            ps_inp_raw_buf->apv_bufs[0] = pu1_buf;
+            ps_inp_raw_buf->au4_wd[0] = mWidth * 2;
+            ps_inp_raw_buf->au4_ht[0] = mHeight;
+            ps_inp_raw_buf->au4_strd[0] = mStride * 2;
+            break;
+        }
+
+        case IV_YUV_420SP_UV:
+        case IV_YUV_420SP_VU:
+        default:
+        {
+            ps_inp_raw_buf->apv_bufs[0] = pu1_buf;
+            pu1_buf += (mStride) * mHeight;
+            ps_inp_raw_buf->apv_bufs[1] = pu1_buf;
+
+            ps_inp_raw_buf->au4_wd[0] = mWidth;
+            ps_inp_raw_buf->au4_wd[1] = mWidth;
+
+            ps_inp_raw_buf->au4_ht[0] = mHeight;
+            ps_inp_raw_buf->au4_ht[1] = mHeight / 2;
+
+            ps_inp_raw_buf->au4_strd[0] = mStride;
+            ps_inp_raw_buf->au4_strd[1] = mStride;
+            break;
+        }
+    }
+
+    ps_encode_ip->u4_is_last = 0;
+
+    if (inputBufferHeader) {
+        ps_encode_ip->u4_timestamp_high = (inputBufferHeader->nTimeStamp) >> 32;
+        ps_encode_ip->u4_timestamp_low = (inputBufferHeader->nTimeStamp) & 0xFFFFFFFF;
+    }
+
+    return OMX_ErrorNone;
+}
+
+void SoftAVC::onQueueFilled(OMX_U32 portIndex) {
+    IV_STATUS_T status;
+    WORD32 timeDelay, timeTaken;
+
+    UNUSED(portIndex);
+
+    // Initialize encoder if not already initialized
+    if (mCodecCtx == NULL) {
+        if (OMX_ErrorNone != initEncoder()) {
+            ALOGE("Failed to initialize encoder");
+            notify(OMX_EventError, OMX_ErrorUndefined, 0 /* arg2 */, NULL /* data */);
+            return;
+        }
+    }
+    if (mSignalledError || mSawInputEOS) {
+        return;
+    }
+
+    List<BufferInfo *> &inQueue = getPortQueue(0);
+    List<BufferInfo *> &outQueue = getPortQueue(1);
+
+    while (!mSawInputEOS && !inQueue.empty() && !outQueue.empty()) {
+        OMX_ERRORTYPE error;
+        ive_video_encode_ip_t s_encode_ip;
+        ive_video_encode_op_t s_encode_op;
+
+        BufferInfo *inputBufferInfo = *inQueue.begin();
+        OMX_BUFFERHEADERTYPE *inputBufferHeader = inputBufferInfo->mHeader;
+
+        BufferInfo *outputBufferInfo = *outQueue.begin();
+        OMX_BUFFERHEADERTYPE *outputBufferHeader = outputBufferInfo->mHeader;
+
+        if (inputBufferHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+            inQueue.erase(inQueue.begin());
+            inputBufferInfo->mOwnedByUs = false;
+            notifyEmptyBufferDone(inputBufferHeader);
+
+            outputBufferHeader->nFilledLen = 0;
+            outputBufferHeader->nFlags = OMX_BUFFERFLAG_EOS;
+
+            outQueue.erase(outQueue.begin());
+            outputBufferInfo->mOwnedByUs = false;
+            notifyFillBufferDone(outputBufferHeader);
+            return;
+        }
+
+        outputBufferHeader->nTimeStamp = 0;
+        outputBufferHeader->nFlags = 0;
+        outputBufferHeader->nOffset = 0;
+        outputBufferHeader->nFilledLen = 0;
+        outputBufferHeader->nOffset = 0;
+
+        uint8_t *outPtr = (uint8_t *)outputBufferHeader->pBuffer;
+
+        if (!mSpsPpsHeaderReceived) {
+            error = setEncodeArgs(&s_encode_ip, &s_encode_op, NULL, outputBufferHeader);
+            if (error != OMX_ErrorNone) {
+                mSignalledError = true;
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
+                return;
+            }
+            status = ive_api_function(mCodecCtx, &s_encode_ip, &s_encode_op);
+
+            if (IV_SUCCESS != status) {
+                ALOGE("Encode Frame failed = 0x%x\n",
+                        s_encode_op.u4_error_code);
+            } else {
+                ALOGV("Bytes Generated in header %d\n",
+                        s_encode_op.s_out_buf.u4_bytes);
+            }
+
+            mSpsPpsHeaderReceived = true;
+
+            outputBufferHeader->nFlags = OMX_BUFFERFLAG_CODECCONFIG;
+            outputBufferHeader->nFilledLen = s_encode_op.s_out_buf.u4_bytes;
+            outputBufferHeader->nTimeStamp = inputBufferHeader->nTimeStamp;
+
+            outQueue.erase(outQueue.begin());
+            outputBufferInfo->mOwnedByUs = false;
+            DUMP_TO_FILE(
+                    mOutFile, outputBufferHeader->pBuffer,
+                    outputBufferHeader->nFilledLen);
+            notifyFillBufferDone(outputBufferHeader);
+
+            setEncMode(IVE_ENC_MODE_PICTURE);
+            return;
+        }
+
+        if (mBitrateUpdated) {
+            setBitRate();
+        }
+
+        if (mKeyFrameRequested) {
+            setFrameType(IV_IDR_FRAME);
+        }
+
+        mPrevTimestampUs = inputBufferHeader->nTimeStamp;
+
+        if (inputBufferHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+            mSawInputEOS = true;
+        }
+
+        error = setEncodeArgs(
+                &s_encode_ip, &s_encode_op, inputBufferHeader, outputBufferHeader);
+        if (error != OMX_ErrorNone) {
+            mSignalledError = true;
+            notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
+            return;
+        }
+
+        DUMP_TO_FILE(
+                mInFile, s_encode_ip.s_inp_buf.apv_bufs[0],
+                (mHeight * mStride * 3 / 2));
+        //DUMP_TO_FILE(mInFile, inputBufferHeader->pBuffer + inputBufferHeader->nOffset,
+        //    inputBufferHeader->nFilledLen);
+
+        GETTIME(&mTimeStart, NULL);
+        /* Compute time elapsed between end of previous decode()
+         * to start of current decode() */
+        TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);
+
+        status = ive_api_function(mCodecCtx, &s_encode_ip, &s_encode_op);
+
+        if (IV_SUCCESS != status) {
+            ALOGE("Encode Frame failed = 0x%x\n",
+                    s_encode_op.u4_error_code);
+            mSignalledError = true;
+            notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
+            return;
+        }
+
+        GETTIME(&mTimeEnd, NULL);
+        /* Compute time taken for decode() */
+        TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
+
+        ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay,
+                s_encode_op.s_out_buf.u4_bytes);
+
+
+        outputBufferHeader->nFlags = inputBufferHeader->nFlags;
+        outputBufferHeader->nFilledLen = s_encode_op.s_out_buf.u4_bytes;
+        outputBufferHeader->nTimeStamp = inputBufferHeader->nTimeStamp;
+
+        if (IV_IDR_FRAME
+                == s_encode_op.u4_encoded_frame_type) {
+            outputBufferHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME;
+        }
+
+        inQueue.erase(inQueue.begin());
+        inputBufferInfo->mOwnedByUs = false;
+
+        notifyEmptyBufferDone(inputBufferHeader);
+
+        if (mSawInputEOS) {
+            outputBufferHeader->nFlags |= OMX_BUFFERFLAG_EOS;
+        }
+
+        outputBufferInfo->mOwnedByUs = false;
+        outQueue.erase(outQueue.begin());
+
+        DUMP_TO_FILE(
+                mOutFile, outputBufferHeader->pBuffer,
+                outputBufferHeader->nFilledLen);
+        notifyFillBufferDone(outputBufferHeader);
+
+    }
+    return;
+}
+
+
+}  // namespace android
+
+android::SoftOMXComponent *createSoftOMXComponent(
+        const char *name, const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
+    return new android::SoftAVC(name, callbacks, appData, component);
+}
diff --git a/media/libstagefright/codecs/avcenc/SoftAVCEnc.h b/media/libstagefright/codecs/avcenc/SoftAVCEnc.h
new file mode 100644
index 0000000..c4e26a9
--- /dev/null
+++ b/media/libstagefright/codecs/avcenc/SoftAVCEnc.h
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SOFT_AVC_ENC_H__
+#define __SOFT_AVC_ENC_H__
+
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/Vector.h>
+
+#include "SoftVideoEncoderOMXComponent.h"
+
+namespace android {
+
+struct MediaBuffer;
+
+#define CODEC_MAX_CORES          4
+#define LEN_STATUS_BUFFER        (10  * 1024)
+#define MAX_VBV_BUFF_SIZE        (120 * 16384)
+#define MAX_NUM_IO_BUFS           3
+
+#define DEFAULT_MAX_REF_FRM         1
+#define DEFAULT_MAX_REORDER_FRM     0
+#define DEFAULT_QP_MIN              10
+#define DEFAULT_QP_MAX              40
+#define DEFAULT_MAX_BITRATE         20000000
+#define DEFAULT_MAX_SRCH_RANGE_X    256
+#define DEFAULT_MAX_SRCH_RANGE_Y    256
+#define DEFAULT_MAX_FRAMERATE       120000
+#define DEFAULT_NUM_CORES           1
+#define DEFAULT_NUM_CORES_PRE_ENC   0
+#define DEFAULT_FPS                 30
+#define DEFAULT_ENC_SPEED           IVE_NORMAL
+
+#define DEFAULT_MEM_REC_CNT         0
+#define DEFAULT_RECON_ENABLE        0
+#define DEFAULT_CHKSUM_ENABLE       0
+#define DEFAULT_START_FRM           0
+#define DEFAULT_NUM_FRMS            0xFFFFFFFF
+#define DEFAULT_INP_COLOR_FORMAT       IV_YUV_420SP_VU
+#define DEFAULT_RECON_COLOR_FORMAT     IV_YUV_420P
+#define DEFAULT_LOOPBACK            0
+#define DEFAULT_SRC_FRAME_RATE      30
+#define DEFAULT_TGT_FRAME_RATE      30
+#define DEFAULT_MAX_WD              1920
+#define DEFAULT_MAX_HT              1920
+#define DEFAULT_MAX_LEVEL           40
+#define DEFAULT_STRIDE              0
+#define DEFAULT_WD                  1280
+#define DEFAULT_HT                  720
+#define DEFAULT_PSNR_ENABLE         0
+#define DEFAULT_ME_SPEED            100
+#define DEFAULT_ENABLE_FAST_SAD     0
+#define DEFAULT_ENABLE_ALT_REF      0
+#define DEFAULT_RC_MODE             IVE_RC_STORAGE
+#define DEFAULT_BITRATE             6000000
+#define DEFAULT_I_QP                22
+#define DEFAULT_I_QP_MAX            DEFAULT_QP_MAX
+#define DEFAULT_I_QP_MIN            DEFAULT_QP_MIN
+#define DEFAULT_P_QP                28
+#define DEFAULT_P_QP_MAX            DEFAULT_QP_MAX
+#define DEFAULT_P_QP_MIN            DEFAULT_QP_MIN
+#define DEFAULT_B_QP                22
+#define DEFAULT_B_QP_MAX            DEFAULT_QP_MAX
+#define DEFAULT_B_QP_MIN            DEFAULT_QP_MIN
+#define DEFAULT_AIR                 IVE_AIR_MODE_NONE
+#define DEFAULT_AIR_REFRESH_PERIOD  30
+#define DEFAULT_SRCH_RNG_X          64
+#define DEFAULT_SRCH_RNG_Y          48
+#define DEFAULT_I_INTERVAL          30
+#define DEFAULT_IDR_INTERVAL        1000
+#define DEFAULT_B_FRAMES            0
+#define DEFAULT_DISABLE_DEBLK_LEVEL 0
+#define DEFAULT_HPEL                1
+#define DEFAULT_QPEL                1
+#define DEFAULT_I4                  1
+#define DEFAULT_EPROFILE            IV_PROFILE_BASE
+#define DEFAULT_SLICE_MODE          IVE_SLICE_MODE_NONE
+#define DEFAULT_SLICE_PARAM         256
+#define DEFAULT_ARCH                ARCH_ARM_A9Q
+#define DEFAULT_SOC                 SOC_GENERIC
+#define DEFAULT_INTRA4x4            0
+#define STRLENGTH                   500
+
+
+
+#define MIN(a, b) ((a) < (b))? (a) : (b)
+#define MAX(a, b) ((a) > (b))? (a) : (b)
+#define ALIGN16(x) ((((x) + 15) >> 4) << 4)
+#define ALIGN128(x) ((((x) + 127) >> 7) << 7)
+#define ALIGN4096(x) ((((x) + 4095) >> 12) << 12)
+
+/** Used to remove warnings about unused parameters */
+#define UNUSED(x) ((void)(x))
+
+/** Get time */
+#define GETTIME(a, b) gettimeofday(a, b);
+
+/** Compute difference between start and end */
+#define TIME_DIFF(start, end, diff) \
+    diff = ((end.tv_sec - start.tv_sec) * 1000000) + \
+            (end.tv_usec - start.tv_usec);
+
+#define ive_aligned_malloc(alignment, size) memalign(alignment, size)
+#define ive_aligned_free(buf) free(buf)
+
+struct SoftAVC : public SoftVideoEncoderOMXComponent {
+    SoftAVC(
+            const char *name,
+            const OMX_CALLBACKTYPE *callbacks,
+            OMX_PTR appData,
+            OMX_COMPONENTTYPE **component);
+
+    // Override SimpleSoftOMXComponent methods
+    virtual OMX_ERRORTYPE internalGetParameter(
+            OMX_INDEXTYPE index, OMX_PTR params);
+
+    virtual OMX_ERRORTYPE internalSetParameter(
+            OMX_INDEXTYPE index, const OMX_PTR params);
+
+    virtual void onQueueFilled(OMX_U32 portIndex);
+
+protected:
+    virtual ~SoftAVC();
+
+private:
+    enum {
+        kNumBuffers = 2,
+    };
+
+    // OMX input buffer's timestamp and flags
+    typedef struct {
+        int64_t mTimeUs;
+        int32_t mFlags;
+    } InputBufferInfo;
+
+    int32_t  mStride;
+
+    uint32_t mFrameRate;
+
+    struct timeval mTimeStart;   // Time at the start of decode()
+    struct timeval mTimeEnd;     // Time at the end of decode()
+
+
+    // If a request for a change it bitrate has been received.
+    bool mBitrateUpdated;
+
+    bool mKeyFrameRequested;
+
+#ifdef FILE_DUMP_ENABLE
+    char mInFile[200];
+    char mOutFile[200];
+#endif /* FILE_DUMP_ENABLE */
+
+    IV_COLOR_FORMAT_T mIvVideoColorFormat;
+
+    int32_t  mIDRFrameRefreshIntervalInSec;
+    IV_PROFILE_T mAVCEncProfile;
+    WORD32   mAVCEncLevel;
+    int64_t  mNumInputFrames;
+    int64_t  mPrevTimestampUs;
+    bool     mStarted;
+    bool     mSpsPpsHeaderReceived;
+
+    bool     mSawInputEOS;
+    bool     mSignalledError;
+    bool     mIntra4x4;
+    bool     mEnableFastSad;
+    bool     mEnableAltRef;
+    bool    mReconEnable;
+    bool    mPSNREnable;
+    IVE_SPEED_CONFIG     mEncSpeed;
+
+    uint8_t *mConversionBuffer;
+
+    iv_obj_t *mCodecCtx;         // Codec context
+    iv_mem_rec_t *mMemRecords;   // Memory records requested by the codec
+    size_t mNumMemRecords;       // Number of memory records requested by codec
+    size_t mNumCores;            // Number of cores used by the codec
+
+    UWORD32 mHeaderGenerated;
+
+    IV_ARCH_T mArch;
+    IVE_SLICE_MODE_T mSliceMode;
+    UWORD32 mSliceParam;
+    bool mHalfPelEnable;
+    UWORD32 mIInterval;
+    UWORD32 mIDRInterval;
+    UWORD32 mDisableDeblkLevel;
+    IVE_AIR_MODE_T mAIRMode;
+    UWORD32 mAIRRefreshPeriod;
+
+    OMX_ERRORTYPE initEncParams();
+    OMX_ERRORTYPE initEncoder();
+    OMX_ERRORTYPE releaseEncoder();
+
+    // Verifies the component role tried to be set to this OMX component is
+    // strictly video_encoder.avc
+    OMX_ERRORTYPE internalSetRoleParams(
+        const OMX_PARAM_COMPONENTROLETYPE *role);
+
+    // Updates bitrate to reflect port settings.
+    OMX_ERRORTYPE internalSetBitrateParams(
+        const OMX_VIDEO_PARAM_BITRATETYPE *bitrate);
+
+    OMX_ERRORTYPE setConfig(
+        OMX_INDEXTYPE index, const OMX_PTR _params);
+
+    // Handles port definition changes.
+    OMX_ERRORTYPE internalSetPortParams(
+        const OMX_PARAM_PORTDEFINITIONTYPE *port);
+
+    OMX_ERRORTYPE internalSetFormatParams(
+        const OMX_VIDEO_PARAM_PORTFORMATTYPE *format);
+
+    OMX_ERRORTYPE setFrameType(IV_PICTURE_CODING_TYPE_T  e_frame_type);
+    OMX_ERRORTYPE setQp();
+    OMX_ERRORTYPE setEncMode(IVE_ENC_MODE_T e_enc_mode);
+    OMX_ERRORTYPE setDimensions();
+    OMX_ERRORTYPE setNumCores();
+    OMX_ERRORTYPE setFrameRate();
+    OMX_ERRORTYPE setIpeParams();
+    OMX_ERRORTYPE setBitRate();
+    OMX_ERRORTYPE setAirParams();
+    OMX_ERRORTYPE setMeParams();
+    OMX_ERRORTYPE setGopParams();
+    OMX_ERRORTYPE setProfileParams();
+    OMX_ERRORTYPE setDeblockParams();
+    OMX_ERRORTYPE setVbvParams();
+    void logVersion();
+    OMX_ERRORTYPE setEncodeArgs(
+        ive_video_encode_ip_t *ps_encode_ip,
+        ive_video_encode_op_t *ps_encode_op,
+        OMX_BUFFERHEADERTYPE *inputBufferHeader,
+        OMX_BUFFERHEADERTYPE *outputBufferHeader);
+
+    DISALLOW_EVIL_CONSTRUCTORS(SoftAVC);
+};
+
+#ifdef FILE_DUMP_ENABLE
+
+#define INPUT_DUMP_PATH     "/sdcard/media/avce_input"
+#define INPUT_DUMP_EXT      "yuv"
+#define OUTPUT_DUMP_PATH    "/sdcard/media/avce_output"
+#define OUTPUT_DUMP_EXT     "h264"
+
+#define GENERATE_FILE_NAMES() {                         \
+    GETTIME(&mTimeStart, NULL);                         \
+    strcpy(mInFile, "");                                \
+    sprintf(mInFile, "%s_%ld.%ld.%s", INPUT_DUMP_PATH,  \
+            mTimeStart.tv_sec, mTimeStart.tv_usec,      \
+            INPUT_DUMP_EXT);                            \
+    strcpy(mOutFile, "");                               \
+    sprintf(mOutFile, "%s_%ld.%ld.%s", OUTPUT_DUMP_PATH,\
+            mTimeStart.tv_sec, mTimeStart.tv_usec,      \
+            OUTPUT_DUMP_EXT);                           \
+}
+
+#define CREATE_DUMP_FILE(m_filename) {                  \
+    FILE *fp = fopen(m_filename, "wb");                 \
+    if (fp != NULL) {                                   \
+        ALOGD("Opened file %s", m_filename);            \
+        fclose(fp);                                     \
+    } else {                                            \
+        ALOGD("Could not open file %s", m_filename);    \
+    }                                                   \
+}
+#define DUMP_TO_FILE(m_filename, m_buf, m_size)         \
+{                                                       \
+    FILE *fp = fopen(m_filename, "ab");                 \
+    if (fp != NULL && m_buf != NULL) {                  \
+        int i;                                          \
+        i = fwrite(m_buf, 1, m_size, fp);               \
+        ALOGD("fwrite ret %d to write %d", i, m_size);  \
+        if (i != (int)m_size) {                         \
+            ALOGD("Error in fwrite, returned %d", i);   \
+            perror("Error in write to file");           \
+        }                                               \
+        fclose(fp);                                     \
+    } else {                                            \
+        ALOGD("Could not write to file %s", m_filename);\
+    }                                                   \
+}
+#else /* FILE_DUMP_ENABLE */
+#define INPUT_DUMP_PATH
+#define INPUT_DUMP_EXT
+#define OUTPUT_DUMP_PATH
+#define OUTPUT_DUMP_EXT
+#define GENERATE_FILE_NAMES()
+#define CREATE_DUMP_FILE(m_filename)
+#define DUMP_TO_FILE(m_filename, m_buf, m_size)
+#endif /* FILE_DUMP_ENABLE */
+
+}  // namespace android
+
+#endif  // __SOFT_AVC_ENC_H__
diff --git a/media/libstagefright/codecs/mpeg2dec/Android.mk b/media/libstagefright/codecs/mpeg2dec/Android.mk
new file mode 100644
index 0000000..23b126d
--- /dev/null
+++ b/media/libstagefright/codecs/mpeg2dec/Android.mk
@@ -0,0 +1,27 @@
+ifeq ($(if $(wildcard external/libmpeg2),1,0),1)
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE            := libstagefright_soft_mpeg2dec
+LOCAL_MODULE_TAGS       := optional
+
+LOCAL_STATIC_LIBRARIES  := libmpeg2dec
+LOCAL_SRC_FILES         := SoftMPEG2.cpp
+
+LOCAL_C_INCLUDES := $(TOP)/external/libmpeg2/decoder
+LOCAL_C_INCLUDES += $(TOP)/external/libmpeg2/common
+LOCAL_C_INCLUDES += $(TOP)/frameworks/av/media/libstagefright/include
+LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/media/openmax
+
+LOCAL_SHARED_LIBRARIES  := libstagefright
+LOCAL_SHARED_LIBRARIES  += libstagefright_omx
+LOCAL_SHARED_LIBRARIES  += libstagefright_foundation
+LOCAL_SHARED_LIBRARIES  += libutils
+LOCAL_SHARED_LIBRARIES  += liblog
+
+LOCAL_LDFLAGS := -Wl,-Bsymbolic
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif
diff --git a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
new file mode 100644
index 0000000..fb7394b
--- /dev/null
+++ b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
@@ -0,0 +1,756 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SoftMPEG2"
+#include <utils/Log.h>
+
+#include "iv_datatypedef.h"
+#include "iv.h"
+#include "ivd.h"
+#include "ithread.h"
+#include "impeg2d.h"
+#include "SoftMPEG2.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <OMX_VideoExt.h>
+
+namespace android {
+
+#define componentName                   "video_decoder.mpeg2"
+#define codingType                      OMX_VIDEO_CodingMPEG2
+#define CODEC_MIME_TYPE                 MEDIA_MIMETYPE_VIDEO_MPEG2
+
+/** Function and structure definitions to keep code similar for each codec */
+#define ivdec_api_function              impeg2d_api_function
+#define ivdext_init_ip_t                impeg2d_init_ip_t
+#define ivdext_init_op_t                impeg2d_init_op_t
+#define ivdext_fill_mem_rec_ip_t        impeg2d_fill_mem_rec_ip_t
+#define ivdext_fill_mem_rec_op_t        impeg2d_fill_mem_rec_op_t
+#define ivdext_ctl_set_num_cores_ip_t   impeg2d_ctl_set_num_cores_ip_t
+#define ivdext_ctl_set_num_cores_op_t   impeg2d_ctl_set_num_cores_op_t
+
+#define IVDEXT_CMD_CTL_SET_NUM_CORES    \
+        (IVD_CONTROL_API_COMMAND_TYPE_T)IMPEG2D_CMD_CTL_SET_NUM_CORES
+
+static const CodecProfileLevel kProfileLevels[] = {
+    { OMX_VIDEO_MPEG2ProfileSimple, OMX_VIDEO_MPEG2LevelLL  },
+    { OMX_VIDEO_MPEG2ProfileSimple, OMX_VIDEO_MPEG2LevelML  },
+    { OMX_VIDEO_MPEG2ProfileSimple, OMX_VIDEO_MPEG2LevelH14 },
+    { OMX_VIDEO_MPEG2ProfileSimple, OMX_VIDEO_MPEG2LevelHL  },
+
+    { OMX_VIDEO_MPEG2ProfileMain  , OMX_VIDEO_MPEG2LevelLL  },
+    { OMX_VIDEO_MPEG2ProfileMain  , OMX_VIDEO_MPEG2LevelML  },
+    { OMX_VIDEO_MPEG2ProfileMain  , OMX_VIDEO_MPEG2LevelH14 },
+    { OMX_VIDEO_MPEG2ProfileMain  , OMX_VIDEO_MPEG2LevelHL  },
+};
+
+SoftMPEG2::SoftMPEG2(
+        const char *name,
+        const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData,
+        OMX_COMPONENTTYPE **component)
+    : SoftVideoDecoderOMXComponent(
+            name, componentName, codingType,
+            kProfileLevels, ARRAY_SIZE(kProfileLevels),
+            320 /* width */, 240 /* height */, callbacks,
+            appData, component),
+      mMemRecords(NULL),
+      mFlushOutBuffer(NULL),
+      mOmxColorFormat(OMX_COLOR_FormatYUV420Planar),
+      mIvColorFormat(IV_YUV_420P),
+      mNewWidth(mWidth),
+      mNewHeight(mHeight),
+      mChangingResolution(false) {
+    initPorts(kNumBuffers, INPUT_BUF_SIZE, kNumBuffers, CODEC_MIME_TYPE);
+
+    // If input dump is enabled, then open create an empty file
+    GENERATE_FILE_NAMES();
+    CREATE_DUMP_FILE(mInFile);
+
+    CHECK_EQ(initDecoder(), (status_t)OK);
+}
+
+SoftMPEG2::~SoftMPEG2() {
+    CHECK_EQ(deInitDecoder(), (status_t)OK);
+}
+
+
+static size_t getMinTimestampIdx(OMX_S64 *pNTimeStamp, bool *pIsTimeStampValid) {
+    OMX_S64 minTimeStamp = LLONG_MAX;
+    int idx = -1;
+    for (size_t i = 0; i < MAX_TIME_STAMPS; i++) {
+        if (pIsTimeStampValid[i]) {
+            if (pNTimeStamp[i] < minTimeStamp) {
+                minTimeStamp = pNTimeStamp[i];
+                idx = i;
+            }
+        }
+    }
+    return idx;
+}
+
+static size_t GetCPUCoreCount() {
+    long cpuCoreCount = 1;
+#if defined(_SC_NPROCESSORS_ONLN)
+    cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
+#else
+    // _SC_NPROC_ONLN must be defined...
+    cpuCoreCount = sysconf(_SC_NPROC_ONLN);
+#endif
+    CHECK(cpuCoreCount >= 1);
+    ALOGV("Number of CPU cores: %ld", cpuCoreCount);
+    return (size_t)cpuCoreCount;
+}
+
+void SoftMPEG2::logVersion() {
+    ivd_ctl_getversioninfo_ip_t s_ctl_ip;
+    ivd_ctl_getversioninfo_op_t s_ctl_op;
+    UWORD8 au1_buf[512];
+    IV_API_CALL_STATUS_T status;
+
+    s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION;
+    s_ctl_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t);
+    s_ctl_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t);
+    s_ctl_ip.pv_version_buffer = au1_buf;
+    s_ctl_ip.u4_version_buffer_size = sizeof(au1_buf);
+
+    status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, (void *)&s_ctl_op);
+
+    if (status != IV_SUCCESS) {
+        ALOGE("Error in getting version number: 0x%x",
+                s_ctl_op.u4_error_code);
+    } else {
+        ALOGV("Ittiam decoder version number: %s",
+                (char *)s_ctl_ip.pv_version_buffer);
+    }
+    return;
+}
+
+status_t SoftMPEG2::setParams(size_t stride) {
+    ivd_ctl_set_config_ip_t s_ctl_ip;
+    ivd_ctl_set_config_op_t s_ctl_op;
+    IV_API_CALL_STATUS_T status;
+    s_ctl_ip.u4_disp_wd = (UWORD32)stride;
+    s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE;
+
+    s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
+    s_ctl_ip.e_vid_dec_mode = IVD_DECODE_FRAME;
+    s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
+    s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
+    s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
+
+    ALOGV("Set the run-time (dynamic) parameters stride = %u", stride);
+    status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, (void *)&s_ctl_op);
+
+    if (status != IV_SUCCESS) {
+        ALOGE("Error in setting the run-time parameters: 0x%x",
+                s_ctl_op.u4_error_code);
+
+        return UNKNOWN_ERROR;
+    }
+    return OK;
+}
+
+status_t SoftMPEG2::resetPlugin() {
+    mIsInFlush = false;
+    mReceivedEOS = false;
+    memset(mTimeStamps, 0, sizeof(mTimeStamps));
+    memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid));
+
+    /* Initialize both start and end times */
+    gettimeofday(&mTimeStart, NULL);
+    gettimeofday(&mTimeEnd, NULL);
+
+    return OK;
+}
+
+status_t SoftMPEG2::resetDecoder() {
+    ivd_ctl_reset_ip_t s_ctl_ip;
+    ivd_ctl_reset_op_t s_ctl_op;
+    IV_API_CALL_STATUS_T status;
+
+    s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
+    s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
+    s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t);
+
+    status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, (void *)&s_ctl_op);
+    if (IV_SUCCESS != status) {
+        ALOGE("Error in reset: 0x%x", s_ctl_op.u4_error_code);
+        return UNKNOWN_ERROR;
+    }
+
+    /* Set the run-time (dynamic) parameters */
+    setParams(outputBufferWidth());
+
+    /* Set number of cores/threads to be used by the codec */
+    setNumCores();
+
+    return OK;
+}
+
+status_t SoftMPEG2::setNumCores() {
+    ivdext_ctl_set_num_cores_ip_t s_set_cores_ip;
+    ivdext_ctl_set_num_cores_op_t s_set_cores_op;
+    IV_API_CALL_STATUS_T status;
+    s_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_set_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES;
+    s_set_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_NUM_CORES);
+    s_set_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t);
+    s_set_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t);
+
+    status = ivdec_api_function(mCodecCtx, (void *)&s_set_cores_ip, (void *)&s_set_cores_op);
+    if (IV_SUCCESS != status) {
+        ALOGE("Error in setting number of cores: 0x%x",
+                s_set_cores_op.u4_error_code);
+        return UNKNOWN_ERROR;
+    }
+    return OK;
+}
+
+status_t SoftMPEG2::setFlushMode() {
+    IV_API_CALL_STATUS_T status;
+    ivd_ctl_flush_ip_t s_video_flush_ip;
+    ivd_ctl_flush_op_t s_video_flush_op;
+
+    s_video_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_video_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH;
+    s_video_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t);
+    s_video_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t);
+
+    /* Set the decoder in Flush mode, subsequent decode() calls will flush */
+    status = ivdec_api_function(
+            mCodecCtx, (void *)&s_video_flush_ip, (void *)&s_video_flush_op);
+
+    if (status != IV_SUCCESS) {
+        ALOGE("Error in setting the decoder in flush mode: (%d) 0x%x", status,
+                s_video_flush_op.u4_error_code);
+        return UNKNOWN_ERROR;
+    }
+
+    mIsInFlush = true;
+    return OK;
+}
+
+status_t SoftMPEG2::initDecoder() {
+    IV_API_CALL_STATUS_T status;
+
+    UWORD32 u4_num_reorder_frames;
+    UWORD32 u4_num_ref_frames;
+    UWORD32 u4_share_disp_buf;
+
+    mNumCores = GetCPUCoreCount();
+
+    /* Initialize number of ref and reorder modes (for MPEG2) */
+    u4_num_reorder_frames = 16;
+    u4_num_ref_frames = 16;
+    u4_share_disp_buf = 0;
+
+    uint32_t displayStride = outputBufferWidth();
+    uint32_t displayHeight = outputBufferHeight();
+    uint32_t displaySizeY = displayStride * displayHeight;
+
+    {
+        iv_num_mem_rec_ip_t s_num_mem_rec_ip;
+        iv_num_mem_rec_op_t s_num_mem_rec_op;
+
+        s_num_mem_rec_ip.u4_size = sizeof(s_num_mem_rec_ip);
+        s_num_mem_rec_op.u4_size = sizeof(s_num_mem_rec_op);
+        s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC;
+
+        status = ivdec_api_function(
+                mCodecCtx, (void *)&s_num_mem_rec_ip, (void *)&s_num_mem_rec_op);
+        if (IV_SUCCESS != status) {
+            ALOGE("Error in getting mem records: 0x%x",
+                    s_num_mem_rec_op.u4_error_code);
+            return UNKNOWN_ERROR;
+        }
+
+        mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec;
+    }
+
+    mMemRecords = (iv_mem_rec_t *)ivd_aligned_malloc(
+            128, mNumMemRecords * sizeof(iv_mem_rec_t));
+    if (mMemRecords == NULL) {
+        ALOGE("Allocation failure");
+        return NO_MEMORY;
+    }
+
+    memset(mMemRecords, 0, mNumMemRecords * sizeof(iv_mem_rec_t));
+
+    {
+        size_t i;
+        ivdext_fill_mem_rec_ip_t s_fill_mem_ip;
+        ivdext_fill_mem_rec_op_t s_fill_mem_op;
+        iv_mem_rec_t *ps_mem_rec;
+
+        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size =
+            sizeof(ivdext_fill_mem_rec_ip_t);
+
+        s_fill_mem_ip.u4_share_disp_buf = u4_share_disp_buf;
+        s_fill_mem_ip.e_output_format = mIvColorFormat;
+
+        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC;
+        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location = mMemRecords;
+        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = displayStride;
+        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = displayHeight;
+        s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size =
+            sizeof(ivdext_fill_mem_rec_op_t);
+
+        ps_mem_rec = mMemRecords;
+        for (i = 0; i < mNumMemRecords; i++) {
+            ps_mem_rec[i].u4_size = sizeof(iv_mem_rec_t);
+        }
+
+        status = ivdec_api_function(
+                mCodecCtx, (void *)&s_fill_mem_ip, (void *)&s_fill_mem_op);
+
+        if (IV_SUCCESS != status) {
+            ALOGE("Error in filling mem records: 0x%x",
+                    s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_error_code);
+            return UNKNOWN_ERROR;
+        }
+        mNumMemRecords =
+            s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_num_mem_rec_filled;
+
+        ps_mem_rec = mMemRecords;
+
+        for (i = 0; i < mNumMemRecords; i++) {
+            ps_mem_rec->pv_base = ivd_aligned_malloc(
+                    ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size);
+            if (ps_mem_rec->pv_base == NULL) {
+                ALOGE("Allocation failure for memory record #%zu of size %u",
+                        i, ps_mem_rec->u4_mem_size);
+                status = IV_FAIL;
+                return NO_MEMORY;
+            }
+
+            ps_mem_rec++;
+        }
+    }
+
+    /* Initialize the decoder */
+    {
+        ivdext_init_ip_t s_init_ip;
+        ivdext_init_op_t s_init_op;
+
+        void *dec_fxns = (void *)ivdec_api_function;
+
+        s_init_ip.s_ivd_init_ip_t.u4_size = sizeof(ivdext_init_ip_t);
+        s_init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT;
+        s_init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords;
+        s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = displayStride;
+        s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = displayHeight;
+
+        s_init_ip.u4_share_disp_buf = u4_share_disp_buf;
+
+        s_init_op.s_ivd_init_op_t.u4_size = sizeof(s_init_op);
+
+        s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = mNumMemRecords;
+        s_init_ip.s_ivd_init_ip_t.e_output_format = mIvColorFormat;
+
+        mCodecCtx = (iv_obj_t *)mMemRecords[0].pv_base;
+        mCodecCtx->pv_fxns = dec_fxns;
+        mCodecCtx->u4_size = sizeof(iv_obj_t);
+
+        status = ivdec_api_function(mCodecCtx, (void *)&s_init_ip, (void *)&s_init_op);
+        if (status != IV_SUCCESS) {
+            ALOGE("Error in init: 0x%x",
+                    s_init_op.s_ivd_init_op_t.u4_error_code);
+            return UNKNOWN_ERROR;
+        }
+    }
+
+    /* Reset the plugin state */
+    resetPlugin();
+
+    /* Set the run time (dynamic) parameters */
+    setParams(displayStride);
+
+    /* Set number of cores/threads to be used by the codec */
+    setNumCores();
+
+    /* Get codec version */
+    logVersion();
+
+    /* Allocate internal picture buffer */
+    uint32_t bufferSize = displaySizeY * 3 / 2;
+    mFlushOutBuffer = (uint8_t *)ivd_aligned_malloc(128, bufferSize);
+    if (NULL == mFlushOutBuffer) {
+        ALOGE("Could not allocate flushOutputBuffer of size %zu", bufferSize);
+        return NO_MEMORY;
+    }
+
+    mInitNeeded = false;
+    mFlushNeeded = false;
+    return OK;
+}
+
+status_t SoftMPEG2::deInitDecoder() {
+    size_t i;
+
+    if (mMemRecords) {
+        iv_mem_rec_t *ps_mem_rec;
+
+        ps_mem_rec = mMemRecords;
+        for (i = 0; i < mNumMemRecords; i++) {
+            if (ps_mem_rec->pv_base) {
+                ivd_aligned_free(ps_mem_rec->pv_base);
+            }
+            ps_mem_rec++;
+        }
+        ivd_aligned_free(mMemRecords);
+        mMemRecords = NULL;
+    }
+
+    if (mFlushOutBuffer) {
+        ivd_aligned_free(mFlushOutBuffer);
+        mFlushOutBuffer = NULL;
+    }
+
+    mInitNeeded = true;
+    mChangingResolution = false;
+
+    return OK;
+}
+
+status_t SoftMPEG2::reInitDecoder() {
+    status_t ret;
+
+    deInitDecoder();
+
+    ret = initDecoder();
+    if (OK != ret) {
+        ALOGE("Create failure");
+        deInitDecoder();
+        return NO_MEMORY;
+    }
+    return OK;
+}
+
+void SoftMPEG2::onReset() {
+    SoftVideoDecoderOMXComponent::onReset();
+
+    resetDecoder();
+    resetPlugin();
+}
+
+OMX_ERRORTYPE SoftMPEG2::internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params) {
+    const uint32_t oldWidth = mWidth;
+    const uint32_t oldHeight = mHeight;
+    OMX_ERRORTYPE ret = SoftVideoDecoderOMXComponent::internalSetParameter(index, params);
+    if (mWidth != oldWidth || mHeight != oldHeight) {
+        reInitDecoder();
+    }
+    return ret;
+}
+
+void SoftMPEG2::setDecodeArgs(
+        ivd_video_decode_ip_t *ps_dec_ip,
+        ivd_video_decode_op_t *ps_dec_op,
+        OMX_BUFFERHEADERTYPE *inHeader,
+        OMX_BUFFERHEADERTYPE *outHeader,
+        size_t timeStampIx) {
+    size_t sizeY = outputBufferWidth() * outputBufferHeight();
+    size_t sizeUV;
+    uint8_t *pBuf;
+
+    ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t);
+    ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t);
+
+    ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
+
+    /* When in flush and after EOS with zero byte input,
+     * inHeader is set to zero. Hence check for non-null */
+    if (inHeader) {
+        ps_dec_ip->u4_ts = timeStampIx;
+        ps_dec_ip->pv_stream_buffer = inHeader->pBuffer
+                + inHeader->nOffset;
+        ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen;
+    } else {
+        ps_dec_ip->u4_ts = 0;
+        ps_dec_ip->pv_stream_buffer = NULL;
+        ps_dec_ip->u4_num_Bytes = 0;
+    }
+
+    if (outHeader) {
+        pBuf = outHeader->pBuffer;
+    } else {
+        pBuf = mFlushOutBuffer;
+    }
+
+    sizeUV = sizeY / 4;
+    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[0] = sizeY;
+    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[1] = sizeUV;
+    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[2] = sizeUV;
+
+    ps_dec_ip->s_out_buffer.pu1_bufs[0] = pBuf;
+    ps_dec_ip->s_out_buffer.pu1_bufs[1] = pBuf + sizeY;
+    ps_dec_ip->s_out_buffer.pu1_bufs[2] = pBuf + sizeY + sizeUV;
+    ps_dec_ip->s_out_buffer.u4_num_bufs = 3;
+    return;
+}
+void SoftMPEG2::onPortFlushCompleted(OMX_U32 portIndex) {
+    /* Once the output buffers are flushed, ignore any buffers that are held in decoder */
+    if (kOutputPortIndex == portIndex) {
+        setFlushMode();
+
+        while (true) {
+            ivd_video_decode_ip_t s_dec_ip;
+            ivd_video_decode_op_t s_dec_op;
+            IV_API_CALL_STATUS_T status;
+            size_t sizeY, sizeUV;
+
+            setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, 0);
+
+            status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
+            if (0 == s_dec_op.u4_output_present) {
+                resetPlugin();
+                break;
+            }
+        }
+    }
+}
+
+void SoftMPEG2::onQueueFilled(OMX_U32 portIndex) {
+    UNUSED(portIndex);
+
+    if (mOutputPortSettingsChange != NONE) {
+        return;
+    }
+
+    List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
+    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
+
+    /* If input EOS is seen and decoder is not in flush mode,
+     * set the decoder in flush mode.
+     * There can be a case where EOS is sent along with last picture data
+     * In that case, only after decoding that input data, decoder has to be
+     * put in flush. This case is handled here  */
+
+    if (mReceivedEOS && !mIsInFlush) {
+        setFlushMode();
+    }
+
+    while (!outQueue.empty()) {
+        BufferInfo *inInfo;
+        OMX_BUFFERHEADERTYPE *inHeader;
+
+        BufferInfo *outInfo;
+        OMX_BUFFERHEADERTYPE *outHeader;
+        size_t timeStampIx;
+
+        inInfo = NULL;
+        inHeader = NULL;
+
+        if (!mIsInFlush) {
+            if (!inQueue.empty()) {
+                inInfo = *inQueue.begin();
+                inHeader = inInfo->mHeader;
+            } else {
+                break;
+            }
+        }
+
+        outInfo = *outQueue.begin();
+        outHeader = outInfo->mHeader;
+        outHeader->nFlags = 0;
+        outHeader->nTimeStamp = 0;
+        outHeader->nOffset = 0;
+
+        if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
+            mReceivedEOS = true;
+            if (inHeader->nFilledLen == 0) {
+                inQueue.erase(inQueue.begin());
+                inInfo->mOwnedByUs = false;
+                notifyEmptyBufferDone(inHeader);
+                inHeader = NULL;
+                setFlushMode();
+            }
+        }
+
+        // When there is an init required and the decoder is not in flush mode,
+        // update output port's definition and reinitialize decoder.
+        if (mInitNeeded && !mIsInFlush) {
+            bool portWillReset = false;
+            handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight);
+
+            CHECK_EQ(reInitDecoder(), (status_t)OK);
+            return;
+        }
+
+        /* Get a free slot in timestamp array to hold input timestamp */
+        {
+            size_t i;
+            timeStampIx = 0;
+            for (i = 0; i < MAX_TIME_STAMPS; i++) {
+                if (!mTimeStampsValid[i]) {
+                    timeStampIx = i;
+                    break;
+                }
+            }
+            if (inHeader != NULL) {
+                mTimeStampsValid[timeStampIx] = true;
+                mTimeStamps[timeStampIx] = inHeader->nTimeStamp;
+            }
+        }
+
+        {
+            ivd_video_decode_ip_t s_dec_ip;
+            ivd_video_decode_op_t s_dec_op;
+            WORD32 timeDelay, timeTaken;
+            size_t sizeY, sizeUV;
+
+            setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx);
+            // If input dump is enabled, then write to file
+            DUMP_TO_FILE(mInFile, s_dec_ip.pv_stream_buffer, s_dec_ip.u4_num_Bytes);
+
+            if (s_dec_ip.u4_num_Bytes > 0) {
+                char *ptr = (char *)s_dec_ip.pv_stream_buffer;
+            }
+
+            GETTIME(&mTimeStart, NULL);
+            /* Compute time elapsed between end of previous decode()
+             * to start of current decode() */
+            TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);
+
+            IV_API_CALL_STATUS_T status;
+            status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
+
+            bool unsupportedDimensions = (IMPEG2D_UNSUPPORTED_DIMENSIONS == s_dec_op.u4_error_code);
+            bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF));
+
+            GETTIME(&mTimeEnd, NULL);
+            /* Compute time taken for decode() */
+            TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
+
+            ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay,
+                   s_dec_op.u4_num_bytes_consumed);
+            if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) {
+                mFlushNeeded = true;
+            }
+
+            if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) {
+                /* If the input did not contain picture data, then ignore
+                 * the associated timestamp */
+                mTimeStampsValid[timeStampIx] = false;
+            }
+
+            // This is needed to handle CTS DecoderTest testCodecResetsMPEG2WithoutSurface,
+            // which is not sending SPS/PPS after port reconfiguration and flush to the codec.
+            if (unsupportedDimensions && !mFlushNeeded) {
+                bool portWillReset = false;
+                handlePortSettingsChange(&portWillReset, s_dec_op.u4_pic_wd, s_dec_op.u4_pic_ht);
+
+                CHECK_EQ(reInitDecoder(), (status_t)OK);
+
+                setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx);
+
+                ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
+                return;
+            }
+
+            // If the decoder is in the changing resolution mode and there is no output present,
+            // that means the switching is done and it's ready to reset the decoder and the plugin.
+            if (mChangingResolution && !s_dec_op.u4_output_present) {
+                mChangingResolution = false;
+                resetDecoder();
+                resetPlugin();
+                continue;
+            }
+
+            if (unsupportedDimensions || resChanged) {
+                mChangingResolution = true;
+                if (mFlushNeeded) {
+                    setFlushMode();
+                }
+
+                if (unsupportedDimensions) {
+                    mNewWidth = s_dec_op.u4_pic_wd;
+                    mNewHeight = s_dec_op.u4_pic_ht;
+                    mInitNeeded = true;
+                }
+                continue;
+            }
+
+            if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) {
+                uint32_t width = s_dec_op.u4_pic_wd;
+                uint32_t height = s_dec_op.u4_pic_ht;
+                bool portWillReset = false;
+                handlePortSettingsChange(&portWillReset, width, height);
+
+                if (portWillReset) {
+                    resetDecoder();
+                    return;
+                }
+            }
+
+            if (s_dec_op.u4_output_present) {
+                size_t timeStampIdx;
+                outHeader->nFilledLen = (mWidth * mHeight * 3) / 2;
+
+                timeStampIdx = getMinTimestampIdx(mTimeStamps, mTimeStampsValid);
+                outHeader->nTimeStamp = mTimeStamps[timeStampIdx];
+                mTimeStampsValid[timeStampIdx] = false;
+
+                outInfo->mOwnedByUs = false;
+                outQueue.erase(outQueue.begin());
+                outInfo = NULL;
+                notifyFillBufferDone(outHeader);
+                outHeader = NULL;
+            } else {
+                /* If in flush mode and no output is returned by the codec,
+                 * then come out of flush mode */
+                mIsInFlush = false;
+
+                /* If EOS was recieved on input port and there is no output
+                 * from the codec, then signal EOS on output port */
+                if (mReceivedEOS) {
+                    outHeader->nFilledLen = 0;
+                    outHeader->nFlags |= OMX_BUFFERFLAG_EOS;
+
+                    outInfo->mOwnedByUs = false;
+                    outQueue.erase(outQueue.begin());
+                    outInfo = NULL;
+                    notifyFillBufferDone(outHeader);
+                    outHeader = NULL;
+                    resetPlugin();
+                }
+            }
+        }
+
+        // TODO: Handle more than one picture data
+        if (inHeader != NULL) {
+            inInfo->mOwnedByUs = false;
+            inQueue.erase(inQueue.begin());
+            inInfo = NULL;
+            notifyEmptyBufferDone(inHeader);
+            inHeader = NULL;
+        }
+    }
+}
+
+}  // namespace android
+
+android::SoftOMXComponent *createSoftOMXComponent(
+        const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData,
+        OMX_COMPONENTTYPE **component) {
+    return new android::SoftMPEG2(name, callbacks, appData, component);
+}
diff --git a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h
new file mode 100644
index 0000000..f7b1961
--- /dev/null
+++ b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SOFT_MPEG2_H_
+
+#define SOFT_MPEG2_H_
+
+#include "SoftVideoDecoderOMXComponent.h"
+#include <sys/time.h>
+
+namespace android {
+
+#define ivd_aligned_malloc(alignment, size) memalign(alignment, size)
+#define ivd_aligned_free(buf) free(buf)
+
+/** Number of entries in the time-stamp array */
+#define MAX_TIME_STAMPS 64
+
+/** Maximum number of cores supported by the codec */
+#define CODEC_MAX_NUM_CORES 4
+
+#define CODEC_MAX_WIDTH     1920
+
+#define CODEC_MAX_HEIGHT    1088
+
+/** Input buffer size */
+#define INPUT_BUF_SIZE (1024 * 1024)
+
+#define MIN(a, b) ((a) < (b)) ? (a) : (b)
+
+/** Used to remove warnings about unused parameters */
+#define UNUSED(x) ((void)(x))
+
+/** Get time */
+#define GETTIME(a, b) gettimeofday(a, b);
+
+/** Compute difference between start and end */
+#define TIME_DIFF(start, end, diff) \
+    diff = ((end.tv_sec - start.tv_sec) * 1000000) + \
+            (end.tv_usec - start.tv_usec);
+
+struct SoftMPEG2 : public SoftVideoDecoderOMXComponent {
+    SoftMPEG2(
+            const char *name, const OMX_CALLBACKTYPE *callbacks,
+            OMX_PTR appData, OMX_COMPONENTTYPE **component);
+
+protected:
+    virtual ~SoftMPEG2();
+
+    virtual void onQueueFilled(OMX_U32 portIndex);
+    virtual void onPortFlushCompleted(OMX_U32 portIndex);
+    virtual void onReset();
+    virtual OMX_ERRORTYPE internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params);
+private:
+    // Number of input and output buffers
+    enum {
+        kNumBuffers = 8
+    };
+
+    iv_obj_t *mCodecCtx;         // Codec context
+    iv_mem_rec_t *mMemRecords;   // Memory records requested by the codec
+    size_t mNumMemRecords;       // Number of memory records requested by the codec
+
+    size_t mNumCores;            // Number of cores to be uesd by the codec
+
+    struct timeval mTimeStart;   // Time at the start of decode()
+    struct timeval mTimeEnd;     // Time at the end of decode()
+
+    // Internal buffer to be used to flush out the buffers from decoder
+    uint8_t *mFlushOutBuffer;
+
+    // Status of entries in the timestamp array
+    bool mTimeStampsValid[MAX_TIME_STAMPS];
+
+    // Timestamp array - Since codec does not take 64 bit timestamps,
+    // they are maintained in the plugin
+    OMX_S64 mTimeStamps[MAX_TIME_STAMPS];
+
+#ifdef FILE_DUMP_ENABLE
+    char mInFile[200];
+#endif /* FILE_DUMP_ENABLE */
+
+    OMX_COLOR_FORMATTYPE mOmxColorFormat;    // OMX Color format
+    IV_COLOR_FORMAT_T mIvColorFormat;        // Ittiam Color format
+
+    bool mIsInFlush;        // codec is flush mode
+    bool mReceivedEOS;      // EOS is receieved on input port
+    bool mInitNeeded;
+    uint32_t mNewWidth;
+    uint32_t mNewHeight;
+    // The input stream has changed to a different resolution, which is still supported by the
+    // codec. So the codec is switching to decode the new resolution.
+    bool mChangingResolution;
+    bool mFlushNeeded;
+
+    status_t initDecoder();
+    status_t deInitDecoder();
+    status_t setFlushMode();
+    status_t setParams(size_t stride);
+    void logVersion();
+    status_t setNumCores();
+    status_t resetDecoder();
+    status_t resetPlugin();
+    status_t reInitDecoder();
+
+    void setDecodeArgs(
+            ivd_video_decode_ip_t *ps_dec_ip,
+            ivd_video_decode_op_t *ps_dec_op,
+            OMX_BUFFERHEADERTYPE *inHeader,
+            OMX_BUFFERHEADERTYPE *outHeader,
+            size_t timeStampIx);
+
+    DISALLOW_EVIL_CONSTRUCTORS(SoftMPEG2);
+};
+
+#ifdef FILE_DUMP_ENABLE
+
+#define INPUT_DUMP_PATH     "/sdcard/media/mpeg2d_input"
+#define INPUT_DUMP_EXT      "m2v"
+
+#define GENERATE_FILE_NAMES() {                         \
+    GETTIME(&mTimeStart, NULL);                         \
+    strcpy(mInFile, "");                                \
+    sprintf(mInFile, "%s_%ld.%ld.%s", INPUT_DUMP_PATH,  \
+            mTimeStart.tv_sec, mTimeStart.tv_usec,      \
+            INPUT_DUMP_EXT);                            \
+}
+
+#define CREATE_DUMP_FILE(m_filename) {                  \
+    FILE *fp = fopen(m_filename, "wb");                 \
+    if (fp != NULL) {                                   \
+        fclose(fp);                                     \
+    } else {                                            \
+        ALOGD("Could not open file %s", m_filename);    \
+    }                                                   \
+}
+#define DUMP_TO_FILE(m_filename, m_buf, m_size)         \
+{                                                       \
+    FILE *fp = fopen(m_filename, "ab");                 \
+    if (fp != NULL && m_buf != NULL) {                  \
+        int i;                                          \
+        i = fwrite(m_buf, 1, m_size, fp);               \
+        ALOGD("fwrite ret %d to write %d", i, m_size);  \
+        if (i != (int)m_size) {                         \
+            ALOGD("Error in fwrite, returned %d", i);   \
+            perror("Error in write to file");           \
+        }                                               \
+        fclose(fp);                                     \
+    } else {                                            \
+        ALOGD("Could not write to file %s", m_filename);\
+    }                                                   \
+}
+#else /* FILE_DUMP_ENABLE */
+#define INPUT_DUMP_PATH
+#define INPUT_DUMP_EXT
+#define OUTPUT_DUMP_PATH
+#define OUTPUT_DUMP_EXT
+#define GENERATE_FILE_NAMES()
+#define CREATE_DUMP_FILE(m_filename)
+#define DUMP_TO_FILE(m_filename, m_buf, m_size)
+#endif /* FILE_DUMP_ENABLE */
+
+} // namespace android
+
+#endif  // SOFT_MPEG2_H_
diff --git a/media/libstagefright/data/media_codecs_google_video.xml b/media/libstagefright/data/media_codecs_google_video.xml
old mode 100644
new mode 100755
index 7e9fa18..740f96b
--- a/media/libstagefright/data/media_codecs_google_video.xml
+++ b/media/libstagefright/data/media_codecs_google_video.xml
@@ -16,6 +16,15 @@
 
 <Included>
     <Decoders>
+        <MediaCodec name="OMX.google.mpeg2.decoder" type="video/mpeg2">
+            <!-- profiles and levels:  ProfileMain : LevelHL -->
+            <Limit name="size" min="16x16" max="1920x1088" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" range="1-244800" />
+            <Limit name="bitrate" range="1-20000000" />
+            <Feature name="adaptive-playback" />
+        </MediaCodec>
         <MediaCodec name="OMX.google.mpeg4.decoder" type="video/mp4v-es">
             <!-- profiles and levels:  ProfileSimple : Level3 -->
             <Limit name="size" min="2x2" max="352x288" />
@@ -34,12 +43,12 @@
             <Feature name="adaptive-playback" />
         </MediaCodec>
         <MediaCodec name="OMX.google.h264.decoder" type="video/avc">
-            <!-- profiles and levels:  ProfileBaseline : Level51 -->
-            <Limit name="size" min="2x2" max="2048x2048" />
+            <!-- profiles and levels:  ProfileHigh : Level41 -->
+            <Limit name="size" min="16x16" max="1920x1088" />
             <Limit name="alignment" value="2x2" />
             <Limit name="block-size" value="16x16" />
-            <Limit name="blocks-per-second" range="1-983040" />
-            <Limit name="bitrate" range="1-40000000" />
+            <Limit name="blocks-per-second" range="1-244800" />
+            <Limit name="bitrate" range="1-12000000" />
             <Feature name="adaptive-playback" />
         </MediaCodec>
         <MediaCodec name="OMX.google.hevc.decoder" type="video/hevc">
@@ -78,12 +87,12 @@
             <Limit name="bitrate" range="1-128000" />
         </MediaCodec>
         <MediaCodec name="OMX.google.h264.encoder" type="video/avc">
-            <!-- profiles and levels:  ProfileBaseline : Level2 -->
-            <Limit name="size" min="16x16" max="896x896" />
-            <Limit name="alignment" value="16x16" />
+            <!-- profiles and levels:  ProfileBaseline : Level41 -->
+            <Limit name="size" min="16x16" max="1920x1088" />
+            <Limit name="alignment" value="2x2" />
             <Limit name="block-size" value="16x16" />
-            <Limit name="blocks-per-second" range="1-11880" />
-            <Limit name="bitrate" range="1-2000000" />
+            <Limit name="blocks-per-second" range="1-244800" />
+            <Limit name="bitrate" range="1-12000000" />
         </MediaCodec>
         <MediaCodec name="OMX.google.mpeg4.encoder" type="video/mp4v-es">
             <!-- profiles and levels:  ProfileCore : Level2 -->
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 77d65e0..4704ad3 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -33,7 +33,7 @@
 
 struct AudioPlayer;
 struct ClockEstimator;
-struct DataSource;
+struct IDataSource;
 struct MediaBuffer;
 struct MediaExtractor;
 struct MediaSource;
diff --git a/media/libstagefright/include/CallbackDataSource.h b/media/libstagefright/include/CallbackDataSource.h
new file mode 100644
index 0000000..678eb2e
--- /dev/null
+++ b/media/libstagefright/include/CallbackDataSource.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_CALLBACKDATASOURCE_H
+#define ANDROID_CALLBACKDATASOURCE_H
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/foundation/ADebug.h>
+
+namespace android {
+
+class IDataSource;
+class IMemory;
+
+// A stagefright DataSource that wraps a binder IDataSource. It's a "Callback"
+// DataSource because it calls back to the IDataSource for data.
+class CallbackDataSource : public DataSource {
+public:
+    CallbackDataSource(const sp<IDataSource>& iDataSource);
+    virtual ~CallbackDataSource();
+
+    // DataSource implementation.
+    virtual status_t initCheck() const;
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+    virtual status_t getSize(off64_t *size);
+
+private:
+    sp<IDataSource> mIDataSource;
+    sp<IMemory> mMemory;
+
+    DISALLOW_EVIL_CONSTRUCTORS(CallbackDataSource);
+};
+
+}; // namespace android
+
+#endif // ANDROID_CALLBACKDATASOURCE_H
diff --git a/media/libstagefright/include/StagefrightMetadataRetriever.h b/media/libstagefright/include/StagefrightMetadataRetriever.h
index 6632c27..96a35f3 100644
--- a/media/libstagefright/include/StagefrightMetadataRetriever.h
+++ b/media/libstagefright/include/StagefrightMetadataRetriever.h
@@ -38,6 +38,7 @@
             const KeyedVector<String8, String8> *headers);
 
     virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
+    virtual status_t setDataSource(const sp<DataSource>& source);
 
     virtual VideoFrame *getFrameAtTime(int64_t timeUs, int option);
     virtual MediaAlbumArt *extractAlbumArt();
@@ -53,6 +54,8 @@
     MediaAlbumArt *mAlbumArt;
 
     void parseMetaData();
+    // Delete album art and clear metadata.
+    void clearMetadata();
 
     StagefrightMetadataRetriever(const StagefrightMetadataRetriever &);
 
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 0a868bc..14ae81c 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -146,6 +146,7 @@
     sp<ABuffer> mBuffer;
     sp<AnotherPacketSource> mSource;
     bool mPayloadStarted;
+    bool mEOSReached;
 
     uint64_t mPrevPTS;
 
@@ -567,6 +568,7 @@
       mPCR_PID(PCR_PID),
       mExpectedContinuityCounter(-1),
       mPayloadStarted(false),
+      mEOSReached(false),
       mPrevPTS(0),
       mQueue(NULL) {
     switch (mStreamType) {
@@ -766,6 +768,8 @@
     if (mSource != NULL) {
         mSource->signalEOS(finalResult);
     }
+    mEOSReached = true;
+    flush();
 }
 
 status_t ATSParser::Stream::parsePES(ABitReader *br) {
@@ -976,6 +980,10 @@
 
     status_t err = mQueue->appendData(data, size, timeUs);
 
+    if (mEOSReached) {
+        mQueue->signalEOS();
+    }
+
     if (err != OK) {
         return;
     }
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index a279049..55262ff 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -38,7 +38,8 @@
 
 ElementaryStreamQueue::ElementaryStreamQueue(Mode mode, uint32_t flags)
     : mMode(mode),
-      mFlags(flags) {
+      mFlags(flags),
+      mEOSReached(false) {
 }
 
 sp<MetaData> ElementaryStreamQueue::getFormat() {
@@ -244,6 +245,11 @@
 
 status_t ElementaryStreamQueue::appendData(
         const void *data, size_t size, int64_t timeUs) {
+
+    if (mEOSReached) {
+        ALOGE("appending data after EOS");
+        return ERROR_MALFORMED;
+    }
     if (mBuffer == NULL || mBuffer->size() == 0) {
         switch (mMode) {
             case H264:
@@ -1274,4 +1280,17 @@
     return NULL;
 }
 
+void ElementaryStreamQueue::signalEOS() {
+    if (!mEOSReached) {
+        if (mMode == MPEG_VIDEO) {
+            const char *theEnd = "\x00\x00\x01\x00";
+            appendData(theEnd, 4, 0);
+        }
+        mEOSReached = true;
+    } else {
+        ALOGW("EOS already signaled");
+    }
+}
+
+
 }  // namespace android
diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h
index 45b4624..5425367 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.h
+++ b/media/libstagefright/mpeg2ts/ESQueue.h
@@ -46,6 +46,7 @@
     ElementaryStreamQueue(Mode mode, uint32_t flags = 0);
 
     status_t appendData(const void *data, size_t size, int64_t timeUs);
+    void signalEOS();
     void clear(bool clearFormat);
 
     sp<ABuffer> dequeueAccessUnit();
@@ -60,6 +61,7 @@
 
     Mode mMode;
     uint32_t mFlags;
+    bool mEOSReached;
 
     sp<ABuffer> mBuffer;
     List<RangeInfo> mRangeInfos;
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index 33cfd1d..74cb5d8 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -204,6 +204,9 @@
     ssize_t n = mDataSource->readAt(mOffset, packet, kTSPacketSize);
 
     if (n < (ssize_t)kTSPacketSize) {
+        if (n >= 0) {
+            mParser->signalEOS(ERROR_END_OF_STREAM);
+        }
         return (n < 0) ? (status_t)n : ERROR_END_OF_STREAM;
     }
 
diff --git a/media/libstagefright/omx/SoftOMXPlugin.cpp b/media/libstagefright/omx/SoftOMXPlugin.cpp
old mode 100644
new mode 100755
index 3ab241a..0f9c00c
--- a/media/libstagefright/omx/SoftOMXPlugin.cpp
+++ b/media/libstagefright/omx/SoftOMXPlugin.cpp
@@ -40,11 +40,12 @@
     { "OMX.google.amrnb.encoder", "amrnbenc", "audio_encoder.amrnb" },
     { "OMX.google.amrwb.decoder", "amrdec", "audio_decoder.amrwb" },
     { "OMX.google.amrwb.encoder", "amrwbenc", "audio_encoder.amrwb" },
-    { "OMX.google.h264.decoder", "h264dec", "video_decoder.avc" },
-    { "OMX.google.h264.encoder", "h264enc", "video_encoder.avc" },
+    { "OMX.google.h264.decoder", "avcdec", "video_decoder.avc" },
+    { "OMX.google.h264.encoder", "avcenc", "video_encoder.avc" },
     { "OMX.google.hevc.decoder", "hevcdec", "video_decoder.hevc" },
     { "OMX.google.g711.alaw.decoder", "g711dec", "audio_decoder.g711alaw" },
     { "OMX.google.g711.mlaw.decoder", "g711dec", "audio_decoder.g711mlaw" },
+    { "OMX.google.mpeg2.decoder", "mpeg2dec", "video_decoder.mpeg2" },
     { "OMX.google.h263.decoder", "mpeg4dec", "video_decoder.h263" },
     { "OMX.google.h263.encoder", "mpeg4enc", "video_encoder.h263" },
     { "OMX.google.mpeg4.decoder", "mpeg4dec", "video_decoder.mpeg4" },
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 48d0e29..58c65fa 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -218,6 +218,11 @@
 
     virtual status_t registerPolicyMixes(Vector<AudioMix> mixes) = 0;
     virtual status_t unregisterPolicyMixes(Vector<AudioMix> mixes) = 0;
+
+    virtual status_t startAudioSource(const struct audio_port_config *source,
+                                      const audio_attributes_t *attributes,
+                                      audio_io_handle_t *handle) = 0;
+    virtual status_t stopAudioSource(audio_io_handle_t handle) = 0;
 };
 
 
@@ -320,6 +325,8 @@
     virtual void onAudioPatchListUpdate() = 0;
 
     virtual audio_unique_id_t newAudioUniqueId() = 0;
+
+    virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state) = 0;
 };
 
 extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface);
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index f1aee46..50f622d 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -123,6 +123,7 @@
     sp<SwAudioOutputDescriptor> mOutput1;    // used by duplicated outputs: first output
     sp<SwAudioOutputDescriptor> mOutput2;    // used by duplicated outputs: second output
     uint32_t mDirectOpenCount; // number of clients using this output (direct outputs only)
+    uint32_t mGlobalRefCount;  // non-stream-specific ref count
 };
 
 class SwAudioOutputCollection :
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 596aa1d..144d8ad 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -225,7 +225,7 @@
     : AudioOutputDescriptor(profile, clientInterface),
     mProfile(profile), mIoHandle(0), mLatency(0),
     mFlags((audio_output_flags_t)0), mPolicyMix(NULL),
-    mOutput1(0), mOutput2(0), mDirectOpenCount(0)
+    mOutput1(0), mOutput2(0), mDirectOpenCount(0), mGlobalRefCount(0)
 {
     if (profile != NULL) {
         mFlags = (audio_output_flags_t)profile->mFlags;
@@ -305,6 +305,27 @@
         mOutput2->changeRefCount(stream, delta);
     }
     AudioOutputDescriptor::changeRefCount(stream, delta);
+
+    // handle stream-independent ref count
+    uint32_t oldGlobalRefCount = mGlobalRefCount;
+    if ((delta + (int)mGlobalRefCount) < 0) {
+        ALOGW("changeRefCount() invalid delta %d globalRefCount %d", delta, mGlobalRefCount);
+        mGlobalRefCount = 0;
+    } else {
+        mGlobalRefCount += delta;
+    }
+    if ((oldGlobalRefCount == 0) && (mGlobalRefCount > 0)) {
+        if ((mPolicyMix != NULL) && ((mPolicyMix->mFlags & MIX_FLAG_NOTIFY_ACTIVITY) != 0)) {
+            mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mRegistrationId,
+                    MIX_STATE_MIXING);
+        }
+
+    } else if ((oldGlobalRefCount > 0) && (mGlobalRefCount == 0)) {
+        if ((mPolicyMix != NULL) && ((mPolicyMix->mFlags & MIX_FLAG_NOTIFY_ACTIVITY) != 0)) {
+            mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mRegistrationId,
+                    MIX_STATE_IDLE);
+        }
+    }
 }
 
 
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index ba9f996..3ea6a11 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2462,6 +2462,18 @@
     return mSoundTriggerSessions.acquireSession(*session, *ioHandle);
 }
 
+status_t AudioPolicyManager::startAudioSource(const struct audio_port_config *source,
+                                       const audio_attributes_t *attributes,
+                                       audio_io_handle_t *handle)
+{
+    return INVALID_OPERATION;
+}
+
+status_t AudioPolicyManager::stopAudioSource(audio_io_handle_t handle)
+{
+    return INVALID_OPERATION;
+}
+
 // ----------------------------------------------------------------------------
 // AudioPolicyManager
 // ----------------------------------------------------------------------------
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index fe6b986..146a7af 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -220,6 +220,11 @@
         virtual status_t registerPolicyMixes(Vector<AudioMix> mixes);
         virtual status_t unregisterPolicyMixes(Vector<AudioMix> mixes);
 
+        virtual status_t startAudioSource(const struct audio_port_config *source,
+                                          const audio_attributes_t *attributes,
+                                          audio_io_handle_t *handle);
+        virtual status_t stopAudioSource(audio_io_handle_t handle);
+
         // Audio policy configuration file parsing (audio_policy.conf)
         // TODO candidates to be moved to ConfigParsingUtils
                 void defaultAudioPolicyConfig(void);
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index 3e090e9..489a9be 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -213,6 +213,12 @@
     mAudioPolicyService->onAudioPatchListUpdate();
 }
 
+void AudioPolicyService::AudioPolicyClient::onDynamicPolicyMixStateUpdate(
+        String8 regId, int32_t state)
+{
+    mAudioPolicyService->onDynamicPolicyMixStateUpdate(regId, state);
+}
+
 audio_unique_id_t AudioPolicyService::AudioPolicyClient::newAudioUniqueId()
 {
     return AudioSystem::newAudioUniqueId();
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 9510727..5f501a5 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -661,4 +661,26 @@
     }
 }
 
+status_t AudioPolicyService::startAudioSource(const struct audio_port_config *source,
+                                  const audio_attributes_t *attributes,
+                                  audio_io_handle_t *handle)
+{
+    Mutex::Autolock _l(mLock);
+    if (mAudioPolicyManager == NULL) {
+        return NO_INIT;
+    }
+
+    return mAudioPolicyManager->startAudioSource(source, attributes, handle);
+}
+
+status_t AudioPolicyService::stopAudioSource(audio_io_handle_t handle)
+{
+    Mutex::Autolock _l(mLock);
+    if (mAudioPolicyManager == NULL) {
+        return NO_INIT;
+    }
+
+    return mAudioPolicyManager->stopAudioSource(handle);
+}
+
 }; // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
index e4ca5dc..f783437 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
@@ -604,4 +604,16 @@
     return INVALID_OPERATION;
 }
 
+status_t AudioPolicyService::startAudioSource(const struct audio_port_config *source,
+                                  const audio_attributes_t *attributes,
+                                  audio_io_handle_t *handle)
+{
+    return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::stopAudioSource(audio_io_handle_t handle)
+{
+    return INVALID_OPERATION;
+}
+
 }; // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 00f188f..ccf9f9b 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -222,6 +222,21 @@
     }
 }
 
+void AudioPolicyService::onDynamicPolicyMixStateUpdate(String8 regId, int32_t state)
+{
+    ALOGV("AudioPolicyService::onDynamicPolicyMixStateUpdate(%s, %d)",
+            regId.string(), state);
+    mOutputCommandThread->dynamicPolicyMixStateUpdateCommand(regId, state);
+}
+
+void AudioPolicyService::doOnDynamicPolicyMixStateUpdate(String8 regId, int32_t state)
+{
+    Mutex::Autolock _l(mNotificationClientsLock);
+    for (size_t i = 0; i < mNotificationClients.size(); i++) {
+        mNotificationClients.valueAt(i)->onDynamicPolicyMixStateUpdate(regId, state);
+    }
+}
+
 status_t AudioPolicyService::clientSetAudioPortConfig(const struct audio_port_config *config,
                                                       int delayMs)
 {
@@ -262,6 +277,14 @@
     }
 }
 
+void AudioPolicyService::NotificationClient::onDynamicPolicyMixStateUpdate(
+        String8 regId, int32_t state)
+{
+    if (mAudioPolicyServiceClient != 0) {
+            mAudioPolicyServiceClient->onDynamicPolicyMixStateUpdate(regId, state);
+    }
+}
+
 void AudioPolicyService::binderDied(const wp<IBinder>& who) {
     ALOGW("binderDied() %p, calling pid %d", who.unsafe_get(),
             IPCThreadState::self()->getCallingPid());
@@ -511,6 +534,20 @@
                         command->mStatus = af->setAudioPortConfig(&data->mConfig);
                     }
                     } break;
+                case DYN_POLICY_MIX_STATE_UPDATE: {
+                    DynPolicyMixStateUpdateData *data =
+                            (DynPolicyMixStateUpdateData *)command->mParam.get();
+                    //###ALOGV("AudioCommandThread() processing dyn policy mix state update");
+                    ALOGV("AudioCommandThread() processing dyn policy mix state update %s %d",
+                            data->mRegId.string(), data->mState);
+                    svc = mService.promote();
+                    if (svc == 0) {
+                        break;
+                    }
+                    mLock.unlock();
+                    svc->doOnDynamicPolicyMixStateUpdate(data->mRegId, data->mState);
+                    mLock.lock();
+                    } break;
                 default:
                     ALOGW("AudioCommandThread() unknown command %d", command->mCommand);
                 }
@@ -747,6 +784,20 @@
     return sendCommand(command, delayMs);
 }
 
+void AudioPolicyService::AudioCommandThread::dynamicPolicyMixStateUpdateCommand(
+        String8 regId, int32_t state)
+{
+    sp<AudioCommand> command = new AudioCommand();
+    command->mCommand = DYN_POLICY_MIX_STATE_UPDATE;
+    DynPolicyMixStateUpdateData *data = new DynPolicyMixStateUpdateData();
+    data->mRegId = regId;
+    data->mState = state;
+    command->mParam = data;
+    ALOGV("AudioCommandThread() sending dynamic policy mix (id=%s) state update to %d",
+            regId.string(), state);
+    sendCommand(command);
+}
+
 status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& command, int delayMs)
 {
     {
@@ -888,6 +939,10 @@
             delayMs = 1;
         } break;
 
+        case DYN_POLICY_MIX_STATE_UPDATE: {
+
+        } break;
+
         case START_TONE:
         case STOP_TONE:
         default:
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index f8dabd3..4e25d33 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -192,6 +192,11 @@
 
     virtual status_t registerPolicyMixes(Vector<AudioMix> mixes, bool registration);
 
+    virtual status_t startAudioSource(const struct audio_port_config *source,
+                                      const audio_attributes_t *attributes,
+                                      audio_io_handle_t *handle);
+    virtual status_t stopAudioSource(audio_io_handle_t handle);
+
             status_t doStopOutput(audio_io_handle_t output,
                                   audio_stream_type_t stream,
                                   audio_session_t session);
@@ -213,6 +218,9 @@
             void onAudioPatchListUpdate();
             void doOnAudioPatchListUpdate();
 
+            void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
+            void doOnDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
+
 private:
                         AudioPolicyService() ANDROID_API;
     virtual             ~AudioPolicyService();
@@ -243,6 +251,7 @@
             UPDATE_AUDIOPORT_LIST,
             UPDATE_AUDIOPATCH_LIST,
             SET_AUDIOPORT_CONFIG,
+            DYN_POLICY_MIX_STATE_UPDATE
         };
 
         AudioCommandThread (String8 name, const wp<AudioPolicyService>& service);
@@ -280,6 +289,7 @@
                     void        updateAudioPatchListCommand();
                     status_t    setAudioPortConfigCommand(const struct audio_port_config *config,
                                                           int delayMs);
+                    void        dynamicPolicyMixStateUpdateCommand(String8 regId, int32_t state);
                     void        insertCommand_l(AudioCommand *command, int delayMs = 0);
 
     private:
@@ -364,6 +374,12 @@
             struct audio_port_config mConfig;
         };
 
+        class DynPolicyMixStateUpdateData : public AudioCommandData {
+        public:
+            String8 mRegId;
+            int32_t mState;
+        };
+
         Mutex   mLock;
         Condition mWaitWorkCV;
         Vector < sp<AudioCommand> > mAudioCommands; // list of pending commands
@@ -469,6 +485,7 @@
 
         virtual void onAudioPortListUpdate();
         virtual void onAudioPatchListUpdate();
+        virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
 
         virtual audio_unique_id_t newAudioUniqueId();
 
@@ -484,8 +501,9 @@
                                                 uid_t uid);
         virtual             ~NotificationClient();
 
-                            void        onAudioPortListUpdate();
-                            void        onAudioPatchListUpdate();
+                            void      onAudioPortListUpdate();
+                            void      onAudioPatchListUpdate();
+                            void      onDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
 
                 // IBinder::DeathRecipient
                 virtual     void        binderDied(const wp<IBinder>& who);
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 414d563..8c5c43a 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -140,76 +140,90 @@
     BnCameraService::onFirstRef();
 
     camera_module_t *rawModule;
-    if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,
-                (const hw_module_t **)&rawModule) < 0) {
-        ALOGE("Could not load camera HAL module");
+    int err = hw_get_module(CAMERA_HARDWARE_MODULE_ID,
+            (const hw_module_t **)&rawModule);
+    if (err < 0) {
+        ALOGE("Could not load camera HAL module: %d (%s)", err, strerror(-err));
+        logServiceError("Could not load camera HAL module", err);
         mNumberOfCameras = 0;
+        return;
     }
-    else {
-        mModule = new CameraModule(rawModule);
-        ALOGI("Loaded \"%s\" camera module", mModule->getModuleName());
-        mNumberOfCameras = mModule->getNumberOfCameras();
 
-        mFlashlight = new CameraFlashlight(*mModule, *this);
-        status_t res = mFlashlight->findFlashUnits();
-        if (res) {
-            // impossible because we haven't open any camera devices.
-            ALOGE("Failed to find flash units.");
-        }
+    mModule = new CameraModule(rawModule);
+    ALOGI("Loaded \"%s\" camera module", mModule->getModuleName());
+    err = mModule->init();
+    if (err != OK) {
+        ALOGE("Could not initialize camera HAL module: %d (%s)", err,
+            strerror(-err));
+        logServiceError("Could not initialize camera HAL module", err);
 
-        for (int i = 0; i < mNumberOfCameras; i++) {
-            String8 cameraId = String8::format("%d", i);
-
-            // Defaults to use for cost and conflicting devices
-            int cost = 100;
-            char** conflicting_devices = nullptr;
-            size_t conflicting_devices_length = 0;
-
-            // If using post-2.4 module version, query the cost + conflicting devices from the HAL
-            if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4) {
-                struct camera_info info;
-                status_t rc = mModule->getCameraInfo(i, &info);
-                if (rc == NO_ERROR) {
-                    cost = info.resource_cost;
-                    conflicting_devices = info.conflicting_devices;
-                    conflicting_devices_length = info.conflicting_devices_length;
-                } else {
-                    ALOGE("%s: Received error loading camera info for device %d, cost and"
-                            " conflicting devices fields set to defaults for this device.",
-                            __FUNCTION__, i);
-                }
-            }
-
-            std::set<String8> conflicting;
-            for (size_t i = 0; i < conflicting_devices_length; i++) {
-                conflicting.emplace(String8(conflicting_devices[i]));
-            }
-
-            // Initialize state for each camera device
-            {
-                Mutex::Autolock lock(mCameraStatesLock);
-                mCameraStates.emplace(cameraId, std::make_shared<CameraState>(cameraId, cost,
-                        conflicting));
-            }
-
-            if (mFlashlight->hasFlashUnit(cameraId)) {
-                mTorchStatusMap.add(cameraId,
-                        ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF);
-            }
-        }
-
-        if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_1) {
-            mModule->setCallbacks(this);
-        }
-
-        VendorTagDescriptor::clearGlobalVendorTagDescriptor();
-
-        if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_2) {
-            setUpVendorTags();
-        }
-
-        CameraDeviceFactory::registerService(this);
+        mNumberOfCameras = 0;
+        delete mModule;
+        mModule = nullptr;
+        return;
     }
+
+    mNumberOfCameras = mModule->getNumberOfCameras();
+
+    mFlashlight = new CameraFlashlight(*mModule, *this);
+    status_t res = mFlashlight->findFlashUnits();
+    if (res) {
+        // impossible because we haven't open any camera devices.
+        ALOGE("Failed to find flash units.");
+    }
+
+    for (int i = 0; i < mNumberOfCameras; i++) {
+        String8 cameraId = String8::format("%d", i);
+
+        // Defaults to use for cost and conflicting devices
+        int cost = 100;
+        char** conflicting_devices = nullptr;
+        size_t conflicting_devices_length = 0;
+
+        // If using post-2.4 module version, query the cost + conflicting devices from the HAL
+        if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4) {
+            struct camera_info info;
+            status_t rc = mModule->getCameraInfo(i, &info);
+            if (rc == NO_ERROR) {
+                cost = info.resource_cost;
+                conflicting_devices = info.conflicting_devices;
+                conflicting_devices_length = info.conflicting_devices_length;
+            } else {
+                ALOGE("%s: Received error loading camera info for device %d, cost and"
+                        " conflicting devices fields set to defaults for this device.",
+                        __FUNCTION__, i);
+            }
+        }
+
+        std::set<String8> conflicting;
+        for (size_t i = 0; i < conflicting_devices_length; i++) {
+            conflicting.emplace(String8(conflicting_devices[i]));
+        }
+
+        // Initialize state for each camera device
+        {
+            Mutex::Autolock lock(mCameraStatesLock);
+            mCameraStates.emplace(cameraId, std::make_shared<CameraState>(cameraId, cost,
+                    conflicting));
+        }
+
+        if (mFlashlight->hasFlashUnit(cameraId)) {
+            mTorchStatusMap.add(cameraId,
+                    ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF);
+        }
+    }
+
+    if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_1) {
+        mModule->setCallbacks(this);
+    }
+
+    VendorTagDescriptor::clearGlobalVendorTagDescriptor();
+
+    if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_2) {
+        setUpVendorTags();
+    }
+
+    CameraDeviceFactory::registerService(this);
 }
 
 CameraService::~CameraService() {
@@ -299,12 +313,11 @@
     ICameraServiceListener::TorchStatus status;
     status_t res = getTorchStatusLocked(cameraId, &status);
     if (res) {
-        ALOGE("%s: cannot get torch status of camera %s", cameraId.string());
+        ALOGE("%s: cannot get torch status of camera %s: %s (%d)",
+                __FUNCTION__, cameraId.string(), strerror(-res), res);
         return;
     }
     if (status == newStatus) {
-        ALOGE("%s: Torch state transition to the same status 0x%x not allowed",
-              __FUNCTION__, (uint32_t)newStatus);
         return;
     }
 
@@ -1139,14 +1152,14 @@
     // verify id is valid.
     auto state = getCameraState(id);
     if (state == nullptr) {
-        ALOGE("%s: camera id is invalid %s", id.string());
+        ALOGE("%s: camera id is invalid %s", __FUNCTION__, id.string());
         return -EINVAL;
     }
 
     ICameraServiceListener::Status cameraStatus = state->getStatus();
     if (cameraStatus != ICameraServiceListener::STATUS_PRESENT &&
             cameraStatus != ICameraServiceListener::STATUS_NOT_AVAILABLE) {
-        ALOGE("%s: camera id is invalid %s", id.string());
+        ALOGE("%s: camera id is invalid %s", __FUNCTION__, id.string());
         return -EINVAL;
     }
 
@@ -1554,6 +1567,11 @@
     logEvent(String8::format("DIED client(s) with PID %d, reason: (%s)", clientPid, reason));
 }
 
+void CameraService::logServiceError(const char* msg, int errorCode) {
+    String8 curTime = getFormattedCurrentTime();
+    logEvent(String8::format("SERVICE ERROR: %s : %d (%s)", msg, errorCode, strerror(errorCode)));
+}
+
 status_t CameraService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
         uint32_t flags) {
 
@@ -1996,6 +2014,10 @@
         if (!mModule) {
             result = String8::format("No camera module available!\n");
             write(fd, result.string(), result.size());
+
+            // Dump event log for error information
+            dumpEventLog(fd);
+
             if (locked) mServiceLock.unlock();
             return NO_ERROR;
         }
@@ -2021,20 +2043,7 @@
             desc->dump(fd, /*verbosity*/2, /*indentation*/4);
         }
 
-        result = String8("Prior client events (most recent at top):\n");
-
-        {
-            Mutex::Autolock l(mLogLock);
-            for (const auto& msg : mEventLog) {
-                result.appendFormat("%s\n", msg.string());
-            }
-
-            if (mEventLog.size() == DEFAULT_EVENT_LOG_LENGTH) {
-                result.append("...\n");
-            }
-        }
-
-        write(fd, result.string(), result.size());
+        dumpEventLog(fd);
 
         bool stateLocked = tryLock(mCameraStatesLock);
         if (!stateLocked) {
@@ -2142,6 +2151,24 @@
     return NO_ERROR;
 }
 
+void CameraService::dumpEventLog(int fd) {
+    String8 result = String8("\nPrior client events (most recent at top):\n");
+
+    Mutex::Autolock l(mLogLock);
+    for (const auto& msg : mEventLog) {
+        result.appendFormat("  %s\n", msg.string());
+    }
+
+    if (mEventLog.size() == DEFAULT_EVENT_LOG_LENGTH) {
+        result.append("  ...\n");
+    } else if (mEventLog.size() == 0) {
+        result.append("  [no events yet]\n");
+    }
+    result.append("\n");
+
+    write(fd, result.string(), result.size());
+}
+
 void CameraService::handleTorchClientBinderDied(const wp<IBinder> &who) {
     Mutex::Autolock al(mTorchClientMapMutex);
     for (size_t i = 0; i < mTorchClientMap.size(); i++) {
@@ -2204,16 +2231,20 @@
     state->updateStatus(status, cameraId, rejectSourceStates, [this]
             (const String8& cameraId, ICameraServiceListener::Status status) {
 
-            // Update torch status
-            if (status == ICameraServiceListener::STATUS_NOT_PRESENT ||
-                status == ICameraServiceListener::STATUS_NOT_AVAILABLE) {
-                // Update torch status to not available when the camera device becomes not present
-                // or not available.
-                onTorchStatusChanged(cameraId, ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE);
-            } else if (status == ICameraServiceListener::STATUS_PRESENT) {
-                // Update torch status to available when the camera device becomes present or
-                // available
-                onTorchStatusChanged(cameraId, ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF);
+            if (status != ICameraServiceListener::STATUS_ENUMERATING) {
+                // Update torch status if it has a flash unit.
+                Mutex::Autolock al(mTorchStatusMutex);
+                ICameraServiceListener::TorchStatus torchStatus;
+                if (getTorchStatusLocked(cameraId, &torchStatus) !=
+                        NAME_NOT_FOUND) {
+                    ICameraServiceListener::TorchStatus newTorchStatus =
+                            status == ICameraServiceListener::STATUS_PRESENT ?
+                            ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF :
+                            ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE;
+                    if (torchStatus != newTorchStatus) {
+                        onTorchStatusChangedLocked(cameraId, newTorchStatus);
+                    }
+                }
             }
 
             Mutex::Autolock lock(mStatusListenerLock);
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 91c7d59..84e61c5 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -590,6 +590,16 @@
      */
     void logClientDied(int clientPid, const char* reason);
 
+    /**
+     * Add a event log message that a serious service-level error has occured
+     */
+    void logServiceError(const char* msg, int errorCode);
+
+    /**
+     * Dump the event log to an FD
+     */
+    void dumpEventLog(int fd);
+
     int                 mNumberOfCameras;
 
     // sounds
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index f53f425..05ede92 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -1710,6 +1710,40 @@
     return mStreamingProcessor->setRecordingBufferCount(count);
 }
 
+void Camera2Client::notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode,
+        const CaptureResultExtras& resultExtras) {
+    int32_t err = CAMERA_ERROR_UNKNOWN;
+    switch(errorCode) {
+        case ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED:
+            err = CAMERA_ERROR_RELEASED;
+            break;
+        case ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE:
+            err = CAMERA_ERROR_UNKNOWN;
+            break;
+        case ICameraDeviceCallbacks::ERROR_CAMERA_SERVICE:
+            err = CAMERA_ERROR_SERVER_DIED;
+            break;
+        case ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST:
+        case ICameraDeviceCallbacks::ERROR_CAMERA_RESULT:
+        case ICameraDeviceCallbacks::ERROR_CAMERA_BUFFER:
+            ALOGW("%s: Received recoverable error %d from HAL - ignoring, requestId %" PRId32,
+                    __FUNCTION__, errorCode, resultExtras.requestId);
+            return;
+        default:
+            err = CAMERA_ERROR_UNKNOWN;
+            break;
+    }
+
+    ALOGE("%s: Error condition %d reported by HAL, requestId %" PRId32, __FUNCTION__, errorCode,
+              resultExtras.requestId);
+
+    SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
+    if (l.mRemoteCallback != nullptr) {
+        l.mRemoteCallback->notifyCallback(CAMERA_MSG_ERROR, err, 0);
+    }
+}
+
+
 /** Device-related methods */
 void Camera2Client::notifyAutoFocus(uint8_t newState, int triggerId) {
     ALOGV("%s: Autofocus state now %d, last trigger %d",
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index 5a8241f..a988037 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -77,6 +77,8 @@
     virtual status_t        setParameters(const String8& params);
     virtual String8         getParameters() const;
     virtual status_t        sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
+    virtual void            notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode,
+                                        const CaptureResultExtras& resultExtras);
 
     /**
      * Interface used by CameraService
diff --git a/services/camera/libcameraservice/common/CameraModule.cpp b/services/camera/libcameraservice/common/CameraModule.cpp
index e5b12ae..ac4d9a6 100644
--- a/services/camera/libcameraservice/common/CameraModule.cpp
+++ b/services/camera/libcameraservice/common/CameraModule.cpp
@@ -57,6 +57,14 @@
     mCameraInfoMap.setCapacity(getNumberOfCameras());
 }
 
+int CameraModule::init() {
+    if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4 &&
+            mModule->init != NULL) {
+        return mModule->init();
+    }
+    return OK;
+}
+
 int CameraModule::getCameraInfo(int cameraId, struct camera_info *info) {
     Mutex::Autolock lock(mCameraInfoLock);
     if (cameraId < 0) {
@@ -78,6 +86,12 @@
         if (ret != 0) {
             return ret;
         }
+        int deviceVersion = cameraInfo.device_version;
+        if (deviceVersion < CAMERA_DEVICE_API_VERSION_2_0) {
+            // static_camera_characteristics is invalid
+            *info = rawInfo;
+            return ret;
+        }
         CameraMetadata m;
         m = rawInfo.static_camera_characteristics;
         deriveCameraCharacteristicsKeys(rawInfo.device_version, m);
@@ -92,7 +106,7 @@
     assert(index != NAME_NOT_FOUND);
     // return the cached camera info
     *info = mCameraInfoMap[index];
-    return 0;
+    return OK;
 }
 
 int CameraModule::open(const char* id, struct hw_device_t** device) {
@@ -160,4 +174,3 @@
 }
 
 }; // namespace android
-
diff --git a/services/camera/libcameraservice/common/CameraModule.h b/services/camera/libcameraservice/common/CameraModule.h
index e285b21..c21092e 100644
--- a/services/camera/libcameraservice/common/CameraModule.h
+++ b/services/camera/libcameraservice/common/CameraModule.h
@@ -34,6 +34,10 @@
 public:
     CameraModule(camera_module_t *module);
 
+    // Must be called after construction
+    // Returns OK on success, NO_INIT on failure
+    int init();
+
     int getCameraInfo(int cameraId, struct camera_info *info);
     int getNumberOfCameras(void);
     int open(const char* id, struct hw_device_t** device);
@@ -63,4 +67,3 @@
 } // namespace android
 
 #endif
-
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index ec9c70c..d2c2482 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -1082,9 +1082,9 @@
         mHal3Device, templateId);
     ATRACE_END();
     if (rawRequest == NULL) {
-        SET_ERR_L("HAL is unable to construct default settings for template %d",
-                templateId);
-        return DEAD_OBJECT;
+        ALOGI("%s: template %d is not supported on this camera device",
+              __FUNCTION__, templateId);
+        return BAD_VALUE;
     }
     *request = rawRequest;
     mRequestTemplateCache[templateId] = rawRequest;
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 3821da1..4c40bb6 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -109,11 +109,7 @@
             // oldUsage/oldMaxBuffers
             return this;
         case STATE_CONFIGURED:
-            if (stream_type == CAMERA3_STREAM_INPUT) {
-                ALOGE("%s: Cannot configure an input stream twice",
-                        __FUNCTION__);
-                return NULL;
-            } else if (hasOutstandingBuffersLocked()) {
+            if (hasOutstandingBuffersLocked()) {
                 ALOGE("%s: Cannot configure stream; has outstanding buffers",
                         __FUNCTION__);
                 return NULL;