Merge "C2SoftAvcEnc: Allocate output buffer as per clip's dimensions"
diff --git a/media/libdatasource/NuCachedSource2.cpp b/media/libdatasource/NuCachedSource2.cpp
index 7f5ae61..6d63ffb 100644
--- a/media/libdatasource/NuCachedSource2.cpp
+++ b/media/libdatasource/NuCachedSource2.cpp
@@ -689,10 +689,6 @@
     restartPrefetcherIfNecessary_l(true /* ignore low water threshold */);
 }
 
-sp<DecryptHandle> NuCachedSource2::DrmInitialization(const char* mime) {
-    return mSource->DrmInitialization(mime);
-}
-
 String8 NuCachedSource2::getUri() {
     return mSource->getUri();
 }
diff --git a/media/libdatasource/include/datasource/NuCachedSource2.h b/media/libdatasource/include/datasource/NuCachedSource2.h
index 596efb8..4c253ad 100644
--- a/media/libdatasource/include/datasource/NuCachedSource2.h
+++ b/media/libdatasource/include/datasource/NuCachedSource2.h
@@ -44,7 +44,6 @@
     virtual status_t getSize(off64_t *size);
     virtual uint32_t flags();
 
-    virtual sp<DecryptHandle> DrmInitialization(const char* mime);
     virtual String8 getUri();
 
     virtual String8 getMIMEType() const;
diff --git a/media/libheif/HeifDecoderImpl.cpp b/media/libheif/HeifDecoderImpl.cpp
index a977300..bbc14a9 100644
--- a/media/libheif/HeifDecoderImpl.cpp
+++ b/media/libheif/HeifDecoderImpl.cpp
@@ -66,9 +66,6 @@
     void close() {}
     uint32_t getFlags() override { return 0; }
     String8 toString() override { return String8("HeifDataSource"); }
-    sp<DecryptHandle> DrmInitialization(const char*) override {
-        return nullptr;
-    }
 
 private:
     enum {
diff --git a/media/libmedia/IDataSource.cpp b/media/libmedia/IDataSource.cpp
index 31c85af..61f0a68 100644
--- a/media/libmedia/IDataSource.cpp
+++ b/media/libmedia/IDataSource.cpp
@@ -23,7 +23,6 @@
 
 #include <binder/IMemory.h>
 #include <binder/Parcel.h>
-#include <drm/drm_framework_common.h>
 #include <media/stagefright/foundation/ADebug.h>
 
 namespace android {
@@ -35,7 +34,6 @@
     CLOSE,
     GET_FLAGS,
     TO_STRING,
-    DRM_INITIALIZATION,
 };
 
 struct BpDataSource : public BpInterface<IDataSource> {
@@ -95,47 +93,6 @@
         remote()->transact(TO_STRING, data, &reply);
         return reply.readString8();
     }
-
-    virtual sp<DecryptHandle> DrmInitialization(const char *mime) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDataSource::getInterfaceDescriptor());
-        if (mime == NULL) {
-            data.writeInt32(0);
-        } else {
-            data.writeInt32(1);
-            data.writeCString(mime);
-        }
-        remote()->transact(DRM_INITIALIZATION, data, &reply);
-        sp<DecryptHandle> handle;
-        if (reply.dataAvail() != 0) {
-            handle = new DecryptHandle();
-            handle->decryptId = reply.readInt32();
-            handle->mimeType = reply.readString8();
-            handle->decryptApiType = reply.readInt32();
-            handle->status = reply.readInt32();
-
-            const int bufferLength = data.readInt32();
-            if (bufferLength != -1) {
-                handle->decryptInfo = new DecryptInfo();
-                handle->decryptInfo->decryptBufferLength = bufferLength;
-            }
-
-            size_t size = data.readInt32();
-            for (size_t i = 0; i < size; ++i) {
-                DrmCopyControl key = (DrmCopyControl)data.readInt32();
-                int value = data.readInt32();
-                handle->copyControlVector.add(key, value);
-            }
-
-            size = data.readInt32();
-            for (size_t i = 0; i < size; ++i) {
-                String8 key = data.readString8();
-                String8 value = data.readString8();
-                handle->extendedData.add(key, value);
-            }
-        }
-        return handle;
-    }
 };
 
 IMPLEMENT_META_INTERFACE(DataSource, "android.media.IDataSource");
@@ -178,42 +135,6 @@
             reply->writeString8(toString());
             return NO_ERROR;
         } break;
-        case DRM_INITIALIZATION: {
-            CHECK_INTERFACE(IDataSource, data, reply);
-            const char *mime = NULL;
-            const int32_t flag = data.readInt32();
-            if (flag != 0) {
-                mime = data.readCString();
-            }
-            sp<DecryptHandle> handle = DrmInitialization(mime);
-            if (handle != NULL) {
-                reply->writeInt32(handle->decryptId);
-                reply->writeString8(handle->mimeType);
-                reply->writeInt32(handle->decryptApiType);
-                reply->writeInt32(handle->status);
-
-                if (handle->decryptInfo != NULL) {
-                    reply->writeInt32(handle->decryptInfo->decryptBufferLength);
-                } else {
-                    reply->writeInt32(-1);
-                }
-
-                size_t size = handle->copyControlVector.size();
-                reply->writeInt32(size);
-                for (size_t i = 0; i < size; ++i) {
-                    reply->writeInt32(handle->copyControlVector.keyAt(i));
-                    reply->writeInt32(handle->copyControlVector.valueAt(i));
-                }
-
-                size = handle->extendedData.size();
-                reply->writeInt32(size);
-                for (size_t i = 0; i < size; ++i) {
-                    reply->writeString8(handle->extendedData.keyAt(i));
-                    reply->writeString8(handle->extendedData.valueAt(i));
-                }
-            }
-            return NO_ERROR;
-        } break;
 
         default:
             return BBinder::onTransact(code, data, reply, flags);
diff --git a/media/libmedia/include/media/IDataSource.h b/media/libmedia/include/media/IDataSource.h
index 3858f78..43e2b50 100644
--- a/media/libmedia/include/media/IDataSource.h
+++ b/media/libmedia/include/media/IDataSource.h
@@ -50,8 +50,6 @@
     virtual uint32_t getFlags() = 0;
     // get a description of the source, e.g. the url or filename it is based on
     virtual String8 toString() = 0;
-    // Initialize DRM and return a DecryptHandle.
-    virtual sp<DecryptHandle> DrmInitialization(const char *mime) = 0;
 
 private:
     DISALLOW_EVIL_CONSTRUCTORS(IDataSource);
diff --git a/media/libmediaplayerservice/datasource/PlayerServiceFileSource.cpp b/media/libmediaplayerservice/datasource/PlayerServiceFileSource.cpp
index 1580891..bb4ba75 100644
--- a/media/libmediaplayerservice/datasource/PlayerServiceFileSource.cpp
+++ b/media/libmediaplayerservice/datasource/PlayerServiceFileSource.cpp
@@ -31,6 +31,7 @@
       mDrmBufOffset(0),
       mDrmBufSize(0),
       mDrmBuf(NULL){
+    (void) DrmInitialization(nullptr);
 }
 
 PlayerServiceFileSource::PlayerServiceFileSource(int fd, int64_t offset, int64_t length)
@@ -40,6 +41,7 @@
       mDrmBufOffset(0),
       mDrmBufSize(0),
       mDrmBuf(NULL) {
+    (void) DrmInitialization(nullptr);
 }
 
 PlayerServiceFileSource::~PlayerServiceFileSource() {
@@ -87,7 +89,9 @@
 }
 
 sp<DecryptHandle> PlayerServiceFileSource::DrmInitialization(const char *mime) {
-    if (getuid() == AID_MEDIA_EX) return nullptr; // no DRM in media extractor
+    if (getuid() == AID_MEDIA_EX) {
+       return NULL; // no DRM in media extractor
+    }
     if (mDrmManagerClient == NULL) {
         mDrmManagerClient = new DrmManagerClient();
     }
diff --git a/media/libmediaplayerservice/datasource/PlayerServiceMediaHTTP.cpp b/media/libmediaplayerservice/datasource/PlayerServiceMediaHTTP.cpp
index 0124720..f99a861 100644
--- a/media/libmediaplayerservice/datasource/PlayerServiceMediaHTTP.cpp
+++ b/media/libmediaplayerservice/datasource/PlayerServiceMediaHTTP.cpp
@@ -32,6 +32,7 @@
 PlayerServiceMediaHTTP::PlayerServiceMediaHTTP(const sp<MediaHTTPConnection> &conn)
     : MediaHTTP(conn),
       mDrmManagerClient(NULL) {
+    (void) DrmInitialization(nullptr);
 }
 
 PlayerServiceMediaHTTP::~PlayerServiceMediaHTTP() {
@@ -40,7 +41,7 @@
 
 // DRM...
 
-sp<DecryptHandle> PlayerServiceMediaHTTP::DrmInitialization(const char* mime) {
+sp<DecryptHandle> PlayerServiceMediaHTTP::DrmInitialization(const char *mime) {
     if (mDrmManagerClient == NULL) {
         mDrmManagerClient = new DrmManagerClient();
     }
diff --git a/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceFileSource.h b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceFileSource.h
index 08a013e..7ae8dda 100644
--- a/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceFileSource.h
+++ b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceFileSource.h
@@ -37,8 +37,6 @@
 
     virtual ssize_t readAt(off64_t offset, void *data, size_t size);
 
-    virtual sp<DecryptHandle> DrmInitialization(const char *mime);
-
     static bool requiresDrm(int fd, int64_t offset, int64_t length, const char *mime);
 
 protected:
@@ -52,6 +50,7 @@
     ssize_t mDrmBufSize;
     unsigned char *mDrmBuf;
 
+    sp<DecryptHandle> DrmInitialization(const char *mime);
     ssize_t readAtDRM_l(off64_t offset, void *data, size_t size);
 
     PlayerServiceFileSource(const PlayerServiceFileSource &);
diff --git a/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceMediaHTTP.h b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceMediaHTTP.h
index 0032cd7..b5124dc 100644
--- a/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceMediaHTTP.h
+++ b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceMediaHTTP.h
@@ -33,12 +33,11 @@
 protected:
     virtual ~PlayerServiceMediaHTTP();
 
-    virtual sp<DecryptHandle> DrmInitialization(const char* mime);
-
 private:
     sp<DecryptHandle> mDecryptHandle;
     DrmManagerClient *mDrmManagerClient;
 
+    sp<DecryptHandle> DrmInitialization(const char *mime);
     void clearDRMState_l();
 
     DISALLOW_EVIL_CONSTRUCTORS(PlayerServiceMediaHTTP);
diff --git a/media/libstagefright/CallbackDataSource.cpp b/media/libstagefright/CallbackDataSource.cpp
index 92e6eb9..265f21b 100644
--- a/media/libstagefright/CallbackDataSource.cpp
+++ b/media/libstagefright/CallbackDataSource.cpp
@@ -113,10 +113,6 @@
     }
 }
 
-sp<DecryptHandle> CallbackDataSource::DrmInitialization(const char *mime) {
-    return mIDataSource->DrmInitialization(mime);
-}
-
 sp<IDataSource> CallbackDataSource::getIDataSource() const {
     return mIDataSource;
 }
@@ -190,14 +186,6 @@
     return mSource->flags();
 }
 
-sp<DecryptHandle> TinyCacheSource::DrmInitialization(const char *mime) {
-    // flush cache when DrmInitialization occurs since decrypted
-    // data may differ from what is in cache.
-    mCachedOffset = 0;
-    mCachedSize = 0;
-    return mSource->DrmInitialization(mime);
-}
-
 sp<IDataSource> TinyCacheSource::getIDataSource() const {
     return mSource->getIDataSource();
 }
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index 4c8be1f..120f354 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -71,9 +71,6 @@
 
     ALOGV("MediaExtractorFactory::CreateFromService %s", mime);
 
-    // initialize source decryption if needed
-    source->DrmInitialization(nullptr /* mime */);
-
     void *meta = nullptr;
     void *creator = NULL;
     FreeMetaFunc freeMeta = nullptr;
diff --git a/media/libstagefright/include/CallbackDataSource.h b/media/libstagefright/include/CallbackDataSource.h
index 9f413cd..e428494 100644
--- a/media/libstagefright/include/CallbackDataSource.h
+++ b/media/libstagefright/include/CallbackDataSource.h
@@ -41,7 +41,6 @@
     virtual String8 toString() {
         return mName;
     }
-    virtual sp<DecryptHandle> DrmInitialization(const char *mime = NULL);
     virtual sp<IDataSource> getIDataSource() const;
 
 private:
@@ -70,7 +69,6 @@
     virtual String8 toString() {
         return mName;
     }
-    virtual sp<DecryptHandle> DrmInitialization(const char *mime = NULL);
     virtual sp<IDataSource> getIDataSource() const;
 
 private:
diff --git a/media/libstagefright/include/ThrottledSource.h b/media/libstagefright/include/ThrottledSource.h
index 71e62f7..5ae0653 100644
--- a/media/libstagefright/include/ThrottledSource.h
+++ b/media/libstagefright/include/ThrottledSource.h
@@ -54,10 +54,6 @@
         return mSource->reconnectAtOffset(offset);
     }
 
-    virtual sp<DecryptHandle> DrmInitialization(const char *mime = NULL) {
-        return mSource->DrmInitialization(mime);
-    }
-
     virtual String8 getMIMEType() const {
         return mSource->getMIMEType();
     }
diff --git a/media/libstagefright/include/media/stagefright/DataSource.h b/media/libstagefright/include/media/stagefright/DataSource.h
index 1f7a473..83d3e5d 100644
--- a/media/libstagefright/include/media/stagefright/DataSource.h
+++ b/media/libstagefright/include/media/stagefright/DataSource.h
@@ -52,11 +52,6 @@
 
     ////////////////////////////////////////////////////////////////////////////
 
-    // for DRM
-    virtual sp<DecryptHandle> DrmInitialization(const char * /*mime*/ = NULL) {
-        return NULL;
-    }
-
     virtual String8 getUri() {
         return String8();
     }
diff --git a/media/libstagefright/include/media/stagefright/RemoteDataSource.h b/media/libstagefright/include/media/stagefright/RemoteDataSource.h
index e191e6a..5a69bd7 100644
--- a/media/libstagefright/include/media/stagefright/RemoteDataSource.h
+++ b/media/libstagefright/include/media/stagefright/RemoteDataSource.h
@@ -66,9 +66,6 @@
     virtual String8 toString()  {
         return mName;
     }
-    virtual sp<DecryptHandle> DrmInitialization(const char *mime) {
-        return mSource->DrmInitialization(mime);
-    }
 
 private:
     enum {
diff --git a/media/libstagefright/tests/writer/Android.bp b/media/libstagefright/tests/writer/Android.bp
new file mode 100644
index 0000000..7e169cb
--- /dev/null
+++ b/media/libstagefright/tests/writer/Android.bp
@@ -0,0 +1,58 @@
+/*
+ * 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_test {
+    name: "writerTest",
+    gtest: true,
+
+    srcs: [
+        "WriterUtility.cpp",
+        "WriterTest.cpp",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "libcutils",
+        "liblog",
+        "libutils",
+    ],
+
+    static_libs: [
+        "libstagefright_webm",
+        "libdatasource",
+        "libstagefright",
+        "libstagefright_foundation",
+        "libstagefright_esds",
+        "libogg",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+    },
+}
diff --git a/media/libstagefright/tests/writer/README.md b/media/libstagefright/tests/writer/README.md
new file mode 100644
index 0000000..52db6f0
--- /dev/null
+++ b/media/libstagefright/tests/writer/README.md
@@ -0,0 +1,30 @@
+## Media Testing ##
+---
+#### Writer :
+The Writer Test Suite validates the writers available in libstagefright.
+
+Run the following steps to build the test suite:
+```
+mmm frameworks/av/media/libstagefright/tests/writer/
+```
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+To test 64-bit binary push binaries from nativetest64.
+
+adb push ${OUT}/data/nativetest64/writerTest/writerTest /data/local/tmp/
+
+To test 32-bit binary push binaries from nativetest.
+
+adb push ${OUT}/data/nativetest/writerTest/writerTest /data/local/tmp/
+
+The resource file for the tests is taken from Codec2 VTS resource folder. Push these files into device for testing.
+```
+adb push  $ANDROID_BUILD_TOP/frameworks/av/media/codec2/hidl/1.0/vts/functional/res /sdcard/
+```
+
+usage: writerTest -P \<path_to_res_folder\>
+```
+adb shell /data/local/tmp/writerTest -P /sdcard/res/
+```
diff --git a/media/libstagefright/tests/writer/WriterTest.cpp b/media/libstagefright/tests/writer/WriterTest.cpp
new file mode 100644
index 0000000..d68438c
--- /dev/null
+++ b/media/libstagefright/tests/writer/WriterTest.cpp
@@ -0,0 +1,400 @@
+/*
+ * 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 "WriterTest"
+#include <utils/Log.h>
+
+#include <fstream>
+#include <iostream>
+
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+
+#include <media/mediarecorder.h>
+
+#include <media/stagefright/AACWriter.h>
+#include <media/stagefright/AMRWriter.h>
+#include <media/stagefright/OggWriter.h>
+#include <media/stagefright/MPEG4Writer.h>
+#include <media/stagefright/MPEG2TSWriter.h>
+#include <webm/WebmWriter.h>
+
+#include "WriterTestEnvironment.h"
+#include "WriterUtility.h"
+
+#define OUTPUT_FILE_NAME "/data/local/tmp/writer.out"
+
+static WriterTestEnvironment *gEnv = nullptr;
+
+struct configFormat {
+    char mime[128];
+    int32_t width;
+    int32_t height;
+    int32_t sampleRate;
+    int32_t channelCount;
+};
+
+// LookUpTable of clips and metadata for component testing
+static const struct InputData {
+    const char *mime;
+    string inputFile;
+    string info;
+    int32_t firstParam;
+    int32_t secondParam;
+    bool isAudio;
+} kInputData[] = {
+        {MEDIA_MIMETYPE_AUDIO_OPUS, "bbb_opus_stereo_128kbps_48000hz.opus",
+         "bbb_opus_stereo_128kbps_48000hz.info", 48000, 2, true},
+        {MEDIA_MIMETYPE_AUDIO_AAC, "bbb_aac_stereo_128kbps_48000hz.aac",
+         "bbb_aac_stereo_128kbps_48000hz.info", 48000, 2, true},
+        {MEDIA_MIMETYPE_AUDIO_AAC_ADTS, "Mps_2_c2_fr1_Sc1_Dc2_0x03_raw.adts",
+         "Mps_2_c2_fr1_Sc1_Dc2_0x03_raw.info", 48000, 2, true},
+        {MEDIA_MIMETYPE_AUDIO_AMR_NB, "sine_amrnb_1ch_12kbps_8000hz.amrnb",
+         "sine_amrnb_1ch_12kbps_8000hz.info", 8000, 1, true},
+        {MEDIA_MIMETYPE_AUDIO_AMR_WB, "bbb_amrwb_1ch_14kbps_16000hz.amrwb",
+         "bbb_amrwb_1ch_14kbps_16000hz.info", 16000, 1, true},
+        {MEDIA_MIMETYPE_AUDIO_VORBIS, "bbb_vorbis_stereo_128kbps_48000hz.vorbis",
+         "bbb_vorbis_stereo_128kbps_48000hz.info", 48000, 2, true},
+        {MEDIA_MIMETYPE_AUDIO_FLAC, "bbb_flac_stereo_680kbps_48000hz.flac",
+         "bbb_flac_stereo_680kbps_48000hz.info", 48000, 2, true},
+        {MEDIA_MIMETYPE_VIDEO_VP9, "bbb_vp9_176x144_285kbps_60fps.vp9",
+         "bbb_vp9_176x144_285kbps_60fps.info", 176, 144, false},
+        {MEDIA_MIMETYPE_VIDEO_VP8, "bbb_vp8_176x144_240kbps_60fps.vp8",
+         "bbb_vp8_176x144_240kbps_60fps.info", 176, 144, false},
+        {MEDIA_MIMETYPE_VIDEO_AVC, "bbb_avc_176x144_300kbps_60fps.h264",
+         "bbb_avc_176x144_300kbps_60fps.info", 176, 144, false},
+        {MEDIA_MIMETYPE_VIDEO_HEVC, "bbb_hevc_176x144_176kbps_60fps.hevc",
+         "bbb_hevc_176x144_176kbps_60fps.info", 176, 144, false},
+        {MEDIA_MIMETYPE_VIDEO_AV1, "bbb_av1_176_144.av1", "bbb_av1_176_144.info", 176, 144, false},
+        {MEDIA_MIMETYPE_VIDEO_H263, "bbb_h263_352x288_300kbps_12fps.h263",
+         "bbb_h263_352x288_300kbps_12fps.info", 352, 288, false},
+        {MEDIA_MIMETYPE_VIDEO_MPEG4, "bbb_mpeg4_352x288_512kbps_30fps.m4v",
+         "bbb_mpeg4_352x288_512kbps_30fps.info", 352, 288, false},
+};
+
+class WriterTest : public ::testing::TestWithParam<pair<string, int32_t>> {
+  public:
+    virtual void SetUp() override {
+        mNumCsds = 0;
+        mInputFrameId = 0;
+        mWriterName = unknown_comp;
+        mDisableTest = false;
+
+        std::map<std::string, standardWriters> mapWriter = {
+                {"ogg", OGG},     {"aac", AAC},      {"aac_adts", AAC_ADTS}, {"webm", WEBM},
+                {"mpeg4", MPEG4}, {"amrnb", AMR_NB}, {"amrwb", AMR_WB},      {"mpeg2Ts", MPEG2TS}};
+        // Find the component type
+        string writerFormat = GetParam().first;
+        if (mapWriter.find(writerFormat) != mapWriter.end()) {
+            mWriterName = mapWriter[writerFormat];
+        }
+        if (mWriterName == standardWriters::unknown_comp) {
+            cout << "[   WARN   ] Test Skipped. No specific writer mentioned\n";
+            mDisableTest = true;
+        }
+    }
+
+    virtual void TearDown() override {
+        mWriter.clear();
+        mFileMeta.clear();
+        mBufferInfo.clear();
+        if (mInputStream) mInputStream.close();
+    }
+
+    void getInputBufferInfo(string inputFileName, string inputInfo);
+
+    int32_t createWriter(int32_t fd);
+
+    int32_t addWriterSource(bool isAudio, configFormat params);
+
+    enum standardWriters {
+        OGG,
+        AAC,
+        AAC_ADTS,
+        WEBM,
+        MPEG4,
+        AMR_NB,
+        AMR_WB,
+        MPEG2TS,
+        unknown_comp,
+    };
+
+    standardWriters mWriterName;
+    sp<MediaWriter> mWriter;
+    sp<MetaData> mFileMeta;
+    sp<MediaAdapter> mCurrentTrack;
+
+    bool mDisableTest;
+    int32_t mNumCsds;
+    int32_t mInputFrameId;
+    ifstream mInputStream;
+    vector<BufferInfo> mBufferInfo;
+};
+
+void WriterTest::getInputBufferInfo(string inputFileName, string inputInfo) {
+    std::ifstream eleInfo;
+    eleInfo.open(inputInfo.c_str());
+    CHECK_EQ(eleInfo.is_open(), true);
+    int32_t bytesCount = 0;
+    uint32_t flags = 0;
+    int64_t timestamp = 0;
+    while (1) {
+        if (!(eleInfo >> bytesCount)) break;
+        eleInfo >> flags;
+        eleInfo >> timestamp;
+        mBufferInfo.push_back({bytesCount, flags, timestamp});
+        if (flags == CODEC_CONFIG_FLAG) mNumCsds++;
+    }
+    eleInfo.close();
+    mInputStream.open(inputFileName.c_str(), std::ifstream::binary);
+    CHECK_EQ(mInputStream.is_open(), true);
+}
+
+int32_t WriterTest::createWriter(int32_t fd) {
+    mFileMeta = new MetaData;
+    switch (mWriterName) {
+        case OGG:
+            mWriter = new OggWriter(fd);
+            mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_OGG);
+            break;
+        case AAC:
+            mWriter = new AACWriter(fd);
+            mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AAC_ADIF);
+            break;
+        case AAC_ADTS:
+            mWriter = new AACWriter(fd);
+            mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AAC_ADTS);
+            break;
+        case WEBM:
+            mWriter = new WebmWriter(fd);
+            mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_WEBM);
+            break;
+        case MPEG4:
+            mWriter = new MPEG4Writer(fd);
+            mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG_4);
+            break;
+        case AMR_NB:
+            mWriter = new AMRWriter(fd);
+            mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_NB);
+            break;
+        case AMR_WB:
+            mWriter = new AMRWriter(fd);
+            mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_WB);
+            break;
+        case MPEG2TS:
+            mWriter = new MPEG2TSWriter(fd);
+            mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG2TS);
+            break;
+        default:
+            return -1;
+    }
+    if (mWriter == nullptr) return -1;
+    mFileMeta->setInt32(kKeyRealTimeRecording, false);
+    return 0;
+}
+
+int32_t WriterTest::addWriterSource(bool isAudio, configFormat params) {
+    if (mInputFrameId) return -1;
+    sp<AMessage> format = new AMessage;
+    if (mInputStream.is_open()) {
+        format->setString("mime", params.mime);
+        if (isAudio) {
+            format->setInt32("channel-count", params.channelCount);
+            format->setInt32("sample-rate", params.sampleRate);
+        } else {
+            format->setInt32("width", params.width);
+            format->setInt32("height", params.height);
+        }
+
+        int32_t status =
+                writeHeaderBuffers(mInputStream, mBufferInfo, mInputFrameId, format, mNumCsds);
+        if (status != 0) return -1;
+    }
+    sp<MetaData> trackMeta = new MetaData;
+    convertMessageToMetaData(format, trackMeta);
+    mCurrentTrack = new MediaAdapter(trackMeta);
+    status_t result = mWriter->addSource(mCurrentTrack);
+    return result;
+}
+
+void getFileDetails(string &inputFilePath, string &info, configFormat &params, bool &isAudio,
+                    int32_t streamIndex = 0) {
+    if (streamIndex >= sizeof(kInputData) / sizeof(kInputData[0])) {
+        return;
+    }
+    inputFilePath += kInputData[streamIndex].inputFile;
+    info += kInputData[streamIndex].info;
+    strcpy(params.mime, kInputData[streamIndex].mime);
+    isAudio = kInputData[streamIndex].isAudio;
+    if (isAudio) {
+        params.sampleRate = kInputData[streamIndex].firstParam;
+        params.channelCount = kInputData[streamIndex].secondParam;
+    } else {
+        params.width = kInputData[streamIndex].firstParam;
+        params.height = kInputData[streamIndex].secondParam;
+    }
+    return;
+}
+
+TEST_P(WriterTest, CreateWriterTest) {
+    if (mDisableTest) return;
+    ALOGV("Tests the creation of writers");
+
+    string outputFile = OUTPUT_FILE_NAME;
+    int32_t fd =
+            open(outputFile.c_str(), O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
+    if (fd < 0) return;
+
+    // Creating writer within a test scope. Destructor should be called when the test ends
+    int32_t status = createWriter(fd);
+    if (status) {
+        cout << "Failed to create writer for output format:" << GetParam().first << "\n";
+        ASSERT_TRUE(false);
+    }
+}
+
+TEST_P(WriterTest, WriterTest) {
+    if (mDisableTest) return;
+    ALOGV("Checks if for a given input, a valid muxed file has been created or not");
+
+    string writerFormat = GetParam().first;
+    string outputFile = OUTPUT_FILE_NAME;
+    int32_t fd =
+            open(outputFile.c_str(), O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
+    if (fd < 0) return;
+    int32_t status = createWriter(fd);
+    if (status) {
+        cout << "Failed to create writer for output format:" << writerFormat << "\n";
+        ASSERT_TRUE(false);
+    }
+    string inputFile = gEnv->getRes();
+    string inputInfo = gEnv->getRes();
+    configFormat param;
+    bool isAudio;
+    int32_t inputFileIdx = GetParam().second;
+    getFileDetails(inputFile, inputInfo, param, isAudio, inputFileIdx);
+    if (!inputFile.compare(gEnv->getRes())) {
+        ALOGV("No input file specified");
+        return;
+    }
+    getInputBufferInfo(inputFile, inputInfo);
+    status = addWriterSource(isAudio, param);
+    if (status) {
+        cout << "Failed to add source for " << writerFormat << "Writer \n";
+        ASSERT_TRUE(false);
+    }
+    CHECK_EQ((status_t)OK, mWriter->start(mFileMeta.get()));
+    status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack, 0,
+                                 mBufferInfo.size());
+    mCurrentTrack->stop();
+    if (status) {
+        cout << writerFormat << " writer failed \n";
+        mWriter->stop();
+        ASSERT_TRUE(false);
+    }
+    CHECK_EQ((status_t)OK, mWriter->stop());
+    close(fd);
+}
+
+TEST_P(WriterTest, PauseWriterTest) {
+    if (mDisableTest) return;
+    ALOGV("Validates the pause() api of writers");
+
+    string writerFormat = GetParam().first;
+    string outputFile = OUTPUT_FILE_NAME;
+    int32_t fd =
+            open(outputFile.c_str(), O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
+    if (fd < 0) return;
+    int32_t status = createWriter(fd);
+    if (status) {
+        cout << "Failed to create writer for output format:" << writerFormat << "\n";
+        ASSERT_TRUE(false);
+    }
+    string inputFile = gEnv->getRes();
+    string inputInfo = gEnv->getRes();
+    configFormat param;
+    bool isAudio;
+    int32_t inputFileIdx = GetParam().second;
+    getFileDetails(inputFile, inputInfo, param, isAudio, inputFileIdx);
+    if (!inputFile.compare(gEnv->getRes())) {
+        ALOGV("No input file specified");
+        return;
+    }
+    getInputBufferInfo(inputFile, inputInfo);
+    status = addWriterSource(isAudio, param);
+    if (status) {
+        cout << "Failed to add source for " << writerFormat << "Writer \n";
+        ASSERT_TRUE(false);
+    }
+    CHECK_EQ((status_t)OK, mWriter->start(mFileMeta.get()));
+    status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack, 0,
+                                 mBufferInfo.size() / 4);
+    if (status) {
+        cout << writerFormat << " writer failed \n";
+        mCurrentTrack->stop();
+        mWriter->stop();
+        ASSERT_TRUE(false);
+    }
+
+    bool isPaused = false;
+    if ((mWriterName != standardWriters::MPEG2TS) && (mWriterName != standardWriters::MPEG4)) {
+        CHECK_EQ((status_t)OK, mWriter->pause());
+        isPaused = true;
+    }
+    // In the pause state, writers shouldn't write anything. Testing the writers for the same
+    int32_t numFramesPaused = mBufferInfo.size() / 4;
+    status |= sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack,
+                                  mInputFrameId, numFramesPaused, isPaused);
+    if (isPaused) {
+        CHECK_EQ((status_t)OK, mWriter->start(mFileMeta.get()));
+    }
+    status |= sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack,
+                                  mInputFrameId, mBufferInfo.size());
+    mCurrentTrack->stop();
+    if (status) {
+        cout << writerFormat << " writer failed \n";
+        mWriter->stop();
+        ASSERT_TRUE(false);
+    }
+    CHECK_EQ((status_t)OK, mWriter->stop());
+    close(fd);
+}
+
+// TODO: (b/144476164)
+// Add AAC_ADTS, FLAC, AV1 input
+INSTANTIATE_TEST_SUITE_P(WriterTestAll, WriterTest,
+                         ::testing::Values(make_pair("ogg", 0), make_pair("webm", 0),
+                                           make_pair("aac", 1), make_pair("mpeg4", 1),
+                                           make_pair("amrnb", 3), make_pair("amrwb", 4),
+                                           make_pair("webm", 5), make_pair("webm", 7),
+                                           make_pair("webm", 8), make_pair("mpeg4", 9),
+                                           make_pair("mpeg4", 10), make_pair("mpeg4", 12),
+                                           make_pair("mpeg4", 13), make_pair("mpeg2Ts", 1),
+                                           make_pair("mpeg2Ts", 9)));
+
+int main(int argc, char **argv) {
+    gEnv = new WriterTestEnvironment();
+    ::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/libstagefright/tests/writer/WriterTestEnvironment.h b/media/libstagefright/tests/writer/WriterTestEnvironment.h
new file mode 100644
index 0000000..34c2baa
--- /dev/null
+++ b/media/libstagefright/tests/writer/WriterTestEnvironment.h
@@ -0,0 +1,72 @@
+/*
+ * 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 __WRITER_TEST_ENVIRONMENT_H__
+#define __WRITER_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class WriterTestEnvironment : public ::testing::Environment {
+  public:
+    WriterTestEnvironment() : res("/sdcard/media/") {}
+
+    // Parses the command line arguments
+    int initFromOptions(int argc, char **argv);
+
+    void setRes(const char *_res) { res = _res; }
+
+    const string getRes() const { return res; }
+
+  private:
+    string res;
+};
+
+int WriterTestEnvironment::initFromOptions(int argc, char **argv) {
+    static struct option options[] = {{"res", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+    while (true) {
+        int index = 0;
+        int c = getopt_long(argc, argv, "P:", options, &index);
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+            case 'P':
+                setRes(optarg);
+                break;
+            default:
+                break;
+        }
+    }
+
+    if (optind < argc) {
+        fprintf(stderr,
+                "unrecognized option: %s\n\n"
+                "usage: %s <gtest options> <test options>\n\n"
+                "test options are:\n\n"
+                "-P, --path: Resource files directory location\n",
+                argv[optind ?: 1], argv[0]);
+        return 2;
+    }
+    return 0;
+}
+
+#endif  // __WRITER_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/tests/writer/WriterUtility.cpp b/media/libstagefright/tests/writer/WriterUtility.cpp
new file mode 100644
index 0000000..2ba90a0
--- /dev/null
+++ b/media/libstagefright/tests/writer/WriterUtility.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 "WriterUtility"
+#include <utils/Log.h>
+
+#include <media/stagefright/MediaBuffer.h>
+
+#include "WriterUtility.h"
+
+int32_t sendBuffersToWriter(ifstream &inputStream, vector<BufferInfo> &bufferInfo,
+                            int32_t &inputFrameId, sp<MediaAdapter> &currentTrack, int32_t offset,
+                            int32_t range, bool isPaused) {
+    while (1) {
+        if (inputFrameId == (int)bufferInfo.size() || inputFrameId >= (offset + range)) break;
+        int32_t size = bufferInfo[inputFrameId].size;
+        char *data = (char *)malloc(size);
+        if (!data) {
+            ALOGE("Insufficient memeory to read input");
+            return -1;
+        }
+
+        inputStream.read(data, size);
+        CHECK_EQ(inputStream.gcount(), size);
+
+        sp<ABuffer> buffer = new ABuffer((void *)data, size);
+        if (buffer.get() == nullptr) {
+            ALOGE("sendBuffersToWriter() got a nullptr buffer.");
+            return -1;
+        }
+        MediaBuffer *mediaBuffer = new MediaBuffer(buffer);
+
+        // Released in MediaAdapter::signalBufferReturned().
+        mediaBuffer->add_ref();
+        mediaBuffer->set_range(buffer->offset(), buffer->size());
+
+        MetaDataBase &sampleMetaData = mediaBuffer->meta_data();
+        sampleMetaData.setInt64(kKeyTime, bufferInfo[inputFrameId].timeUs);
+        // Just set the kKeyDecodingTime as the presentation time for now.
+        sampleMetaData.setInt64(kKeyDecodingTime, bufferInfo[inputFrameId].timeUs);
+
+        if (bufferInfo[inputFrameId].flags == 1) {
+            sampleMetaData.setInt32(kKeyIsSyncFrame, true);
+        }
+
+        // This pushBuffer will wait until the mediaBuffer is consumed.
+        int status = currentTrack->pushBuffer(mediaBuffer);
+        free(data);
+        inputFrameId++;
+
+        if (OK != status) {
+            if (!isPaused) return status;
+            else {
+                ALOGD("Writer is in paused state. Input buffers won't get consumed");
+                return 0;
+            }
+        }
+    }
+    return 0;
+}
+
+int32_t writeHeaderBuffers(ifstream &inputStream, vector<BufferInfo> &bufferInfo,
+                           int32_t &inputFrameId, sp<AMessage> &format, int32_t numCsds) {
+    char csdName[kMaxCSDStrlen];
+    for (int csdId = 0; csdId < numCsds; csdId++) {
+        int32_t flags = bufferInfo[inputFrameId].flags;
+        if (flags == CODEC_CONFIG_FLAG) {
+            int32_t size = bufferInfo[inputFrameId].size;
+            char *data = (char *)malloc(size);
+            if (!data) {
+                ALOGE("Insufficient memeory to read input");
+                return -1;
+            }
+            inputStream.read(data, size);
+            CHECK_EQ(inputStream.gcount(), size);
+
+            sp<ABuffer> csdBuffer = ABuffer::CreateAsCopy((void *)data, size);
+            if (csdBuffer.get() == nullptr || csdBuffer->base() == nullptr) {
+                return -1;
+            }
+            snprintf(csdName, sizeof(csdName), "csd-%d", csdId);
+            format->setBuffer(csdName, csdBuffer);
+            inputFrameId++;
+            free(data);
+        }
+    }
+    return 0;
+}
diff --git a/media/libstagefright/tests/writer/WriterUtility.h b/media/libstagefright/tests/writer/WriterUtility.h
new file mode 100644
index 0000000..d402798
--- /dev/null
+++ b/media/libstagefright/tests/writer/WriterUtility.h
@@ -0,0 +1,50 @@
+/*
+ * 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 WRITER_UTILITY_H_
+#define WRITER_UTILITY_H_
+
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include <media/stagefright/MediaAdapter.h>
+
+using namespace android;
+using namespace std;
+
+#define CODEC_CONFIG_FLAG 32
+
+constexpr uint32_t kMaxCSDStrlen = 16;
+
+struct BufferInfo {
+    int32_t size;
+    uint32_t flags;
+    int64_t timeUs;
+};
+
+int32_t sendBuffersToWriter(ifstream &inputStream, vector<BufferInfo> &bufferInfo,
+                            int32_t &inputFrameId, sp<MediaAdapter> &currentTrack, int32_t offset,
+                            int32_t range, bool isPaused = false);
+
+int32_t writeHeaderBuffers(ifstream &inputStream, vector<BufferInfo> &bufferInfo,
+                           int32_t &inputFrameId, sp<AMessage> &format, int32_t numCsds);
+
+#endif  // WRITER_UTILITY_H_
diff --git a/media/tests/benchmark/src/native/common/Android.bp b/media/tests/benchmark/src/native/common/Android.bp
index 08ef2d1..babc329 100644
--- a/media/tests/benchmark/src/native/common/Android.bp
+++ b/media/tests/benchmark/src/native/common/Android.bp
@@ -24,6 +24,7 @@
     srcs: [
         "BenchmarkCommon.cpp",
         "Stats.cpp",
+        "utils/Timers.cpp",
     ],
 
     export_include_dirs: ["."],
@@ -49,7 +50,6 @@
     shared_libs: [
         "libmediandk",
         "liblog",
-        "libutils",
     ],
 
     cflags: [
diff --git a/media/tests/benchmark/src/native/common/BenchmarkCommon.cpp b/media/tests/benchmark/src/native/common/BenchmarkCommon.cpp
index 5bdb48a..ab74508 100644
--- a/media/tests/benchmark/src/native/common/BenchmarkCommon.cpp
+++ b/media/tests/benchmark/src/native/common/BenchmarkCommon.cpp
@@ -56,10 +56,10 @@
 
 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);
+    ALOGE("OnErrorCB: err(%d), actionCode(%d), detail(%s)", err, actionCode, detail);
     CallBackHandle *self = (CallBackHandle *)userdata;
     self->mSawError = true;
+    self->mIOQueue.push([self, codec, err]() { self->onError(codec, err); });
 }
 
 AMediaCodec *createMediaCodec(AMediaFormat *format, const char *mime, string codecName,
diff --git a/media/tests/benchmark/src/native/common/BenchmarkCommon.h b/media/tests/benchmark/src/native/common/BenchmarkCommon.h
index df16baf..8153a86 100644
--- a/media/tests/benchmark/src/native/common/BenchmarkCommon.h
+++ b/media/tests/benchmark/src/native/common/BenchmarkCommon.h
@@ -17,8 +17,6 @@
 #ifndef __BENCHMARK_COMMON_H__
 #define __BENCHMARK_COMMON_H__
 
-#include <utils/Log.h>
-
 #include <inttypes.h>
 #include <mutex>
 #include <queue>
@@ -89,6 +87,10 @@
         (void)codec;
         (void)format;
     }
+    virtual void onError(AMediaCodec *codec, media_status_t err) {
+        (void)codec;
+        (void)err;
+    }
     virtual void onOutputAvailable(AMediaCodec *codec, int32_t index,
                                    AMediaCodecBufferInfo *bufferInfo) {
         (void)codec;
diff --git a/media/tests/benchmark/src/native/common/Stats.cpp b/media/tests/benchmark/src/native/common/Stats.cpp
index 6bcd3ce..2d9bb31 100644
--- a/media/tests/benchmark/src/native/common/Stats.cpp
+++ b/media/tests/benchmark/src/native/common/Stats.cpp
@@ -19,7 +19,6 @@
 
 #include <iostream>
 #include <stdint.h>
-#include <utils/Log.h>
 
 #include "Stats.h"
 
diff --git a/media/tests/benchmark/src/native/common/Stats.h b/media/tests/benchmark/src/native/common/Stats.h
index 024319a..2f556ee 100644
--- a/media/tests/benchmark/src/native/common/Stats.h
+++ b/media/tests/benchmark/src/native/common/Stats.h
@@ -17,11 +17,28 @@
 #ifndef __STATS_H__
 #define __STATS_H__
 
+#include <android/log.h>
+
+#ifndef ALOG
+#define ALOG(priority, tag, ...) ((void)__android_log_print(ANDROID_##priority, tag, __VA_ARGS__))
+
+#define ALOGI(...) ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define ALOGE(...) ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)
+#define ALOGD(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+#if LOG_NDEBUG
+#define ALOGV(cond, ...)   ((void)0)
+#else
+#define ALOGV(...) ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
+#endif
+#endif  // ALOG
+
 #include <sys/time.h>
 #include <algorithm>
 #include <numeric>
 #include <vector>
-#include <utils/Timers.h>
+
+// Include local copy of Timers taken from system/core/libutils
+#include "utils/Timers.h"
 
 using namespace std;
 
diff --git a/media/tests/benchmark/src/native/common/utils/Timers.cpp b/media/tests/benchmark/src/native/common/utils/Timers.cpp
new file mode 100644
index 0000000..1acbdb3
--- /dev/null
+++ b/media/tests/benchmark/src/native/common/utils/Timers.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Timer functions.
+//
+
+#define LOG_TAG "Timers"
+
+#include <limits.h>
+#include <time.h>
+
+#include "Timers.h"
+
+#if defined(__ANDROID__)
+nsecs_t systemTime(int clock) {
+    static const clockid_t clocks[] = {CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID,
+                                       CLOCK_THREAD_CPUTIME_ID, CLOCK_BOOTTIME};
+    struct timespec t;
+    t.tv_sec = t.tv_nsec = 0;
+    clock_gettime(clocks[clock], &t);
+    return nsecs_t(t.tv_sec) * 1000000000LL + t.tv_nsec;
+}
+#else
+nsecs_t systemTime(int /*clock*/) {
+    // Clock support varies widely across hosts. Mac OS doesn't support
+    // posix clocks, older glibcs don't support CLOCK_BOOTTIME and Windows
+    // is windows.
+    struct timeval t;
+    t.tv_sec = t.tv_usec = 0;
+    gettimeofday(&t, NULL);
+    return nsecs_t(t.tv_sec) * 1000000000LL + nsecs_t(t.tv_usec) * 1000LL;
+}
+#endif
+
+int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime) {
+    nsecs_t timeoutDelayMillis;
+    if (timeoutTime > referenceTime) {
+        uint64_t timeoutDelay = uint64_t(timeoutTime - referenceTime);
+        if (timeoutDelay > uint64_t((INT_MAX - 1) * 1000000LL)) {
+            timeoutDelayMillis = -1;
+        } else {
+            timeoutDelayMillis = (timeoutDelay + 999999LL) / 1000000LL;
+        }
+    } else {
+        timeoutDelayMillis = 0;
+    }
+    return (int)timeoutDelayMillis;
+}
diff --git a/media/tests/benchmark/src/native/common/utils/Timers.h b/media/tests/benchmark/src/native/common/utils/Timers.h
new file mode 100644
index 0000000..d643dcd
--- /dev/null
+++ b/media/tests/benchmark/src/native/common/utils/Timers.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Timer functions.
+//
+
+#ifndef _LIBS_UTILS_TIMERS_H
+#define _LIBS_UTILS_TIMERS_H
+
+#include <stdint.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+// ------------------------------------------------------------------
+// C API
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int64_t nsecs_t;  // nano-seconds
+
+static inline nsecs_t seconds_to_nanoseconds(nsecs_t secs) {
+    return secs * 1000000000;
+}
+
+static inline nsecs_t milliseconds_to_nanoseconds(nsecs_t secs) {
+    return secs * 1000000;
+}
+
+static inline nsecs_t microseconds_to_nanoseconds(nsecs_t secs) {
+    return secs * 1000;
+}
+
+static inline nsecs_t nanoseconds_to_seconds(nsecs_t secs) {
+    return secs / 1000000000;
+}
+
+static inline nsecs_t nanoseconds_to_milliseconds(nsecs_t secs) {
+    return secs / 1000000;
+}
+
+static inline nsecs_t nanoseconds_to_microseconds(nsecs_t secs) {
+    return secs / 1000;
+}
+
+static inline nsecs_t s2ns(nsecs_t v) {
+    return seconds_to_nanoseconds(v);
+}
+static inline nsecs_t ms2ns(nsecs_t v) {
+    return milliseconds_to_nanoseconds(v);
+}
+static inline nsecs_t us2ns(nsecs_t v) {
+    return microseconds_to_nanoseconds(v);
+}
+static inline nsecs_t ns2s(nsecs_t v) {
+    return nanoseconds_to_seconds(v);
+}
+static inline nsecs_t ns2ms(nsecs_t v) {
+    return nanoseconds_to_milliseconds(v);
+}
+static inline nsecs_t ns2us(nsecs_t v) {
+    return nanoseconds_to_microseconds(v);
+}
+
+static inline nsecs_t seconds(nsecs_t v) {
+    return s2ns(v);
+}
+static inline nsecs_t milliseconds(nsecs_t v) {
+    return ms2ns(v);
+}
+static inline nsecs_t microseconds(nsecs_t v) {
+    return us2ns(v);
+}
+
+enum {
+    SYSTEM_TIME_REALTIME = 0,   // system-wide realtime clock
+    SYSTEM_TIME_MONOTONIC = 1,  // monotonic time since unspecified starting point
+    SYSTEM_TIME_PROCESS = 2,    // high-resolution per-process clock
+    SYSTEM_TIME_THREAD = 3,     // high-resolution per-thread clock
+    SYSTEM_TIME_BOOTTIME = 4    // same as SYSTEM_TIME_MONOTONIC, but including CPU suspend time
+};
+
+// return the system-time according to the specified clock
+#ifdef __cplusplus
+nsecs_t systemTime(int clock = SYSTEM_TIME_MONOTONIC);
+#else
+nsecs_t systemTime(int clock);
+#endif  // def __cplusplus
+
+/**
+ * Returns the number of milliseconds to wait between the reference time and the timeout time.
+ * If the timeout is in the past relative to the reference time, returns 0.
+ * If the timeout is more than INT_MAX milliseconds in the future relative to the reference time,
+ * such as when timeoutTime == LLONG_MAX, returns -1 to indicate an infinite timeout delay.
+ * Otherwise, returns the difference between the reference time and timeout time
+ * rounded up to the next millisecond.
+ */
+int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // _LIBS_UTILS_TIMERS_H
diff --git a/media/tests/benchmark/src/native/decoder/Decoder.cpp b/media/tests/benchmark/src/native/decoder/Decoder.cpp
index ef84537..ac0d525 100644
--- a/media/tests/benchmark/src/native/decoder/Decoder.cpp
+++ b/media/tests/benchmark/src/native/decoder/Decoder.cpp
@@ -32,8 +32,8 @@
     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);
+        ALOGE("Error : Buffer size is insufficient to read sample");
+        return make_tuple(0, AMEDIA_ERROR_MALFORMED, 0);
     }
 
     memcpy(buf, inputBuffer + offset, bytesCount);
@@ -54,6 +54,7 @@
         size_t bufSize;
         uint8_t *buf = AMediaCodec_getInputBuffer(mCodec, bufIdx, &bufSize);
         if (!buf) {
+            mErrorCode = AMEDIA_ERROR_IO;
             mSignalledError = true;
             mDecoderDoneCondition.notify_one();
             return;
@@ -64,7 +65,8 @@
         int64_t presentationTimeUs = 0;
         tie(bytesRead, flag, presentationTimeUs) = readSampleData(
                 mInputBuffer, mOffset, mFrameMetaData, buf, mNumInputFrame, bufSize);
-        if (flag == AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE) {
+        if (flag == AMEDIA_ERROR_MALFORMED) {
+            mErrorCode = (media_status_t)flag;
             mSignalledError = true;
             mDecoderDoneCondition.notify_one();
             return;
@@ -74,9 +76,10 @@
         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);
+        media_status_t status = AMediaCodec_queueInputBuffer(mCodec, bufIdx, 0 /* offset */,
+                                                             bytesRead, presentationTimeUs, flag);
         if (AMEDIA_OK != status) {
+            mErrorCode = status;
             mSignalledError = true;
             mDecoderDoneCondition.notify_one();
             return;
@@ -127,6 +130,16 @@
     }
 }
 
+void Decoder::onError(AMediaCodec *mediaCodec, media_status_t err) {
+    ALOGV("In %s", __func__);
+    if (mediaCodec == mCodec && mediaCodec) {
+        ALOGE("Received Error %d", err);
+        mErrorCode = err;
+        mSignalledError = true;
+        mDecoderDoneCondition.notify_one();
+    }
+}
+
 void Decoder::setupDecoder() {
     if (!mFormat) mFormat = mExtractor->getFormat();
 }
@@ -168,7 +181,8 @@
                 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;
+                    mErrorCode = (media_status_t)inIdx;
+                    return mErrorCode;
                 } else if (inIdx >= 0) {
                     mStats->addInputTime();
                     onInputAvailable(mCodec, inIdx);
@@ -188,13 +202,18 @@
             } 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;
+                mErrorCode = (media_status_t)outIdx;
+                return mErrorCode;
             }
         }
     } else {
         unique_lock<mutex> lock(mMutex);
         mDecoderDoneCondition.wait(lock, [this]() { return (mSawOutputEOS || mSignalledError); });
     }
+    if (mSignalledError) {
+        ALOGE("Received Error while Decoding");
+        return mErrorCode;
+    }
 
     if (codecName.empty()) {
         char *decName;
diff --git a/media/tests/benchmark/src/native/decoder/Decoder.h b/media/tests/benchmark/src/native/decoder/Decoder.h
index 7630e7b..aeda080 100644
--- a/media/tests/benchmark/src/native/decoder/Decoder.h
+++ b/media/tests/benchmark/src/native/decoder/Decoder.h
@@ -38,6 +38,7 @@
           mSawInputEOS(false),
           mSawOutputEOS(false),
           mSignalledError(false),
+          mErrorCode(AMEDIA_OK),
           mInputBuffer(nullptr),
           mOutFp(nullptr) {
         mExtractor = new Extractor();
@@ -61,6 +62,8 @@
 
     void onFormatChanged(AMediaCodec *codec, AMediaFormat *format) override;
 
+    void onError(AMediaCodec *mediaCodec, media_status_t err) override;
+
     void onOutputAvailable(AMediaCodec *codec, int32_t index,
                            AMediaCodecBufferInfo *bufferInfo) override;
 
@@ -82,6 +85,7 @@
     bool mSawInputEOS;
     bool mSawOutputEOS;
     bool mSignalledError;
+    media_status_t mErrorCode;
 
     int32_t mOffset;
     uint8_t *mInputBuffer;
diff --git a/media/tests/benchmark/src/native/encoder/Encoder.cpp b/media/tests/benchmark/src/native/encoder/Encoder.cpp
index 5fdf9e3..a5605de 100644
--- a/media/tests/benchmark/src/native/encoder/Encoder.cpp
+++ b/media/tests/benchmark/src/native/encoder/Encoder.cpp
@@ -34,6 +34,7 @@
         size_t bufSize = 0;
         char *buf = (char *)AMediaCodec_getInputBuffer(mCodec, bufIdx, &bufSize);
         if (!buf) {
+            mErrorCode = AMEDIA_ERROR_IO;
             mSignalledError = true;
             mEncoderDoneCondition.notify_one();
             return;
@@ -41,6 +42,7 @@
 
         if (mInputBufferSize < mOffset) {
             ALOGE("Out of bound access of input buffer\n");
+            mErrorCode = AMEDIA_ERROR_MALFORMED;
             mSignalledError = true;
             mEncoderDoneCondition.notify_one();
             return;
@@ -51,6 +53,7 @@
         }
         if (bufSize < bytesRead) {
             ALOGE("bytes to read %zu bufSize %zu \n", bytesRead, bufSize);
+            mErrorCode = AMEDIA_ERROR_MALFORMED;
             mSignalledError = true;
             mEncoderDoneCondition.notify_one();
             return;
@@ -58,6 +61,7 @@
         if (bytesRead < mParams.frameSize && mNumInputFrame < mParams.numFrames - 1) {
             ALOGE("Partial frame at frameID %d bytesRead %zu frameSize %d total numFrames %d\n",
                   mNumInputFrame, bytesRead, mParams.frameSize, mParams.numFrames);
+            mErrorCode = AMEDIA_ERROR_MALFORMED;
             mSignalledError = true;
             mEncoderDoneCondition.notify_one();
             return;
@@ -66,6 +70,7 @@
         size_t bytesgcount = mEleStream->gcount();
         if (bytesgcount != bytesRead) {
             ALOGE("bytes to read %zu actual bytes read %zu \n", bytesRead, bytesgcount);
+            mErrorCode = AMEDIA_ERROR_MALFORMED;
             mSignalledError = true;
             mEncoderDoneCondition.notify_one();
             return;
@@ -89,9 +94,10 @@
         ALOGV("%s bytesRead : %zd presentationTimeUs : %" PRIu64 " mSawInputEOS : %s", __FUNCTION__,
               bytesRead, presentationTimeUs, mSawInputEOS ? "TRUE" : "FALSE");
 
-        int status = AMediaCodec_queueInputBuffer(mCodec, bufIdx, 0 /* offset */, bytesRead,
-                                                  presentationTimeUs, flag);
+        media_status_t status = AMediaCodec_queueInputBuffer(mCodec, bufIdx, 0 /* offset */,
+                                                             bytesRead, presentationTimeUs, flag);
         if (AMEDIA_OK != status) {
+            mErrorCode = status;
             mSignalledError = true;
             mEncoderDoneCondition.notify_one();
             return;
@@ -133,6 +139,16 @@
     }
 }
 
+void Encoder::onError(AMediaCodec *mediaCodec, media_status_t err) {
+    ALOGV("In %s", __func__);
+    if (mediaCodec == mCodec && mediaCodec) {
+        ALOGE("Received Error %d", err);
+        mErrorCode = err;
+        mSignalledError = true;
+        mEncoderDoneCondition.notify_one();
+    }
+}
+
 void Encoder::setupEncoder() {
     if (!mFormat) mFormat = AMediaFormat_new();
 }
@@ -235,7 +251,8 @@
                 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;
+                    mErrorCode = (media_status_t)inIdx;
+                    return mErrorCode;
                 } else if (inIdx >= 0) {
                     mStats->addInputTime();
                     onInputAvailable(mCodec, inIdx);
@@ -255,13 +272,18 @@
             } 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;
+                mErrorCode = (media_status_t)outIdx;
+                return mErrorCode;
             }
         }
     } else {
         unique_lock<mutex> lock(mMutex);
         mEncoderDoneCondition.wait(lock, [this]() { return (mSawOutputEOS || mSignalledError); });
     }
+    if (mSignalledError) {
+        ALOGE("Received Error while Encoding");
+        return mErrorCode;
+    }
 
     if (codecName.empty()) {
         char *encName;
diff --git a/media/tests/benchmark/src/native/encoder/Encoder.h b/media/tests/benchmark/src/native/encoder/Encoder.h
index 75d9941..6059c4a 100644
--- a/media/tests/benchmark/src/native/encoder/Encoder.h
+++ b/media/tests/benchmark/src/native/encoder/Encoder.h
@@ -49,7 +49,8 @@
           mNumOutputFrame(0),
           mSawInputEOS(false),
           mSawOutputEOS(false),
-          mSignalledError(false) {}
+          mSignalledError(false),
+          mErrorCode(AMEDIA_OK) {}
 
     virtual ~Encoder() {}
 
@@ -65,6 +66,8 @@
 
     void onFormatChanged(AMediaCodec *codec, AMediaFormat *format) override;
 
+    void onError(AMediaCodec *mediaCodec, media_status_t err) override;
+
     void onOutputAvailable(AMediaCodec *codec, int32_t index,
                            AMediaCodecBufferInfo *bufferInfo) override;
 
@@ -83,6 +86,7 @@
     bool mSawInputEOS;
     bool mSawOutputEOS;
     bool mSignalledError;
+    media_status_t mErrorCode;
 
     char *mMime;
     int32_t mOffset;
diff --git a/media/tests/benchmark/tests/DecoderTest.cpp b/media/tests/benchmark/tests/DecoderTest.cpp
index 242178f..fa37435 100644
--- a/media/tests/benchmark/tests/DecoderTest.cpp
+++ b/media/tests/benchmark/tests/DecoderTest.cpp
@@ -93,7 +93,7 @@
         decoder->setupDecoder();
         status = decoder->decode(inputBuffer, frameInfo, codecName, asyncMode);
         if (status != AMEDIA_OK) {
-            cout << "[   WARN   ] Test Skipped. Decode returned error \n";
+            cout << "[   WARN   ] Test Failed. Decode returned error " << status << endl;
             free(inputBuffer);
             return;
         }
diff --git a/media/tests/benchmark/tests/EncoderTest.cpp b/media/tests/benchmark/tests/EncoderTest.cpp
index 9f42c64..c3963f8 100644
--- a/media/tests/benchmark/tests/EncoderTest.cpp
+++ b/media/tests/benchmark/tests/EncoderTest.cpp
@@ -143,7 +143,11 @@
         string codecName = get<1>(params);
         bool asyncMode = get<2>(params);
         status = encoder->encode(codecName, eleStream, eleSize, asyncMode, encParams, (char *)mime);
-        ASSERT_EQ(status, 0);
+        if (status != AMEDIA_OK) {
+            cout << "[   WARN   ] Test Failed. Encode returned error " << status << endl;
+            free(inputBuffer);
+            return;
+        }
         encoder->deInitCodec();
         cout << "codec : " << codecName << endl;
         string inputReference = get<0>(params);
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
index 84c2ec7..3089181 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
@@ -139,7 +139,9 @@
     mOutputSlots.clear();
     mConsumerBufferCount.clear();
 
-    mConsumer->consumerDisconnect();
+    if (mConsumer.get() != nullptr) {
+        mConsumer->consumerDisconnect();
+    }
 
     if (mBuffers.size() > 0) {
         SP_LOGW("%zu buffers still being tracked", mBuffers.size());