CCodec: support region of interest parameters
Bug: 325549730
Bug: 299191092
Test: ./ccodec_unit_test \
--gtest_filter=CCodecConfigTest.SetRegionOfInterestParams
Change-Id: I9654d7815cc8838c781b2655ff7dd7912d40e481
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index d14068d..5396d25 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -21,6 +21,8 @@
#include <sstream>
#include <thread>
+#include <android_media_codec.h>
+
#include <C2Config.h>
#include <C2Debug.h>
#include <C2ParamInternal.h>
@@ -1411,6 +1413,23 @@
}
}
+ /*
+ * configure mock region of interest if Feature_Roi is enabled
+ */
+ if (android::media::codec::provider_->region_of_interest()
+ && android::media::codec::provider_->region_of_interest_support()) {
+ if ((config->mDomain & Config::IS_ENCODER) && (config->mDomain & Config::IS_VIDEO)) {
+ int32_t enableRoi;
+ if (msg->findInt32("feature-region-of-interest", &enableRoi) && enableRoi != 0) {
+ if (!msg->contains(PARAMETER_KEY_QP_OFFSET_MAP) &&
+ !msg->contains(PARAMETER_KEY_QP_OFFSET_RECTS)) {
+ msg->setString(PARAMETER_KEY_QP_OFFSET_RECTS,
+ AStringPrintf("%d,%d-%d,%d=%d;", 0, 0, 16, 16, 0));
+ }
+ }
+ }
+ }
+
std::vector<std::unique_ptr<C2Param>> configUpdate;
// NOTE: We used to ignore "video-bitrate" at configure; replicate
// the behavior here.
diff --git a/media/codec2/sfplugin/CCodecConfig.cpp b/media/codec2/sfplugin/CCodecConfig.cpp
index c22deca..db59227 100644
--- a/media/codec2/sfplugin/CCodecConfig.cpp
+++ b/media/codec2/sfplugin/CCodecConfig.cpp
@@ -19,6 +19,8 @@
#include <initializer_list>
+#include <android_media_codec.h>
+
#include <cutils/properties.h>
#include <log/log.h>
#include <utils/NativeHandle.h>
@@ -591,6 +593,13 @@
}
return C2Value();
}));
+
+ if (android::media::codec::provider_->region_of_interest()
+ && android::media::codec::provider_->region_of_interest_support()) {
+ add(ConfigMapper(C2_PARAMKEY_QP_OFFSET_RECTS, C2_PARAMKEY_QP_OFFSET_RECTS, "")
+ .limitTo(D::VIDEO & (D::CONFIG | D::PARAM) & D::ENCODER & D::INPUT));
+ }
+
deprecated(ConfigMapper(PARAMETER_KEY_REQUEST_SYNC_FRAME,
"coding.request-sync", "value")
.limitTo(D::PARAM & D::ENCODER)
@@ -1121,6 +1130,11 @@
mParamUpdater->clear();
mParamUpdater->supportWholeParam(
C2_PARAMKEY_TEMPORAL_LAYERING, C2StreamTemporalLayeringTuning::CORE_INDEX);
+ if (android::media::codec::provider_->region_of_interest()
+ && android::media::codec::provider_->region_of_interest_support()) {
+ mParamUpdater->supportWholeParam(
+ C2_PARAMKEY_QP_OFFSET_RECTS, C2StreamQpOffsetRects::CORE_INDEX);
+ }
mParamUpdater->addParamDesc(mReflector, mParamDescs);
// TEMP: add some standard fields even if not reflected
@@ -1871,6 +1885,39 @@
}
}
+ if (android::media::codec::provider_->region_of_interest()
+ && android::media::codec::provider_->region_of_interest_support()) {
+ if (mDomain == (IS_VIDEO | IS_ENCODER)) {
+ AString qpOffsetRects;
+ if (params->findString(PARAMETER_KEY_QP_OFFSET_RECTS, &qpOffsetRects)) {
+ std::vector<C2QpOffsetRectStruct> c2QpOffsetRects;
+ char mutableStrQpOffsetRects[strlen(qpOffsetRects.c_str()) + 1];
+ strcpy(mutableStrQpOffsetRects, qpOffsetRects.c_str());
+ char* box = strtok(mutableStrQpOffsetRects, ";");
+ while (box != nullptr) {
+ int top, left, bottom, right, offset;
+ if (sscanf(box, "%d,%d-%d,%d=%d", &top, &left, &bottom, &right, &offset) == 5) {
+ left = c2_max(0, left);
+ top = c2_max(0, top);
+ if (right > left && bottom > top) {
+ C2Rect rect(right - left, bottom - top);
+ rect.at(left, top);
+ c2QpOffsetRects.push_back(C2QpOffsetRectStruct(rect, offset));
+ }
+ }
+ box = strtok(nullptr, ";");
+ }
+ if (c2QpOffsetRects.size() != 0) {
+ const std::unique_ptr<C2StreamQpOffsetRects::output> regions =
+ C2StreamQpOffsetRects::output::AllocUnique(
+ c2QpOffsetRects.size(), 0u, c2QpOffsetRects);
+ params->setBuffer(C2_PARAMKEY_QP_OFFSET_RECTS,
+ ABuffer::CreateAsCopy(regions.get(), regions->size()));
+ }
+ }
+ }
+ }
+
// this is to verify that we set proper signedness for standard parameters
bool beVeryStrict = property_get_bool("debug.stagefright.ccodec_strict_type", false);
// this is to allow vendors to use the wrong signedness for standard parameters
diff --git a/media/codec2/sfplugin/tests/Android.bp b/media/codec2/sfplugin/tests/Android.bp
index 246e563..2739f44 100644
--- a/media/codec2/sfplugin/tests/Android.bp
+++ b/media/codec2/sfplugin/tests/Android.bp
@@ -42,6 +42,7 @@
],
static_libs: [
+ "android.media.codec-aconfig-cc",
"libcodec2_hidl@1.0",
"libstagefright_bufferpool@2.0",
],
diff --git a/media/codec2/sfplugin/tests/CCodecConfig_test.cpp b/media/codec2/sfplugin/tests/CCodecConfig_test.cpp
index 3615289..508bec2 100644
--- a/media/codec2/sfplugin/tests/CCodecConfig_test.cpp
+++ b/media/codec2/sfplugin/tests/CCodecConfig_test.cpp
@@ -20,6 +20,8 @@
#include <gtest/gtest.h>
+#include <android_media_codec.h>
+
#include <codec2/hidl/1.0/Configurable.h>
#include <codec2/hidl/client.h>
#include <util/C2InterfaceHelper.h>
@@ -235,6 +237,22 @@
})
.withSetter(Setter<C2StreamProfileLevelInfo::output>)
.build());
+
+ std::vector<C2QpOffsetRectStruct> c2QpOffsetRectsInfo;
+ addParameter(
+ DefineParam(mInputQpOffsetRects, C2_PARAMKEY_QP_OFFSET_RECTS)
+ .withDefault(C2StreamQpOffsetRects::output::AllocShared(
+ c2QpOffsetRectsInfo.size(), 0, c2QpOffsetRectsInfo))
+ .withFields({
+ C2F(mInputQpOffsetRects, m.values[0].qpOffset)
+ .inRange(-128, 127),
+ C2F(mInputQpOffsetRects, m.values[0].left).any(),
+ C2F(mInputQpOffsetRects, m.values[0].top).any(),
+ C2F(mInputQpOffsetRects, m.values[0].width).any(),
+ C2F(mInputQpOffsetRects, m.values[0].height).any(),
+ })
+ .withSetter(Setter<C2StreamQpOffsetRects::output>)
+ .build());
}
// TODO: more SDK params
@@ -254,6 +272,7 @@
std::shared_ptr<C2StreamBitrateInfo::output> mOutputBitrate;
std::shared_ptr<C2StreamProfileLevelInfo::input> mInputProfileLevel;
std::shared_ptr<C2StreamProfileLevelInfo::output> mOutputProfileLevel;
+ std::shared_ptr<C2StreamQpOffsetRects::output> mInputQpOffsetRects;
template<typename T>
static C2R Setter(bool, C2P<T> &) {
@@ -636,4 +655,56 @@
HdrProfilesTest,
::testing::ValuesIn(kHdrProfilesParams));
+TEST_F(CCodecConfigTest, SetRegionOfInterestParams) {
+ if (!android::media::codec::provider_->region_of_interest()
+ || !android::media::codec::provider_->region_of_interest_support()) {
+ GTEST_SKIP() << "Skipping the test as region_of_interest flags are not enabled.\n";
+ }
+
+ init(C2Component::DOMAIN_VIDEO, C2Component::KIND_ENCODER, MIMETYPE_VIDEO_VP9);
+
+ ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
+
+ const int kWidth = 32;
+ const int kHeight = 32;
+ const int kNumBlocks = ((kWidth + 15) / 16) * ((kHeight + 15) / 16);
+ int8_t mapInfo[kNumBlocks] = {-1, 0, 1, 1};
+ int top[kNumBlocks] = {0, 0, 16, 16};
+ int left[kNumBlocks] = {0, 16, 0, 16};
+ int bottom[kNumBlocks] = {16, 16, 32, 32};
+ int right[kNumBlocks] = {16, 32, 16, 32};
+ sp<AMessage> format{new AMessage};
+ format->setInt32(KEY_WIDTH, kWidth);
+ format->setInt32(KEY_HEIGHT, kHeight);
+ AString val;
+ for (int i = 0; i < kNumBlocks; i++) {
+ val.append(AStringPrintf("%d,%d-%d,%d=%d;", top[i], left[i], bottom[i],
+ right[i], mapInfo[i]));
+ }
+ format->setString(PARAMETER_KEY_QP_OFFSET_RECTS, val);
+
+ std::vector<std::unique_ptr<C2Param>> configUpdate;
+ ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(mConfigurable, format, D::CONFIG,
+ C2_MAY_BLOCK, &configUpdate));
+
+ EXPECT_EQ(1u, configUpdate.size());
+
+ C2StreamQpOffsetRects::output* qpRectParam =
+ FindParam<std::remove_pointer<decltype(qpRectParam)>::type>(configUpdate);
+ ASSERT_NE(nullptr, qpRectParam);
+ ASSERT_EQ(kNumBlocks, qpRectParam->flexCount());
+ for (auto i = 0; i < kNumBlocks; i++) {
+ EXPECT_EQ(mapInfo[i], (int8_t)qpRectParam->m.values[i].qpOffset)
+ << "qp offset for index " << i << " is not as expected ";
+ EXPECT_EQ(left[i], qpRectParam->m.values[i].left)
+ << "left for index " << i << " is not as expected ";
+ EXPECT_EQ(top[i], qpRectParam->m.values[i].top)
+ << "top for index " << i << " is not as expected ";
+ EXPECT_EQ(right[i] - left[i], qpRectParam->m.values[i].width)
+ << "width for index " << i << " is not as expected ";
+ EXPECT_EQ(bottom[i] - top[i], qpRectParam->m.values[i].height)
+ << "height for index " << i << " is not as expected ";
+ }
+}
+
} // namespace android