Merge "VolumeShaper: Ensure consistent observable state when muted" into qt-dev
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/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/opus/C2SoftOpusEnc.cpp b/media/codec2/components/opus/C2SoftOpusEnc.cpp
index 7b58c9b..2d110f7 100644
--- a/media/codec2/components/opus/C2SoftOpusEnc.cpp
+++ b/media/codec2/components/opus/C2SoftOpusEnc.cpp
@@ -205,15 +205,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;
@@ -406,13 +397,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/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]);