C2/CCodec: allow setting temporal layering

- add constructors for temporal layering (and info structures, the
  only other flex structure without a flex constructor)
- support setting temporal layering

TODO: query temporal layering

Bug: 90469941
Change-Id: I12a2751f2064b2a226e67af184e6ec75e2c3c1bb
diff --git a/codec2/include/C2Config.h b/codec2/include/C2Config.h
index 93897bf..91349f7 100644
--- a/codec2/include/C2Config.h
+++ b/codec2/include/C2Config.h
@@ -710,6 +710,12 @@
     C2SupplementalDataStruct()
         : type_(INFO_NONE) { }
 
+    C2SupplementalDataStruct(
+            size_t flexCount, C2Config::supplemental_info_t type, std::vector<uint8_t> data_)
+        : type_(type) {
+            memcpy(data, &data_[0], c2_min(data_.size(), flexCount));
+    }
+
     C2Config::supplemental_info_t type_;
     uint8_t data[];
 
@@ -1705,9 +1711,21 @@
     C2TemporalLayeringStruct()
         : layerCount(0), bLayerCount(0) { }
 
-    C2TemporalLayeringStruct(uint32_t layerCount_, uint32_t bLayerCount_)
+    C2TemporalLayeringStruct(size_t /* flexCount */, uint32_t layerCount_, uint32_t bLayerCount_)
         : layerCount(layerCount_), bLayerCount(c2_min(layerCount_, bLayerCount_)) { }
 
+    C2TemporalLayeringStruct(size_t flexCount, uint32_t layerCount_, uint32_t bLayerCount_,
+                             std::initializer_list<float> ratios)
+        : layerCount(layerCount_), bLayerCount(c2_min(layerCount_, bLayerCount_)) {
+        size_t ix = 0;
+        for (float ratio : ratios) {
+            if (ix == flexCount) {
+                break;
+            }
+            bitrateRatios[ix++] = ratio;
+        }
+    }
+
     uint32_t layerCount;     ///< total number of layers (0 means no temporal layering)
     uint32_t bLayerCount;    ///< total number of bidirectional layers (<= num layers)
     /**
diff --git a/media/sfplugin/CCodecConfig.cpp b/media/sfplugin/CCodecConfig.cpp
index d68031e..1a6e641 100644
--- a/media/sfplugin/CCodecConfig.cpp
+++ b/media/sfplugin/CCodecConfig.cpp
@@ -138,7 +138,7 @@
 
     Domain domain() const { return mDomain; }
     std::string mediaKey() const { return mMediaKey; }
-    std::string path() const { return mStruct + '.' + mField; }
+    std::string path() const { return mField.size() ? mStruct + '.' + mField : mStruct; }
     Mapper mapper() const { return mMapper; }
     Mapper reverse() const { return mReverse; }
 
@@ -446,6 +446,9 @@
     add(ConfigMapper("csd-0",           C2_PARAMKEY_INIT_DATA,       "value")
         .limitTo(D::OUTPUT & D::READ));
 
+    add(ConfigMapper(C2_PARAMKEY_TEMPORAL_LAYERING, C2_PARAMKEY_TEMPORAL_LAYERING, "")
+        .limitTo(D::ENCODER & D::VIDEO & D::OUTPUT));
+
     // Pixel Format (use local key for actual pixel format as we don't distinguish between
     // SDK layouts for flexible format and we need the actual SDK color format in the media format)
     add(ConfigMapper("android._color-format",  C2_PARAMKEY_PIXEL_FORMAT, "value")
@@ -735,6 +738,8 @@
     // enumerate all fields
     mParamUpdater = std::make_shared<ReflectedParamUpdater>();
     mParamUpdater->clear();
+    mParamUpdater->supportWholeParam(
+            C2_PARAMKEY_TEMPORAL_LAYERING, C2StreamTemporalLayeringTuning::CORE_INDEX);
     mParamUpdater->addParamDesc(mReflector, mParamDescs);
 
     // TEMP: add some standard fields even if not reflected
@@ -994,6 +999,50 @@
         }
     }
 
+    {   // reflect temporal layering into a binary blob
+        AString schema;
+        if (params->findString(KEY_TEMPORAL_LAYERING, &schema)) {
+            unsigned int numLayers = 0;
+            unsigned int numBLayers = 0;
+            int tags;
+            char dummy;
+            std::unique_ptr<C2StreamTemporalLayeringTuning::output> layering;
+            if (sscanf(schema.c_str(), "webrtc.vp8.%u-layer%c", &numLayers, &dummy) == 1
+                && numLayers > 0) {
+                switch (numLayers) {
+                    case 1:
+                        layering = C2StreamTemporalLayeringTuning::output::AllocUnique(
+                                {}, 0u, 1u, 0u);
+                        break;
+                    case 2:
+                        layering = C2StreamTemporalLayeringTuning::output::AllocUnique(
+                                { .6f }, 0u, 2u, 0u);
+                        break;
+                    case 3:
+                        layering = C2StreamTemporalLayeringTuning::output::AllocUnique(
+                                { .4f, .6f }, 0u, 3u, 0u);
+                        break;
+                    default:
+                        layering = C2StreamTemporalLayeringTuning::output::AllocUnique(
+                                { .25f, .4f, .6f }, 0u, 4u, 0u);
+                        break;
+                }
+            } else if ((tags = sscanf(schema.c_str(), "android.generic.%u%c%u%c",
+                        &numLayers, &dummy, &numBLayers, &dummy))
+                && (tags == 1 || (tags == 3 && dummy == '+'))
+                && numLayers > 0 && numLayers < UINT32_MAX - numBLayers) {
+                layering = C2StreamTemporalLayeringTuning::output::AllocUnique(
+                        {}, 0u, numLayers, numBLayers);
+            } else {
+                ALOGD("Ignoring unsupported ts-schema [%s]", schema.c_str());
+            }
+            if (layering) {
+                params->setBuffer(C2_PARAMKEY_TEMPORAL_LAYERING,
+                                  ABuffer::CreateAsCopy(layering.get(), layering->size()));
+            }
+        }
+    }
+
     { // convert from MediaFormat rect to Codec 2.0 rect
         int32_t offset;
         int32_t end;