C2SoftAomEnc: Compute appropriate level based on the configuration
Minimum level required for the given configuration is now computed
and signalled in the output format
Bug : 268574609
Test: atest android.mediav2.cts.EncoderLevelTest
Change-Id: I8191499bcc0898d203bfb88d549d9efe9ee0b7f6
diff --git a/media/codec2/components/aom/C2SoftAomEnc.cpp b/media/codec2/components/aom/C2SoftAomEnc.cpp
index e08bf43..e38735d 100644
--- a/media/codec2/components/aom/C2SoftAomEnc.cpp
+++ b/media/codec2/components/aom/C2SoftAomEnc.cpp
@@ -116,7 +116,7 @@
LEVEL_AV1_3_2, LEVEL_AV1_3_3, LEVEL_AV1_4,
LEVEL_AV1_4_1}),
})
- .withSetter(ProfileLevelSetter)
+ .withSetter(ProfileLevelSetter, mSize, mFrameRate, mBitrate)
.build());
std::vector<uint32_t> pixelFormats = {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
@@ -201,12 +201,69 @@
}
C2R C2SoftAomEnc::IntfImpl::ProfileLevelSetter(bool mayBlock,
- C2P<C2StreamProfileLevelInfo::output>& me) {
+ C2P<C2StreamProfileLevelInfo::output>& me,
+ const C2P<C2StreamPictureSizeInfo::input>& size,
+ const C2P<C2StreamFrameRateInfo::output>& frameRate,
+ const C2P<C2StreamBitrateInfo::output>& bitrate) {
(void)mayBlock;
if (!me.F(me.v.profile).supportsAtAll(me.v.profile)) {
me.set().profile = PROFILE_AV1_0;
}
+ struct LevelLimits {
+ C2Config::level_t level;
+ float samplesPerSec;
+ uint64_t samples;
+ uint32_t bitrate;
+ size_t maxHSize;
+ size_t maxVSize;
+ };
+ constexpr LevelLimits kLimits[] = {
+ {LEVEL_AV1_2, 4423680, 147456, 1500000, 2048, 1152},
+ {LEVEL_AV1_2_1, 8363520, 278784, 3000000, 2816, 1584},
+ {LEVEL_AV1_3, 19975680, 665856, 6000000, 4352, 2448},
+ {LEVEL_AV1_3_1, 37950720, 1065024, 10000000, 5504, 3096},
+ {LEVEL_AV1_4, 70778880, 2359296, 12000000, 6144, 3456},
+ {LEVEL_AV1_4_1, 141557760, 2359296, 20000000, 6144, 3456},
+ };
+
+ uint64_t samples = size.v.width * size.v.height;
+ float samplesPerSec = float(samples) * frameRate.v.value;
+
+ // Check if the supplied level meets the samples / bitrate requirements.
+ // If not, update the level with the lowest level meeting the requirements.
+ bool found = false;
+
+ // By default needsUpdate = false in case the supplied level does meet
+ // the requirements.
+ bool needsUpdate = false;
if (!me.F(me.v.level).supportsAtAll(me.v.level)) {
+ needsUpdate = true;
+ }
+ for (const LevelLimits& limit : kLimits) {
+ if (samples <= limit.samples && samplesPerSec <= limit.samplesPerSec &&
+ bitrate.v.value <= limit.bitrate && size.v.width <= limit.maxHSize &&
+ size.v.height <= limit.maxVSize) {
+ // This is the lowest level that meets the requirements, and if
+ // we haven't seen the supplied level yet, that means we don't
+ // need the update.
+ if (needsUpdate) {
+ ALOGD("Given level %x does not cover current configuration: "
+ "adjusting to %x",
+ me.v.level, limit.level);
+ me.set().level = limit.level;
+ }
+ found = true;
+ break;
+ }
+ if (me.v.level == limit.level) {
+ // We break out of the loop when the lowest feasible level is
+ // found. The fact that we're here means that our level doesn't
+ // meet the requirement and needs to be updated.
+ needsUpdate = true;
+ }
+ }
+ if (!found) {
+ // We set to the highest supported level.
me.set().level = LEVEL_AV1_4_1;
}
return C2R::Ok();