Merge "Make a copy of output format in onOutputFormatChanged"
diff --git a/apex/manifest.json b/apex/manifest.json
index 3011ee8..ddd642e 100644
--- a/apex/manifest.json
+++ b/apex/manifest.json
@@ -1,4 +1,4 @@
 {
   "name": "com.android.media",
-  "version": 290000000
+  "version": 300000000
 }
diff --git a/apex/manifest_codec.json b/apex/manifest_codec.json
index 83a5178..2320fd7 100644
--- a/apex/manifest_codec.json
+++ b/apex/manifest_codec.json
@@ -1,4 +1,4 @@
 {
   "name": "com.android.media.swcodec",
-  "version": 290000000
+  "version": 300000000
 }
diff --git a/drm/drmserver/Android.bp b/drm/drmserver/Android.bp
index c25a0a1..fd71837 100644
--- a/drm/drmserver/Android.bp
+++ b/drm/drmserver/Android.bp
@@ -25,6 +25,7 @@
 
     shared_libs: [
         "libmedia",
+        "libmediametrics",
         "libutils",
         "liblog",
         "libbinder",
diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
index afbcb39..66610b3 100644
--- a/drm/drmserver/DrmManager.cpp
+++ b/drm/drmserver/DrmManager.cpp
@@ -19,7 +19,10 @@
 #include "utils/Log.h"
 
 #include <utils/String8.h>
+
+#include <binder/IPCThreadState.h>
 #include <drm/DrmInfo.h>
+
 #include <drm/DrmInfoEvent.h>
 #include <drm/DrmRights.h>
 #include <drm/DrmConstraints.h>
@@ -28,6 +31,7 @@
 #include <drm/DrmInfoRequest.h>
 #include <drm/DrmSupportInfo.h>
 #include <drm/DrmConvertedStatus.h>
+#include <media/MediaAnalyticsItem.h>
 #include <IDrmEngine.h>
 
 #include "DrmManager.h"
@@ -50,6 +54,40 @@
 
 }
 
+void DrmManager::reportEngineMetrics(
+        const char func[], const String8& plugInId, const String8& mimeType) {
+    IDrmEngine& engine = mPlugInManager.getPlugIn(plugInId);
+
+    std::unique_ptr<MediaAnalyticsItem> item(MediaAnalyticsItem::create("drmmanager"));
+    item->generateSessionID();
+    item->setUid(IPCThreadState::self()->getCallingUid());
+    item->setCString("function_name", func);
+    item->setCString("plugin_id", plugInId.getPathLeaf().getBasePath().c_str());
+
+    std::unique_ptr<DrmSupportInfo> info(engine.getSupportInfo(0));
+    if (NULL != info) {
+        item->setCString("description", info->getDescription().c_str());
+    }
+
+    if (!mimeType.isEmpty()) {
+        item->setCString("mime_types", mimeType.c_str());
+    } else if (NULL != info) {
+        DrmSupportInfo::MimeTypeIterator mimeIter = info->getMimeTypeIterator();
+        String8 mimes;
+        while (mimeIter.hasNext()) {
+            mimes += mimeIter.next();
+            if (mimeIter.hasNext()) {
+                mimes += ",";
+            }
+        }
+        item->setCString("mime_types", mimes.c_str());
+    }
+
+    if (!item->selfrecord()) {
+        ALOGE("Failed to record metrics");
+    }
+}
+
 int DrmManager::addUniqueId(bool isNative) {
     Mutex::Autolock _l(mLock);
 
@@ -147,27 +185,36 @@
     for (size_t index = 0; index < plugInIdList.size(); index++) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInIdList.itemAt(index));
         rDrmEngine.terminate(uniqueId);
+        reportEngineMetrics(__func__, plugInIdList[index]);
     }
 }
 
 DrmConstraints* DrmManager::getConstraints(int uniqueId, const String8* path, const int action) {
     Mutex::Autolock _l(mLock);
+    DrmConstraints *constraints = NULL;
     const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, *path);
     if (EMPTY_STRING != plugInId) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
-        return rDrmEngine.getConstraints(uniqueId, path, action);
+        constraints = rDrmEngine.getConstraints(uniqueId, path, action);
     }
-    return NULL;
+    if (NULL != constraints) {
+        reportEngineMetrics(__func__, plugInId);
+    }
+    return constraints;
 }
 
 DrmMetadata* DrmManager::getMetadata(int uniqueId, const String8* path) {
     Mutex::Autolock _l(mLock);
+    DrmMetadata *meta = NULL;
     const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, *path);
     if (EMPTY_STRING != plugInId) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
-        return rDrmEngine.getMetadata(uniqueId, path);
+        meta = rDrmEngine.getMetadata(uniqueId, path);
     }
-    return NULL;
+    if (NULL != meta) {
+        reportEngineMetrics(__func__, plugInId);
+    }
+    return meta;
 }
 
 bool DrmManager::canHandle(int uniqueId, const String8& path, const String8& mimeType) {
@@ -175,6 +222,10 @@
     const String8 plugInId = getSupportedPlugInId(mimeType);
     bool result = (EMPTY_STRING != plugInId) ? true : false;
 
+    if (result) {
+        reportEngineMetrics(__func__, plugInId, mimeType);
+    }
+
     if (0 < path.length()) {
         if (result) {
             IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
@@ -191,12 +242,17 @@
 
 DrmInfoStatus* DrmManager::processDrmInfo(int uniqueId, const DrmInfo* drmInfo) {
     Mutex::Autolock _l(mLock);
-    const String8 plugInId = getSupportedPlugInId(drmInfo->getMimeType());
+    DrmInfoStatus *infoStatus = NULL;
+    const String8 mimeType = drmInfo->getMimeType();
+    const String8 plugInId = getSupportedPlugInId(mimeType);
     if (EMPTY_STRING != plugInId) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
-        return rDrmEngine.processDrmInfo(uniqueId, drmInfo);
+        infoStatus = rDrmEngine.processDrmInfo(uniqueId, drmInfo);
     }
-    return NULL;
+    if (NULL != infoStatus) {
+        reportEngineMetrics(__func__, plugInId, mimeType);
+    }
+    return infoStatus;
 }
 
 bool DrmManager::canHandle(int uniqueId, const String8& path) {
@@ -208,6 +264,7 @@
         result = rDrmEngine.canHandle(uniqueId, path);
 
         if (result) {
+            reportEngineMetrics(__func__, plugInPathList[i]);
             break;
         }
     }
@@ -216,54 +273,75 @@
 
 DrmInfo* DrmManager::acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest) {
     Mutex::Autolock _l(mLock);
-    const String8 plugInId = getSupportedPlugInId(drmInfoRequest->getMimeType());
+    DrmInfo *info = NULL;
+    const String8 mimeType = drmInfoRequest->getMimeType();
+    const String8 plugInId = getSupportedPlugInId(mimeType);
     if (EMPTY_STRING != plugInId) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
-        return rDrmEngine.acquireDrmInfo(uniqueId, drmInfoRequest);
+        info = rDrmEngine.acquireDrmInfo(uniqueId, drmInfoRequest);
     }
-    return NULL;
+    if (NULL != info) {
+        reportEngineMetrics(__func__, plugInId, mimeType);
+    }
+    return info;
 }
 
 status_t DrmManager::saveRights(int uniqueId, const DrmRights& drmRights,
             const String8& rightsPath, const String8& contentPath) {
     Mutex::Autolock _l(mLock);
-    const String8 plugInId = getSupportedPlugInId(drmRights.getMimeType());
+    const String8 mimeType = drmRights.getMimeType();
+    const String8 plugInId = getSupportedPlugInId(mimeType);
     status_t result = DRM_ERROR_UNKNOWN;
     if (EMPTY_STRING != plugInId) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
         result = rDrmEngine.saveRights(uniqueId, drmRights, rightsPath, contentPath);
     }
+    if (DRM_NO_ERROR == result) {
+        reportEngineMetrics(__func__, plugInId, mimeType);
+    }
     return result;
 }
 
 String8 DrmManager::getOriginalMimeType(int uniqueId, const String8& path, int fd) {
     Mutex::Autolock _l(mLock);
+    String8 mimeType(EMPTY_STRING);
     const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, path);
     if (EMPTY_STRING != plugInId) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
-        return rDrmEngine.getOriginalMimeType(uniqueId, path, fd);
+        mimeType = rDrmEngine.getOriginalMimeType(uniqueId, path, fd);
     }
-    return EMPTY_STRING;
+    if (!mimeType.isEmpty()) {
+        reportEngineMetrics(__func__, plugInId, mimeType);
+    }
+    return mimeType;
 }
 
 int DrmManager::getDrmObjectType(int uniqueId, const String8& path, const String8& mimeType) {
     Mutex::Autolock _l(mLock);
+    int type = DrmObjectType::UNKNOWN;
     const String8 plugInId = getSupportedPlugInId(uniqueId, path, mimeType);
     if (EMPTY_STRING != plugInId) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
-        return rDrmEngine.getDrmObjectType(uniqueId, path, mimeType);
+        type = rDrmEngine.getDrmObjectType(uniqueId, path, mimeType);
     }
-    return DrmObjectType::UNKNOWN;
+    if (DrmObjectType::UNKNOWN != type) {
+        reportEngineMetrics(__func__, plugInId, mimeType);
+    }
+    return type;
 }
 
 int DrmManager::checkRightsStatus(int uniqueId, const String8& path, int action) {
     Mutex::Autolock _l(mLock);
+    int rightsStatus = RightsStatus::RIGHTS_INVALID;
     const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, path);
     if (EMPTY_STRING != plugInId) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
-        return rDrmEngine.checkRightsStatus(uniqueId, path, action);
+        rightsStatus = rDrmEngine.checkRightsStatus(uniqueId, path, action);
     }
-    return RightsStatus::RIGHTS_INVALID;
+    if (RightsStatus::RIGHTS_INVALID != rightsStatus) {
+        reportEngineMetrics(__func__, plugInId);
+    }
+    return rightsStatus;
 }
 
 status_t DrmManager::consumeRights(
@@ -307,6 +385,9 @@
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
         result = rDrmEngine.removeRights(uniqueId, path);
     }
+    if (DRM_NO_ERROR == result) {
+        reportEngineMetrics(__func__, plugInId);
+    }
     return result;
 }
 
@@ -319,6 +400,7 @@
         if (DRM_NO_ERROR != result) {
             break;
         }
+        reportEngineMetrics(__func__, plugInIdList[index]);
     }
     return result;
 }
@@ -335,6 +417,7 @@
             ++mConvertId;
             convertId = mConvertId;
             mConvertSessionMap.add(convertId, &rDrmEngine);
+            reportEngineMetrics(__func__, plugInId, mimeType);
         }
     }
     return convertId;
@@ -415,6 +498,7 @@
             if (DRM_NO_ERROR == result) {
                 ++mDecryptSessionId;
                 mDecryptSessionMap.add(mDecryptSessionId, &rDrmEngine);
+                reportEngineMetrics(__func__, plugInId, String8(mime));
                 break;
             }
         }
@@ -443,6 +527,7 @@
             if (DRM_NO_ERROR == result) {
                 ++mDecryptSessionId;
                 mDecryptSessionMap.add(mDecryptSessionId, &rDrmEngine);
+                reportEngineMetrics(__func__, plugInId, String8(mime));
                 break;
             }
         }
@@ -472,6 +557,7 @@
             if (DRM_NO_ERROR == result) {
                 ++mDecryptSessionId;
                 mDecryptSessionMap.add(mDecryptSessionId, &rDrmEngine);
+                reportEngineMetrics(__func__, plugInId, mimeType);
                 break;
             }
         }
diff --git a/drm/drmserver/DrmManager.h b/drm/drmserver/DrmManager.h
index 26222bc..75fc1a8 100644
--- a/drm/drmserver/DrmManager.h
+++ b/drm/drmserver/DrmManager.h
@@ -143,6 +143,9 @@
 
     bool canHandle(int uniqueId, const String8& path);
 
+    void reportEngineMetrics(const char func[],
+            const String8& plugInId, const String8& mimeType = String8(""));
+
 private:
     enum {
         kMaxNumUniqueIds = 0x1000,
diff --git a/media/codec2/components/avc/C2SoftAvcDec.cpp b/media/codec2/components/avc/C2SoftAvcDec.cpp
index 3f015b4..fa98178 100644
--- a/media/codec2/components/avc/C2SoftAvcDec.cpp
+++ b/media/codec2/components/avc/C2SoftAvcDec.cpp
@@ -33,7 +33,8 @@
 namespace {
 
 constexpr char COMPONENT_NAME[] = "c2.android.avc.decoder";
-
+constexpr uint32_t kDefaultOutputDelay = 8;
+constexpr uint32_t kMaxOutputDelay = 16;
 }  // namespace
 
 class C2SoftAvcDec::IntfImpl : public SimpleInterface<void>::BaseParams {
@@ -54,7 +55,9 @@
         // TODO: Proper support for reorder depth.
         addParameter(
                 DefineParam(mActualOutputDelay, C2_PARAMKEY_OUTPUT_DELAY)
-                .withConstValue(new C2PortActualDelayTuning::output(8u))
+                .withDefault(new C2PortActualDelayTuning::output(kDefaultOutputDelay))
+                .withFields({C2F(mActualOutputDelay, value).inRange(0, kMaxOutputDelay)})
+                .withSetter(Setter<decltype(*mActualOutputDelay)>::StrictValueWithNoDeps)
                 .build());
 
         // TODO: output latency and reordering
@@ -196,7 +199,6 @@
                                      0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
                 .build());
     }
-
     static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::output> &oldMe,
                           C2P<C2StreamPictureSizeInfo::output> &me) {
         (void)mayBlock;
@@ -333,6 +335,7 @@
       mDecHandle(nullptr),
       mOutBufferFlush(nullptr),
       mIvColorFormat(IV_YUV_420P),
+      mOutputDelay(kDefaultOutputDelay),
       mWidth(320),
       mHeight(240),
       mHeaderDecoded(false),
@@ -882,6 +885,26 @@
             work->result = C2_CORRUPTED;
             return;
         }
+        if (s_decode_op.i4_reorder_depth >= 0 && mOutputDelay != s_decode_op.i4_reorder_depth) {
+            mOutputDelay = s_decode_op.i4_reorder_depth;
+            ALOGV("New Output delay %d ", mOutputDelay);
+
+            C2PortActualDelayTuning::output outputDelay(mOutputDelay);
+            std::vector<std::unique_ptr<C2SettingResult>> failures;
+            c2_status_t err =
+                mIntf->config({&outputDelay}, C2_MAY_BLOCK, &failures);
+            if (err == OK) {
+                work->worklets.front()->output.configUpdate.push_back(
+                    C2Param::Copy(outputDelay));
+            } else {
+                ALOGE("Cannot set output delay");
+                mSignalledError = true;
+                work->workletsProcessed = 1u;
+                work->result = C2_CORRUPTED;
+                return;
+            }
+            continue;
+        }
         if (0 < s_decode_op.u4_pic_wd && 0 < s_decode_op.u4_pic_ht) {
             if (mHeaderDecoded == false) {
                 mHeaderDecoded = true;
diff --git a/media/codec2/components/avc/C2SoftAvcDec.h b/media/codec2/components/avc/C2SoftAvcDec.h
index 72ee583..4414a26 100644
--- a/media/codec2/components/avc/C2SoftAvcDec.h
+++ b/media/codec2/components/avc/C2SoftAvcDec.h
@@ -157,7 +157,7 @@
 
     size_t mNumCores;
     IV_COLOR_FORMAT_T mIvColorFormat;
-
+    uint32_t mOutputDelay;
     uint32_t mWidth;
     uint32_t mHeight;
     uint32_t mStride;
diff --git a/media/codec2/components/hevc/C2SoftHevcDec.cpp b/media/codec2/components/hevc/C2SoftHevcDec.cpp
index 7232572..df677c2 100644
--- a/media/codec2/components/hevc/C2SoftHevcDec.cpp
+++ b/media/codec2/components/hevc/C2SoftHevcDec.cpp
@@ -33,7 +33,8 @@
 namespace {
 
 constexpr char COMPONENT_NAME[] = "c2.android.hevc.decoder";
-
+constexpr uint32_t kDefaultOutputDelay = 8;
+constexpr uint32_t kMaxOutputDelay = 16;
 }  // namespace
 
 class C2SoftHevcDec::IntfImpl : public SimpleInterface<void>::BaseParams {
@@ -54,7 +55,9 @@
         // TODO: Proper support for reorder depth.
         addParameter(
                 DefineParam(mActualOutputDelay, C2_PARAMKEY_OUTPUT_DELAY)
-                .withConstValue(new C2PortActualDelayTuning::output(8u))
+                .withDefault(new C2PortActualDelayTuning::output(kDefaultOutputDelay))
+                .withFields({C2F(mActualOutputDelay, value).inRange(0, kMaxOutputDelay)})
+                .withSetter(Setter<decltype(*mActualOutputDelay)>::StrictValueWithNoDeps)
                 .build());
 
         addParameter(
@@ -327,6 +330,7 @@
         mDecHandle(nullptr),
         mOutBufferFlush(nullptr),
         mIvColorformat(IV_YUV_420P),
+        mOutputDelay(kDefaultOutputDelay),
         mWidth(320),
         mHeight(240),
         mHeaderDecoded(false),
@@ -877,6 +881,26 @@
             work->result = C2_CORRUPTED;
             return;
         }
+        if (s_decode_op.i4_reorder_depth >= 0 && mOutputDelay != s_decode_op.i4_reorder_depth) {
+            mOutputDelay = s_decode_op.i4_reorder_depth;
+            ALOGV("New Output delay %d ", mOutputDelay);
+
+            C2PortActualDelayTuning::output outputDelay(mOutputDelay);
+            std::vector<std::unique_ptr<C2SettingResult>> failures;
+            c2_status_t err =
+                mIntf->config({&outputDelay}, C2_MAY_BLOCK, &failures);
+            if (err == OK) {
+                work->worklets.front()->output.configUpdate.push_back(
+                    C2Param::Copy(outputDelay));
+            } else {
+                ALOGE("Cannot set output delay");
+                mSignalledError = true;
+                work->workletsProcessed = 1u;
+                work->result = C2_CORRUPTED;
+                return;
+            }
+            continue;
+        }
         if (0 < s_decode_op.u4_pic_wd && 0 < s_decode_op.u4_pic_ht) {
             if (mHeaderDecoded == false) {
                 mHeaderDecoded = true;
diff --git a/media/codec2/components/hevc/C2SoftHevcDec.h b/media/codec2/components/hevc/C2SoftHevcDec.h
index b7664e6..ce63a6c 100644
--- a/media/codec2/components/hevc/C2SoftHevcDec.h
+++ b/media/codec2/components/hevc/C2SoftHevcDec.h
@@ -115,7 +115,7 @@
 
     size_t mNumCores;
     IV_COLOR_FORMAT_T mIvColorformat;
-
+    uint32_t mOutputDelay;
     uint32_t mWidth;
     uint32_t mHeight;
     uint32_t mStride;
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
index 6469735..a8a552c 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
@@ -547,6 +547,10 @@
     if (mCompName == raw) {
         bitStreamInfo[0] = 8000;
         bitStreamInfo[1] = 1;
+    } else if (mCompName == g711alaw || mCompName == g711mlaw) {
+        // g711 test data is all 1-channel and has no embedded config info.
+        bitStreamInfo[0] = 8000;
+        bitStreamInfo[1] = 1;
     } else {
         ASSERT_NO_FATAL_FAILURE(
             getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 8b97fbe..8de6381 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -1,10 +1,3 @@
-cc_defaults {
-    name: "libmedia_defaults",
-    include_dirs: [
-        "bionic/libc/private",
-    ],
-}
-
 cc_library_headers {
     name: "libmedia_headers",
     vendor_available: true,
@@ -227,8 +220,6 @@
 cc_library {
     name: "libmedia",
 
-    defaults: [ "libmedia_defaults" ],
-
     srcs: [
         "IDataSource.cpp",
         "BufferingSettings.cpp",
@@ -274,6 +265,7 @@
     },
 
     header_libs: [
+        "bionic_libc_platform_headers",
         "libstagefright_headers",
         "media_ndk_headers",
     ],
@@ -339,8 +331,6 @@
 cc_library_static {
     name: "libmedia_player2_util",
 
-    defaults: [ "libmedia_defaults" ],
-
     srcs: [
         "AudioParameter.cpp",
         "BufferingSettings.cpp",
diff --git a/media/libmedia/MediaUtils.cpp b/media/libmedia/MediaUtils.cpp
index 31972fa..2efb30e 100644
--- a/media/libmedia/MediaUtils.cpp
+++ b/media/libmedia/MediaUtils.cpp
@@ -22,7 +22,7 @@
 #include <sys/resource.h>
 #include <unistd.h>
 
-#include <bionic_malloc.h>
+#include <bionic/malloc.h>
 
 #include "MediaUtils.h"
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 39be40d..c30f048 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -33,6 +33,7 @@
 #include <media/stagefright/Utils.h>
 #include <media/stagefright/VideoFrameScheduler.h>
 #include <media/MediaCodecBuffer.h>
+#include <utils/SystemClock.h>
 
 #include <inttypes.h>
 
@@ -156,6 +157,7 @@
     CHECK(mediaClock != NULL);
     mPlaybackRate = mPlaybackSettings.mSpeed;
     mMediaClock->setPlaybackRate(mPlaybackRate);
+    (void)mSyncFlag.test_and_set();
 }
 
 NuPlayer::Renderer::~Renderer() {
@@ -326,9 +328,27 @@
         mSyncQueues = false;
     }
 
+    // Wait until the current job in the message queue is done, to make sure
+    // buffer processing from the old generation is finished. After the current
+    // job is finished, access to buffers are protected by generation.
+    Mutex::Autolock syncLock(mSyncLock);
+    int64_t syncCount = mSyncCount;
+    mSyncFlag.clear();
+
+    // Make sure message queue is not empty after mSyncFlag is cleared.
     sp<AMessage> msg = new AMessage(kWhatFlush, this);
     msg->setInt32("audio", static_cast<int32_t>(audio));
     msg->post();
+
+    int64_t uptimeMs = uptimeMillis();
+    while (mSyncCount == syncCount) {
+        (void)mSyncCondition.waitRelative(mSyncLock, ms2ns(1000));
+        if (uptimeMillis() - uptimeMs > 1000) {
+            ALOGW("flush(): no wake-up from sync point for 1s; stop waiting to "
+                  "prevent being stuck indefinitely.");
+            break;
+        }
+    }
 }
 
 void NuPlayer::Renderer::signalTimeDiscontinuity() {
@@ -781,6 +801,11 @@
             TRESPASS();
             break;
     }
+    if (!mSyncFlag.test_and_set()) {
+        Mutex::Autolock syncLock(mSyncLock);
+        ++mSyncCount;
+        mSyncCondition.broadcast();
+    }
 }
 
 void NuPlayer::Renderer::postDrainAudioQueue_l(int64_t delayUs) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index a521f62..3d2b033 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -18,6 +18,8 @@
 
 #define NUPLAYER_RENDERER_H_
 
+#include <atomic>
+
 #include <media/AudioResamplerPublic.h>
 #include <media/AVSyncSettings.h>
 
@@ -220,6 +222,11 @@
 
     sp<AWakeLock> mWakeLock;
 
+    std::atomic_flag mSyncFlag = ATOMIC_FLAG_INIT;
+    Mutex mSyncLock;
+    Condition mSyncCondition;
+    int64_t mSyncCount{0};
+
     status_t getCurrentPositionOnLooper(int64_t *mediaUs);
     status_t getCurrentPositionOnLooper(
             int64_t *mediaUs, int64_t nowUs, bool allowPastQueuedVideo = false);
diff --git a/media/libstagefright/bqhelper/GraphicBufferSource.cpp b/media/libstagefright/bqhelper/GraphicBufferSource.cpp
index 59317e7..591b9e9 100644
--- a/media/libstagefright/bqhelper/GraphicBufferSource.cpp
+++ b/media/libstagefright/bqhelper/GraphicBufferSource.cpp
@@ -29,6 +29,7 @@
 #include <media/stagefright/foundation/ColorUtils.h>
 #include <media/stagefright/foundation/FileDescriptor.h>
 
+#include <android-base/properties.h>
 #include <media/hardware/MetadataBufferType.h>
 #include <ui/GraphicBuffer.h>
 #include <gui/BufferItem.h>
@@ -800,6 +801,9 @@
     }
 }
 
+#ifdef __clang__
+__attribute__((no_sanitize("integer")))
+#endif
 bool GraphicBufferSource::calculateCodecTimestamp_l(
         nsecs_t bufferTimeNs, int64_t *codecTimeUs) {
     int64_t timeUs = bufferTimeNs / 1000;
@@ -816,14 +820,15 @@
             mPrevFrameUs = mBaseFrameUs =
                     std::llround((timeUs * mCaptureFps) / mFps);
             mFrameCount = 0;
-        } else {
-            // snap to nearest capture point
+        } else if (mSnapTimestamps) {
             double nFrames = (timeUs - mPrevCaptureUs) * mCaptureFps / 1000000;
             if (nFrames < 0.5 - kTimestampFluctuation) {
                 // skip this frame as it's too close to previous capture
-                ALOGD("skipping frame, timeUs %lld", static_cast<long long>(timeUs));
+                ALOGD("skipping frame, timeUs %lld",
+                      static_cast<long long>(timeUs));
                 return false;
             }
+            // snap to nearest capture point
             if (nFrames <= 1.0) {
                 nFrames = 1.0;
             }
@@ -832,6 +837,22 @@
                     mFrameCount * 1000000 / mCaptureFps);
             mPrevFrameUs = mBaseFrameUs + std::llround(
                     mFrameCount * 1000000 / mFps);
+        } else {
+            if (timeUs <= mPrevCaptureUs) {
+                if (mFrameDropper != NULL && mFrameDropper->disabled()) {
+                    // Warn only, client has disabled frame drop logic possibly for image
+                    // encoding cases where camera's ZSL mode could send out of order frames.
+                    ALOGW("Received frame that's going backward in time");
+                } else {
+                    // Drop the frame if it's going backward in time. Bad timestamp
+                    // could disrupt encoder's rate control completely.
+                    ALOGW("Dropping frame that's going backward in time");
+                    return false;
+                }
+            }
+            mPrevCaptureUs = timeUs;
+            mPrevFrameUs = mBaseFrameUs + std::llround(
+                    (timeUs - mBaseCaptureUs) * (mCaptureFps / mFps));
         }
 
         ALOGV("timeUs %lld, captureUs %lld, frameUs %lld",
@@ -1359,6 +1380,12 @@
 
     mFps = fps;
     mCaptureFps = captureFps;
+    if (captureFps > fps) {
+        mSnapTimestamps = 1 == base::GetIntProperty(
+                "debug.stagefright.snap_timestamps", int64_t(1));
+    } else {
+        mSnapTimestamps = false;
+    }
 
     return OK;
 }
diff --git a/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/GraphicBufferSource.h b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/GraphicBufferSource.h
index b4c4d4a..ed5d7cb 100644
--- a/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/GraphicBufferSource.h
+++ b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/GraphicBufferSource.h
@@ -461,12 +461,33 @@
     // Slow motion mode is enabled if both encoding and capture frame rates are
     // defined and the encoding frame rate is less than half the capture frame
     // rate. In this mode, the source is expected to produce frames with an even
-    // timestamp interval (after rounding) with the configured capture fps. The
-    // first source timestamp is used as the source base time. Afterwards, the
-    // timestamp of each source frame is snapped to the nearest expected capture
-    // timestamp and scaled to match the configured encoding frame rate.
+    // timestamp interval (after rounding) with the configured capture fps.
+    //
+    // These modes must be configured by calling setTimeLapseConfig() before
+    // using this source.
+    //
+    // Timestamp snapping for slow motion recording
+    // ============================================
+    //
+    // When the slow motion mode is configured with setTimeLapseConfig(), the
+    // property "debug.stagefright.snap_timestamps" will be checked. If the
+    // value of the property is set to any value other than 1, mSnapTimestamps
+    // will be set to false. Otherwise, mSnapTimestamps will be set to true.
+    // (mSnapTimestamps will be false for time lapse recording regardless of the
+    // value of the property.)
+    //
+    // If mSnapTimestamps is true, i.e., timestamp snapping is enabled, the
+    // first source timestamp will be used as the source base time; afterwards,
+    // the timestamp of each source frame will be snapped to the nearest
+    // expected capture timestamp and scaled to match the configured encoding
+    // frame rate.
+    //
+    // If timestamp snapping is disabled, the timestamp of source frames will
+    // be scaled to match the ratio between the configured encoding frame rate
+    // and the configured capture frame rate.
 
-    // These modes must be enabled before using this source.
+    // whether timestamps will be snapped
+    bool mSnapTimestamps{true};
 
     // adjusted capture timestamp of the base frame
     int64_t mBaseCaptureUs;
diff --git a/media/tests/benchmark/README.md b/media/tests/benchmark/README.md
index 327f0e2..0acfab8 100644
--- a/media/tests/benchmark/README.md
+++ b/media/tests/benchmark/README.md
@@ -28,3 +28,23 @@
 ```
 adb shell /data/local/tmp/extractorTest -P /sdcard/res/
 ```
+
+## Decoder
+
+The test decodes input stream and benchmarks the decoders available in NDK.
+
+Setup steps are same as extractor.
+
+```
+adb shell /data/local/tmp/decoderTest -P /sdcard/res/
+```
+
+## Muxer
+
+The test muxes elementary stream and benchmarks the muxers available in NDK.
+
+Setup steps are same as extractor.
+
+```
+adb shell /data/local/tmp/muxerTest -P /sdcard/res/
+```
diff --git a/media/tests/benchmark/src/native/common/Android.bp b/media/tests/benchmark/src/native/common/Android.bp
index e4f9ab6..64ea1ee 100644
--- a/media/tests/benchmark/src/native/common/Android.bp
+++ b/media/tests/benchmark/src/native/common/Android.bp
@@ -22,6 +22,7 @@
     ],
 
     srcs: [
+        "BenchmarkCommon.cpp",
         "Timer.cpp",
     ],
 
diff --git a/media/tests/benchmark/src/native/common/BenchmarkCommon.cpp b/media/tests/benchmark/src/native/common/BenchmarkCommon.cpp
new file mode 100644
index 0000000..bbc8790
--- /dev/null
+++ b/media/tests/benchmark/src/native/common/BenchmarkCommon.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2019 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 "BenchmarkCommon"
+
+#include "BenchmarkCommon.h"
+#include <iostream>
+
+void CallBackHandle::ioThread() {
+    ALOGV("In %s mIsDone : %d, mSawError : %d ", __func__, mIsDone, mSawError);
+    while (!mIsDone && !mSawError) {
+        auto task = mIOQueue.pop();
+        task();
+    }
+}
+
+void OnInputAvailableCB(AMediaCodec *codec, void *userdata, int32_t index) {
+    ALOGV("OnInputAvailableCB: index(%d)", index);
+    CallBackHandle *self = (CallBackHandle *)userdata;
+    self->getTimer()->addInputTime();
+    self->mIOQueue.push([self, codec, index]() { self->onInputAvailable(codec, index); });
+}
+
+void OnOutputAvailableCB(AMediaCodec *codec, void *userdata, int32_t index,
+                         AMediaCodecBufferInfo *bufferInfo) {
+    ALOGV("OnOutputAvailableCB: index(%d), (%d, %d, %lld, 0x%x)", index, bufferInfo->offset,
+          bufferInfo->size, (long long)bufferInfo->presentationTimeUs, bufferInfo->flags);
+    CallBackHandle *self = (CallBackHandle *)userdata;
+    self->getTimer()->addOutputTime();
+    AMediaCodecBufferInfo bufferInfoCopy = *bufferInfo;
+    self->mIOQueue.push([self, codec, index, bufferInfoCopy]() {
+        AMediaCodecBufferInfo bc = bufferInfoCopy;
+        self->onOutputAvailable(codec, index, &bc);
+    });
+}
+
+void OnFormatChangedCB(AMediaCodec *codec, void *userdata, AMediaFormat *format) {
+    ALOGV("OnFormatChangedCB: format(%s)", AMediaFormat_toString(format));
+    CallBackHandle *self = (CallBackHandle *)userdata;
+    self->mIOQueue.push([self, codec, format]() { self->onFormatChanged(codec, format); });
+}
+
+void OnErrorCB(AMediaCodec *codec, void *userdata, media_status_t err, int32_t actionCode,
+               const char *detail) {
+    (void)codec;
+    ALOGV("OnErrorCB: err(%d), actionCode(%d), detail(%s)", err, actionCode, detail);
+    CallBackHandle *self = (CallBackHandle *)userdata;
+    self->mSawError = true;
+}
+
+AMediaCodec *createMediaCodec(AMediaFormat *format, const char *mime, string codecName,
+                              bool isEncoder) {
+    ALOGV("In %s", __func__);
+    if (!mime) {
+        ALOGE("Please specify a mime type to create codec");
+        return nullptr;
+    }
+
+    AMediaCodec *codec;
+    if (!codecName.empty()) {
+        codec = AMediaCodec_createCodecByName(codecName.c_str());
+        if (!codec) {
+            ALOGE("Unable to create codec by name: %s", codecName.c_str());
+            return nullptr;
+        }
+    } else {
+        if (isEncoder) {
+            codec = AMediaCodec_createEncoderByType(mime);
+        } else {
+            codec = AMediaCodec_createDecoderByType(mime);
+        }
+        if (!codec) {
+            ALOGE("Unable to create codec by mime: %s", mime);
+            return nullptr;
+        }
+    }
+
+    /* Configure codec with the given format*/
+    const char *s = AMediaFormat_toString(format);
+    ALOGV("Input format: %s\n", s);
+
+    media_status_t status = AMediaCodec_configure(codec, format, nullptr, nullptr, isEncoder);
+    if (status != AMEDIA_OK) {
+        ALOGE("AMediaCodec_configure failed %d", status);
+        return nullptr;
+    }
+    return codec;
+}
\ No newline at end of file
diff --git a/media/tests/benchmark/src/native/common/BenchmarkCommon.h b/media/tests/benchmark/src/native/common/BenchmarkCommon.h
index bad6346..7b87c04 100644
--- a/media/tests/benchmark/src/native/common/BenchmarkCommon.h
+++ b/media/tests/benchmark/src/native/common/BenchmarkCommon.h
@@ -19,11 +19,107 @@
 
 #include <utils/Log.h>
 
+#include <inttypes.h>
+#include <mutex>
+#include <queue>
+#include <thread>
+
 #include <media/NdkMediaCodec.h>
 #include <media/NdkMediaError.h>
 
+#include "Timer.h"
+
+using namespace std;
+
 constexpr uint32_t kQueueDequeueTimeoutUs = 1000;
 constexpr uint32_t kMaxCSDStrlen = 16;
 constexpr uint32_t kMaxBufferSize = 1024 * 1024 * 16;
 
+template <typename T>
+class CallBackQueue {
+  public:
+    CallBackQueue() {}
+    ~CallBackQueue() {}
+
+    void push(T elem) {
+        bool needsNotify = false;
+        {
+            lock_guard<mutex> lock(mMutex);
+            needsNotify = mQueue.empty();
+            mQueue.push(move(elem));
+        }
+        if (needsNotify) mQueueNotEmptyCondition.notify_one();
+    }
+
+    T pop() {
+        unique_lock<mutex> lock(mMutex);
+        if (mQueue.empty()) {
+            mQueueNotEmptyCondition.wait(lock, [this]() { return !mQueue.empty(); });
+        }
+        auto result = mQueue.front();
+        mQueue.pop();
+        return result;
+    }
+
+  private:
+    mutex mMutex;
+    queue<T> mQueue;
+    condition_variable mQueueNotEmptyCondition;
+};
+
+class CallBackHandle {
+  public:
+    CallBackHandle() : mSawError(false), mIsDone(false), mTimer(nullptr) {}
+
+    virtual ~CallBackHandle() {
+        if (mIOThread.joinable()) mIOThread.join();
+        if (mTimer) delete mTimer;
+    }
+
+    void ioThread();
+
+    // Implementation in child class (Decoder/Encoder)
+    virtual void onInputAvailable(AMediaCodec *codec, int32_t index) {
+        (void)codec;
+        (void)index;
+    }
+    virtual void onFormatChanged(AMediaCodec *codec, AMediaFormat *format) {
+        (void)codec;
+        (void)format;
+    }
+    virtual void onOutputAvailable(AMediaCodec *codec, int32_t index,
+                                   AMediaCodecBufferInfo *bufferInfo) {
+        (void)codec;
+        (void)index;
+        (void)bufferInfo;
+    }
+
+    virtual Timer *getTimer() { return mTimer; }
+
+    // Keep a queue of all function callbacks.
+    typedef function<void()> IOTask;
+    CallBackQueue<IOTask> mIOQueue;
+    thread mIOThread;
+    bool mSawError;
+    bool mIsDone;
+
+  private:
+    Timer *mTimer;
+};
+
+// Async API's callback
+void OnInputAvailableCB(AMediaCodec *codec, void *userdata, int32_t index);
+
+void OnOutputAvailableCB(AMediaCodec *codec, void *userdata, int32_t index,
+                         AMediaCodecBufferInfo *bufferInfo);
+
+void OnFormatChangedCB(AMediaCodec *codec, void *userdata, AMediaFormat *format);
+
+void OnErrorCB(AMediaCodec *codec, void * /* userdata */, media_status_t err, int32_t actionCode,
+               const char *detail);
+
+// Utility to create and configure AMediaCodec
+AMediaCodec *createMediaCodec(AMediaFormat *format, const char *mime, string codecName,
+                              bool isEncoder);
+
 #endif  // __BENCHMARK_COMMON_H__
diff --git a/media/tests/benchmark/src/native/decoder/Android.bp b/media/tests/benchmark/src/native/decoder/Android.bp
new file mode 100644
index 0000000..f2d3db5
--- /dev/null
+++ b/media/tests/benchmark/src/native/decoder/Android.bp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+cc_library_static {
+    name: "libbenchmark_decoder",
+    defaults: [
+        "libbenchmark_common-defaults",
+        "libbenchmark_soft_sanitize_all-defaults",
+    ],
+
+    srcs: ["Decoder.cpp"],
+
+    static_libs: ["libbenchmark_extractor"],
+
+    export_include_dirs: ["."],
+
+    ldflags: ["-Wl,-Bsymbolic"]
+}
diff --git a/media/tests/benchmark/src/native/decoder/Decoder.cpp b/media/tests/benchmark/src/native/decoder/Decoder.cpp
new file mode 100644
index 0000000..21fc420
--- /dev/null
+++ b/media/tests/benchmark/src/native/decoder/Decoder.cpp
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2019 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 "decoder"
+
+#include <iostream>
+
+#include "Decoder.h"
+
+tuple<ssize_t, uint32_t, int64_t> readSampleData(uint8_t *inputBuffer, int32_t &offset,
+                                                 vector<AMediaCodecBufferInfo> &frameInfo,
+                                                 uint8_t *buf, int32_t frameID, size_t bufSize) {
+    ALOGV("In %s", __func__);
+    if (frameID == (int32_t)frameInfo.size()) {
+        return make_tuple(0, AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM, 0);
+    }
+    uint32_t flags = frameInfo[frameID].flags;
+    int64_t timestamp = frameInfo[frameID].presentationTimeUs;
+    ssize_t bytesCount = frameInfo[frameID].size;
+    if (bufSize < bytesCount) {
+        ALOGE("Error : insufficient resource");
+        return make_tuple(0, AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE, 0);
+    }
+
+    memcpy(buf, inputBuffer + offset, bytesCount);
+    offset += bytesCount;
+    return make_tuple(bytesCount, flags, timestamp);
+}
+
+void Decoder::onInputAvailable(AMediaCodec *mediaCodec, int32_t bufIdx) {
+    ALOGV("In %s", __func__);
+    if (mediaCodec == mCodec && mediaCodec) {
+        if (mSawInputEOS || bufIdx < 0) return;
+        if (mSignalledError) {
+            CallBackHandle::mSawError = true;
+            mDecoderDoneCondition.notify_one();
+            return;
+        }
+
+        size_t bufSize;
+        uint8_t *buf = AMediaCodec_getInputBuffer(mCodec, bufIdx, &bufSize);
+        if (!buf) {
+            mSignalledError = true;
+            mDecoderDoneCondition.notify_one();
+            return;
+        }
+
+        ssize_t bytesRead = 0;
+        uint32_t flag = 0;
+        int64_t presentationTimeUs = 0;
+        tie(bytesRead, flag, presentationTimeUs) = readSampleData(
+                mInputBuffer, mOffset, mFrameMetaData, buf, mNumInputFrame, bufSize);
+        if (flag == AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE) {
+            mSignalledError = true;
+            mDecoderDoneCondition.notify_one();
+            return;
+        }
+
+        if (flag == AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) mSawInputEOS = true;
+        ALOGV("%s bytesRead : %zd presentationTimeUs : %" PRId64 " mSawInputEOS : %s", __FUNCTION__,
+              bytesRead, presentationTimeUs, mSawInputEOS ? "TRUE" : "FALSE");
+
+        int status = AMediaCodec_queueInputBuffer(mCodec, bufIdx, 0 /* offset */, bytesRead,
+                                                  presentationTimeUs, flag);
+        if (AMEDIA_OK != status) {
+            mSignalledError = true;
+            mDecoderDoneCondition.notify_one();
+            return;
+        }
+        mNumInputFrame++;
+    }
+}
+
+void Decoder::onOutputAvailable(AMediaCodec *mediaCodec, int32_t bufIdx,
+                                AMediaCodecBufferInfo *bufferInfo) {
+    ALOGV("In %s", __func__);
+    if (mediaCodec == mCodec && mediaCodec) {
+        if (mSawOutputEOS || bufIdx < 0) return;
+        if (mSignalledError) {
+            CallBackHandle::mSawError = true;
+            mDecoderDoneCondition.notify_one();
+            return;
+        }
+
+        AMediaCodec_releaseOutputBuffer(mCodec, bufIdx, false);
+        mSawOutputEOS = (0 != (bufferInfo->flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM));
+        mNumOutputFrame++;
+        ALOGV("%s index : %d  mSawOutputEOS : %s count : %u", __FUNCTION__, bufIdx,
+              mSawOutputEOS ? "TRUE" : "FALSE", mNumOutputFrame);
+
+        if (mSawOutputEOS) {
+            CallBackHandle::mIsDone = true;
+            mDecoderDoneCondition.notify_one();
+        }
+    }
+}
+
+void Decoder::onFormatChanged(AMediaCodec *mediaCodec, AMediaFormat *format) {
+    ALOGV("In %s", __func__);
+    if (mediaCodec == mCodec && mediaCodec) {
+        ALOGV("%s { %s }", __FUNCTION__, AMediaFormat_toString(format));
+        mFormat = format;
+    }
+}
+
+void Decoder::setupDecoder() {
+    if (!mFormat) mFormat = mExtractor->getFormat();
+    if (!mTimer) mTimer = new Timer();
+}
+
+int32_t Decoder::decode(uint8_t *inputBuffer, vector<AMediaCodecBufferInfo> &frameInfo,
+                        string &codecName, bool asyncMode) {
+    ALOGV("In %s", __func__);
+    mInputBuffer = inputBuffer;
+    mFrameMetaData = frameInfo;
+    mOffset = 0;
+
+    const char *mime = nullptr;
+    AMediaFormat_getString(mFormat, AMEDIAFORMAT_KEY_MIME, &mime);
+    if (!mime) return AMEDIA_ERROR_INVALID_OBJECT;
+
+    int64_t sTime = mTimer->getCurTime();
+    mCodec = createMediaCodec(mFormat, mime, codecName, false /*isEncoder*/);
+    if (!mCodec) return AMEDIA_ERROR_INVALID_OBJECT;
+
+    if (asyncMode) {
+        AMediaCodecOnAsyncNotifyCallback aCB = {OnInputAvailableCB, OnOutputAvailableCB,
+                                                OnFormatChangedCB, OnErrorCB};
+        AMediaCodec_setAsyncNotifyCallback(mCodec, aCB, this);
+
+        CallBackHandle *callbackHandle = new CallBackHandle();
+        callbackHandle->mIOThread = thread(&CallBackHandle::ioThread, this);
+    }
+
+    AMediaCodec_start(mCodec);
+    int64_t eTime = mTimer->getCurTime();
+    int64_t timeTaken = mTimer->getTimeDiff(sTime, eTime);
+    mTimer->setInitTime(timeTaken);
+
+    mTimer->setStartTime();
+    if (!asyncMode) {
+        while (!mSawOutputEOS && !mSignalledError) {
+            /* Queue input data */
+            if (!mSawInputEOS) {
+                ssize_t inIdx = AMediaCodec_dequeueInputBuffer(mCodec, kQueueDequeueTimeoutUs);
+                if (inIdx < 0 && inIdx != AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
+                    ALOGE("AMediaCodec_dequeueInputBuffer returned invalid index %zd\n", inIdx);
+                    return AMEDIA_ERROR_IO;
+                } else if (inIdx >= 0) {
+                    mTimer->addInputTime();
+                    onInputAvailable(mCodec, inIdx);
+                }
+            }
+
+            /* Dequeue output data */
+            AMediaCodecBufferInfo info;
+            ssize_t outIdx = AMediaCodec_dequeueOutputBuffer(mCodec, &info, kQueueDequeueTimeoutUs);
+            if (outIdx == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
+                mFormat = AMediaCodec_getOutputFormat(mCodec);
+                const char *s = AMediaFormat_toString(mFormat);
+                ALOGI("Output format: %s\n", s);
+            } else if (outIdx >= 0) {
+                mTimer->addOutputTime();
+                onOutputAvailable(mCodec, outIdx, &info);
+            } else if (!(outIdx == AMEDIACODEC_INFO_TRY_AGAIN_LATER ||
+                         outIdx == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED)) {
+                ALOGE("AMediaCodec_dequeueOutputBuffer returned invalid index %zd\n", outIdx);
+                return AMEDIA_ERROR_IO;
+            }
+        }
+    } else {
+        unique_lock<mutex> lock(mMutex);
+        mDecoderDoneCondition.wait(lock, [this]() { return (mSawOutputEOS || mSignalledError); });
+    }
+
+    if (codecName.empty()) {
+        char *decName;
+        AMediaCodec_getName(mCodec, &decName);
+        codecName.assign(decName);
+        AMediaCodec_releaseName(mCodec, decName);
+    }
+    return AMEDIA_OK;
+}
+
+void Decoder::deInitCodec() {
+    int64_t sTime = mTimer->getCurTime();
+    if (mFormat) {
+        AMediaFormat_delete(mFormat);
+        mFormat = nullptr;
+    }
+    if (!mCodec) return;
+    AMediaCodec_stop(mCodec);
+    AMediaCodec_delete(mCodec);
+    int64_t eTime = mTimer->getCurTime();
+    int64_t timeTaken = mTimer->getTimeDiff(sTime, eTime);
+    mTimer->setDeInitTime(timeTaken);
+}
+
+void Decoder::dumpStatistics(string inputReference) {
+    int64_t durationUs = mExtractor->getClipDuration();
+    string operation = "decode";
+    mTimer->dumpStatistics(operation, inputReference, durationUs);
+}
+
+void Decoder::resetDecoder() {
+    if (mTimer) mTimer->resetTimers();
+    if (mInputBuffer) mInputBuffer = nullptr;
+    if (!mFrameMetaData.empty()) mFrameMetaData.clear();
+}
diff --git a/media/tests/benchmark/src/native/decoder/Decoder.h b/media/tests/benchmark/src/native/decoder/Decoder.h
new file mode 100644
index 0000000..0a64128
--- /dev/null
+++ b/media/tests/benchmark/src/native/decoder/Decoder.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2019 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 __DECODER_H__
+#define __DECODER_H__
+
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+#include <queue>
+#include <thread>
+
+#include "BenchmarkCommon.h"
+#include "Extractor.h"
+#include "Timer.h"
+
+class Decoder : public CallBackHandle {
+  public:
+    Decoder()
+        : mCodec(nullptr),
+          mFormat(nullptr),
+          mExtractor(nullptr),
+          mTimer(nullptr),
+          mNumInputFrame(0),
+          mNumOutputFrame(0),
+          mSawInputEOS(false),
+          mSawOutputEOS(false),
+          mSignalledError(false),
+          mInputBuffer(nullptr) {
+        mExtractor = new Extractor();
+    }
+
+    virtual ~Decoder() {
+        if (mTimer) delete mTimer;
+        if (mExtractor) delete mExtractor;
+    }
+
+    Timer *getTimer() override { return mTimer; }
+
+    Extractor *getExtractor() { return mExtractor; }
+
+    // Decoder related utilities
+    void setupDecoder();
+
+    void deInitCodec();
+
+    void resetDecoder();
+
+    // Async callback APIs
+    void onInputAvailable(AMediaCodec *codec, int32_t index) override;
+
+    void onFormatChanged(AMediaCodec *codec, AMediaFormat *format) override;
+
+    void onOutputAvailable(AMediaCodec *codec, int32_t index,
+                           AMediaCodecBufferInfo *bufferInfo) override;
+
+    // Process the frames and give decoded output
+    int32_t decode(uint8_t *inputBuffer, vector<AMediaCodecBufferInfo> &frameInfo,
+                   string &codecName, bool asyncMode);
+
+    void dumpStatistics(string inputReference);
+
+  private:
+    AMediaCodec *mCodec;
+    AMediaFormat *mFormat;
+
+    Extractor *mExtractor;
+
+    Timer *mTimer;
+
+    int32_t mNumInputFrame;
+    int32_t mNumOutputFrame;
+
+    bool mSawInputEOS;
+    bool mSawOutputEOS;
+    bool mSignalledError;
+
+    int32_t mOffset;
+    uint8_t *mInputBuffer;
+    vector<AMediaCodecBufferInfo> mFrameMetaData;
+
+    /* Asynchronous locks */
+    mutex mMutex;
+    condition_variable mDecoderDoneCondition;
+};
+
+// Read input samples
+tuple<ssize_t, uint32_t, int64_t> readSampleData(uint8_t *inputBuffer, int32_t &offset,
+                                                 vector<AMediaCodecBufferInfo> &frameSizes,
+                                                 uint8_t *buf, int32_t frameID, size_t bufSize);
+
+#endif  // __DECODER_H__
diff --git a/media/tests/benchmark/src/native/muxer/Android.bp b/media/tests/benchmark/src/native/muxer/Android.bp
new file mode 100644
index 0000000..6ef2a2e
--- /dev/null
+++ b/media/tests/benchmark/src/native/muxer/Android.bp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+cc_library_static {
+    name: "libbenchmark_muxer",
+    defaults: [
+        "libbenchmark_common-defaults",
+        "libbenchmark_soft_sanitize_all-defaults",
+    ],
+
+    srcs: ["Muxer.cpp"],
+
+    static_libs: ["libbenchmark_extractor"],
+
+    export_include_dirs: ["."],
+
+    ldflags: ["-Wl,-Bsymbolic"]
+}
diff --git a/media/tests/benchmark/src/native/muxer/Muxer.cpp b/media/tests/benchmark/src/native/muxer/Muxer.cpp
new file mode 100644
index 0000000..877f7ad
--- /dev/null
+++ b/media/tests/benchmark/src/native/muxer/Muxer.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2019 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 "muxer"
+
+#include <fstream>
+#include <iostream>
+
+#include "Muxer.h"
+
+int32_t Muxer::initMuxer(int32_t fd, MUXER_OUTPUT_T outputFormat) {
+    if (!mFormat) mFormat = mExtractor->getFormat();
+    if (!mTimer) mTimer = new Timer();
+
+    int64_t sTime = mTimer->getCurTime();
+    mMuxer = AMediaMuxer_new(fd, (OutputFormat)outputFormat);
+    if (!mMuxer) {
+        cout << "[   WARN   ] Test Skipped. Unable to create muxer \n";
+        return AMEDIA_ERROR_INVALID_OBJECT;
+    }
+    /*
+     * AMediaMuxer_addTrack returns the index of the new track or a negative value
+     * in case of failure, which can be interpreted as a media_status_t.
+     */
+    ssize_t index = AMediaMuxer_addTrack(mMuxer, mFormat);
+    if (index < 0) {
+        cout << "[   WARN   ] Test Skipped. Format not supported \n";
+        return index;
+    }
+    AMediaMuxer_start(mMuxer);
+    int64_t eTime = mTimer->getCurTime();
+    int64_t timeTaken = mTimer->getTimeDiff(sTime, eTime);
+    mTimer->setInitTime(timeTaken);
+    return AMEDIA_OK;
+}
+
+void Muxer::deInitMuxer() {
+    int64_t sTime = mTimer->getCurTime();
+    if (mFormat) {
+        AMediaFormat_delete(mFormat);
+        mFormat = nullptr;
+    }
+    if (!mMuxer) return;
+    AMediaMuxer_stop(mMuxer);
+    AMediaMuxer_delete(mMuxer);
+    int64_t eTime = mTimer->getCurTime();
+    int64_t timeTaken = mTimer->getTimeDiff(sTime, eTime);
+    mTimer->setDeInitTime(timeTaken);
+}
+
+void Muxer::resetMuxer() {
+    if (mTimer) mTimer->resetTimers();
+}
+
+void Muxer::dumpStatistics(string inputReference) {
+    string operation = "mux";
+    mTimer->dumpStatistics(operation, inputReference, mExtractor->getClipDuration());
+}
+
+int32_t Muxer::mux(uint8_t *inputBuffer, vector<AMediaCodecBufferInfo> &frameInfos) {
+    // Mux frame data
+    size_t frameIdx = 0;
+    mTimer->setStartTime();
+    while (frameIdx < frameInfos.size()) {
+        AMediaCodecBufferInfo info = frameInfos.at(frameIdx);
+        media_status_t status = AMediaMuxer_writeSampleData(mMuxer, 0, inputBuffer, &info);
+        if (status != 0) {
+            ALOGE("Error in AMediaMuxer_writeSampleData");
+            return status;
+        }
+        mTimer->addOutputTime();
+        frameIdx++;
+    }
+    return AMEDIA_OK;
+}
diff --git a/media/tests/benchmark/src/native/muxer/Muxer.h b/media/tests/benchmark/src/native/muxer/Muxer.h
new file mode 100644
index 0000000..154fd20
--- /dev/null
+++ b/media/tests/benchmark/src/native/muxer/Muxer.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 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 __MUXER_H__
+#define __MUXER_H__
+
+#include <media/NdkMediaMuxer.h>
+
+#include "BenchmarkCommon.h"
+#include "Timer.h"
+#include "Extractor.h"
+
+typedef enum {
+    MUXER_OUTPUT_FORMAT_MPEG_4 = 0,
+    MUXER_OUTPUT_FORMAT_WEBM = 1,
+    MUXER_OUTPUT_FORMAT_3GPP = 2,
+    MUXER_OUTPUT_FORMAT_OGG = 4,
+    MUXER_OUTPUT_FORMAT_INVALID = 5,
+} MUXER_OUTPUT_T;
+
+class Muxer {
+  public:
+    Muxer() : mFormat(nullptr), mMuxer(nullptr), mTimer(nullptr) { mExtractor = new Extractor(); }
+
+    virtual ~Muxer() {
+        if (mTimer) delete mTimer;
+        if (mExtractor) delete mExtractor;
+    }
+
+    Timer *getTimer() { return mTimer; }
+    Extractor *getExtractor() { return mExtractor; }
+
+    /* Muxer related utilities */
+    int32_t initMuxer(int32_t fd, MUXER_OUTPUT_T outputFormat);
+    void deInitMuxer();
+    void resetMuxer();
+
+    /* Process the frames and give Muxed output */
+    int32_t mux(uint8_t *inputBuffer, vector<AMediaCodecBufferInfo> &frameSizes);
+
+    void dumpStatistics(string inputReference);
+
+  private:
+    AMediaFormat *mFormat;
+    AMediaMuxer *mMuxer;
+    Extractor *mExtractor;
+    Timer *mTimer;
+};
+
+#endif  // __MUXER_H__
diff --git a/media/tests/benchmark/tests/Android.bp b/media/tests/benchmark/tests/Android.bp
index 30d6e20..353d60e 100644
--- a/media/tests/benchmark/tests/Android.bp
+++ b/media/tests/benchmark/tests/Android.bp
@@ -26,3 +26,35 @@
 
     static_libs: ["libbenchmark_extractor"]
 }
+
+cc_test {
+    name: "decoderTest",
+    gtest: true,
+    defaults: [
+        "libbenchmark_common-defaults",
+        "libbenchmark_soft_sanitize_all-defaults",
+    ],
+
+    srcs: ["DecoderTest.cpp"],
+
+    static_libs: [
+        "libbenchmark_extractor",
+        "libbenchmark_decoder",
+    ],
+}
+
+cc_test {
+    name: "muxerTest",
+    gtest: true,
+    defaults: [
+        "libbenchmark_common-defaults",
+        "libbenchmark_soft_sanitize_all-defaults",
+    ],
+
+    srcs: ["MuxerTest.cpp"],
+
+    static_libs: [
+        "libbenchmark_extractor",
+        "libbenchmark_muxer",
+    ],
+}
diff --git a/media/tests/benchmark/tests/DecoderTest.cpp b/media/tests/benchmark/tests/DecoderTest.cpp
new file mode 100644
index 0000000..6cb42d6
--- /dev/null
+++ b/media/tests/benchmark/tests/DecoderTest.cpp
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2019 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 "decoderTest"
+
+#include <fstream>
+#include <iostream>
+#include <limits>
+
+#include "Decoder.h"
+#include "BenchmarkTestEnvironment.h"
+
+static BenchmarkTestEnvironment *gEnv = nullptr;
+
+class DecoderTest : public ::testing::TestWithParam<tuple<string, string, bool>> {};
+
+TEST_P(DecoderTest, Decode) {
+    ALOGV("Decode the samples given by extractor");
+    tuple<string /* InputFile */, string /* CodecName */, bool /* asyncMode */> params = GetParam();
+
+    string inputFile = gEnv->getRes() + get<0>(params);
+    FILE *inputFp = fopen(inputFile.c_str(), "rb");
+    if (!inputFp) {
+        cout << "[   WARN   ] Test Skipped. Unable to open input file for reading \n";
+        return;
+    }
+
+    Decoder *decoder = new Decoder();
+    Extractor *extractor = decoder->getExtractor();
+    if (!extractor) {
+        cout << "[   WARN   ] Test Skipped. Extractor creation failed \n";
+        return;
+    }
+
+    // Read file properties
+    fseek(inputFp, 0, SEEK_END);
+    size_t fileSize = ftell(inputFp);
+    fseek(inputFp, 0, SEEK_SET);
+    int32_t fd = fileno(inputFp);
+
+    int32_t trackCount = extractor->initExtractor(fd, fileSize);
+    if (trackCount <= 0) {
+        cout << "[   WARN   ] Test Skipped. initExtractor failed\n";
+        return;
+    }
+    for (int curTrack = 0; curTrack < trackCount; curTrack++) {
+        int32_t status = extractor->setupTrackFormat(curTrack);
+        if (status != 0) {
+            cout << "[   WARN   ] Test Skipped. Track Format invalid \n";
+            return;
+        }
+
+        uint8_t *inputBuffer = (uint8_t *)malloc(kMaxBufferSize);
+        if (!inputBuffer) {
+            cout << "[   WARN   ] Test Skipped. Insufficient memory \n";
+            return;
+        }
+        vector<AMediaCodecBufferInfo> frameInfo;
+        AMediaCodecBufferInfo info;
+        uint32_t inputBufferOffset = 0;
+        int32_t idx = 0;
+
+        // Get CSD data
+        while (1) {
+            void *csdBuffer = extractor->getCSDSample(info, idx);
+            if (!csdBuffer || !info.size) break;
+
+            // copy the meta data and buffer to be passed to decoder
+            if (inputBufferOffset + info.size > kMaxBufferSize) {
+                cout << "[   WARN   ] Test Skipped. Memory allocated not sufficient\n";
+                free(inputBuffer);
+                return;
+            }
+            memcpy(inputBuffer + inputBufferOffset, csdBuffer, info.size);
+            frameInfo.push_back(info);
+            inputBufferOffset += info.size;
+            idx++;
+        }
+        // Get frame data
+        while (1) {
+            status = extractor->getFrameSample(info);
+            if (status || !info.size) break;
+            // copy the meta data and buffer to be passed to decoder
+            if (inputBufferOffset + info.size > kMaxBufferSize) {
+                cout << "[   WARN   ] Test Skipped. Memory allocated not sufficient\n";
+                free(inputBuffer);
+                return;
+            }
+            memcpy(inputBuffer + inputBufferOffset, extractor->getFrameBuf(), info.size);
+            frameInfo.push_back(info);
+            inputBufferOffset += info.size;
+        }
+
+        string codecName = get<1>(params);
+        bool asyncMode = get<2>(params);
+        decoder->setupDecoder();
+        status = decoder->decode(inputBuffer, frameInfo, codecName, asyncMode);
+        if (status != AMEDIA_OK) {
+            cout << "[   WARN   ] Test Skipped. Decode returned error \n";
+            free(inputBuffer);
+            return;
+        }
+        decoder->deInitCodec();
+        cout << "codec : " << codecName << endl;
+        string inputReference = get<0>(params);
+        decoder->dumpStatistics(inputReference);
+        free(inputBuffer);
+        decoder->resetDecoder();
+    }
+    fclose(inputFp);
+    extractor->deInitExtractor();
+    delete decoder;
+}
+
+// TODO: (b/140549596)
+// Add wav files
+INSTANTIATE_TEST_SUITE_P(
+        AudioDecoderSyncTest, DecoderTest,
+        ::testing::Values(make_tuple("bbb_44100hz_2ch_128kbps_aac_30sec.mp4", "", false),
+                          make_tuple("bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", "", false),
+                          make_tuple("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "", false),
+                          make_tuple("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "", false),
+                          make_tuple("bbb_44100hz_2ch_80kbps_vorbis_30sec.mp4", "", false),
+                          make_tuple("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "", false)));
+
+INSTANTIATE_TEST_SUITE_P(
+        AudioDecoderAsyncTest, DecoderTest,
+        ::testing::Values(make_tuple("bbb_44100hz_2ch_128kbps_aac_30sec.mp4", "", true),
+                          make_tuple("bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", "", true),
+                          make_tuple("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "", true),
+                          make_tuple("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "", true),
+                          make_tuple("bbb_44100hz_2ch_80kbps_vorbis_30sec.mp4", "", true),
+                          make_tuple("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "", true)));
+
+INSTANTIATE_TEST_SUITE_P(VideDecoderSyncTest, DecoderTest,
+                         ::testing::Values(
+                                 // Hardware codecs
+                                 make_tuple("crowd_1920x1080_25fps_4000kbps_vp9.webm", "", false),
+                                 make_tuple("crowd_1920x1080_25fps_4000kbps_vp8.webm", "", false),
+                                 make_tuple("crowd_1920x1080_25fps_4000kbps_av1.webm", "", false),
+                                 make_tuple("crowd_1920x1080_25fps_7300kbps_mpeg2.mp4", "", false),
+                                 make_tuple("crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", "", false),
+                                 make_tuple("crowd_352x288_25fps_6000kbps_h263.3gp", "", false),
+                                 make_tuple("crowd_1920x1080_25fps_6700kbps_h264.ts", "", false),
+                                 make_tuple("crowd_1920x1080_25fps_4000kbps_h265.mkv", "", false),
+                                 // Software codecs
+                                 make_tuple("crowd_1920x1080_25fps_4000kbps_vp9.webm",
+                                            "c2.android.vp9.decoder", false),
+                                 make_tuple("crowd_1920x1080_25fps_4000kbps_vp8.webm",
+                                            "c2.android.vp8.decoder", false),
+                                 make_tuple("crowd_1920x1080_25fps_4000kbps_av1.webm",
+                                            "c2.android.av1.decoder", false),
+                                 make_tuple("crowd_1920x1080_25fps_7300kbps_mpeg2.mp4",
+                                            "c2.android.mpeg2.decoder", false),
+                                 make_tuple("crowd_1920x1080_25fps_6000kbps_mpeg4.mp4",
+                                            "c2.android.mpeg4.decoder", false),
+                                 make_tuple("crowd_352x288_25fps_6000kbps_h263.3gp",
+                                            "c2.android.h263.decoder", false),
+                                 make_tuple("crowd_1920x1080_25fps_6700kbps_h264.ts",
+                                            "c2.android.avc.decoder", false),
+                                 make_tuple("crowd_1920x1080_25fps_4000kbps_h265.mkv",
+                                            "c2.android.hevc.decoder", false)));
+
+INSTANTIATE_TEST_SUITE_P(VideoDecoderAsyncTest, DecoderTest,
+                         ::testing::Values(
+                                 // Hardware codecs
+                                 make_tuple("crowd_1920x1080_25fps_4000kbps_vp9.webm", "", true),
+                                 make_tuple("crowd_1920x1080_25fps_4000kbps_vp8.webm", "", true),
+                                 make_tuple("crowd_1920x1080_25fps_4000kbps_av1.webm", "", true),
+                                 make_tuple("crowd_1920x1080_25fps_7300kbps_mpeg2.mp4", "", true),
+                                 make_tuple("crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", "", true),
+                                 make_tuple("crowd_352x288_25fps_6000kbps_h263.3gp", "", true),
+                                 make_tuple("crowd_1920x1080_25fps_6700kbps_h264.ts", "", true),
+                                 make_tuple("crowd_1920x1080_25fps_4000kbps_h265.mkv", "", true),
+                                 // Software codecs
+                                 make_tuple("crowd_1920x1080_25fps_4000kbps_vp9.webm",
+                                            "c2.android.vp9.decoder", true),
+                                 make_tuple("crowd_1920x1080_25fps_4000kbps_vp8.webm",
+                                            "c2.android.vp8.decoder", true),
+                                 make_tuple("crowd_1920x1080_25fps_4000kbps_av1.webm",
+                                            "c2.android.av1.decoder", true),
+                                 make_tuple("crowd_1920x1080_25fps_7300kbps_mpeg2.mp4",
+                                            "c2.android.mpeg2.decoder", true),
+                                 make_tuple("crowd_1920x1080_25fps_6000kbps_mpeg4.mp4",
+                                            "c2.android.mpeg4.decoder", true),
+                                 make_tuple("crowd_352x288_25fps_6000kbps_h263.3gp",
+                                            "c2.android.h263.decoder", true),
+                                 make_tuple("crowd_1920x1080_25fps_6700kbps_h264.ts",
+                                            "c2.android.avc.decoder", true),
+                                 make_tuple("crowd_1920x1080_25fps_4000kbps_h265.mkv",
+                                            "c2.android.hevc.decoder", true)));
+
+int main(int argc, char **argv) {
+    gEnv = new BenchmarkTestEnvironment();
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = gEnv->initFromOptions(argc, argv);
+    if (status == 0) {
+        status = RUN_ALL_TESTS();
+        ALOGD("Decoder Test result = %d\n", status);
+    }
+    return status;
+}
\ No newline at end of file
diff --git a/media/tests/benchmark/tests/MuxerTest.cpp b/media/tests/benchmark/tests/MuxerTest.cpp
new file mode 100644
index 0000000..e814f90
--- /dev/null
+++ b/media/tests/benchmark/tests/MuxerTest.cpp
@@ -0,0 +1,181 @@
+
+/*
+ * Copyright (C) 2019 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 "muxerTest"
+
+#include <fstream>
+#include <iostream>
+
+#include "Muxer.h"
+#include "BenchmarkTestEnvironment.h"
+
+#define OUTPUT_FILE_NAME "/data/local/tmp/mux.out"
+
+static BenchmarkTestEnvironment *gEnv = nullptr;
+
+class MuxerTest : public ::testing::TestWithParam<pair<string, string>> {};
+
+static MUXER_OUTPUT_T getMuxerOutFormat(string fmt) {
+    static const struct {
+        string name;
+        MUXER_OUTPUT_T value;
+    } kFormatMaps[] = {{"mp4", MUXER_OUTPUT_FORMAT_MPEG_4},
+                       {"webm", MUXER_OUTPUT_FORMAT_WEBM},
+                       {"3gpp", MUXER_OUTPUT_FORMAT_3GPP},
+                       {"ogg", MUXER_OUTPUT_FORMAT_OGG}};
+
+    MUXER_OUTPUT_T format = MUXER_OUTPUT_FORMAT_INVALID;
+    for (size_t i = 0; i < sizeof(kFormatMaps) / sizeof(kFormatMaps[0]); ++i) {
+        if (!fmt.compare(kFormatMaps[i].name)) {
+            format = kFormatMaps[i].value;
+            break;
+        }
+    }
+    return format;
+}
+
+TEST_P(MuxerTest, Mux) {
+    ALOGV("Mux the samples given by extractor");
+    string inputFile = gEnv->getRes() + GetParam().first;
+    FILE *inputFp = fopen(inputFile.c_str(), "rb");
+    if (!inputFp) {
+        cout << "[   WARN   ] Test Skipped. Unable to open input file for reading \n";
+        return;
+    }
+    string fmt = GetParam().second;
+    MUXER_OUTPUT_T outputFormat = getMuxerOutFormat(fmt);
+    if (outputFormat == MUXER_OUTPUT_FORMAT_INVALID) {
+        ALOGE("output format is MUXER_OUTPUT_FORMAT_INVALID");
+        return;
+    }
+
+    Muxer *muxerObj = new Muxer();
+    Extractor *extractor = muxerObj->getExtractor();
+    if (!extractor) {
+        cout << "[   WARN   ] Test Skipped. Extractor creation failed \n";
+        return;
+    }
+
+    // Read file properties
+    size_t fileSize = 0;
+    fseek(inputFp, 0, SEEK_END);
+    fileSize = ftell(inputFp);
+    fseek(inputFp, 0, SEEK_SET);
+    int32_t fd = fileno(inputFp);
+
+    int32_t trackCount = extractor->initExtractor(fd, fileSize);
+    if (trackCount <= 0) {
+        cout << "[   WARN   ] Test Skipped. initExtractor failed\n";
+        return;
+    }
+
+    for (int curTrack = 0; curTrack < trackCount; curTrack++) {
+        int32_t status = extractor->setupTrackFormat(curTrack);
+        if (status != 0) {
+            cout << "[   WARN   ] Test Skipped. Track Format invalid \n";
+            return;
+        }
+
+        uint8_t *inputBuffer = (uint8_t *)malloc(kMaxBufferSize);
+        if (!inputBuffer) {
+            std::cout << "[   WARN   ] Test Skipped. Insufficient memory \n";
+            return;
+        }
+        // AMediaCodecBufferInfo : <size of frame> <flags> <presentationTimeUs> <offset>
+        vector<AMediaCodecBufferInfo> frameInfos;
+        AMediaCodecBufferInfo info;
+        uint32_t inputBufferOffset = 0;
+
+        // Get Frame Data
+        while (1) {
+            status = extractor->getFrameSample(info);
+            if (status || !info.size) break;
+            // copy the meta data and buffer to be passed to muxer
+            if (inputBufferOffset + info.size > kMaxBufferSize) {
+                cout << "[   WARN   ] Test Skipped. Memory allocated not sufficient\n";
+                free(inputBuffer);
+                return;
+            }
+            memcpy(inputBuffer + inputBufferOffset, extractor->getFrameBuf(), info.size);
+            info.offset = inputBufferOffset;
+            frameInfos.push_back(info);
+            inputBufferOffset += info.size;
+        }
+
+        string outputFileName = OUTPUT_FILE_NAME;
+        FILE *outputFp = fopen(outputFileName.c_str(), "w+b");
+        if (!outputFp) {
+            cout << "[   WARN   ] Test Skipped. Unable to open output file for writing \n";
+            return;
+        }
+        int32_t fd = fileno(outputFp);
+        status = muxerObj->initMuxer(fd, outputFormat);
+        if (status != 0) {
+            cout << "[   WARN   ] Test Skipped. initMuxer failed\n";
+            return;
+        }
+
+        status = muxerObj->mux(inputBuffer, frameInfos);
+        if (status != 0) {
+            cout << "[   WARN   ] Test Skipped. Mux failed \n";
+            return;
+        }
+        muxerObj->deInitMuxer();
+        muxerObj->dumpStatistics(GetParam().first + "." + fmt.c_str());
+        free(inputBuffer);
+        fclose(outputFp);
+        muxerObj->resetMuxer();
+    }
+    fclose(inputFp);
+    extractor->deInitExtractor();
+    delete muxerObj;
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        MuxerTestAll, MuxerTest,
+        ::testing::Values(make_pair("crowd_1920x1080_25fps_4000kbps_vp8.webm", "webm"),
+                          make_pair("crowd_1920x1080_25fps_4000kbps_vp9.webm", "webm"),
+                          make_pair("crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", "mp4"),
+                          make_pair("crowd_352x288_25fps_6000kbps_h263.3gp", "mp4"),
+                          make_pair("crowd_1920x1080_25fps_6700kbps_h264.ts", "mp4"),
+                          make_pair("crowd_1920x1080_25fps_4000kbps_h265.mkv", "mp4"),
+                          make_pair("crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", "3gpp"),
+                          make_pair("crowd_352x288_25fps_6000kbps_h263.3gp", "3gpp"),
+                          make_pair("crowd_1920x1080_25fps_6700kbps_h264.ts", "3gpp"),
+                          make_pair("crowd_1920x1080_25fps_4000kbps_h265.mkv", "3gpp"),
+                          make_pair("bbb_48000hz_2ch_100kbps_opus_5mins.webm", "ogg"),
+                          make_pair("bbb_44100hz_2ch_80kbps_vorbis_5mins.mp4", "webm"),
+                          make_pair("bbb_48000hz_2ch_100kbps_opus_5mins.webm", "webm"),
+                          make_pair("bbb_44100hz_2ch_128kbps_aac_5mins.mp4", "mp4"),
+                          make_pair("bbb_8000hz_1ch_8kbps_amrnb_5mins.3gp", "mp4"),
+                          make_pair("bbb_16000hz_1ch_9kbps_amrwb_5mins.3gp", "mp4"),
+                          make_pair("bbb_44100hz_2ch_128kbps_aac_5mins.mp4", "3gpp"),
+                          make_pair("bbb_8000hz_1ch_8kbps_amrnb_5mins.3gp", "3gpp"),
+                          make_pair("bbb_16000hz_1ch_9kbps_amrwb_5mins.3gp", "3gpp")));
+
+int main(int argc, char **argv) {
+    gEnv = new BenchmarkTestEnvironment();
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = gEnv->initFromOptions(argc, argv);
+    if (status == 0) {
+        status = RUN_ALL_TESTS();
+        ALOGV("Test result = %d\n", status);
+    }
+    return status;
+}
diff --git a/media/utils/Android.bp b/media/utils/Android.bp
index 0ed92f7..2dbc476 100644
--- a/media/utils/Android.bp
+++ b/media/utils/Android.bp
@@ -45,10 +45,10 @@
         "-Werror",
     ],
 
-    include_dirs: [
-        // For android_mallopt definitions.
-        "bionic/libc/private"
+    header_libs: [
+        "bionic_libc_platform_headers",
     ],
+
     local_include_dirs: ["include"],
     export_include_dirs: ["include"],
 }
diff --git a/media/utils/MemoryLeakTrackUtil.cpp b/media/utils/MemoryLeakTrackUtil.cpp
index 2988b52..6166859 100644
--- a/media/utils/MemoryLeakTrackUtil.cpp
+++ b/media/utils/MemoryLeakTrackUtil.cpp
@@ -22,7 +22,7 @@
 #include "media/MemoryLeakTrackUtil.h"
 #include <sstream>
 
-#include <bionic_malloc.h>
+#include <bionic/malloc.h>
 
 /*
  * The code here originally resided in MediaPlayerService.cpp
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 1f8ceec..14d6178 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -5098,7 +5098,7 @@
             if (invalidate) continue;
 
             for (auto client : desc->clientsList(false /*activeOnly*/)) {
-                if (!desc->mProfile->isDirectOutput()) {
+                if (desc->isDuplicated() || !desc->mProfile->isDirectOutput()) {
                     // a client on a non direct outputs has necessarily a linear PCM format
                     // so we can call selectOutput() safely
                     const audio_io_handle_t newOutput = selectOutput(dstOutputs,
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
index 052112a..410fd2c 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
@@ -1210,7 +1210,7 @@
     outputFormat->setInt32(KEY_I_FRAME_INTERVAL, 0);
     outputFormat->setInt32(KEY_COLOR_FORMAT,
             useGrid ? COLOR_FormatYUV420Flexible : COLOR_FormatSurface);
-    outputFormat->setInt32(KEY_FRAME_RATE, gridRows * gridCols);
+    outputFormat->setInt32(KEY_FRAME_RATE, useGrid ? gridRows * gridCols : kNoGridOpRate);
     // This only serves as a hint to encoder when encoding is not real-time.
     outputFormat->setInt32(KEY_OPERATING_RATE, useGrid ? kGridOpRate : kNoGridOpRate);
 
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index dd5a62b..3188892 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2802,6 +2802,27 @@
         mOperatingMode = operatingMode;
     }
 
+    // In case called from configureStreams, abort queued input buffers not belonging to
+    // any pending requests.
+    if (mInputStream != NULL && notifyRequestThread) {
+        while (true) {
+            camera3_stream_buffer_t inputBuffer;
+            status_t res = mInputStream->getInputBuffer(&inputBuffer,
+                    /*respectHalLimit*/ false);
+            if (res != OK) {
+                // Exhausted acquiring all input buffers.
+                break;
+            }
+
+            inputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR;
+            res = mInputStream->returnInputBuffer(inputBuffer);
+            if (res != OK) {
+                ALOGE("%s: %d: couldn't return input buffer while clearing input queue: "
+                        "%s (%d)", __FUNCTION__, __LINE__, strerror(-res), res);
+            }
+        }
+    }
+
     if (!mNeedConfig) {
         ALOGV("%s: Skipping config, no stream changes", __FUNCTION__);
         return OK;
@@ -5084,6 +5105,7 @@
                     ALOGW("%s: %d: couldn't get input buffer while clearing the request "
                             "list: %s (%d)", __FUNCTION__, __LINE__, strerror(-res), res);
                 } else {
+                    inputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR;
                     res = (*it)->mInputStream->returnInputBuffer(inputBuffer);
                     if (res != OK) {
                         ALOGE("%s: %d: couldn't return input buffer while clearing the request "
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
index fc83684..cb59a76 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
@@ -71,7 +71,8 @@
 
     res = mConsumer->acquireBuffer(&bufferItem, /*waitForFence*/false);
     if (res != OK) {
-        ALOGE("%s: Stream %d: Can't acquire next output buffer: %s (%d)",
+        // This may or may not be an error condition depending on caller.
+        ALOGV("%s: Stream %d: Can't acquire next output buffer: %s (%d)",
                 __FUNCTION__, mId, strerror(-res), res);
         return res;
     }