Merge "Cannot play mp4 file with major brand 'wmf'"
diff --git a/camera/ndk/ndk_vendor/impl/utils.cpp b/camera/ndk/ndk_vendor/impl/utils.cpp
index 7193006..5d2d47c 100644
--- a/camera/ndk/ndk_vendor/impl/utils.cpp
+++ b/camera/ndk/ndk_vendor/impl/utils.cpp
@@ -70,7 +70,6 @@
         return;
     }
     size_t size = get_camera_metadata_size(src);
-    ALOGE("Converting metadata size: %d", (int)size);
     dst->setToExternal((uint8_t *) src, size);
     return;
 }
diff --git a/media/codec2/components/opus/Android.bp b/media/codec2/components/opus/Android.bp
index 240cdb9..0ed141b 100644
--- a/media/codec2/components/opus/Android.bp
+++ b/media/codec2/components/opus/Android.bp
@@ -9,3 +9,14 @@
 
     shared_libs: ["libopus"],
 }
+cc_library_shared {
+    name: "libcodec2_soft_opusenc",
+    defaults: [
+        "libcodec2_soft-defaults",
+        "libcodec2_soft_sanitize_all-defaults",
+    ],
+
+    srcs: ["C2SoftOpusEnc.cpp"],
+
+    shared_libs: ["libopus"],
+}
diff --git a/media/codec2/components/opus/C2SoftOpusDec.cpp b/media/codec2/components/opus/C2SoftOpusDec.cpp
index 2439c3c..3ce1fd6 100644
--- a/media/codec2/components/opus/C2SoftOpusDec.cpp
+++ b/media/codec2/components/opus/C2SoftOpusDec.cpp
@@ -19,10 +19,9 @@
 #include <log/log.h>
 
 #include <media/stagefright/foundation/MediaDefs.h>
-
+#include <media/stagefright/foundation/OpusHeader.h>
 #include <C2PlatformSupport.h>
 #include <SimpleC2Interface.h>
-
 #include "C2SoftOpusDec.h"
 
 extern "C" {
@@ -188,16 +187,6 @@
     work->workletsProcessed = 1u;
 }
 
-static uint16_t ReadLE16(const uint8_t *data, size_t data_size,
-                         uint32_t read_offset) {
-    if (read_offset + 1 > data_size)
-        return 0;
-    uint16_t val;
-    val = data[read_offset];
-    val |= data[read_offset + 1] << 8;
-    return val;
-}
-
 static const int kRate = 48000;
 
 // Opus uses Vorbis channel mapping, and Vorbis channel mapping specifies
@@ -216,81 +205,6 @@
 static const int kMaxChannelsWithDefaultLayout = 2;
 static const uint8_t kDefaultOpusChannelLayout[kMaxChannelsWithDefaultLayout] = { 0, 1 };
 
-// Parses Opus Header. Header spec: http://wiki.xiph.org/OggOpus#ID_Header
-static bool ParseOpusHeader(const uint8_t *data, size_t data_size,
-                            OpusHeader* header) {
-    // Size of the Opus header excluding optional mapping information.
-    const size_t kOpusHeaderSize = 19;
-
-    // Offset to the channel count byte in the Opus header.
-    const size_t kOpusHeaderChannelsOffset = 9;
-
-    // Offset to the pre-skip value in the Opus header.
-    const size_t kOpusHeaderSkipSamplesOffset = 10;
-
-    // Offset to the gain value in the Opus header.
-    const size_t kOpusHeaderGainOffset = 16;
-
-    // Offset to the channel mapping byte in the Opus header.
-    const size_t kOpusHeaderChannelMappingOffset = 18;
-
-    // Opus Header contains a stream map. The mapping values are in the header
-    // beyond the always present |kOpusHeaderSize| bytes of data. The mapping
-    // data contains stream count, coupling information, and per channel mapping
-    // values:
-    //   - Byte 0: Number of streams.
-    //   - Byte 1: Number coupled.
-    //   - Byte 2: Starting at byte 2 are |header->channels| uint8 mapping
-    //             values.
-    const size_t kOpusHeaderNumStreamsOffset = kOpusHeaderSize;
-    const size_t kOpusHeaderNumCoupledOffset = kOpusHeaderNumStreamsOffset + 1;
-    const size_t kOpusHeaderStreamMapOffset = kOpusHeaderNumStreamsOffset + 2;
-
-    if (data_size < kOpusHeaderSize) {
-        ALOGE("Header size is too small.");
-        return false;
-    }
-    header->channels = *(data + kOpusHeaderChannelsOffset);
-    if (header->channels <= 0 || header->channels > kMaxChannels) {
-        ALOGE("Invalid Header, wrong channel count: %d", header->channels);
-        return false;
-    }
-
-    header->skip_samples = ReadLE16(data,
-                                    data_size,
-                                    kOpusHeaderSkipSamplesOffset);
-
-    header->gain_db = static_cast<int16_t>(ReadLE16(data,
-                                                    data_size,
-                                                    kOpusHeaderGainOffset));
-
-    header->channel_mapping = *(data + kOpusHeaderChannelMappingOffset);
-    if (!header->channel_mapping) {
-        if (header->channels > kMaxChannelsWithDefaultLayout) {
-            ALOGE("Invalid Header, missing stream map.");
-            return false;
-        }
-        header->num_streams = 1;
-        header->num_coupled = header->channels > 1;
-        header->stream_map[0] = 0;
-        header->stream_map[1] = 1;
-        return true;
-    }
-    if (data_size < kOpusHeaderStreamMapOffset + header->channels) {
-        ALOGE("Invalid stream map; insufficient data for current channel "
-              "count: %d", header->channels);
-        return false;
-    }
-    header->num_streams = *(data + kOpusHeaderNumStreamsOffset);
-    header->num_coupled = *(data + kOpusHeaderNumCoupledOffset);
-    if (header->num_streams + header->num_coupled != header->channels) {
-        ALOGE("Inconsistent channel mapping.");
-        return false;
-    }
-    for (int i = 0; i < header->channels; ++i)
-        header->stream_map[i] = *(data + kOpusHeaderStreamMapOffset + i);
-    return true;
-}
 
 // Convert nanoseconds to number of samples.
 static uint64_t ns_to_samples(uint64_t ns, int rate) {
@@ -338,7 +252,19 @@
     const uint8_t *data = rView.data() + inOffset;
     if (mInputBufferCount < 3) {
         if (mInputBufferCount == 0) {
-            if (!ParseOpusHeader(data, inSize, &mHeader)) {
+            size_t opusHeadSize = inSize;
+            size_t codecDelayBufSize = 0;
+            size_t seekPreRollBufSize = 0;
+            void *opusHeadBuf = (void *)data;
+            void *codecDelayBuf = NULL;
+            void *seekPreRollBuf = NULL;
+
+            GetOpusHeaderBuffers(data, inSize, &opusHeadBuf,
+                                &opusHeadSize, &codecDelayBuf,
+                                &codecDelayBufSize, &seekPreRollBuf,
+                                &seekPreRollBufSize);
+
+            if (!ParseOpusHeader((uint8_t *)opusHeadBuf, opusHeadSize, &mHeader)) {
                 ALOGE("Encountered error while Parsing Opus Header.");
                 mSignalledError = true;
                 work->result = C2_CORRUPTED;
@@ -377,6 +303,20 @@
                 work->result = C2_CORRUPTED;
                 return;
             }
+
+            if (codecDelayBuf && codecDelayBufSize == 8) {
+                uint64_t value;
+                memcpy(&value, codecDelayBuf, sizeof(uint64_t));
+                mCodecDelay = ns_to_samples(value, kRate);
+                mSamplesToDiscard = mCodecDelay;
+                ++mInputBufferCount;
+            }
+            if (seekPreRollBuf && seekPreRollBufSize == 8) {
+                uint64_t value;
+                memcpy(&value, codecDelayBuf, sizeof(uint64_t));
+                mSeekPreRoll = ns_to_samples(value, kRate);
+                ++mInputBufferCount;
+            }
         } else {
             if (inSize < 8) {
                 ALOGE("Input sample size is too small.");
@@ -392,29 +332,30 @@
             }
             else {
                 mSeekPreRoll = samples;
-
-                ALOGI("Configuring decoder: %d Hz, %d channels",
-                       kRate, mHeader.channels);
-                C2StreamSampleRateInfo::output sampleRateInfo(0u, kRate);
-                C2StreamChannelCountInfo::output channelCountInfo(0u, mHeader.channels);
-                std::vector<std::unique_ptr<C2SettingResult>> failures;
-                c2_status_t err = mIntf->config(
-                        { &sampleRateInfo, &channelCountInfo },
-                        C2_MAY_BLOCK,
-                        &failures);
-                if (err == OK) {
-                    work->worklets.front()->output.configUpdate.push_back(C2Param::Copy(sampleRateInfo));
-                    work->worklets.front()->output.configUpdate.push_back(C2Param::Copy(channelCountInfo));
-                } else {
-                    ALOGE("Config Update failed");
-                    mSignalledError = true;
-                    work->result = C2_CORRUPTED;
-                    return;
-                }
             }
         }
 
         ++mInputBufferCount;
+        if (mInputBufferCount == 3) {
+            ALOGI("Configuring decoder: %d Hz, %d channels",
+                   kRate, mHeader.channels);
+            C2StreamSampleRateInfo::output sampleRateInfo(0u, kRate);
+            C2StreamChannelCountInfo::output channelCountInfo(0u, mHeader.channels);
+            std::vector<std::unique_ptr<C2SettingResult>> failures;
+            c2_status_t err = mIntf->config(
+                    { &sampleRateInfo, &channelCountInfo },
+                    C2_MAY_BLOCK,
+                    &failures);
+            if (err == OK) {
+                work->worklets.front()->output.configUpdate.push_back(C2Param::Copy(sampleRateInfo));
+                work->worklets.front()->output.configUpdate.push_back(C2Param::Copy(channelCountInfo));
+            } else {
+                ALOGE("Config Update failed");
+                mSignalledError = true;
+                work->result = C2_CORRUPTED;
+                return;
+            }
+        }
         fillEmptyWork(work);
         if (eos) {
             mSignalledOutputEos = true;
diff --git a/media/codec2/components/opus/C2SoftOpusDec.h b/media/codec2/components/opus/C2SoftOpusDec.h
index 92b7426..b0715ac 100644
--- a/media/codec2/components/opus/C2SoftOpusDec.h
+++ b/media/codec2/components/opus/C2SoftOpusDec.h
@@ -24,16 +24,6 @@
 
 namespace android {
 
-struct OpusHeader {
-  int channels;
-  int skip_samples;
-  int channel_mapping;
-  int num_streams;
-  int num_coupled;
-  int16_t gain_db;
-  uint8_t stream_map[8];
-};
-
 struct C2SoftOpusDec : public SimpleC2Component {
     class IntfImpl;
 
diff --git a/media/codec2/components/opus/C2SoftOpusEnc.cpp b/media/codec2/components/opus/C2SoftOpusEnc.cpp
new file mode 100644
index 0000000..d6ed5ff
--- /dev/null
+++ b/media/codec2/components/opus/C2SoftOpusEnc.cpp
@@ -0,0 +1,638 @@
+/*
+ * 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 "C2SoftOpusEnc"
+#include <utils/Log.h>
+
+#include <C2PlatformSupport.h>
+#include <SimpleC2Interface.h>
+#include <media/stagefright/foundation/MediaDefs.h>
+#include <media/stagefright/foundation/OpusHeader.h>
+#include "C2SoftOpusEnc.h"
+
+extern "C" {
+    #include <opus.h>
+    #include <opus_multistream.h>
+}
+
+#define DEFAULT_FRAME_DURATION_MS 20
+namespace android {
+
+constexpr char COMPONENT_NAME[] = "c2.android.opus.encoder";
+
+class C2SoftOpusEnc::IntfImpl : public C2InterfaceHelper {
+public:
+    explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
+        : C2InterfaceHelper(helper) {
+
+        setDerivedInstance(this);
+
+        addParameter(
+                DefineParam(mInputFormat, C2_NAME_INPUT_STREAM_FORMAT_SETTING)
+                .withConstValue(new C2StreamFormatConfig::input(0u, C2FormatAudio))
+                .build());
+
+        addParameter(
+                DefineParam(mOutputFormat, C2_NAME_OUTPUT_STREAM_FORMAT_SETTING)
+                .withConstValue(new C2StreamFormatConfig::output(0u, C2FormatCompressed))
+                .build());
+
+        addParameter(
+                DefineParam(mInputMediaType, C2_NAME_INPUT_PORT_MIME_SETTING)
+                .withConstValue(AllocSharedString<C2PortMimeConfig::input>(
+                        MEDIA_MIMETYPE_AUDIO_RAW))
+                .build());
+
+        addParameter(
+                DefineParam(mOutputMediaType, C2_NAME_OUTPUT_PORT_MIME_SETTING)
+                .withConstValue(AllocSharedString<C2PortMimeConfig::output>(
+                        MEDIA_MIMETYPE_AUDIO_OPUS))
+                .build());
+
+        addParameter(
+                DefineParam(mSampleRate, C2_NAME_STREAM_SAMPLE_RATE_SETTING)
+                .withDefault(new C2StreamSampleRateInfo::input(0u, 48000))
+                .withFields({C2F(mSampleRate, value).oneOf({
+                    8000, 12000, 16000, 24000, 48000})})
+                .withSetter((Setter<decltype(*mSampleRate)>::StrictValueWithNoDeps))
+                .build());
+
+        addParameter(
+                DefineParam(mChannelCount, C2_NAME_STREAM_CHANNEL_COUNT_SETTING)
+                .withDefault(new C2StreamChannelCountInfo::input(0u, 1))
+                .withFields({C2F(mChannelCount, value).inRange(1, 8)})
+                .withSetter((Setter<decltype(*mChannelCount)>::StrictValueWithNoDeps))
+                .build());
+
+        addParameter(
+                DefineParam(mBitrate, C2_NAME_STREAM_BITRATE_SETTING)
+                .withDefault(new C2BitrateTuning::output(0u, 128000))
+                .withFields({C2F(mBitrate, value).inRange(500, 512000)})
+                .withSetter(Setter<decltype(*mBitrate)>::NonStrictValueWithNoDeps)
+                .build());
+
+        addParameter(
+                DefineParam(mComplexity, C2_PARAMKEY_COMPLEXITY)
+                .withDefault(new C2StreamComplexityTuning::output(0u, 10))
+                .withFields({C2F(mComplexity, value).inRange(1, 10)})
+                .withSetter(Setter<decltype(*mComplexity)>::NonStrictValueWithNoDeps)
+                .build());
+
+        addParameter(
+                DefineParam(mInputMaxBufSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
+                .withConstValue(new C2StreamMaxBufferSizeInfo::input(0u, 3840))
+                .build());
+    }
+
+    uint32_t getSampleRate() const { return mSampleRate->value; }
+    uint32_t getChannelCount() const { return mChannelCount->value; }
+    uint32_t getBitrate() const { return mBitrate->value; }
+    uint32_t getComplexity() const { return mComplexity->value; }
+
+private:
+    std::shared_ptr<C2StreamFormatConfig::input> mInputFormat;
+    std::shared_ptr<C2StreamFormatConfig::output> mOutputFormat;
+    std::shared_ptr<C2PortMimeConfig::input> mInputMediaType;
+    std::shared_ptr<C2PortMimeConfig::output> mOutputMediaType;
+    std::shared_ptr<C2StreamSampleRateInfo::input> mSampleRate;
+    std::shared_ptr<C2StreamChannelCountInfo::input> mChannelCount;
+    std::shared_ptr<C2BitrateTuning::output> mBitrate;
+    std::shared_ptr<C2StreamComplexityTuning::output> mComplexity;
+    std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mInputMaxBufSize;
+};
+
+C2SoftOpusEnc::C2SoftOpusEnc(const char* name, c2_node_id_t id,
+                               const std::shared_ptr<IntfImpl>& intfImpl)
+    : SimpleC2Component(
+          std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
+      mIntf(intfImpl),
+      mOutputBlock(nullptr),
+      mEncoder(nullptr),
+      mInputBufferPcm16(nullptr),
+      mOutIndex(0u) {
+}
+
+C2SoftOpusEnc::~C2SoftOpusEnc() {
+    onRelease();
+}
+
+c2_status_t C2SoftOpusEnc::onInit() {
+    return initEncoder();
+}
+
+c2_status_t C2SoftOpusEnc::configureEncoder() {
+    unsigned char mono_mapping[256] = {0};
+    unsigned char stereo_mapping[256] = {0, 1};
+    unsigned char surround_mapping[256] = {0, 1, 255};
+    mSampleRate = mIntf->getSampleRate();
+    mChannelCount = mIntf->getChannelCount();
+    uint32_t bitrate = mIntf->getBitrate();
+    int complexity = mIntf->getComplexity();
+    mNumSamplesPerFrame = mSampleRate / (1000 / mFrameDurationMs);
+    mNumPcmBytesPerInputFrame =
+        mChannelCount * mNumSamplesPerFrame * sizeof(int16_t);
+    int err = C2_OK;
+
+    unsigned char* mapping;
+    if (mChannelCount < 2) {
+        mapping = mono_mapping;
+    } else if (mChannelCount == 2) {
+        mapping = stereo_mapping;
+    } else {
+        mapping = surround_mapping;
+    }
+
+    if (mEncoder != nullptr) {
+        opus_multistream_encoder_destroy(mEncoder);
+    }
+
+    mEncoder = opus_multistream_encoder_create(mSampleRate, mChannelCount,
+        1, 1, mapping, OPUS_APPLICATION_AUDIO, &err);
+    if (err) {
+        ALOGE("Could not create libopus encoder. Error code: %i", err);
+        return C2_CORRUPTED;
+    }
+
+    // Complexity
+    if (opus_multistream_encoder_ctl(
+            mEncoder, OPUS_SET_COMPLEXITY(complexity)) != OPUS_OK) {
+        ALOGE("failed to set complexity");
+        return C2_BAD_VALUE;
+    }
+
+    // DTX
+    if (opus_multistream_encoder_ctl(mEncoder, OPUS_SET_DTX(0) != OPUS_OK)) {
+        ALOGE("failed to set dtx");
+        return C2_BAD_VALUE;
+    }
+
+    // Application
+    if (opus_multistream_encoder_ctl(mEncoder,
+            OPUS_SET_APPLICATION(OPUS_APPLICATION_AUDIO)) != OPUS_OK) {
+        ALOGE("failed to set application");
+        return C2_BAD_VALUE;
+    }
+
+    // Signal type
+    if (opus_multistream_encoder_ctl(mEncoder, OPUS_SET_SIGNAL(OPUS_AUTO)) !=
+        OPUS_OK) {
+        ALOGE("failed to set signal");
+        return C2_BAD_VALUE;
+    }
+
+    // Unconstrained VBR
+    if (opus_multistream_encoder_ctl(mEncoder, OPUS_SET_VBR(0) != OPUS_OK)) {
+        ALOGE("failed to set vbr type");
+        return C2_BAD_VALUE;
+    }
+    if (opus_multistream_encoder_ctl(mEncoder, OPUS_SET_VBR_CONSTRAINT(0) !=
+            OPUS_OK)) {
+        ALOGE("failed to set vbr constraint");
+        return C2_BAD_VALUE;
+    }
+
+    // Bitrate
+    if (opus_multistream_encoder_ctl(mEncoder, OPUS_SET_BITRATE(bitrate)) !=
+            OPUS_OK) {
+        ALOGE("failed to set bitrate");
+        return C2_BAD_VALUE;
+    }
+
+    // Get codecDelay
+    int32_t lookahead;
+    if (opus_multistream_encoder_ctl(mEncoder, OPUS_GET_LOOKAHEAD(&lookahead)) !=
+            OPUS_OK) {
+        ALOGE("failed to get lookahead");
+        return C2_BAD_VALUE;
+    }
+    mCodecDelay = lookahead * 1000000000ll / mSampleRate;
+
+    // Set seek preroll to 80 ms
+    mSeekPreRoll = 80000000;
+    return C2_OK;
+}
+
+c2_status_t C2SoftOpusEnc::initEncoder() {
+    mSignalledEos = false;
+    mSignalledError = false;
+    mHeaderGenerated = false;
+    mIsFirstFrame = true;
+    mEncoderFlushed = false;
+    mBufferAvailable = false;
+    mAnchorTimeStamp = 0ull;
+    mProcessedSamples = 0;
+    mFilledLen = 0;
+    mFrameDurationMs = DEFAULT_FRAME_DURATION_MS;
+    if (!mInputBufferPcm16) {
+        mInputBufferPcm16 =
+            (int16_t*)malloc(kFrameSize * kMaxNumChannels * sizeof(int16_t));
+    }
+    if (!mInputBufferPcm16) return C2_NO_MEMORY;
+
+    /* Default Configurations */
+    c2_status_t status = configureEncoder();
+    return status;
+}
+
+c2_status_t C2SoftOpusEnc::onStop() {
+    mSignalledEos = false;
+    mSignalledError = false;
+    mIsFirstFrame = true;
+    mEncoderFlushed = false;
+    mBufferAvailable = false;
+    mAnchorTimeStamp = 0ull;
+    mProcessedSamples = 0u;
+    mFilledLen = 0;
+    if (mEncoder) {
+        int status = opus_multistream_encoder_ctl(mEncoder, OPUS_RESET_STATE);
+        if (status != OPUS_OK) {
+            ALOGE("OPUS_RESET_STATE failed status = %s", opus_strerror(status));
+            mSignalledError = true;
+            return C2_CORRUPTED;
+        }
+    }
+    if (mOutputBlock) mOutputBlock.reset();
+    mOutputBlock = nullptr;
+
+    return C2_OK;
+}
+
+void C2SoftOpusEnc::onReset() {
+    (void)onStop();
+}
+
+void C2SoftOpusEnc::onRelease() {
+    (void)onStop();
+    if (mInputBufferPcm16) {
+        free(mInputBufferPcm16);
+        mInputBufferPcm16 = nullptr;
+    }
+    if (mEncoder) {
+        opus_multistream_encoder_destroy(mEncoder);
+        mEncoder = nullptr;
+    }
+}
+
+c2_status_t C2SoftOpusEnc::onFlush_sm() {
+    return onStop();
+}
+
+// Drain the encoder to get last frames (if any)
+int C2SoftOpusEnc::drainEncoder(uint8_t* outPtr) {
+    memset((uint8_t *)mInputBufferPcm16 + mFilledLen, 0,
+        (mNumPcmBytesPerInputFrame - mFilledLen));
+    int encodedBytes = opus_multistream_encode(
+        mEncoder, mInputBufferPcm16, mNumSamplesPerFrame, outPtr, kMaxPayload);
+    if (encodedBytes > mOutputBlock->capacity()) {
+        ALOGE("not enough space left to write encoded data, dropping %d bytes",
+              mBytesEncoded);
+        // a fatal error would stop the encoding
+        return -1;
+    }
+    ALOGV("encoded %i Opus bytes from %zu PCM bytes", encodedBytes,
+          mNumPcmBytesPerInputFrame);
+    mEncoderFlushed = true;
+    mFilledLen = 0;
+    return encodedBytes;
+}
+
+void C2SoftOpusEnc::process(const std::unique_ptr<C2Work>& work,
+                            const std::shared_ptr<C2BlockPool>& pool) {
+    // Initialize output work
+    work->result = C2_OK;
+    work->workletsProcessed = 1u;
+    work->worklets.front()->output.flags = work->input.flags;
+
+    if (mSignalledError || mSignalledEos) {
+        work->result = C2_BAD_VALUE;
+        return;
+    }
+
+    bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
+    C2ReadView rView = mDummyReadView;
+    size_t inOffset = 0u;
+    size_t inSize = 0u;
+    c2_status_t err = C2_OK;
+    if (!work->input.buffers.empty()) {
+        rView =
+            work->input.buffers[0]->data().linearBlocks().front().map().get();
+        inSize = rView.capacity();
+        if (inSize && rView.error()) {
+            ALOGE("read view map failed %d", rView.error());
+            work->result = C2_CORRUPTED;
+            return;
+        }
+    }
+
+    ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
+          inSize, (int)work->input.ordinal.timestamp.peeku(),
+          (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
+
+    if (!mEncoder) {
+        if (initEncoder() != C2_OK) {
+            ALOGE("initEncoder failed with status %d", err);
+            work->result = err;
+            mSignalledError = true;
+            return;
+        }
+    }
+    if (mIsFirstFrame) {
+        mAnchorTimeStamp = work->input.ordinal.timestamp.peekull();
+        mIsFirstFrame = false;
+    }
+
+    C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
+    err = pool->fetchLinearBlock(kMaxPayload, usage, &mOutputBlock);
+    if (err != C2_OK) {
+        ALOGE("fetchLinearBlock for Output failed with status %d", err);
+        work->result = C2_NO_MEMORY;
+        return;
+    }
+
+    C2WriteView wView = mOutputBlock->map().get();
+    if (wView.error()) {
+        ALOGE("write view map failed %d", wView.error());
+        work->result = C2_CORRUPTED;
+        mOutputBlock.reset();
+        return;
+    }
+
+    size_t inPos = 0;
+    size_t processSize = 0;
+    mBytesEncoded = 0;
+    uint64_t outTimeStamp = 0u;
+    std::shared_ptr<C2Buffer> buffer;
+    uint64_t inputIndex = work->input.ordinal.frameIndex.peeku();
+    const uint8_t* inPtr = rView.data() + inOffset;
+
+    class FillWork {
+    public:
+        FillWork(uint32_t flags, C2WorkOrdinalStruct ordinal,
+                 const std::shared_ptr<C2Buffer> &buffer)
+            : mFlags(flags), mOrdinal(ordinal), mBuffer(buffer) {
+        }
+        ~FillWork() = default;
+
+        void operator()(const std::unique_ptr<C2Work>& work) {
+            work->worklets.front()->output.flags = (C2FrameData::flags_t)mFlags;
+            work->worklets.front()->output.buffers.clear();
+            work->worklets.front()->output.ordinal = mOrdinal;
+            work->workletsProcessed = 1u;
+            work->result = C2_OK;
+            if (mBuffer) {
+                work->worklets.front()->output.buffers.push_back(mBuffer);
+            }
+            ALOGV("timestamp = %lld, index = %lld, w/%s buffer",
+                  mOrdinal.timestamp.peekll(),
+                  mOrdinal.frameIndex.peekll(),
+                  mBuffer ? "" : "o");
+        }
+
+    private:
+        const uint32_t mFlags;
+        const C2WorkOrdinalStruct mOrdinal;
+        const std::shared_ptr<C2Buffer> mBuffer;
+    };
+
+    C2WorkOrdinalStruct outOrdinal = work->input.ordinal;
+
+    if (!mHeaderGenerated) {
+        uint8_t header[AOPUS_UNIFIED_CSD_MAXSIZE];
+        memset(header, 0, sizeof(header));
+        OpusHeader opusHeader;
+        opusHeader.channels = mChannelCount;
+        opusHeader.num_streams = mChannelCount;
+        opusHeader.num_coupled = 0;
+        opusHeader.channel_mapping = ((mChannelCount > 8) ? 255 : (mChannelCount > 2));
+        opusHeader.gain_db = 0;
+        opusHeader.skip_samples = 0;
+        int headerLen = WriteOpusHeaders(opusHeader, mSampleRate, header,
+            sizeof(header), mCodecDelay, mSeekPreRoll);
+
+        std::unique_ptr<C2StreamCsdInfo::output> csd =
+            C2StreamCsdInfo::output::AllocUnique(headerLen, 0u);
+        if (!csd) {
+            ALOGE("CSD allocation failed");
+            mSignalledError = true;
+            work->result = C2_NO_MEMORY;
+            return;
+        }
+        ALOGV("put csd, %d bytes", headerLen);
+        memcpy(csd->m.value, header, headerLen);
+        work->worklets.front()->output.configUpdate.push_back(std::move(csd));
+        mHeaderGenerated = true;
+    }
+
+    /*
+     * For buffer size which is not a multiple of mNumPcmBytesPerInputFrame, we will
+     * accumulate the input and keep it. Once the input is filled with expected number
+     * of bytes, we will send it to encoder. mFilledLen manages the bytes of input yet
+     * to be processed. The next call will fill mNumPcmBytesPerInputFrame - mFilledLen
+     * bytes to input and send it to the encoder.
+     */
+    while (inPos < inSize) {
+        const uint8_t* pcmBytes = inPtr + inPos;
+        int filledSamples = mFilledLen / sizeof(int16_t);
+        if ((inPos + (mNumPcmBytesPerInputFrame - mFilledLen)) <= inSize) {
+            processSize = mNumPcmBytesPerInputFrame - mFilledLen;
+            mBufferAvailable = true;
+        } else {
+            processSize = inSize - inPos;
+            mBufferAvailable = false;
+            if (eos) {
+                memset(mInputBufferPcm16 + filledSamples, 0,
+                       (mNumPcmBytesPerInputFrame - mFilledLen));
+                mBufferAvailable = true;
+            }
+        }
+        const unsigned nInputSamples = processSize / sizeof(int16_t);
+
+        for (unsigned i = 0; i < nInputSamples; i++) {
+            int32_t data = pcmBytes[2 * i + 1] << 8 | pcmBytes[2 * i];
+            data = ((data & 0xFFFF) ^ 0x8000) - 0x8000;
+            mInputBufferPcm16[i + filledSamples] = data;
+        }
+        inPos += processSize;
+        mFilledLen += processSize;
+        if (!mBufferAvailable) break;
+        uint8_t* outPtr = wView.data() + mBytesEncoded;
+        int encodedBytes =
+            opus_multistream_encode(mEncoder, mInputBufferPcm16,
+                                    mNumSamplesPerFrame, outPtr, kMaxPayload);
+        ALOGV("encoded %i Opus bytes from %zu PCM bytes", encodedBytes,
+              processSize);
+
+        if (encodedBytes < 0 || encodedBytes > kMaxPayload) {
+            ALOGE("opus_encode failed, encodedBytes : %d", encodedBytes);
+            mSignalledError = true;
+            work->result = C2_CORRUPTED;
+            return;
+        }
+        if (buffer) {
+            outOrdinal.frameIndex = mOutIndex++;
+            outOrdinal.timestamp = mAnchorTimeStamp + outTimeStamp;
+            cloneAndSend(
+                inputIndex, work,
+                FillWork(C2FrameData::FLAG_INCOMPLETE, outOrdinal, buffer));
+            buffer.reset();
+        }
+        if (encodedBytes > 0) {
+            buffer =
+                createLinearBuffer(mOutputBlock, mBytesEncoded, encodedBytes);
+        }
+        mBytesEncoded += encodedBytes;
+        mProcessedSamples += (filledSamples + nInputSamples);
+        outTimeStamp =
+            mProcessedSamples * 1000000ll / mChannelCount / mSampleRate;
+        if ((processSize + mFilledLen) < mNumPcmBytesPerInputFrame)
+            mEncoderFlushed = true;
+        mFilledLen = 0;
+    }
+
+    uint32_t flags = 0;
+    if (eos) {
+        ALOGV("signalled eos");
+        mSignalledEos = true;
+        if (!mEncoderFlushed) {
+            if (buffer) {
+                outOrdinal.frameIndex = mOutIndex++;
+                outOrdinal.timestamp = mAnchorTimeStamp + outTimeStamp;
+                cloneAndSend(
+                    inputIndex, work,
+                    FillWork(C2FrameData::FLAG_INCOMPLETE, outOrdinal, buffer));
+                buffer.reset();
+            }
+            // drain the encoder for last buffer
+            drainInternal(pool, work);
+        }
+        flags = C2FrameData::FLAG_END_OF_STREAM;
+    }
+    if (buffer) {
+        outOrdinal.frameIndex = mOutIndex++;
+        outOrdinal.timestamp = mAnchorTimeStamp + outTimeStamp;
+        FillWork((C2FrameData::flags_t)(flags), outOrdinal, buffer)(work);
+        buffer.reset();
+    }
+    mOutputBlock = nullptr;
+}
+
+c2_status_t C2SoftOpusEnc::drainInternal(
+        const std::shared_ptr<C2BlockPool>& pool,
+        const std::unique_ptr<C2Work>& work) {
+    mBytesEncoded = 0;
+    std::shared_ptr<C2Buffer> buffer = nullptr;
+    C2WorkOrdinalStruct outOrdinal = work->input.ordinal;
+    bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
+
+    C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
+    c2_status_t err = pool->fetchLinearBlock(kMaxPayload, usage, &mOutputBlock);
+    if (err != C2_OK) {
+        ALOGE("fetchLinearBlock for Output failed with status %d", err);
+        return C2_NO_MEMORY;
+    }
+
+    C2WriteView wView = mOutputBlock->map().get();
+    if (wView.error()) {
+        ALOGE("write view map failed %d", wView.error());
+        mOutputBlock.reset();
+        return C2_CORRUPTED;
+    }
+
+    int encBytes = drainEncoder(wView.data());
+    if (encBytes > 0) mBytesEncoded += encBytes;
+    if (mBytesEncoded > 0) {
+        buffer = createLinearBuffer(mOutputBlock, 0, mBytesEncoded);
+        mOutputBlock.reset();
+    }
+    mProcessedSamples += (mNumPcmBytesPerInputFrame / sizeof(int16_t));
+    uint64_t outTimeStamp =
+        mProcessedSamples * 1000000ll / mChannelCount / mSampleRate;
+    outOrdinal.frameIndex = mOutIndex++;
+    outOrdinal.timestamp = mAnchorTimeStamp + outTimeStamp;
+    work->worklets.front()->output.flags =
+        (C2FrameData::flags_t)(eos ? C2FrameData::FLAG_END_OF_STREAM : 0);
+    work->worklets.front()->output.buffers.clear();
+    work->worklets.front()->output.ordinal = outOrdinal;
+    work->workletsProcessed = 1u;
+    work->result = C2_OK;
+    if (buffer) {
+        work->worklets.front()->output.buffers.push_back(buffer);
+    }
+    mOutputBlock = nullptr;
+    return C2_OK;
+}
+
+c2_status_t C2SoftOpusEnc::drain(uint32_t drainMode,
+                                 const std::shared_ptr<C2BlockPool>& pool) {
+    if (drainMode == NO_DRAIN) {
+        ALOGW("drain with NO_DRAIN: no-op");
+        return C2_OK;
+    }
+    if (drainMode == DRAIN_CHAIN) {
+        ALOGW("DRAIN_CHAIN not supported");
+        return C2_OMITTED;
+    }
+    mIsFirstFrame = true;
+    mAnchorTimeStamp = 0ull;
+    mProcessedSamples = 0u;
+    return drainInternal(pool, nullptr);
+}
+
+class C2SoftOpusEncFactory : public C2ComponentFactory {
+public:
+    C2SoftOpusEncFactory()
+        : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
+              GetCodec2PlatformComponentStore()->getParamReflector())) {}
+
+    virtual c2_status_t createComponent(
+        c2_node_id_t id, std::shared_ptr<C2Component>* const component,
+        std::function<void(C2Component*)> deleter) override {
+        *component = std::shared_ptr<C2Component>(
+            new C2SoftOpusEnc(
+                COMPONENT_NAME, id,
+                std::make_shared<C2SoftOpusEnc::IntfImpl>(mHelper)),
+            deleter);
+        return C2_OK;
+    }
+
+    virtual c2_status_t createInterface(
+        c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
+        std::function<void(C2ComponentInterface*)> deleter) override {
+        *interface = std::shared_ptr<C2ComponentInterface>(
+            new SimpleInterface<C2SoftOpusEnc::IntfImpl>(
+                COMPONENT_NAME, id,
+                std::make_shared<C2SoftOpusEnc::IntfImpl>(mHelper)),
+            deleter);
+        return C2_OK;
+    }
+
+    virtual ~C2SoftOpusEncFactory() override = default;
+private:
+    std::shared_ptr<C2ReflectorHelper> mHelper;
+};
+
+}  // namespace android
+
+extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
+    ALOGV("in %s", __func__);
+    return new ::android::C2SoftOpusEncFactory();
+}
+
+extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
+    ALOGV("in %s", __func__);
+    delete factory;
+}
diff --git a/media/codec2/components/opus/C2SoftOpusEnc.h b/media/codec2/components/opus/C2SoftOpusEnc.h
new file mode 100644
index 0000000..69e5240
--- /dev/null
+++ b/media/codec2/components/opus/C2SoftOpusEnc.h
@@ -0,0 +1,90 @@
+/*
+ * 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 ANDROID_C2_SOFT_OPUS_ENC_H_
+#define ANDROID_C2_SOFT_OPUS_ENC_H_
+
+#include <atomic>
+#include <SimpleC2Component.h>
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+struct OpusMSEncoder;
+
+namespace android {
+
+struct C2SoftOpusEnc : public SimpleC2Component {
+    class IntfImpl;
+
+    C2SoftOpusEnc(const char *name, c2_node_id_t id,
+               const std::shared_ptr<IntfImpl> &intfImpl);
+    virtual ~C2SoftOpusEnc();
+
+    // From SimpleC2Component
+    c2_status_t onInit() override;
+    c2_status_t onStop() override;
+    void onReset() override;
+    void onRelease() override;
+    c2_status_t onFlush_sm() override;
+    void process(
+            const std::unique_ptr<C2Work> &work,
+            const std::shared_ptr<C2BlockPool> &pool) override;
+    c2_status_t drain(
+            uint32_t drainMode,
+            const std::shared_ptr<C2BlockPool> &pool) override;
+private:
+    /* OPUS_FRAMESIZE_20_MS */
+    const int kFrameSize = 960;
+    const int kMaxPayload = 4000;
+    const int kMaxNumChannels = 8;
+
+    std::shared_ptr<IntfImpl> mIntf;
+    std::shared_ptr<C2LinearBlock> mOutputBlock;
+
+    OpusMSEncoder* mEncoder;
+    int16_t* mInputBufferPcm16;
+
+    bool mHeaderGenerated;
+    bool mIsFirstFrame;
+    bool mEncoderFlushed;
+    bool mBufferAvailable;
+    bool mSignalledEos;
+    bool mSignalledError;
+    uint32_t mSampleRate;
+    uint32_t mChannelCount;
+    uint32_t mFrameDurationMs;
+    uint64_t mAnchorTimeStamp;
+    uint64_t mProcessedSamples;
+    // Codec delay in ns
+    uint64_t mCodecDelay;
+    // Seek pre-roll in ns
+    uint64_t mSeekPreRoll;
+    int mNumSamplesPerFrame;
+    int mBytesEncoded;
+    int32_t mFilledLen;
+    size_t mNumPcmBytesPerInputFrame;
+    std::atomic_uint64_t mOutIndex;
+    c2_status_t initEncoder();
+    c2_status_t configureEncoder();
+    int drainEncoder(uint8_t* outPtr);
+    c2_status_t drainInternal(const std::shared_ptr<C2BlockPool>& pool,
+                              const std::unique_ptr<C2Work>& work);
+
+    C2_DO_NOT_COPY(C2SoftOpusEnc);
+};
+
+}  // namespace android
+
+#endif  // ANDROID_C2_SOFT_OPUS_ENC_H_
diff --git a/media/codec2/core/include/C2Config.h b/media/codec2/core/include/C2Config.h
index cf1f6cf..23939b5 100644
--- a/media/codec2/core/include/C2Config.h
+++ b/media/codec2/core/include/C2Config.h
@@ -638,7 +638,7 @@
     LEVEL_VP9_6_1,                              ///< VP9 Level 6.1
     LEVEL_VP9_6_2,                              ///< VP9 Level 6.2
 
-    // Dolby Vision level
+    // Dolby Vision levels
     LEVEL_DV_MAIN_HD_24 = _C2_PL_DV_BASE,       ///< Dolby Vision main tier hd24
     LEVEL_DV_MAIN_HD_30,                        ///< Dolby Vision main tier hd30
     LEVEL_DV_MAIN_FHD_24,                       ///< Dolby Vision main tier fhd24
@@ -659,6 +659,7 @@
     LEVEL_DV_HIGH_UHD_48,                       ///< Dolby Vision high tier uhd48
     LEVEL_DV_HIGH_UHD_60,                       ///< Dolby Vision high tier uhd60
 
+    // AV1 levels
     LEVEL_AV1_2    = _C2_PL_AV1_BASE ,          ///< AV1 Level 2
     LEVEL_AV1_2_1,                              ///< AV1 Level 2.1
     LEVEL_AV1_2_2,                              ///< AV1 Level 2.2
diff --git a/media/codec2/vndk/C2Config.cpp b/media/codec2/vndk/C2Config.cpp
index 782bec5..8a27088 100644
--- a/media/codec2/vndk/C2Config.cpp
+++ b/media/codec2/vndk/C2Config.cpp
@@ -221,6 +221,30 @@
         { "vp9-6", C2Config::LEVEL_VP9_6 },
         { "vp9-6.1", C2Config::LEVEL_VP9_6_1 },
         { "vp9-6.2", C2Config::LEVEL_VP9_6_2 },
+        { "av1-2", C2Config::LEVEL_AV1_2 },
+        { "av1-2.1", C2Config::LEVEL_AV1_2_1 },
+        { "av1-2.2", C2Config::LEVEL_AV1_2_2 },
+        { "av1-2.3", C2Config::LEVEL_AV1_2_3 },
+        { "av1-3", C2Config::LEVEL_AV1_3 },
+        { "av1-3.1", C2Config::LEVEL_AV1_3_1 },
+        { "av1-3.2", C2Config::LEVEL_AV1_3_2 },
+        { "av1-3.3", C2Config::LEVEL_AV1_3_3 },
+        { "av1-4", C2Config::LEVEL_AV1_4 },
+        { "av1-4.1", C2Config::LEVEL_AV1_4_1 },
+        { "av1-4.2", C2Config::LEVEL_AV1_4_2 },
+        { "av1-4.3", C2Config::LEVEL_AV1_4_3 },
+        { "av1-5", C2Config::LEVEL_AV1_5 },
+        { "av1-5.1", C2Config::LEVEL_AV1_5_1 },
+        { "av1-5.2", C2Config::LEVEL_AV1_5_2 },
+        { "av1-5.3", C2Config::LEVEL_AV1_5_3 },
+        { "av1-6", C2Config::LEVEL_AV1_6 },
+        { "av1-6.1", C2Config::LEVEL_AV1_6_1 },
+        { "av1-6.2", C2Config::LEVEL_AV1_6_2 },
+        { "av1-6.3", C2Config::LEVEL_AV1_6_3 },
+        { "av1-7", C2Config::LEVEL_AV1_7 },
+        { "av1-7.1", C2Config::LEVEL_AV1_7_1 },
+        { "av1-7.2", C2Config::LEVEL_AV1_7_2 },
+        { "av1-7.3", C2Config::LEVEL_AV1_7_3 },
 }))
 
 DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(C2BufferData::type_t, ({
diff --git a/media/codec2/vndk/C2Store.cpp b/media/codec2/vndk/C2Store.cpp
index a5dd203..dc7e89c 100644
--- a/media/codec2/vndk/C2Store.cpp
+++ b/media/codec2/vndk/C2Store.cpp
@@ -817,6 +817,7 @@
     emplace("c2.android.mp3.decoder", "libcodec2_soft_mp3dec.so");
     emplace("c2.android.vorbis.decoder", "libcodec2_soft_vorbisdec.so");
     emplace("c2.android.opus.decoder", "libcodec2_soft_opusdec.so");
+    emplace("c2.android.opus.encoder", "libcodec2_soft_opusenc.so");
     emplace("c2.android.vp8.decoder", "libcodec2_soft_vp8dec.so");
     emplace("c2.android.vp9.decoder", "libcodec2_soft_vp9dec.so");
     emplace("c2.android.vp8.encoder", "libcodec2_soft_vp8enc.so");
diff --git a/media/extractors/mp4/ItemTable.cpp b/media/extractors/mp4/ItemTable.cpp
index 7816473..eb6602c 100644
--- a/media/extractors/mp4/ItemTable.cpp
+++ b/media/extractors/mp4/ItemTable.cpp
@@ -1687,8 +1687,31 @@
     }
 
     // skip the first 4-byte of the offset to TIFF header
-    *offset = mItemIdToExifMap[exifIndex].offset + 4;
-    *size = mItemIdToExifMap[exifIndex].size - 4;
+    uint32_t tiffOffset;
+    if (!mDataSource->readAt(
+            mItemIdToExifMap[exifIndex].offset, &tiffOffset, 4)) {
+        return ERROR_IO;
+    }
+
+    // We need 'Exif\0\0' before the tiff header
+    tiffOffset = ntohl(tiffOffset);
+    if (tiffOffset < 6) {
+        return ERROR_MALFORMED;
+    }
+    // The first 4-byte of the item is the offset of the tiff header within the
+    // exif data. The size of the item should be > 4 for a non-empty exif (this
+    // was already checked when the item was added). Also check that the tiff
+    // header offset is valid.
+    if (mItemIdToExifMap[exifIndex].size <= 4 ||
+            tiffOffset > mItemIdToExifMap[exifIndex].size - 4) {
+        return ERROR_MALFORMED;
+    }
+
+    // Offset of 'Exif\0\0' relative to the beginning of 'Exif' item
+    // (first 4-byte is the tiff header offset)
+    uint32_t exifOffset = 4 + tiffOffset - 6;
+    *offset = mItemIdToExifMap[exifIndex].offset + exifOffset;
+    *size = mItemIdToExifMap[exifIndex].size - exifOffset;
     return OK;
 }
 
diff --git a/media/libeffects/lvm/tests/Android.bp b/media/libeffects/lvm/tests/Android.bp
index 8ee807c..003ce9e 100644
--- a/media/libeffects/lvm/tests/Android.bp
+++ b/media/libeffects/lvm/tests/Android.bp
@@ -44,3 +44,16 @@
         "-Wextra",
     ],
 }
+
+cc_test {
+    name: "snr",
+    host_supported: false,
+
+    srcs: ["snr.cpp"],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+}
diff --git a/media/libeffects/lvm/tests/build_and_run_all_unit_tests.sh b/media/libeffects/lvm/tests/build_and_run_all_unit_tests.sh
index 861ee64..41a4f04 100755
--- a/media/libeffects/lvm/tests/build_and_run_all_unit_tests.sh
+++ b/media/libeffects/lvm/tests/build_and_run_all_unit_tests.sh
@@ -25,16 +25,17 @@
 adb shell mkdir -p $testdir
 adb push $ANDROID_BUILD_TOP/cts/tests/tests/media/res/raw/sinesweepraw.raw $testdir
 adb push $OUT/testcases/lvmtest/arm64/lvmtest $testdir
+adb push $OUT/testcases/snr/arm64/snr $testdir
 
 flags_arr=(
     "-csE"
     "-eqE"
     "-tE"
     "-csE -tE -eqE"
-    "-bE"
+    "-bE -M"
     "-csE -tE"
     "-csE -eqE" "-tE -eqE"
-    "-csE -tE -bE -eqE"
+    "-csE -tE -bE -M -eqE"
 )
 
 fs_arr=(
@@ -79,6 +80,10 @@
             then
                 adb shell cmp $testdir/sinesweep_2_$((fs)).raw \
                     $testdir/sinesweep_$((ch))_$((fs)).raw
+            elif [[ $flags == *"-bE"* ]] && [ "$ch" -gt 2 ]
+            then
+                adb shell $testdir/snr $testdir/sinesweep_2_$((fs)).raw \
+                    $testdir/sinesweep_$((ch))_$((fs)).raw -thr:90.308998
             fi
 
         done
diff --git a/media/libeffects/lvm/tests/snr.cpp b/media/libeffects/lvm/tests/snr.cpp
new file mode 100644
index 0000000..88110c0
--- /dev/null
+++ b/media/libeffects/lvm/tests/snr.cpp
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+#include <assert.h>
+#include <inttypes.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <vector>
+
+template <typename T, typename A = float>
+std::pair<A, A> getSignalNoise(FILE *finp, FILE *fref) {
+  constexpr size_t framesize = 256;
+  std::vector<T> in(framesize);
+  std::vector<T> ref(framesize);
+  A signal{};
+  A noise{};
+
+  for (;;) {
+    size_t read_samples_in = fread(&in[0], sizeof(T), framesize, finp);
+    const size_t read_samples_ref = fread(&ref[0], sizeof(T), framesize, fref);
+    if (read_samples_in != read_samples_ref) {
+      printf("file sizes do not match (last %zu %zu)", read_samples_in, read_samples_ref);
+      read_samples_in = std::min(read_samples_in, read_samples_ref);
+    }
+    if (read_samples_in == 0) {
+        return { signal, noise };
+    }
+    for (size_t i = 0; i < read_samples_in; ++i) {
+       const A value(ref[i]);
+       const A diff(A(in[i]) - value);
+       signal += value * value;
+       noise += diff * diff;
+    }
+  }
+}
+
+void printUsage() {
+  printf("\nUsage: ");
+  printf("\n     snr <ref_file> <test_file> [options]\n");
+  printf("\nwhere, \n     <ref_file>  is the reference file name");
+  printf("\n                  on which will be taken as pure signal");
+  printf("\n     <test_file> is test file for snr calculation");
+  printf("\n     and options are mentioned below");
+  printf("\n");
+  printf("\n     -pcm_format:<pcm format of input files>");
+  printf("\n           0 - 16 bit pcm");
+  printf("\n           1 - 32 bit float");
+  printf("\n           default 0");
+  printf("\n     -thr:<threshold value>");
+  printf("\n           default - negative infinity\n\n");
+}
+
+int main(int argc, const char *argv[]) {
+  if (argc < 3) {
+    printUsage();
+    return -1;
+  }
+  int pcm_format = 0;
+  float thr = - std::numeric_limits<float>::infinity();
+  FILE *fref = fopen(argv[1], "rb");
+  FILE *finp = fopen(argv[2], "rb");
+  for (int i = 3; i < argc; i++) {
+    if (!strncmp(argv[i], "-pcm_format:", 12)) {
+      pcm_format = atoi(argv[i] + 12);
+    } else if (!strncmp(argv[i], "-thr:", 5)) {
+      thr = atof(argv[i] + 5);
+    }
+  }
+  if (finp == nullptr || fref == nullptr) {
+    printf("\nError: missing input/reference files\n");
+    return -1;
+  }
+  auto sn = pcm_format == 0
+      ? getSignalNoise<short>(finp, fref)
+      : getSignalNoise<float>(finp, fref);
+  if (sn.first > 0.f && sn.second > 0.f) {
+    float snr = 10.f * log(sn.first / sn.second);
+    // compare the measured snr value with threshold
+    if (snr < thr) {
+      printf("%.6f less than threshold %.6f\n", snr, thr);
+    } else {
+      printf("%.6f\n", snr);
+    }
+  }
+  fclose(finp);
+  fclose(fref);
+
+  return 0;
+}
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index f45cc58..03eef48 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -160,7 +160,6 @@
         "libstagefright_codecbase",
         "libstagefright_foundation",
         "libstagefright_omx_utils",
-        "libstagefright_opus_common",
         "libRScpp",
         "libhidlallocatorutils",
         "libhidlbase",
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 7df1a2d..c4015fb 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -85,7 +85,7 @@
 static const int kTimestampDebugCount = 10;
 static const int kItemIdBase = 10000;
 static const char kExifHeader[] = {'E', 'x', 'i', 'f', '\0', '\0'};
-static const int32_t kTiffHeaderOffset = htonl(sizeof(kExifHeader));
+static const uint8_t kExifApp1Marker[] = {'E', 'x', 'i', 'f', 0xff, 0xe1};
 
 static const uint8_t kMandatoryHevcNalUnitTypes[3] = {
     kHevcNalUnitTypeVps,
@@ -125,7 +125,7 @@
     bool isAudio() const { return mIsAudio; }
     bool isMPEG4() const { return mIsMPEG4; }
     bool usePrefix() const { return mIsAvc || mIsHevc || mIsHeic; }
-    bool isExifData(const MediaBufferBase *buffer) const;
+    bool isExifData(MediaBufferBase *buffer, uint32_t *tiffHdrOffset) const;
     void addChunkOffset(off64_t offset);
     void addItemOffsetAndSize(off64_t offset, size_t size, bool isExif);
     void flushItemRefs();
@@ -364,7 +364,7 @@
 
     Vector<uint16_t> mProperties;
     ItemRefs mDimgRefs;
-    ItemRefs mCdscRefs;
+    Vector<uint16_t> mExifList;
     uint16_t mImageItemId;
     int32_t mIsPrimary;
     int32_t mWidth, mHeight;
@@ -1368,14 +1368,16 @@
 }
 
 off64_t MPEG4Writer::addSample_l(
-        MediaBuffer *buffer, bool usePrefix, bool isExif, size_t *bytesWritten) {
+        MediaBuffer *buffer, bool usePrefix,
+        uint32_t tiffHdrOffset, size_t *bytesWritten) {
     off64_t old_offset = mOffset;
 
     if (usePrefix) {
         addMultipleLengthPrefixedSamples_l(buffer);
     } else {
-        if (isExif) {
-            ::write(mFd, &kTiffHeaderOffset, 4); // exif_tiff_header_offset field
+        if (tiffHdrOffset > 0) {
+            tiffHdrOffset = htonl(tiffHdrOffset);
+            ::write(mFd, &tiffHdrOffset, 4); // exif_tiff_header_offset field
             mOffset += 4;
         }
 
@@ -1803,7 +1805,6 @@
       mStartTimestampUs(-1),
       mRotation(0),
       mDimgRefs("dimg"),
-      mCdscRefs("cdsc"),
       mImageItemId(0),
       mIsPrimary(0),
       mWidth(0),
@@ -1984,11 +1985,34 @@
     return OK;
 }
 
-bool MPEG4Writer::Track::isExifData(const MediaBufferBase *buffer) const {
-    return mIsHeic
-            && (buffer->range_length() > sizeof(kExifHeader))
-            && !memcmp((uint8_t *)buffer->data() + buffer->range_offset(),
-                    kExifHeader, sizeof(kExifHeader));
+bool MPEG4Writer::Track::isExifData(
+        MediaBufferBase *buffer, uint32_t *tiffHdrOffset) const {
+    if (!mIsHeic) {
+        return false;
+    }
+
+    // Exif block starting with 'Exif\0\0'
+    size_t length = buffer->range_length();
+    uint8_t *data = (uint8_t *)buffer->data() + buffer->range_offset();
+    if ((length > sizeof(kExifHeader))
+        && !memcmp(data, kExifHeader, sizeof(kExifHeader))) {
+        *tiffHdrOffset = sizeof(kExifHeader);
+        return true;
+    }
+
+    // Exif block starting with fourcc 'Exif' followed by APP1 marker
+    if ((length > sizeof(kExifApp1Marker) + 2 + sizeof(kExifHeader))
+            && !memcmp(data, kExifApp1Marker, sizeof(kExifApp1Marker))
+            && !memcmp(data + sizeof(kExifApp1Marker) + 2, kExifHeader, sizeof(kExifHeader))) {
+        // skip 'Exif' fourcc
+        buffer->set_range(4, buffer->range_length() - 4);
+
+        // 2-byte APP1 + 2-byte size followed by kExifHeader
+        *tiffHdrOffset = 2 + 2 + sizeof(kExifHeader);
+        return true;
+    }
+
+    return false;
 }
 
 void MPEG4Writer::Track::addChunkOffset(off64_t offset) {
@@ -2014,7 +2038,7 @@
     }
 
     if (isExif) {
-         mCdscRefs.value.push_back(mOwner->addItem_l({
+         mExifList.push_back(mOwner->addItem_l({
             .itemType = "Exif",
             .isPrimary = false,
             .isHidden = false,
@@ -2117,7 +2141,16 @@
 
     if (mImageItemId > 0) {
         mOwner->addRefs_l(mImageItemId, mDimgRefs);
-        mOwner->addRefs_l(mImageItemId, mCdscRefs);
+
+        if (!mExifList.empty()) {
+            // The "cdsc" ref is from the metadata/exif item to the image item.
+            // So the refs all contain the image item.
+            ItemRefs cdscRefs("cdsc");
+            cdscRefs.value.push_back(mImageItemId);
+            for (uint16_t exifItem : mExifList) {
+                mOwner->addRefs_l(exifItem, cdscRefs);
+            }
+        }
     }
 }
 
@@ -2269,14 +2302,16 @@
     while (!chunk->mSamples.empty()) {
         List<MediaBuffer *>::iterator it = chunk->mSamples.begin();
 
-        int32_t isExif;
-        if (!(*it)->meta_data().findInt32(kKeyIsExif, &isExif)) {
-            isExif = 0;
+        uint32_t tiffHdrOffset;
+        if (!(*it)->meta_data().findInt32(
+                kKeyExifTiffOffset, (int32_t*)&tiffHdrOffset)) {
+            tiffHdrOffset = 0;
         }
+        bool isExif = (tiffHdrOffset > 0);
         bool usePrefix = chunk->mTrack->usePrefix() && !isExif;
 
         size_t bytesWritten;
-        off64_t offset = addSample_l(*it, usePrefix, isExif, &bytesWritten);
+        off64_t offset = addSample_l(*it, usePrefix, tiffHdrOffset, &bytesWritten);
 
         if (chunk->mTrack->isHeic()) {
             chunk->mTrack->addItemOffsetAndSize(offset, bytesWritten, isExif);
@@ -3002,10 +3037,11 @@
         }
 
         bool isExif = false;
+        uint32_t tiffHdrOffset = 0;
         int32_t isMuxerData;
         if (buffer->meta_data().findInt32(kKeyIsMuxerData, &isMuxerData) && isMuxerData) {
             // We only support one type of muxer data, which is Exif data block.
-            isExif = isExifData(buffer);
+            isExif = isExifData(buffer, &tiffHdrOffset);
             if (!isExif) {
                 ALOGW("Ignoring bad Exif data block");
                 buffer->release();
@@ -3027,7 +3063,7 @@
         buffer = NULL;
 
         if (isExif) {
-            copy->meta_data().setInt32(kKeyIsExif, 1);
+            copy->meta_data().setInt32(kKeyExifTiffOffset, tiffHdrOffset);
         }
         bool usePrefix = this->usePrefix() && !isExif;
 
@@ -3300,7 +3336,8 @@
         }
         if (!hasMultipleTracks) {
             size_t bytesWritten;
-            off64_t offset = mOwner->addSample_l(copy, usePrefix, isExif, &bytesWritten);
+            off64_t offset = mOwner->addSample_l(
+                    copy, usePrefix, tiffHdrOffset, &bytesWritten);
 
             if (mIsHeic) {
                 addItemOffsetAndSize(offset, bytesWritten, isExif);
diff --git a/media/libstagefright/OggWriter.cpp b/media/libstagefright/OggWriter.cpp
index ad55c56..5c13983 100644
--- a/media/libstagefright/OggWriter.cpp
+++ b/media/libstagefright/OggWriter.cpp
@@ -30,7 +30,7 @@
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/OggWriter.h>
 #include <media/stagefright/foundation/ADebug.h>
-#include "OpusHeader.h"
+#include <media/stagefright/foundation/OpusHeader.h>
 
 extern "C" {
 #include <ogg/ogg.h>
@@ -114,30 +114,17 @@
     }
 
     mSampleRate = sampleRate;
-
-    OpusHeader header;
-    header.channels = nChannels;
-    header.num_streams = nChannels;
-    header.num_coupled = 0;
-    header.channel_mapping = ((nChannels > 8) ? 255 : (nChannels > 2));
-    header.gain_db = 0;
-    header.skip_samples = 0;
-
-    // headers are 21-bytes + something driven by channel count
-    // expect numbers in the low 30's here. WriteOpusHeader() will tell us
-    // if things are bad.
-    unsigned char header_data[100];
-    ogg_packet op;
-    ogg_page og;
-
-    const int packet_size = WriteOpusHeader(header, mSampleRate, (uint8_t*)header_data,
-                                            sizeof(header_data));
-
-    if (packet_size < 0) {
-        ALOGE("opus header writing failed");
+    uint32_t type;
+    const void *header_data;
+    size_t packet_size;
+    if (!source->getFormat()->findData(kKeyOpusHeader, &type, &header_data, &packet_size)) {
+        ALOGE("opus header not found");
         return UNKNOWN_ERROR;
     }
-    op.packet = header_data;
+
+    ogg_packet op;
+    ogg_page og;
+    op.packet = (unsigned char *)header_data;
     op.bytes = packet_size;
     op.b_o_s = 1;
     op.e_o_s = 0;
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 49e485a..2e7da01 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -37,6 +37,7 @@
 #include <media/stagefright/foundation/ALookup.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/ByteUtils.h>
+#include <media/stagefright/foundation/OpusHeader.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/AudioSystem.h>
@@ -1745,12 +1746,34 @@
         } else if (mime == MEDIA_MIMETYPE_VIDEO_VP9) {
             meta->setData(kKeyVp9CodecPrivate, 0, csd0->data(), csd0->size());
         } else if (mime == MEDIA_MIMETYPE_AUDIO_OPUS) {
-            meta->setData(kKeyOpusHeader, 0, csd0->data(), csd0->size());
+            size_t opusHeadSize = csd0->size();
+            size_t codecDelayBufSize = 0;
+            size_t seekPreRollBufSize = 0;
+            void *opusHeadBuf = csd0->data();
+            void *codecDelayBuf = NULL;
+            void *seekPreRollBuf = NULL;
             if (msg->findBuffer("csd-1", &csd1)) {
-                meta->setData(kKeyOpusCodecDelay, 0, csd1->data(), csd1->size());
+                codecDelayBufSize = csd1->size();
+                codecDelayBuf = csd1->data();
             }
             if (msg->findBuffer("csd-2", &csd2)) {
-                meta->setData(kKeyOpusSeekPreRoll, 0, csd2->data(), csd2->size());
+                seekPreRollBufSize = csd2->size();
+                seekPreRollBuf = csd2->data();
+            }
+            /* Extract codec delay and seek pre roll from csd-0,
+             * if csd-1 and csd-2 are not present */
+            if (!codecDelayBuf && !seekPreRollBuf) {
+                GetOpusHeaderBuffers(csd0->data(), csd0->size(), &opusHeadBuf,
+                                    &opusHeadSize, &codecDelayBuf,
+                                    &codecDelayBufSize, &seekPreRollBuf,
+                                    &seekPreRollBufSize);
+            }
+            meta->setData(kKeyOpusHeader, 0, opusHeadBuf, opusHeadSize);
+            if (codecDelayBuf) {
+                meta->setData(kKeyOpusCodecDelay, 0, codecDelayBuf, codecDelayBufSize);
+            }
+            if (seekPreRollBuf) {
+                meta->setData(kKeyOpusSeekPreRoll, 0, seekPreRollBuf, seekPreRollBufSize);
             }
         } else if (mime == MEDIA_MIMETYPE_AUDIO_VORBIS) {
             meta->setData(kKeyVorbisInfo, 0, csd0->data(), csd0->size());
diff --git a/media/libstagefright/data/media_codecs_google_c2_audio.xml b/media/libstagefright/data/media_codecs_google_c2_audio.xml
index 0b554a2..88cd08d 100644
--- a/media/libstagefright/data/media_codecs_google_c2_audio.xml
+++ b/media/libstagefright/data/media_codecs_google_c2_audio.xml
@@ -93,5 +93,12 @@
             <Limit name="complexity" range="0-8"  default="5" />
             <Feature name="bitrate-modes" value="CQ" />
         </MediaCodec>
+        <MediaCodec name="c2.android.opus.encoder" type="audio/opus">
+            <Limit name="channel-count" max="2" />
+            <Limit name="sample-rate" ranges="8000,12000,16000,24000,48000" />
+            <Limit name="bitrate" range="500-512000" />
+            <Limit name="complexity" range="0-10"  default="5" />
+            <Feature name="bitrate-modes" value="CQ" />
+        </MediaCodec>
     </Encoders>
 </Included>
diff --git a/media/libstagefright/data/media_codecs_google_c2_video.xml b/media/libstagefright/data/media_codecs_google_c2_video.xml
index adb45b3..c49789e 100644
--- a/media/libstagefright/data/media_codecs_google_c2_video.xml
+++ b/media/libstagefright/data/media_codecs_google_c2_video.xml
@@ -71,6 +71,15 @@
             <Limit name="bitrate" range="1-40000000" />
             <Feature name="adaptive-playback" />
         </MediaCodec>
+        <MediaCodec name="c2.android.av1.decoder" type="video/av01">
+            <Limit name="size" min="96x96" max="1920x1080" />
+            <Limit name="alignment" value="2x2" />
+            <Limit name="block-size" value="16x16" />
+            <Limit name="blocks-per-second" min="24" max="2073600" />
+            <Limit name="bitrate" range="1-120000000" />
+            <Limit name="frame-rate" range="1-60" />
+            <Feature name="adaptive-playback" />
+        </MediaCodec>
     </Decoders>
 
     <Encoders>
diff --git a/media/libstagefright/foundation/Android.bp b/media/libstagefright/foundation/Android.bp
index dd1d904..533cd72 100644
--- a/media/libstagefright/foundation/Android.bp
+++ b/media/libstagefright/foundation/Android.bp
@@ -72,6 +72,7 @@
         "MediaKeys.cpp",
         "MetaData.cpp",
         "MetaDataBase.cpp",
+        "OpusHeader.cpp",
         "avc_utils.cpp",
         "base64.cpp",
         "hexdump.cpp",
diff --git a/media/libstagefright/opus/OpusHeader.cpp b/media/libstagefright/foundation/OpusHeader.cpp
similarity index 69%
rename from media/libstagefright/opus/OpusHeader.cpp
rename to media/libstagefright/foundation/OpusHeader.cpp
index e4a460c..9faede1 100644
--- a/media/libstagefright/opus/OpusHeader.cpp
+++ b/media/libstagefright/foundation/OpusHeader.cpp
@@ -16,7 +16,7 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "SoftOpus"
-
+#include <algorithm>
 #include <cstring>
 #include <stdint.h>
 
@@ -43,9 +43,6 @@
         {0, 6, 1, 2, 3, 4, 5, 7},
 };
 
-// Opus always has a 48kHz output rate. This is true for all Opus, not just this
-// implementation.
-constexpr int kRate = 48000;
 // Size of the Opus header excluding optional mapping information.
 constexpr size_t kOpusHeaderSize = 19;
 // Offset to magic string that starts Opus header.
@@ -76,15 +73,12 @@
 constexpr size_t kOpusHeaderNumCoupledStreamsOffset = 20;
 // Offset to the stream to channel mapping in the Opus header.
 constexpr size_t kOpusHeaderStreamMapOffset = 21;
-// Maximum packet size used in Xiph's opusdec.
-constexpr int kMaxOpusOutputPacketSizeSamples = 960 * 6;
 
 // Default audio output channel layout. Used to initialize |stream_map| in
 // OpusHeader, and passed to opus_multistream_decoder_create() when the header
 // does not contain mapping information. The values are valid only for mono and
 // stereo output: Opus streams with more than 2 channels require a stream map.
 constexpr int kMaxChannelsWithDefaultLayout = 2;
-constexpr uint8_t kDefaultOpusChannelLayout[kMaxChannelsWithDefaultLayout] = {0, 1};
 
 static uint16_t ReadLE16(const uint8_t* data, size_t data_size, uint32_t read_offset) {
     // check whether the 2nd byte is within the buffer
@@ -182,4 +176,88 @@
     }
 }
 
+int WriteOpusHeaders(const OpusHeader &header, int inputSampleRate,
+                     uint8_t* output, size_t outputSize, uint64_t codecDelay,
+                     uint64_t seekPreRoll) {
+    if (outputSize < AOPUS_UNIFIED_CSD_MINSIZE) {
+        ALOGD("Buffer not large enough to hold unified OPUS CSD");
+        return -1;
+    }
+
+    int headerLen = WriteOpusHeader(header, inputSampleRate, output,
+        outputSize);
+    if (headerLen < 0) {
+        ALOGD("WriteOpusHeader failed");
+        return -1;
+    }
+    if (headerLen >= (outputSize - 2 * AOPUS_TOTAL_CSD_SIZE)) {
+        ALOGD("Buffer not large enough to hold codec delay and seek pre roll");
+        return -1;
+    }
+
+    uint64_t length = AOPUS_LENGTH;
+
+    /*
+      Following is the CSD syntax for signalling codec delay and
+      seek pre-roll which is to be appended after OpusHeader
+
+      Marker (8 bytes) | Length (8 bytes) | Samples (8 bytes)
+
+      Markers supported:
+      AOPUSDLY - Signals Codec Delay
+      AOPUSPRL - Signals seek pre roll
+
+      Length should be 8.
+    */
+
+    // Add codec delay
+    memcpy(output + headerLen, AOPUS_CSD_CODEC_DELAY_MARKER, AOPUS_MARKER_SIZE);
+    headerLen += AOPUS_MARKER_SIZE;
+    memcpy(output + headerLen, &length, AOPUS_LENGTH_SIZE);
+    headerLen += AOPUS_LENGTH_SIZE;
+    memcpy(output + headerLen, &codecDelay, AOPUS_CSD_SIZE);
+    headerLen += AOPUS_CSD_SIZE;
+
+    // Add skip pre roll
+    memcpy(output + headerLen, AOPUS_CSD_SEEK_PREROLL_MARKER, AOPUS_MARKER_SIZE);
+    headerLen += AOPUS_MARKER_SIZE;
+    memcpy(output + headerLen, &length, AOPUS_LENGTH_SIZE);
+    headerLen += AOPUS_LENGTH_SIZE;
+    memcpy(output + headerLen, &seekPreRoll, AOPUS_CSD_SIZE);
+    headerLen += AOPUS_CSD_SIZE;
+
+    return headerLen;
+}
+
+void GetOpusHeaderBuffers(const uint8_t *data, size_t data_size,
+                          void **opusHeadBuf, size_t *opusHeadSize,
+                          void **codecDelayBuf, size_t *codecDelaySize,
+                          void **seekPreRollBuf, size_t *seekPreRollSize) {
+    *codecDelayBuf = NULL;
+    *codecDelaySize = 0;
+    *seekPreRollBuf = NULL;
+    *seekPreRollSize = 0;
+    *opusHeadBuf = (void *)data;
+    *opusHeadSize = data_size;
+    if (data_size >= AOPUS_UNIFIED_CSD_MINSIZE) {
+        size_t i = 0;
+        while (i < data_size - AOPUS_TOTAL_CSD_SIZE) {
+            uint8_t *csdBuf = (uint8_t *)data + i;
+            if (!memcmp(csdBuf, AOPUS_CSD_CODEC_DELAY_MARKER, AOPUS_MARKER_SIZE)) {
+                *opusHeadSize = std::min(*opusHeadSize, i);
+                *codecDelayBuf = csdBuf + AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE;
+                *codecDelaySize = AOPUS_CSD_SIZE;
+                i += AOPUS_TOTAL_CSD_SIZE;
+            } else if (!memcmp(csdBuf, AOPUS_CSD_SEEK_PREROLL_MARKER, AOPUS_MARKER_SIZE)) {
+                *opusHeadSize = std::min(*opusHeadSize, i);
+                *seekPreRollBuf = csdBuf + AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE;
+                *seekPreRollSize = AOPUS_CSD_SIZE;
+                i += AOPUS_TOTAL_CSD_SIZE;
+            } else {
+                i++;
+            }
+        }
+    }
+}
+
 }  // namespace android
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/OpusHeader.h b/media/libstagefright/foundation/include/media/stagefright/foundation/OpusHeader.h
new file mode 100644
index 0000000..9bffccb
--- /dev/null
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/OpusHeader.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+/*
+ * The Opus specification is part of IETF RFC 6716:
+ * http://tools.ietf.org/html/rfc6716
+ */
+
+#ifndef OPUS_HEADER_H_
+#define OPUS_HEADER_H_
+
+namespace android {
+
+/* Constants used for delimiting Opus CSD */
+#define AOPUS_CSD_CODEC_DELAY_MARKER "AOPUSDLY"
+#define AOPUS_CSD_SEEK_PREROLL_MARKER "AOPUSPRL"
+#define AOPUS_CSD_SIZE 8
+#define AOPUS_LENGTH 8
+#define AOPUS_MARKER_SIZE 8
+#define AOPUS_LENGTH_SIZE 8
+#define AOPUS_TOTAL_CSD_SIZE \
+    ((AOPUS_MARKER_SIZE) + (AOPUS_LENGTH_SIZE) + (AOPUS_CSD_SIZE))
+#define AOPUS_CSD0_MINSIZE 19
+#define AOPUS_UNIFIED_CSD_MINSIZE \
+    ((AOPUS_CSD0_MINSIZE) + 2 * (AOPUS_TOTAL_CSD_SIZE))
+
+/* CSD0 at max can be 22 bytes + max number of channels (255) */
+#define AOPUS_CSD0_MAXSIZE 277
+#define AOPUS_UNIFIED_CSD_MAXSIZE \
+    ((AOPUS_CSD0_MAXSIZE) + 2 * (AOPUS_TOTAL_CSD_SIZE))
+
+struct OpusHeader {
+    int channels;
+    int channel_mapping;
+    int num_streams;
+    int num_coupled;
+    int16_t gain_db;
+    int skip_samples;
+    uint8_t stream_map[8];
+};
+
+bool ParseOpusHeader(const uint8_t* data, size_t data_size, OpusHeader* header);
+int WriteOpusHeader(const OpusHeader &header, int input_sample_rate, uint8_t* output, size_t output_size);
+void GetOpusHeaderBuffers(const uint8_t *data, size_t data_size,
+                          void **opusHeadBuf, size_t *opusHeadSize,
+                          void **codecDelayBuf, size_t *codecDelaySize,
+                          void **seekPreRollBuf, size_t *seekPreRollSize);
+int WriteOpusHeaders(const OpusHeader &header, int inputSampleRate,
+                     uint8_t* output, size_t outputSize, uint64_t codecDelay,
+                     uint64_t seekPreRoll);
+}  // namespace android
+
+#endif  // OPUS_HEADER_H_
diff --git a/media/libstagefright/include/media/stagefright/MPEG4Writer.h b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
index 1abef8c..803155d 100644
--- a/media/libstagefright/include/media/stagefright/MPEG4Writer.h
+++ b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
@@ -257,7 +257,9 @@
     void initInternal(int fd, bool isFirstSession);
 
     // Acquire lock before calling these methods
-    off64_t addSample_l(MediaBuffer *buffer, bool usePrefix, bool isExif, size_t *bytesWritten);
+    off64_t addSample_l(
+            MediaBuffer *buffer, bool usePrefix,
+            uint32_t tiffHdrOffset, size_t *bytesWritten);
     void addLengthPrefixedSample_l(MediaBuffer *buffer);
     void addMultipleLengthPrefixedSamples_l(MediaBuffer *buffer);
     uint16_t addProperty_l(const ItemProperty &);
diff --git a/media/libstagefright/include/media/stagefright/MetaDataBase.h b/media/libstagefright/include/media/stagefright/MetaDataBase.h
index b99c14c..2910bd3 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataBase.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataBase.h
@@ -221,7 +221,8 @@
     kKeyFrameCount       = 'nfrm', // int32_t, total number of frame in video track
     kKeyExifOffset       = 'exof', // int64_t, Exif data offset
     kKeyExifSize         = 'exsz', // int64_t, Exif data size
-    kKeyIsExif           = 'exif', // bool (int32_t) buffer contains exif data block
+    kKeyExifTiffOffset   = 'thdr', // int32_t, if > 0, buffer contains exif data block with
+                                   // tiff hdr at specified offset
     kKeyPcmBigEndian     = 'pcmb', // bool (int32_t)
 
     // Key for ALAC Magic Cookie
diff --git a/media/libstagefright/opus/Android.bp b/media/libstagefright/opus/Android.bp
deleted file mode 100644
index c5086ec..0000000
--- a/media/libstagefright/opus/Android.bp
+++ /dev/null
@@ -1,21 +0,0 @@
-cc_library_shared {
-    name: "libstagefright_opus_common",
-    vendor_available: true,
-
-    export_include_dirs: ["include"],
-
-    srcs: ["OpusHeader.cpp"],
-
-    shared_libs: ["liblog"],
-
-    cflags: ["-Werror"],
-
-    sanitize: {
-        integer_overflow: true,
-        cfi: true,
-        diag: {
-            integer_overflow: true,
-            cfi: true,
-        },
-    },
-}
\ No newline at end of file
diff --git a/media/libstagefright/opus/include/OpusHeader.h b/media/libstagefright/opus/include/OpusHeader.h
deleted file mode 100644
index f9f79cd..0000000
--- a/media/libstagefright/opus/include/OpusHeader.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-/*
- * The Opus specification is part of IETF RFC 6716:
- * http://tools.ietf.org/html/rfc6716
- */
-
-#ifndef OPUS_HEADER_H_
-#define OPUS_HEADER_H_
-
-namespace android {
-
-struct OpusHeader {
-    int channels;
-    int channel_mapping;
-    int num_streams;
-    int num_coupled;
-    int16_t gain_db;
-    int skip_samples;
-    uint8_t stream_map[8];
-};
-
-bool ParseOpusHeader(const uint8_t* data, size_t data_size, OpusHeader* header);
-int WriteOpusHeader(const OpusHeader &header, int input_sample_rate, uint8_t* output, size_t output_size);
-}  // namespace android
-
-#endif  // OPUS_HEADER_H_
diff --git a/media/libstagefright/webm/Android.bp b/media/libstagefright/webm/Android.bp
index 1f840b7..64ecc2d 100644
--- a/media/libstagefright/webm/Android.bp
+++ b/media/libstagefright/webm/Android.bp
@@ -28,7 +28,6 @@
 
     shared_libs: [
         "libstagefright_foundation",
-        "libstagefright_opus_common",
         "libutils",
         "liblog",
     ],
diff --git a/media/libstagefright/webm/WebmWriter.cpp b/media/libstagefright/webm/WebmWriter.cpp
index 7b4b23a..b0a303e 100644
--- a/media/libstagefright/webm/WebmWriter.cpp
+++ b/media/libstagefright/webm/WebmWriter.cpp
@@ -24,7 +24,7 @@
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/hexdump.h>
-#include <OpusHeader.h>
+#include <media/stagefright/foundation/OpusHeader.h>
 
 #include <utils/Errors.h>
 
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 17e12f5..cf9c298 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -5372,7 +5372,7 @@
     //  AND force is not specified
     //  AND the output is connected by a valid audio patch.
     // Doing this check here allows the caller to call setOutputDevices() without conditions
-    if ((!filteredDevices.isEmpty() || filteredDevices == prevDevices) &&
+    if ((filteredDevices.isEmpty() || filteredDevices == prevDevices) &&
             !force && outputDesc->getPatchHandle() != 0) {
         ALOGV("%s setting same device %s or null device, force=%d, patch handle=%d", __func__,
               filteredDevices.toString().c_str(), force, outputDesc->getPatchHandle());
diff --git a/services/audiopolicy/tests/Android.mk b/services/audiopolicy/tests/Android.mk
index 2ccb542..e4fba0f 100644
--- a/services/audiopolicy/tests/Android.mk
+++ b/services/audiopolicy/tests/Android.mk
@@ -29,6 +29,8 @@
 
 LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
 
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
 include $(BUILD_NATIVE_TEST)
 
 # system/audio.h utilities test
@@ -55,4 +57,6 @@
 
 LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
 
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
 include $(BUILD_NATIVE_TEST)
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 24326bb..e9f4657 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -117,9 +117,14 @@
     explicit PatchCountCheck(AudioPolicyManagerTestClient *client)
             : mClient{client},
               mInitialCount{mClient->getActivePatchesCount()} {}
-    void assertDelta(int delta) const {
-        ASSERT_EQ(mInitialCount + delta, mClient->getActivePatchesCount()); }
-    void assertNoChange() const { assertDelta(0); }
+    int deltaFromSnapshot() const {
+        size_t currentCount = mClient->getActivePatchesCount();
+        if (mInitialCount <= currentCount) {
+            return currentCount - mInitialCount;
+        } else {
+            return -(static_cast<int>(mInitialCount - currentCount));
+        }
+    }
   private:
     const AudioPolicyManagerTestClient *mClient;
     const size_t mInitialCount;
@@ -139,7 +144,7 @@
             int sampleRate,
             audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
             audio_port_handle_t *portId = nullptr);
-    PatchCountCheck snapPatchCount() { return PatchCountCheck(mClient.get()); }
+    PatchCountCheck snapshotPatchCount() { return PatchCountCheck(mClient.get()); }
 
     std::unique_ptr<AudioPolicyManagerTestClient> mClient;
     std::unique_ptr<AudioPolicyTestManager> mManager;
@@ -225,7 +230,7 @@
 TEST_F(AudioPolicyManagerTest, CreateAudioPatchFailure) {
     audio_patch patch{};
     audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
-    const PatchCountCheck patchCount = snapPatchCount();
+    const PatchCountCheck patchCount = snapshotPatchCount();
     ASSERT_EQ(BAD_VALUE, mManager->createAudioPatch(nullptr, &handle, 0));
     ASSERT_EQ(BAD_VALUE, mManager->createAudioPatch(&patch, nullptr, 0));
     ASSERT_EQ(BAD_VALUE, mManager->createAudioPatch(&patch, &handle, 0));
@@ -252,20 +257,20 @@
     ASSERT_EQ(INVALID_OPERATION, mManager->createAudioPatch(&patch, &handle, 0));
     // Verify that the handle is left unchanged.
     ASSERT_EQ(AUDIO_PATCH_HANDLE_NONE, handle);
-    patchCount.assertNoChange();
+    ASSERT_EQ(0, patchCount.deltaFromSnapshot());
 }
 
 TEST_F(AudioPolicyManagerTest, CreateAudioPatchFromMix) {
     audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
     uid_t uid = 42;
-    const PatchCountCheck patchCount = snapPatchCount();
+    const PatchCountCheck patchCount = snapshotPatchCount();
     ASSERT_FALSE(mManager->getConfig().getAvailableInputDevices().isEmpty());
     PatchBuilder patchBuilder;
     patchBuilder.addSource(mManager->getConfig().getAvailableInputDevices()[0]).
             addSink(mManager->getConfig().getDefaultOutputDevice());
     ASSERT_EQ(NO_ERROR, mManager->createAudioPatch(patchBuilder.patch(), &handle, uid));
     ASSERT_NE(AUDIO_PATCH_HANDLE_NONE, handle);
-    patchCount.assertDelta(1);
+    ASSERT_EQ(1, patchCount.deltaFromSnapshot());
 }
 
 // TODO: Add patch creation tests that involve already existing patch
@@ -350,84 +355,82 @@
 }
 
 TEST_F(AudioPolicyManagerTestMsd, PatchCreationOnSetForceUse) {
-    const PatchCountCheck patchCount = snapPatchCount();
+    const PatchCountCheck patchCount = snapshotPatchCount();
     mManager->setForceUse(AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND,
             AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS);
-    patchCount.assertDelta(1);
+    ASSERT_EQ(1, patchCount.deltaFromSnapshot());
 }
 
 TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrEncodedRoutesToMsd) {
-    const PatchCountCheck patchCount = snapPatchCount();
+    const PatchCountCheck patchCount = snapshotPatchCount();
     audio_port_handle_t selectedDeviceId;
     getOutputForAttr(&selectedDeviceId,
             AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
     ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
-    patchCount.assertDelta(1);
+    ASSERT_EQ(1, patchCount.deltaFromSnapshot());
 }
 
 TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrPcmRoutesToMsd) {
-    const PatchCountCheck patchCount = snapPatchCount();
+    const PatchCountCheck patchCount = snapshotPatchCount();
     audio_port_handle_t selectedDeviceId;
     getOutputForAttr(&selectedDeviceId,
             AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000);
     ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
-    patchCount.assertDelta(1);
+    ASSERT_EQ(1, patchCount.deltaFromSnapshot());
 }
 
 TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrEncodedPlusPcmRoutesToMsd) {
-    const PatchCountCheck patchCount = snapPatchCount();
+    const PatchCountCheck patchCount = snapshotPatchCount();
     audio_port_handle_t selectedDeviceId;
     getOutputForAttr(&selectedDeviceId,
             AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
     ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
-    patchCount.assertDelta(1);
+    ASSERT_EQ(1, patchCount.deltaFromSnapshot());
     getOutputForAttr(&selectedDeviceId,
             AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000);
     ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
-    patchCount.assertDelta(1);
+    ASSERT_EQ(1, patchCount.deltaFromSnapshot());
 }
 
 TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrUnsupportedFormatBypassesMsd) {
-    const PatchCountCheck patchCount = snapPatchCount();
+    const PatchCountCheck patchCount = snapshotPatchCount();
     audio_port_handle_t selectedDeviceId;
     getOutputForAttr(&selectedDeviceId,
             AUDIO_FORMAT_DTS, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
     ASSERT_NE(selectedDeviceId, mMsdOutputDevice->getId());
-    patchCount.assertNoChange();
+    ASSERT_EQ(0, patchCount.deltaFromSnapshot());
 }
 
 TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrFormatSwitching) {
     // Switch between formats that are supported and not supported by MSD.
     {
-        const PatchCountCheck patchCount = snapPatchCount();
+        const PatchCountCheck patchCount = snapshotPatchCount();
         audio_port_handle_t selectedDeviceId, portId;
         getOutputForAttr(&selectedDeviceId,
                 AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT,
                 &portId);
         ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
-        patchCount.assertDelta(1);
+        ASSERT_EQ(1, patchCount.deltaFromSnapshot());
         mManager->releaseOutput(portId);
-        patchCount.assertDelta(1);  // compared to the state at the block entry
-        // TODO: make PatchCountCheck asserts more obvious. It's easy to
-        // miss the fact that it is immutable.
+        ASSERT_EQ(1, patchCount.deltaFromSnapshot());
     }
     {
-        const PatchCountCheck patchCount = snapPatchCount();
+        const PatchCountCheck patchCount = snapshotPatchCount();
         audio_port_handle_t selectedDeviceId, portId;
         getOutputForAttr(&selectedDeviceId,
                 AUDIO_FORMAT_DTS, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT,
                 &portId);
         ASSERT_NE(selectedDeviceId, mMsdOutputDevice->getId());
-        patchCount.assertDelta(-1);
+        ASSERT_EQ(-1, patchCount.deltaFromSnapshot());
         mManager->releaseOutput(portId);
-        patchCount.assertNoChange();
+        ASSERT_EQ(0, patchCount.deltaFromSnapshot());
     }
     {
-        const PatchCountCheck patchCount = snapPatchCount();
+        const PatchCountCheck patchCount = snapshotPatchCount();
         audio_port_handle_t selectedDeviceId;
         getOutputForAttr(&selectedDeviceId,
                 AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
         ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
-        patchCount.assertNoChange();
+        ASSERT_EQ(0, patchCount.deltaFromSnapshot());
     }
 }
diff --git a/services/mediacodec/registrant/Android.bp b/services/mediacodec/registrant/Android.bp
index 8ae3376..80d3630 100644
--- a/services/mediacodec/registrant/Android.bp
+++ b/services/mediacodec/registrant/Android.bp
@@ -38,6 +38,7 @@
         "libcodec2_soft_mp3dec",
         "libcodec2_soft_vorbisdec",
         "libcodec2_soft_opusdec",
+        "libcodec2_soft_opusenc",
         "libcodec2_soft_vp8dec",
         "libcodec2_soft_vp9dec",
         "libcodec2_soft_av1dec",