Merge "C2SoftOpusEnc: Fix mono encoding" into qt-dev
diff --git a/apex/AndroidManifest-media.xml b/apex/AndroidManifest-media.xml
index 78ed0ed..1af4586 100644
--- a/apex/AndroidManifest-media.xml
+++ b/apex/AndroidManifest-media.xml
@@ -18,10 +18,9 @@
   package="com.android.media">
   <!-- APEX does not have classes.dex -->
   <application android:hasCode="false" />
-  <!-- Setting maxSdk to lock the module to Q. minSdk is 28 for now to cover Q beta devices. -->
+  <!-- Setting maxSdk to lock the module to Q. minSdk is auto-set by build system -->
   <uses-sdk
-      android:minSdkVersion="28"
       android:maxSdkVersion="29"
-      android:targetSdkVersion="28"
+      android:targetSdkVersion="29"
   />
 </manifest>
diff --git a/apex/AndroidManifest-swcodec.xml b/apex/AndroidManifest-swcodec.xml
index 9558644..de50864 100644
--- a/apex/AndroidManifest-swcodec.xml
+++ b/apex/AndroidManifest-swcodec.xml
@@ -18,10 +18,9 @@
   package="com.android.media.swcodec">
   <!-- APEX does not have classes.dex -->
   <application android:hasCode="false" />
-  <!-- Setting maxSdk to lock the module to Q. minSdk is 28 for now to cover Q beta devices. -->
+  <!-- Setting maxSdk to lock the module to Q. minSdk is auto-set by build system -->
   <uses-sdk
-      android:minSdkVersion="28"
       android:maxSdkVersion="29"
-      android:targetSdkVersion="28"
+      android:targetSdkVersion="29"
   />
 </manifest>
diff --git a/apex/ld.config.txt b/apex/ld.config.txt
index 87af5a1..a5937fd 100644
--- a/apex/ld.config.txt
+++ b/apex/ld.config.txt
@@ -127,3 +127,5 @@
 # namespace.sphal.link.platform.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
 namespace.sphal.link.platform.shared_libs = libEGL.so:libGLESv1_CM.so:libGLESv2.so:libGLESv3.so:libRS.so:libandroid_net.so:libc.so:libcgrouprc.so:libclang_rt.asan-aarch64-android.so:libclang_rt.asan-arm-android.so:libclang_rt.hwasan-aarch64-android.so:libclang_rt.asan-i686-android.so:libclang_rt.asan-x86_64-android.so:libdl.so:libft2.so:liblog.so:libm.so:libmediandk.so:libnativewindow.so:libneuralnetworks.so:libsync.so:libvndksupport.so:libvulkan.so
 
+# Add a link for libz.so which is llndk on devices where VNDK is not enforced.
+namespace.sphal.link.platform.shared_libs += libz.so
diff --git a/media/codec2/components/aac/C2SoftAacEnc.cpp b/media/codec2/components/aac/C2SoftAacEnc.cpp
index 7efc7f1..8e3852c 100644
--- a/media/codec2/components/aac/C2SoftAacEnc.cpp
+++ b/media/codec2/components/aac/C2SoftAacEnc.cpp
@@ -103,11 +103,24 @@
                 })
                 .withSetter(ProfileLevelSetter)
                 .build());
+
+       addParameter(
+                DefineParam(mSBRMode, C2_PARAMKEY_AAC_SBR_MODE)
+                .withDefault(new C2StreamAacSbrModeTuning::input(0u, AAC_SBR_AUTO))
+                .withFields({C2F(mSBRMode, value).oneOf({
+                            C2Config::AAC_SBR_OFF,
+                            C2Config::AAC_SBR_SINGLE_RATE,
+                            C2Config::AAC_SBR_DUAL_RATE,
+                            C2Config::AAC_SBR_AUTO })})
+                .withSetter(Setter<decltype(*mSBRMode)>::NonStrictValueWithNoDeps)
+                .build());
     }
 
     uint32_t getSampleRate() const { return mSampleRate->value; }
     uint32_t getChannelCount() const { return mChannelCount->value; }
     uint32_t getBitrate() const { return mBitrate->value; }
+    uint32_t getSBRMode() const { return mSBRMode->value; }
+    uint32_t getProfile() const { return mProfileLevel->profile; }
     static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::output> &me) {
         (void)mayBlock;
         (void)me;  // TODO: validate
@@ -129,6 +142,7 @@
     std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
     std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mInputMaxBufSize;
     std::shared_ptr<C2StreamProfileLevelInfo::output> mProfileLevel;
+    std::shared_ptr<C2StreamAacSbrModeTuning::input> mSBRMode;
 };
 
 C2SoftAacEnc::C2SoftAacEnc(
@@ -138,9 +152,6 @@
     : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
       mIntf(intfImpl),
       mAACEncoder(nullptr),
-      mSBRMode(-1),
-      mSBRRatio(0),
-      mAACProfile(AOT_AAC_LC),
       mNumBytesPerInputFrame(0u),
       mOutBufferSize(0u),
       mSentCodecSpecificData(false),
@@ -208,31 +219,37 @@
     return chMode;
 }
 
-//static AUDIO_OBJECT_TYPE getAOTFromProfile(OMX_U32 profile) {
-//    if (profile == OMX_AUDIO_AACObjectLC) {
-//        return AOT_AAC_LC;
-//    } else if (profile == OMX_AUDIO_AACObjectHE) {
-//        return AOT_SBR;
-//    } else if (profile == OMX_AUDIO_AACObjectHE_PS) {
-//        return AOT_PS;
-//    } else if (profile == OMX_AUDIO_AACObjectLD) {
-//        return AOT_ER_AAC_LD;
-//    } else if (profile == OMX_AUDIO_AACObjectELD) {
-//        return AOT_ER_AAC_ELD;
-//    } else {
-//        ALOGW("Unsupported AAC profile - defaulting to AAC-LC");
-//        return AOT_AAC_LC;
-//    }
-//}
+static AUDIO_OBJECT_TYPE getAOTFromProfile(uint32_t profile) {
+   if (profile == C2Config::PROFILE_AAC_LC) {
+       return AOT_AAC_LC;
+   } else if (profile == C2Config::PROFILE_AAC_HE) {
+       return AOT_SBR;
+   } else if (profile == C2Config::PROFILE_AAC_HE_PS) {
+       return AOT_PS;
+   } else if (profile == C2Config::PROFILE_AAC_LD) {
+       return AOT_ER_AAC_LD;
+   } else if (profile == C2Config::PROFILE_AAC_ELD) {
+       return AOT_ER_AAC_ELD;
+   } else {
+       ALOGW("Unsupported AAC profile - defaulting to AAC-LC");
+       return AOT_AAC_LC;
+   }
+}
 
 status_t C2SoftAacEnc::setAudioParams() {
     // We call this whenever sample rate, number of channels, bitrate or SBR mode change
     // in reponse to setParameter calls.
+    int32_t sbrRatio = 0;
+    uint32_t sbrMode = mIntf->getSBRMode();
+    if (sbrMode == AAC_SBR_SINGLE_RATE) sbrRatio = 1;
+    else if (sbrMode == AAC_SBR_DUAL_RATE) sbrRatio = 2;
 
     ALOGV("setAudioParams: %u Hz, %u channels, %u bps, %i sbr mode, %i sbr ratio",
-         mIntf->getSampleRate(), mIntf->getChannelCount(), mIntf->getBitrate(), mSBRMode, mSBRRatio);
+         mIntf->getSampleRate(), mIntf->getChannelCount(), mIntf->getBitrate(),
+         sbrMode, sbrRatio);
 
-    if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_AOT, mAACProfile)) {
+    uint32_t aacProfile = mIntf->getProfile();
+    if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_AOT, getAOTFromProfile(aacProfile))) {
         ALOGE("Failed to set AAC encoder parameters");
         return UNKNOWN_ERROR;
     }
@@ -255,8 +272,8 @@
         return UNKNOWN_ERROR;
     }
 
-    if (mSBRMode != -1 && mAACProfile == AOT_ER_AAC_ELD) {
-        if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_SBR_MODE, mSBRMode)) {
+    if (sbrMode != -1 && aacProfile == C2Config::PROFILE_AAC_ELD) {
+        if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_SBR_MODE, sbrMode)) {
             ALOGE("Failed to set AAC encoder parameters");
             return UNKNOWN_ERROR;
         }
@@ -268,7 +285,7 @@
        1: Downsampled SBR (default for ELD)
        2: Dualrate SBR (default for HE-AAC)
      */
-    if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_SBR_RATIO, mSBRRatio)) {
+    if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_SBR_RATIO, sbrRatio)) {
         ALOGE("Failed to set AAC encoder parameters");
         return UNKNOWN_ERROR;
     }
diff --git a/media/codec2/components/aac/C2SoftAacEnc.h b/media/codec2/components/aac/C2SoftAacEnc.h
index 779365b..a38be19 100644
--- a/media/codec2/components/aac/C2SoftAacEnc.h
+++ b/media/codec2/components/aac/C2SoftAacEnc.h
@@ -50,9 +50,6 @@
 
     HANDLE_AACENCODER mAACEncoder;
 
-    int32_t mSBRMode;
-    int32_t mSBRRatio;
-    AUDIO_OBJECT_TYPE mAACProfile;
     UINT mNumBytesPerInputFrame;
     UINT mOutBufferSize;
 
diff --git a/media/codec2/components/avc/C2SoftAvcEnc.cpp b/media/codec2/components/avc/C2SoftAvcEnc.cpp
index 8d9f21a..b41c271 100644
--- a/media/codec2/components/avc/C2SoftAvcEnc.cpp
+++ b/media/codec2/components/avc/C2SoftAvcEnc.cpp
@@ -41,6 +41,37 @@
 
 constexpr char COMPONENT_NAME[] = "c2.android.avc.encoder";
 
+void ParseGop(
+        const C2StreamGopTuning::output &gop,
+        uint32_t *syncInterval, uint32_t *iInterval, uint32_t *maxBframes) {
+    uint32_t syncInt = 1;
+    uint32_t iInt = 1;
+    for (size_t i = 0; i < gop.flexCount(); ++i) {
+        const C2GopLayerStruct &layer = gop.m.values[i];
+        if (layer.count == UINT32_MAX) {
+            syncInt = 0;
+        } else if (syncInt <= UINT32_MAX / (layer.count + 1)) {
+            syncInt *= (layer.count + 1);
+        }
+        if ((layer.type_ & I_FRAME) == 0) {
+            if (layer.count == UINT32_MAX) {
+                iInt = 0;
+            } else if (iInt <= UINT32_MAX / (layer.count + 1)) {
+                iInt *= (layer.count + 1);
+            }
+        }
+        if (layer.type_ == C2Config::picture_type_t(P_FRAME | B_FRAME) && maxBframes) {
+            *maxBframes = layer.count;
+        }
+    }
+    if (syncInterval) {
+        *syncInterval = syncInt;
+    }
+    if (iInterval) {
+        *iInterval = iInt;
+    }
+}
+
 }  // namespace
 
 class C2SoftAvcEnc::IntfImpl : public SimpleInterface<void>::BaseParams {
@@ -81,10 +112,19 @@
                 .build());
 
         addParameter(
+                DefineParam(mGop, C2_PARAMKEY_GOP)
+                .withDefault(C2StreamGopTuning::output::AllocShared(
+                        0 /* flexCount */, 0u /* stream */))
+                .withFields({C2F(mGop, m.values[0].type_).any(),
+                             C2F(mGop, m.values[0].count).any()})
+                .withSetter(GopSetter)
+                .build());
+
+        addParameter(
                 DefineParam(mActualInputDelay, C2_PARAMKEY_INPUT_DELAY)
                 .withDefault(new C2PortActualDelayTuning::input(DEFAULT_B_FRAMES))
                 .withFields({C2F(mActualInputDelay, value).inRange(0, MAX_B_FRAMES)})
-                .withSetter(Setter<decltype(*mActualInputDelay)>::StrictValueWithNoDeps)
+                .calculatedAs(InputDelaySetter, mGop)
                 .build());
 
         addParameter(
@@ -160,6 +200,17 @@
                 .build());
     }
 
+    static C2R InputDelaySetter(
+            bool mayBlock,
+            C2P<C2PortActualDelayTuning::input> &me,
+            const C2P<C2StreamGopTuning::output> &gop) {
+        (void)mayBlock;
+        uint32_t maxBframes = 0;
+        ParseGop(gop.v, nullptr, nullptr, &maxBframes);
+        me.set().value = maxBframes;
+        return C2R::Ok();
+    }
+
     static C2R BitrateSetter(bool mayBlock, C2P<C2StreamBitrateInfo::output> &me) {
         (void)mayBlock;
         C2R res = C2R::Ok();
@@ -273,6 +324,18 @@
         return res;
     }
 
+    static C2R GopSetter(bool mayBlock, C2P<C2StreamGopTuning::output> &me) {
+        (void)mayBlock;
+        for (size_t i = 0; i < me.v.flexCount(); ++i) {
+            const C2GopLayerStruct &layer = me.v.m.values[0];
+            if (layer.type_ == C2Config::picture_type_t(P_FRAME | B_FRAME)
+                    && layer.count > MAX_B_FRAMES) {
+                me.set().m.values[i].count = MAX_B_FRAMES;
+            }
+        }
+        return C2R::Ok();
+    }
+
     IV_PROFILE_T getProfile_l() const {
         switch (mProfileLevel->profile) {
         case PROFILE_AVC_CONSTRAINED_BASELINE:  [[fallthrough]];
@@ -314,6 +377,7 @@
         ALOGD("Unrecognized level: %x", mProfileLevel->level);
         return 41;
     }
+
     uint32_t getSyncFramePeriod_l() const {
         if (mSyncFramePeriod->value < 0 || mSyncFramePeriod->value == INT64_MAX) {
             return 0;
@@ -328,6 +392,7 @@
     std::shared_ptr<C2StreamFrameRateInfo::output> getFrameRate_l() const { return mFrameRate; }
     std::shared_ptr<C2StreamBitrateInfo::output> getBitrate_l() const { return mBitrate; }
     std::shared_ptr<C2StreamRequestSyncFrameTuning::output> getRequestSync_l() const { return mRequestSync; }
+    std::shared_ptr<C2StreamGopTuning::output> getGop_l() const { return mGop; }
 
 private:
     std::shared_ptr<C2StreamUsageTuning::input> mUsage;
@@ -338,6 +403,7 @@
     std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
     std::shared_ptr<C2StreamProfileLevelInfo::output> mProfileLevel;
     std::shared_ptr<C2StreamSyncFrameIntervalTuning::output> mSyncFramePeriod;
+    std::shared_ptr<C2StreamGopTuning::output> mGop;
 };
 
 #define ive_api_function  ih264e_api_function
@@ -850,6 +916,7 @@
 
     c2_status_t errType = C2_OK;
 
+    std::shared_ptr<C2StreamGopTuning::output> gop;
     {
         IntfImpl::Lock lock = mIntf->lock();
         mSize = mIntf->getSize_l();
@@ -859,6 +926,25 @@
         mAVCEncLevel = mIntf->getLevel_l();
         mIInterval = mIntf->getSyncFramePeriod_l();
         mIDRInterval = mIntf->getSyncFramePeriod_l();
+        gop = mIntf->getGop_l();
+    }
+    if (gop && gop->flexCount() > 0) {
+        uint32_t syncInterval = 1;
+        uint32_t iInterval = 1;
+        uint32_t maxBframes = 0;
+        ParseGop(*gop, &syncInterval, &iInterval, &maxBframes);
+        if (syncInterval > 0) {
+            ALOGD("Updating IDR interval from GOP: old %u new %u", mIDRInterval, syncInterval);
+            mIDRInterval = syncInterval;
+        }
+        if (iInterval > 0) {
+            ALOGD("Updating I interval from GOP: old %u new %u", mIInterval, iInterval);
+            mIInterval = iInterval;
+        }
+        if (mBframes != maxBframes) {
+            ALOGD("Updating max B frames from GOP: old %u new %u", mBframes, maxBframes);
+            mBframes = maxBframes;
+        }
     }
     uint32_t width = mSize->width;
     uint32_t height = mSize->height;
@@ -868,8 +954,8 @@
     // TODO
     mIvVideoColorFormat = IV_YUV_420P;
 
-    ALOGD("Params width %d height %d level %d colorFormat %d", width,
-            height, mAVCEncLevel, mIvVideoColorFormat);
+    ALOGD("Params width %d height %d level %d colorFormat %d bframes %d", width,
+            height, mAVCEncLevel, mIvVideoColorFormat, mBframes);
 
     /* Getting Number of MemRecords */
     {
diff --git a/media/codec2/components/hevc/C2SoftHevcEnc.cpp b/media/codec2/components/hevc/C2SoftHevcEnc.cpp
index 9b93cf3..b129b1b 100644
--- a/media/codec2/components/hevc/C2SoftHevcEnc.cpp
+++ b/media/codec2/components/hevc/C2SoftHevcEnc.cpp
@@ -861,6 +861,22 @@
             return;
         }
     }
+
+    // handle dynamic config parameters
+    {
+        IntfImpl::Lock lock = mIntf->lock();
+        std::shared_ptr<C2StreamBitrateInfo::output> bitrate = mIntf->getBitrate_l();
+        lock.unlock();
+
+        if (bitrate != mBitrate) {
+            mBitrate = bitrate;
+            mEncParams.s_tgt_lyr_prms.as_tgt_params[0].ai4_tgt_bitrate[0] =
+                mBitrate->value;
+            mEncParams.s_tgt_lyr_prms.as_tgt_params[0].ai4_peak_bitrate[0] =
+                mBitrate->value << 1;
+        }
+    }
+
     ihevce_inp_buf_t s_encode_ip{};
     ihevce_out_buf_t s_encode_op{};
     uint64_t workIndex = work->input.ordinal.frameIndex.peekull();
diff --git a/media/codec2/components/opus/C2SoftOpusEnc.cpp b/media/codec2/components/opus/C2SoftOpusEnc.cpp
index d6517ea..384d58b 100644
--- a/media/codec2/components/opus/C2SoftOpusEnc.cpp
+++ b/media/codec2/components/opus/C2SoftOpusEnc.cpp
@@ -207,15 +207,6 @@
         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;
@@ -408,13 +399,26 @@
     if (!mHeaderGenerated) {
         uint8_t header[AOPUS_UNIFIED_CSD_MAXSIZE];
         memset(header, 0, sizeof(header));
+
+        // Get codecDelay
+        int32_t lookahead;
+        if (opus_multistream_encoder_ctl(mEncoder, OPUS_GET_LOOKAHEAD(&lookahead)) !=
+                OPUS_OK) {
+            ALOGE("failed to get lookahead");
+            mSignalledError = true;
+            work->result = C2_CORRUPTED;
+            return;
+        }
+        mCodecDelay = lookahead * 1000000000ll / mSampleRate;
+
         OpusHeader opusHeader;
+        memset(&opusHeader, 0, sizeof(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;
+        opusHeader.skip_samples = lookahead;
         int headerLen = WriteOpusHeaders(opusHeader, mSampleRate, header,
             sizeof(header), mCodecDelay, mSeekPreRoll);
 
diff --git a/media/codec2/components/raw/C2SoftRawDec.cpp b/media/codec2/components/raw/C2SoftRawDec.cpp
index 8e94a18..95eb909 100644
--- a/media/codec2/components/raw/C2SoftRawDec.cpp
+++ b/media/codec2/components/raw/C2SoftRawDec.cpp
@@ -58,7 +58,7 @@
         addParameter(
                 DefineParam(mSampleRate, C2_PARAMKEY_SAMPLE_RATE)
                 .withDefault(new C2StreamSampleRateInfo::output(0u, 44100))
-                .withFields({C2F(mSampleRate, value).inRange(8000, 192000)})
+                .withFields({C2F(mSampleRate, value).inRange(8000, 384000)})
                 .withSetter((Setter<decltype(*mSampleRate)>::StrictValueWithNoDeps))
                 .build());
 
@@ -72,7 +72,7 @@
         addParameter(
                 DefineParam(mBitrate, C2_PARAMKEY_BITRATE)
                 .withDefault(new C2StreamBitrateInfo::input(0u, 64000))
-                .withFields({C2F(mBitrate, value).inRange(1, 10000000)})
+                .withFields({C2F(mBitrate, value).inRange(1, 98304000)})
                 .withSetter(Setter<decltype(*mBitrate)>::NonStrictValueWithNoDeps)
                 .build());
 
diff --git a/media/codec2/core/include/C2Config.h b/media/codec2/core/include/C2Config.h
index c395d62..9f484a3 100644
--- a/media/codec2/core/include/C2Config.h
+++ b/media/codec2/core/include/C2Config.h
@@ -1644,6 +1644,7 @@
  * frames.
  */
 struct C2GopLayerStruct {
+    C2GopLayerStruct() : type_((C2Config::picture_type_t)0), count(0) {}
     C2GopLayerStruct(C2Config::picture_type_t type, uint32_t count_)
         : type_(type), count(count_) { }
 
diff --git a/media/codec2/sfplugin/C2OMXNode.cpp b/media/codec2/sfplugin/C2OMXNode.cpp
index 6ae1c13..f0f62f6 100644
--- a/media/codec2/sfplugin/C2OMXNode.cpp
+++ b/media/codec2/sfplugin/C2OMXNode.cpp
@@ -50,14 +50,8 @@
 }  // namespace
 
 C2OMXNode::C2OMXNode(const std::shared_ptr<Codec2Client::Component> &comp)
-    : mComp(comp), mFrameIndex(0), mWidth(0), mHeight(0),
+    : mComp(comp), mFrameIndex(0), mWidth(0), mHeight(0), mUsage(0),
       mAdjustTimestampGapUs(0), mFirstInputFrame(true) {
-    // TODO: read from intf()
-    if (!strncmp(comp->getName().c_str(), "c2.android.", 11)) {
-        mUsage = GRALLOC_USAGE_SW_READ_OFTEN;
-    } else {
-        mUsage = GRALLOC_USAGE_HW_VIDEO_ENCODER;
-    }
 }
 
 status_t C2OMXNode::freeNode() {
@@ -103,13 +97,25 @@
 }
 
 status_t C2OMXNode::setParameter(OMX_INDEXTYPE index, const void *params, size_t size) {
-    // handle max/fixed frame duration control
-    if (index == (OMX_INDEXTYPE)OMX_IndexParamMaxFrameDurationForBitrateControl
-            && params != NULL
-            && size == sizeof(OMX_PARAM_U32TYPE)) {
-        // The incoming number is an int32_t contained in OMX_U32.
-        mAdjustTimestampGapUs = (int32_t)((OMX_PARAM_U32TYPE*)params)->nU32;
-        return OK;
+    if (params == NULL) {
+        return BAD_VALUE;
+    }
+    switch ((uint32_t)index) {
+        case OMX_IndexParamMaxFrameDurationForBitrateControl:
+            // handle max/fixed frame duration control
+            if (size != sizeof(OMX_PARAM_U32TYPE)) {
+                return BAD_VALUE;
+            }
+            // The incoming number is an int32_t contained in OMX_U32.
+            mAdjustTimestampGapUs = (int32_t)((OMX_PARAM_U32TYPE*)params)->nU32;
+            return OK;
+
+        case OMX_IndexParamConsumerUsageBits:
+            if (size != sizeof(OMX_U32)) {
+                return BAD_VALUE;
+            }
+            mUsage = *((OMX_U32 *)params);
+            return OK;
     }
     return ERROR_UNSUPPORTED;
 }
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 85c783b..f5a4d94 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -183,9 +183,11 @@
     GraphicBufferSourceWrapper(
             const sp<BGraphicBufferSource> &source,
             uint32_t width,
-            uint32_t height)
+            uint32_t height,
+            uint64_t usage)
         : mSource(source), mWidth(width), mHeight(height) {
         mDataSpace = HAL_DATASPACE_BT709;
+        mConfig.mUsage = usage;
     }
     ~GraphicBufferSourceWrapper() override = default;
 
@@ -193,6 +195,12 @@
         mNode = new C2OMXNode(comp);
         mNode->setFrameSize(mWidth, mHeight);
 
+        // Usage is queried during configure(), so setting it beforehand.
+        OMX_U32 usage = mConfig.mUsage & 0xFFFFFFFF;
+        (void)mNode->setParameter(
+                (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits,
+                &usage, sizeof(usage));
+
         // NOTE: we do not use/pass through color aspects from GraphicBufferSource as we
         // communicate that directly to the component.
         mSource->configure(mNode, mDataSpace);
@@ -364,7 +372,8 @@
 
         // color aspects (android._color-aspects)
 
-        // consumer usage
+        // consumer usage is queried earlier.
+
         ALOGD("ISConfig%s", status.str().c_str());
         return err;
     }
@@ -745,11 +754,8 @@
                 return BAD_VALUE;
             }
             if ((config->mDomain & Config::IS_ENCODER) && (config->mDomain & Config::IS_VIDEO)) {
-                C2Config::bitrate_mode_t mode = C2Config::BITRATE_VARIABLE;
-                if (msg->findInt32(KEY_BITRATE_MODE, &i32)) {
-                    mode = (C2Config::bitrate_mode_t) i32;
-                }
-                if (mode == BITRATE_MODE_CQ) {
+                int32_t mode = BITRATE_MODE_VBR;
+                if (msg->findInt32(KEY_BITRATE_MODE, &mode) && mode == BITRATE_MODE_CQ) {
                     if (!msg->findInt32(KEY_QUALITY, &i32)) {
                         ALOGD("quality is missing, which is required for video encoders in CQ.");
                         return BAD_VALUE;
@@ -766,6 +772,11 @@
                     ALOGD("I frame interval is missing, which is required for video encoders.");
                     return BAD_VALUE;
                 }
+                if (!msg->findInt32(KEY_FRAME_RATE, &i32)
+                        && !msg->findFloat(KEY_FRAME_RATE, &flt)) {
+                    ALOGD("frame rate is missing, which is required for video encoders.");
+                    return BAD_VALUE;
+                }
             }
         }
 
@@ -813,6 +824,7 @@
                     config->mISConfig->mSuspended = true;
                 }
             }
+            config->mISConfig->mUsage = 0;
         }
 
         /*
@@ -849,6 +861,22 @@
         if (err != OK) {
             ALOGW("failed to convert configuration to c2 params");
         }
+
+        int32_t maxBframes = 0;
+        if ((config->mDomain & Config::IS_ENCODER)
+                && (config->mDomain & Config::IS_VIDEO)
+                && sdkParams->findInt32(KEY_MAX_B_FRAMES, &maxBframes)
+                && maxBframes > 0) {
+            std::unique_ptr<C2StreamGopTuning::output> gop =
+                C2StreamGopTuning::output::AllocUnique(2 /* flexCount */, 0u /* stream */);
+            gop->m.values[0] = { P_FRAME, UINT32_MAX };
+            gop->m.values[1] = {
+                C2Config::picture_type_t(P_FRAME | B_FRAME),
+                uint32_t(maxBframes)
+            };
+            configUpdate.push_back(std::move(gop));
+        }
+
         err = config->setParameters(comp, configUpdate, C2_DONT_BLOCK);
         if (err != OK) {
             ALOGW("failed to configure c2 params");
@@ -876,8 +904,14 @@
                     indices.size(), params.size());
             return UNKNOWN_ERROR;
         }
-        if (usage && (usage.value & C2MemoryUsage::CPU_READ)) {
-            config->mInputFormat->setInt32("using-sw-read-often", true);
+        if (usage) {
+            if (usage.value & C2MemoryUsage::CPU_READ) {
+                config->mInputFormat->setInt32("using-sw-read-often", true);
+            }
+            if (config->mISConfig) {
+                C2AndroidMemoryUsage androidUsage(C2MemoryUsage(usage.value));
+                config->mISConfig->mUsage = androidUsage.asGrallocUsage();
+            }
         }
 
         // NOTE: we don't blindly use client specified input size if specified as clients
@@ -1068,10 +1102,12 @@
 
     sp<AMessage> inputFormat;
     sp<AMessage> outputFormat;
+    uint64_t usage = 0;
     {
         Mutexed<Config>::Locked config(mConfig);
         inputFormat = config->mInputFormat;
         outputFormat = config->mOutputFormat;
+        usage = config->mISConfig ? config->mISConfig->mUsage : 0;
     }
 
     sp<PersistentSurface> persistentSurface = CreateCompatibleInputSurface();
@@ -1095,7 +1131,7 @@
         int32_t height = 0;
         (void)outputFormat->findInt32("height", &height);
         err = setupInputSurface(std::make_shared<GraphicBufferSourceWrapper>(
-                persistentSurface->getBufferSource(), width, height));
+                persistentSurface->getBufferSource(), width, height, usage));
         bufferProducer = persistentSurface->getBufferProducer();
     }
 
@@ -1155,10 +1191,12 @@
 void CCodec::setInputSurface(const sp<PersistentSurface> &surface) {
     sp<AMessage> inputFormat;
     sp<AMessage> outputFormat;
+    uint64_t usage = 0;
     {
         Mutexed<Config>::Locked config(mConfig);
         inputFormat = config->mInputFormat;
         outputFormat = config->mOutputFormat;
+        usage = config->mISConfig ? config->mISConfig->mUsage : 0;
     }
     auto hidlTarget = surface->getHidlTarget();
     if (hidlTarget) {
@@ -1182,7 +1220,7 @@
         int32_t height = 0;
         (void)outputFormat->findInt32("height", &height);
         status_t err = setupInputSurface(std::make_shared<GraphicBufferSourceWrapper>(
-                surface->getBufferSource(), width, height));
+                surface->getBufferSource(), width, height, usage));
         if (err != OK) {
             ALOGE("Failed to set up input surface: %d", err);
             mCallback->onInputSurfaceDeclined(err);
diff --git a/media/codec2/sfplugin/CCodecConfig.cpp b/media/codec2/sfplugin/CCodecConfig.cpp
index 428f032..4c3fff7 100644
--- a/media/codec2/sfplugin/CCodecConfig.cpp
+++ b/media/codec2/sfplugin/CCodecConfig.cpp
@@ -358,14 +358,7 @@
         .limitTo(D::ENCODER & D::VIDEO & D::PARAM));
     add(ConfigMapper(KEY_BITRATE_MODE, C2_PARAMKEY_BITRATE_MODE, "value")
         .limitTo(D::ENCODER & D::CODED)
-        .withMapper([](C2Value v) -> C2Value {
-            int32_t value;
-            C2Config::bitrate_mode_t mode;
-            if (v.get(&value) && C2Mapper::map(value, &mode)) {
-                return mode;
-            }
-            return C2Value();
-        }));
+        .withC2Mappers<C2Config::bitrate_mode_t>());
     // remove when codecs switch to PARAMKEY and new modes
     deprecated(ConfigMapper(KEY_BITRATE_MODE, "coded.bitrate-mode", "value")
                .limitTo(D::ENCODER));
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 0fd5731..c6cbad3 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -739,6 +739,7 @@
         ALOGD("ConstGraphicBlockBuffer::copy: set back buffer failed");
         return false;
     }
+    setRange(0, aBuffer->size());  // align size info
     converter.copyToMediaImage();
     setImageData(converter.imageData());
     mBufferRef = buffer;
diff --git a/media/codec2/sfplugin/InputSurfaceWrapper.h b/media/codec2/sfplugin/InputSurfaceWrapper.h
index 8341fd5..bb35763 100644
--- a/media/codec2/sfplugin/InputSurfaceWrapper.h
+++ b/media/codec2/sfplugin/InputSurfaceWrapper.h
@@ -78,6 +78,7 @@
         // IN PARAMS (CODEC WRAPPER)
         float mFixedAdjustedFps; // fixed fps via PTS manipulation
         float mMinAdjustedFps; // minimum fps via PTS manipulation
+        uint64_t mUsage; // consumer usage
     };
 
     /**
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index f54690d..527bb77 100755
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -1754,6 +1754,15 @@
                 // http://wiki.xiph.org/OggOpus#ID_Header
                 strncpy((char *)opusInfo, "OpusHead", 8);
 
+                // Version shall be 0 as per mp4 Opus Specific Box
+                // (https://opus-codec.org/docs/opus_in_isobmff.html#4.3.2)
+                if (opusInfo[8]) {
+                    return ERROR_MALFORMED;
+                }
+                // Force version to 1 as per OpusHead definition
+                // (http://wiki.xiph.org/OggOpus#ID_Header)
+                opusInfo[8] = 1;
+
                 // Read Opus Specific Box values
                 size_t opusOffset = 10;
                 uint16_t pre_skip = U16_AT(&opusInfo[opusOffset]);
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 1d99b88..ce408be 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -4918,6 +4918,10 @@
             // read original volumes with volume control
             float typeVolume = mStreamTypes[track->streamType()].volume;
             float v = masterVolume * typeVolume;
+            // Always fetch volumeshaper volume to ensure state is updated.
+            const sp<AudioTrackServerProxy> proxy = track->mAudioTrackServerProxy;
+            const float vh = track->getVolumeHandler()->getVolume(
+                    track->mAudioTrackServerProxy->framesReleased()).first;
 
             if (track->isPausing() || mStreamTypes[track->streamType()].mute
                     || track->isPlaybackRestricted()) {
@@ -4927,7 +4931,6 @@
                     track->setPaused();
                 }
             } else {
-                sp<AudioTrackServerProxy> proxy = track->mAudioTrackServerProxy;
                 gain_minifloat_packed_t vlr = proxy->getVolumeLR();
                 vlf = float_from_gain(gain_minifloat_unpack_left(vlr));
                 vrf = float_from_gain(gain_minifloat_unpack_right(vlr));
@@ -4940,8 +4943,6 @@
                     ALOGV("Track right volume out of range: %.3g", vrf);
                     vrf = GAIN_FLOAT_UNITY;
                 }
-                const float vh = track->getVolumeHandler()->getVolume(
-                        track->mAudioTrackServerProxy->framesReleased()).first;
                 // now apply the master volume and stream type volume and shaper volume
                 vlf *= v * vh;
                 vrf *= v * vh;
@@ -5021,7 +5022,7 @@
                 (void *)(uintptr_t)(mChannelMask | mHapticChannelMask));
             // limit track sample rate to 2 x output sample rate, which changes at re-configuration
             uint32_t maxSampleRate = mSampleRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX;
-            uint32_t reqSampleRate = track->mAudioTrackServerProxy->getSampleRate();
+            uint32_t reqSampleRate = proxy->getSampleRate();
             if (reqSampleRate == 0) {
                 reqSampleRate = mSampleRate;
             } else if (reqSampleRate > maxSampleRate) {
@@ -5033,7 +5034,7 @@
                 AudioMixer::SAMPLE_RATE,
                 (void *)(uintptr_t)reqSampleRate);
 
-            AudioPlaybackRate playbackRate = track->mAudioTrackServerProxy->getPlaybackRate();
+            AudioPlaybackRate playbackRate = proxy->getPlaybackRate();
             mAudioMixer->setParameter(
                 trackId,
                 AudioMixer::TIMESTRETCH,
@@ -5507,19 +5508,17 @@
 {
     float left, right;
 
+    // Ensure volumeshaper state always advances even when muted.
+    const sp<AudioTrackServerProxy> proxy = track->mAudioTrackServerProxy;
+    const auto [shaperVolume, shaperActive] = track->getVolumeHandler()->getVolume(
+            proxy->framesReleased());
+    mVolumeShaperActive = shaperActive;
+
     if (mMasterMute || mStreamTypes[track->streamType()].mute || track->isPlaybackRestricted()) {
         left = right = 0;
     } else {
         float typeVolume = mStreamTypes[track->streamType()].volume;
-        float v = mMasterVolume * typeVolume;
-        sp<AudioTrackServerProxy> proxy = track->mAudioTrackServerProxy;
-
-        // Get volumeshaper scaling
-        std::pair<float /* volume */, bool /* active */>
-            vh = track->getVolumeHandler()->getVolume(
-                    track->mAudioTrackServerProxy->framesReleased());
-        v *= vh.first;
-        mVolumeShaperActive = vh.second;
+        const float v = mMasterVolume * typeVolume * shaperVolume;
 
         gain_minifloat_packed_t vlr = proxy->getVolumeLR();
         left = float_from_gain(gain_minifloat_unpack_left(vlr));