Decode Target Information for VP8 libvpx encoder.

In this CL:
 - Created static helper function GenericFrameInfo::DecodeTargetInfo to
   convert DTI symbols to a list of GenericFrameInfo::OperatingPointIndication.
 - Added per frame DTI information for the different stream structures.

Bug: webrtc:10342
Change-Id: I62ff2e9fc9b380fe1d0447ff071e86b6b35ab249
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/129923
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Commit-Queue: Philip Eliasson <philipel@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27350}
diff --git a/common_video/generic_frame_descriptor/generic_frame_info.cc b/common_video/generic_frame_descriptor/generic_frame_info.cc
index 94a6192..1c01b6c 100644
--- a/common_video/generic_frame_descriptor/generic_frame_info.cc
+++ b/common_video/generic_frame_descriptor/generic_frame_info.cc
@@ -15,6 +15,24 @@
 
 namespace webrtc {
 
+absl::InlinedVector<GenericFrameInfo::DecodeTargetIndication, 10>
+GenericFrameInfo::DecodeTargetInfo(absl::string_view indication_symbols) {
+  absl::InlinedVector<DecodeTargetIndication, 10> decode_targets;
+  for (char symbol : indication_symbols) {
+    DecodeTargetIndication indication;
+    switch (symbol) {
+      case '-': indication = DecodeTargetIndication::kNotPresent; break;
+      case 'D': indication = DecodeTargetIndication::kDiscardable; break;
+      case 'R': indication = DecodeTargetIndication::kRequired; break;
+      case 'S': indication = DecodeTargetIndication::kSwitch; break;
+      default: RTC_NOTREACHED();
+    }
+    decode_targets.push_back(indication);
+  }
+
+  return decode_targets;
+}
+
 GenericFrameInfo::GenericFrameInfo() = default;
 GenericFrameInfo::GenericFrameInfo(const GenericFrameInfo&) = default;
 GenericFrameInfo::~GenericFrameInfo() = default;
@@ -38,19 +56,7 @@
 
 GenericFrameInfo::Builder& GenericFrameInfo::Builder::Dtis(
     absl::string_view indication_symbols) {
-  for (const auto& symbol : indication_symbols) {
-    DecodeTargetIndication indication;
-    switch (symbol) {
-      case '-': indication = DecodeTargetIndication::kNotPresent; break;
-      case 'D': indication = DecodeTargetIndication::kDiscardable; break;
-      case 'R': indication = DecodeTargetIndication::kRequired; break;
-      case 'S': indication = DecodeTargetIndication::kSwitch; break;
-      default: RTC_NOTREACHED();
-    }
-
-    info_.decode_target_indications.push_back(indication);
-  }
-
+  info_.decode_target_indications = DecodeTargetInfo(indication_symbols);
   return *this;
 }
 
diff --git a/common_video/generic_frame_descriptor/generic_frame_info.h b/common_video/generic_frame_descriptor/generic_frame_info.h
index 91a0868..7909291 100644
--- a/common_video/generic_frame_descriptor/generic_frame_info.h
+++ b/common_video/generic_frame_descriptor/generic_frame_info.h
@@ -22,12 +22,15 @@
 
 struct GenericFrameInfo {
   enum class DecodeTargetIndication {
-    kNotPresent,   // GenericFrameInfo::Builder symbol '-'
-    kDiscardable,  // GenericFrameInfo::Builder symbol 'D'
-    kSwitch,       // GenericFrameInfo::Builder symbol 'S'
-    kRequired      // GenericFrameInfo::Builder symbol 'R'
+    kNotPresent,   // DecodeTargetInfo symbol '-'
+    kDiscardable,  // DecodeTargetInfo symbol 'D'
+    kSwitch,       // DecodeTargetInfo symbol 'S'
+    kRequired      // DecodeTargetInfo symbol 'R'
   };
 
+  static absl::InlinedVector<DecodeTargetIndication, 10> DecodeTargetInfo(
+      absl::string_view indication_symbols);
+
   class Builder;
 
   GenericFrameInfo();
diff --git a/modules/video_coding/codecs/vp8/default_temporal_layers.cc b/modules/video_coding/codecs/vp8/default_temporal_layers.cc
index d47317e..abab490 100644
--- a/modules/video_coding/codecs/vp8/default_temporal_layers.cc
+++ b/modules/video_coding/codecs/vp8/default_temporal_layers.cc
@@ -31,10 +31,10 @@
 DefaultTemporalLayers::PendingFrame::PendingFrame(
     bool expired,
     uint8_t updated_buffers_mask,
-    const Vp8FrameConfig& frame_config)
+    const DependencyInfo& dependency_info)
     : expired(expired),
       updated_buffer_mask(updated_buffers_mask),
-      frame_config(frame_config) {}
+      dependency_info(dependency_info) {}
 
 namespace {
 using Buffer = Vp8FrameConfig::Buffer;
@@ -99,27 +99,10 @@
   }
   return flags;
 }
-
-// Find the set of buffers that are never updated by the given pattern.
-std::set<Vp8BufferReference> FindKfBuffers(
-    const std::vector<Vp8FrameConfig>& frame_configs) {
-  std::set<Vp8BufferReference> kf_buffers(kAllBuffers.begin(),
-                                          kAllBuffers.end());
-  for (Vp8FrameConfig config : frame_configs) {
-    // Get bit-masked set of update buffers for this frame config.
-    uint8_t updated_buffers = GetUpdatedBuffers(config);
-    for (Vp8BufferReference buffer : kAllBuffers) {
-      if (static_cast<uint8_t>(buffer) & updated_buffers) {
-        kf_buffers.erase(buffer);
-      }
-    }
-  }
-  return kf_buffers;
-}
 }  // namespace
 
-std::vector<Vp8FrameConfig> DefaultTemporalLayers::GetTemporalPattern(
-    size_t num_layers) {
+std::vector<DefaultTemporalLayers::DependencyInfo>
+DefaultTemporalLayers::GetDependencyInfo(size_t num_layers) {
   // For indexing in the patterns described below (which temporal layers they
   // belong to), see the diagram above.
   // Layer sync is done similarly for all patterns (except single stream) and
@@ -133,10 +116,11 @@
   // so that if scene changes occur (user walks between rooms or rotates webcam)
   // the 'arf' (or 'golden' respectively) is not stuck on a no-longer relevant
   // keyframe.
+
   switch (num_layers) {
     case 1:
       // Always reference and update the same buffer.
-      return {Vp8FrameConfig(kReferenceAndUpdate, kNone, kNone)};
+      return {{"S", {kReferenceAndUpdate, kNone, kNone}}};
     case 2:
       // All layers can reference but not update the 'alt' buffer, this means
       // that the 'alt' buffer reference is effectively the last keyframe.
@@ -147,23 +131,23 @@
         //   1---1   1---1 ...
         //  /   /   /   /
         // 0---0---0---0 ...
-        return {Vp8FrameConfig(kReferenceAndUpdate, kNone, kNone),
-                Vp8FrameConfig(kReference, kUpdate, kNone),
-                Vp8FrameConfig(kReferenceAndUpdate, kNone, kNone),
-                Vp8FrameConfig(kReference, kReference, kNone, kFreezeEntropy)};
+        return {{"SS", {kReferenceAndUpdate, kNone, kNone}},
+                {"-S", {kReference, kUpdate, kNone}},
+                {"SR", {kReferenceAndUpdate, kNone, kNone}},
+                {"-D", {kReference, kReference, kNone, kFreezeEntropy}}};
       } else {
         // "Default" 8-frame pattern:
         //   1---1---1---1   1---1---1---1 ...
         //  /   /   /   /   /   /   /   /
         // 0---0---0---0---0---0---0---0 ...
-        return {Vp8FrameConfig(kReferenceAndUpdate, kNone, kNone),
-                Vp8FrameConfig(kReference, kUpdate, kNone),
-                Vp8FrameConfig(kReferenceAndUpdate, kNone, kNone),
-                Vp8FrameConfig(kReference, kReferenceAndUpdate, kNone),
-                Vp8FrameConfig(kReferenceAndUpdate, kNone, kNone),
-                Vp8FrameConfig(kReference, kReferenceAndUpdate, kNone),
-                Vp8FrameConfig(kReferenceAndUpdate, kNone, kNone),
-                Vp8FrameConfig(kReference, kReference, kNone, kFreezeEntropy)};
+        return {{"SS", {kReferenceAndUpdate, kNone, kNone}},
+                {"-S", {kReference, kUpdate, kNone}},
+                {"SR", {kReferenceAndUpdate, kNone, kNone}},
+                {"-R", {kReference, kReferenceAndUpdate, kNone}},
+                {"SR", {kReferenceAndUpdate, kNone, kNone}},
+                {"-R", {kReference, kReferenceAndUpdate, kNone}},
+                {"SR", {kReferenceAndUpdate, kNone, kNone}},
+                {"-D", {kReference, kReference, kNone, kFreezeEntropy}}};
       }
     case 3:
       if (field_trial::IsEnabled("WebRTC-UseShortVP8TL3Pattern")) {
@@ -183,62 +167,59 @@
         // TL1  references 'last' and references and updates 'golden'.
         // TL2 references both 'last' & 'golden' and references and updates
         // 'arf'.
-        return {
-            Vp8FrameConfig(kReferenceAndUpdate, kNone, kNone),
-            Vp8FrameConfig(kReference, kNone, kUpdate),
-            Vp8FrameConfig(kReference, kUpdate, kNone),
-            Vp8FrameConfig(kReference, kReference, kReference, kFreezeEntropy)};
+        return {{"SSS", {kReferenceAndUpdate, kNone, kNone}},
+                {"--S", {kReference, kNone, kUpdate}},
+                {"-DR", {kReference, kUpdate, kNone}},
+                {"--D", {kReference, kReference, kReference, kFreezeEntropy}}};
       } else {
         // All layers can reference but not update the 'alt' buffer, this means
         // that the 'alt' buffer reference is effectively the last keyframe.
         // TL0 also references and updates the 'last' buffer.
         // TL1 also references 'last' and references and updates 'golden'.
         // TL2 references both 'last' and 'golden' but updates no buffer.
-        return {
-            Vp8FrameConfig(kReferenceAndUpdate, kNone, kReference),
-            Vp8FrameConfig(kReference, kNone, kReference, kFreezeEntropy),
-            Vp8FrameConfig(kReference, kUpdate, kReference),
-            Vp8FrameConfig(kReference, kReference, kReference, kFreezeEntropy),
-            Vp8FrameConfig(kReferenceAndUpdate, kNone, kReference),
-            Vp8FrameConfig(kReference, kReference, kReference, kFreezeEntropy),
-            Vp8FrameConfig(kReference, kReferenceAndUpdate, kReference),
-            Vp8FrameConfig(kReference, kReference, kReference, kFreezeEntropy)};
+        return {{"SSS", {kReferenceAndUpdate, kNone, kReference}},
+                {"--D", {kReference, kNone, kReference, kFreezeEntropy}},
+                {"-SS", {kReference, kUpdate, kReference}},
+                {"--D", {kReference, kReference, kReference, kFreezeEntropy}},
+                {"SRR", {kReferenceAndUpdate, kNone, kReference}},
+                {"--D", {kReference, kReference, kReference, kFreezeEntropy}},
+                {"-DS", {kReference, kReferenceAndUpdate, kReference}},
+                {"--D", {kReference, kReference, kReference, kFreezeEntropy}}};
       }
     case 4:
       // TL0 references and updates only the 'last' buffer.
       // TL1 references 'last' and updates and references 'golden'.
       // TL2 references 'last' and 'golden', and references and updates 'arf'.
       // TL3 references all buffers but update none of them.
-      return {
-          Vp8FrameConfig(kReferenceAndUpdate, kNone, kNone),
-          Vp8FrameConfig(kReference, kNone, kNone, kFreezeEntropy),
-          Vp8FrameConfig(kReference, kNone, kUpdate),
-          Vp8FrameConfig(kReference, kNone, kReference, kFreezeEntropy),
-          Vp8FrameConfig(kReference, kUpdate, kNone),
-          Vp8FrameConfig(kReference, kReference, kReference, kFreezeEntropy),
-          Vp8FrameConfig(kReference, kReference, kReferenceAndUpdate),
-          Vp8FrameConfig(kReference, kReference, kReference, kFreezeEntropy),
-          Vp8FrameConfig(kReferenceAndUpdate, kNone, kNone),
-          Vp8FrameConfig(kReference, kReference, kReference, kFreezeEntropy),
-          Vp8FrameConfig(kReference, kReference, kReferenceAndUpdate),
-          Vp8FrameConfig(kReference, kReference, kReference, kFreezeEntropy),
-          Vp8FrameConfig(kReference, kReferenceAndUpdate, kNone),
-          Vp8FrameConfig(kReference, kReference, kReference, kFreezeEntropy),
-          Vp8FrameConfig(kReference, kReference, kReferenceAndUpdate),
-          Vp8FrameConfig(kReference, kReference, kReference, kFreezeEntropy)};
+      // TODO(philipel): Set decode target information for this structure.
+      return {{"----", {kReferenceAndUpdate, kNone, kNone}},
+              {"----", {kReference, kNone, kNone, kFreezeEntropy}},
+              {"----", {kReference, kNone, kUpdate}},
+              {"----", {kReference, kNone, kReference, kFreezeEntropy}},
+              {"----", {kReference, kUpdate, kNone}},
+              {"----", {kReference, kReference, kReference, kFreezeEntropy}},
+              {"----", {kReference, kReference, kReferenceAndUpdate}},
+              {"----", {kReference, kReference, kReference, kFreezeEntropy}},
+              {"----", {kReferenceAndUpdate, kNone, kNone}},
+              {"----", {kReference, kReference, kReference, kFreezeEntropy}},
+              {"----", {kReference, kReference, kReferenceAndUpdate}},
+              {"----", {kReference, kReference, kReference, kFreezeEntropy}},
+              {"----", {kReference, kReferenceAndUpdate, kNone}},
+              {"----", {kReference, kReference, kReference, kFreezeEntropy}},
+              {"----", {kReference, kReference, kReferenceAndUpdate}},
+              {"----", {kReference, kReference, kReference, kFreezeEntropy}}};
     default:
       RTC_NOTREACHED();
       break;
   }
   RTC_NOTREACHED();
-  return {Vp8FrameConfig(kNone, kNone, kNone)};
+  return {{"", {kNone, kNone, kNone}}};
 }
 
 DefaultTemporalLayers::DefaultTemporalLayers(int number_of_temporal_layers)
     : num_layers_(std::max(1, number_of_temporal_layers)),
       temporal_ids_(GetTemporalIds(num_layers_)),
-      temporal_pattern_(GetTemporalPattern(num_layers_)),
-      kf_buffers_(FindKfBuffers(temporal_pattern_)),
+      temporal_pattern_(GetDependencyInfo(num_layers_)),
       pattern_idx_(kUninitializedPatternIndex) {
   RTC_CHECK_GE(kMaxTemporalStreams, number_of_temporal_layers);
   RTC_CHECK_GE(number_of_temporal_layers, 0);
@@ -257,6 +238,16 @@
   for (Vp8BufferReference buffer : kAllBuffers) {
     frames_since_buffer_refresh_[buffer] = 0;
   }
+
+  kf_buffers_ = {kAllBuffers.begin(), kAllBuffers.end()};
+  for (DependencyInfo info : temporal_pattern_) {
+    uint8_t updated_buffers = GetUpdatedBuffers(info.frame_config);
+
+    for (Vp8BufferReference buffer : kAllBuffers) {
+      if (static_cast<uint8_t>(buffer) & updated_buffers)
+        kf_buffers_.erase(buffer);
+    }
+  }
 }
 
 DefaultTemporalLayers::~DefaultTemporalLayers() = default;
@@ -347,7 +338,8 @@
   RTC_DCHECK_GT(temporal_pattern_.size(), 0);
 
   pattern_idx_ = (pattern_idx_ + 1) % temporal_pattern_.size();
-  Vp8FrameConfig tl_config = temporal_pattern_[pattern_idx_];
+  DependencyInfo dependency_info = temporal_pattern_[pattern_idx_];
+  Vp8FrameConfig& tl_config = dependency_info.frame_config;
   tl_config.encoder_layer_id = tl_config.packetizer_temporal_idx =
       temporal_ids_[pattern_idx_ % temporal_ids_.size()];
 
@@ -386,7 +378,7 @@
 
   // Add frame to set of pending frames, awaiting completion.
   pending_frames_[timestamp] =
-      PendingFrame{false, GetUpdatedBuffers(tl_config), tl_config};
+      PendingFrame{false, GetUpdatedBuffers(tl_config), dependency_info};
 
 #if RTC_DCHECK_IS_ON
   // Checker does not yet support encoder frame dropping, so validate flags
@@ -472,10 +464,11 @@
   }
 
   PendingFrame& frame = pending_frame->second;
+  const Vp8FrameConfig& frame_config = frame.dependency_info.frame_config;
 #if RTC_DCHECK_IS_ON
   if (is_keyframe) {
     // Signal key-frame so checker resets state.
-    RTC_DCHECK(checker_->CheckTemporalConfig(true, frame.frame_config));
+    RTC_DCHECK(checker_->CheckTemporalConfig(true, frame_config));
   }
 #endif
 
@@ -503,8 +496,8 @@
       }
     } else {
       // Delta frame, update codec specifics with temporal id and sync flag.
-      vp8_info.temporalIdx = frame.frame_config.packetizer_temporal_idx;
-      vp8_info.layerSync = frame.frame_config.layer_sync;
+      vp8_info.temporalIdx = frame_config.packetizer_temporal_idx;
+      vp8_info.layerSync = frame_config.layer_sync;
     }
   }
 
@@ -513,13 +506,13 @@
   RTC_DCHECK_EQ(vp8_info.updatedBuffersCount, 0u);
 
   for (int i = 0; i < static_cast<int>(Buffer::kCount); ++i) {
-    if (!is_keyframe && frame.frame_config.References(static_cast<Buffer>(i))) {
+    if (!is_keyframe && frame_config.References(static_cast<Buffer>(i))) {
       RTC_DCHECK_LT(vp8_info.referencedBuffersCount,
                     arraysize(CodecSpecificInfoVP8::referencedBuffers));
       vp8_info.referencedBuffers[vp8_info.referencedBuffersCount++] = i;
     }
 
-    if (is_keyframe || frame.frame_config.Updates(static_cast<Buffer>(i))) {
+    if (is_keyframe || frame_config.Updates(static_cast<Buffer>(i))) {
       RTC_DCHECK_LT(vp8_info.updatedBuffersCount,
                     arraysize(CodecSpecificInfoVP8::updatedBuffers));
       vp8_info.updatedBuffers[vp8_info.updatedBuffersCount++] = i;
@@ -532,6 +525,10 @@
     info->template_structure = GetTemplateStructure(num_layers_);
   }
 
+  GenericFrameInfo& generic_frame_info = info->generic_frame_info.emplace();
+  generic_frame_info.decode_target_indications =
+      frame.dependency_info.decode_target_indications;
+
   if (!frame.expired) {
     for (Vp8BufferReference buffer : kAllBuffers) {
       if (frame.updated_buffer_mask & static_cast<uint8_t>(buffer)) {
diff --git a/modules/video_coding/codecs/vp8/default_temporal_layers.h b/modules/video_coding/codecs/vp8/default_temporal_layers.h
index ee2333e..9aa95db 100644
--- a/modules/video_coding/codecs/vp8/default_temporal_layers.h
+++ b/modules/video_coding/codecs/vp8/default_temporal_layers.h
@@ -18,6 +18,7 @@
 #include <map>
 #include <memory>
 #include <set>
+#include <utility>
 #include <vector>
 
 #include "absl/types/optional.h"
@@ -61,7 +62,20 @@
   void OnRttUpdate(int64_t rtt_ms) override;
 
  private:
-  static std::vector<Vp8FrameConfig> GetTemporalPattern(size_t num_layers);
+  struct DependencyInfo {
+    DependencyInfo() = default;
+    DependencyInfo(absl::string_view indication_symbols,
+                   Vp8FrameConfig frame_config)
+        : decode_target_indications(
+              GenericFrameInfo::DecodeTargetInfo(indication_symbols)),
+          frame_config(frame_config) {}
+
+    absl::InlinedVector<GenericFrameInfo::DecodeTargetIndication, 10>
+        decode_target_indications;
+    Vp8FrameConfig frame_config;
+  };
+
+  static std::vector<DependencyInfo> GetDependencyInfo(size_t num_layers);
   bool IsSyncFrame(const Vp8FrameConfig& config) const;
   void ValidateReferences(Vp8FrameConfig::BufferFlags* flags,
                           Vp8FrameConfig::Vp8BufferReference ref) const;
@@ -69,9 +83,9 @@
 
   const size_t num_layers_;
   const std::vector<unsigned int> temporal_ids_;
-  const std::vector<Vp8FrameConfig> temporal_pattern_;
+  const std::vector<DependencyInfo> temporal_pattern_;
   // Set of buffers that are never updated except by keyframes.
-  const std::set<Vp8FrameConfig::Vp8BufferReference> kf_buffers_;
+  std::set<Vp8FrameConfig::Vp8BufferReference> kf_buffers_;
   TemplateStructure GetTemplateStructure(int num_layers) const;
 
   uint8_t pattern_idx_;
@@ -82,7 +96,7 @@
     PendingFrame();
     PendingFrame(bool expired,
                  uint8_t updated_buffers_mask,
-                 const Vp8FrameConfig& frame_config);
+                 const DependencyInfo& dependency_info);
     // Flag indicating if this frame has expired, ie it belongs to a previous
     // iteration of the temporal pattern.
     bool expired = false;
@@ -90,7 +104,7 @@
     // updates.
     uint8_t updated_buffer_mask = 0;
     // The frame config return by UpdateLayerConfig() for this frame.
-    Vp8FrameConfig frame_config;
+    DependencyInfo dependency_info;
   };
   // Map from rtp timestamp to pending frame status. Reset on pattern loop.
   std::map<uint32_t, PendingFrame> pending_frames_;
diff --git a/modules/video_coding/codecs/vp8/screenshare_layers.cc b/modules/video_coding/codecs/vp8/screenshare_layers.cc
index 9412ba4..11a1cbd 100644
--- a/modules/video_coding/codecs/vp8/screenshare_layers.cc
+++ b/modules/video_coding/codecs/vp8/screenshare_layers.cc
@@ -90,16 +90,16 @@
   auto it = pending_frame_configs_.find(timestamp);
   if (it != pending_frame_configs_.end()) {
     // Drop and re-encode, reuse the previous config.
-    return it->second;
+    return it->second.frame_config;
   }
 
   if (number_of_temporal_layers_ <= 1) {
     // No flags needed for 1 layer screenshare.
     // TODO(pbos): Consider updating only last, and not all buffers.
-    Vp8FrameConfig tl_config(kReferenceAndUpdate, kReferenceAndUpdate,
-                             kReferenceAndUpdate);
-    pending_frame_configs_[timestamp] = tl_config;
-    return tl_config;
+    DependencyInfo dependency_info{
+        "S", {kReferenceAndUpdate, kReferenceAndUpdate, kReferenceAndUpdate}};
+    pending_frame_configs_[timestamp] = dependency_info;
+    return dependency_info.frame_config;
   }
 
   const int64_t now_ms = rtc::TimeMillis();
@@ -199,35 +199,35 @@
       RTC_NOTREACHED();
   }
 
-  Vp8FrameConfig tl_config;
+  DependencyInfo dependency_info;
   // TODO(pbos): Consider referencing but not updating the 'alt' buffer for all
   // layers.
   switch (layer_state) {
     case TemporalLayerState::kDrop:
-      tl_config = Vp8FrameConfig(kNone, kNone, kNone);
+      dependency_info = {"", {kNone, kNone, kNone}};
       break;
     case TemporalLayerState::kTl0:
       // TL0 only references and updates 'last'.
-      tl_config = Vp8FrameConfig(kReferenceAndUpdate, kNone, kNone);
-      tl_config.packetizer_temporal_idx = 0;
+      dependency_info = {"SS", {kReferenceAndUpdate, kNone, kNone}};
+      dependency_info.frame_config.packetizer_temporal_idx = 0;
       break;
     case TemporalLayerState::kTl1:
       // TL1 references both 'last' and 'golden' but only updates 'golden'.
-      tl_config = Vp8FrameConfig(kReference, kReferenceAndUpdate, kNone);
-      tl_config.packetizer_temporal_idx = 1;
+      dependency_info = {"-R", {kReference, kReferenceAndUpdate, kNone}};
+      dependency_info.frame_config.packetizer_temporal_idx = 1;
       break;
     case TemporalLayerState::kTl1Sync:
       // Predict from only TL0 to allow participants to switch to the high
       // bitrate stream. Updates 'golden' so that TL1 can continue to refer to
       // and update 'golden' from this point on.
-      tl_config = Vp8FrameConfig(kReference, kUpdate, kNone);
-      tl_config.packetizer_temporal_idx = 1;
+      dependency_info = {"-S", {kReference, kUpdate, kNone}};
+      dependency_info.frame_config.packetizer_temporal_idx = 1;
+      dependency_info.frame_config.layer_sync = true;
       break;
   }
 
-  tl_config.layer_sync = layer_state == TemporalLayerState::kTl1Sync;
-  pending_frame_configs_[timestamp] = tl_config;
-  return tl_config;
+  pending_frame_configs_[timestamp] = dependency_info;
+  return dependency_info.frame_config;
 }
 
 void ScreenshareLayers::OnRatesUpdated(
@@ -286,28 +286,38 @@
     return;
   }
 
-  absl::optional<Vp8FrameConfig> frame_config;
+  absl::optional<DependencyInfo> dependency_info;
   auto it = pending_frame_configs_.find(rtp_timestamp);
   if (it != pending_frame_configs_.end()) {
-    frame_config = it->second;
+    dependency_info = it->second;
     pending_frame_configs_.erase(it);
 
     if (checker_) {
-      RTC_DCHECK(checker_->CheckTemporalConfig(is_keyframe, *frame_config));
+      RTC_DCHECK(checker_->CheckTemporalConfig(is_keyframe,
+                                               dependency_info->frame_config));
     }
   }
 
   CodecSpecificInfoVP8& vp8_info = info->codecSpecific.VP8;
+  GenericFrameInfo& generic_frame_info = info->generic_frame_info.emplace();
+
   if (number_of_temporal_layers_ == 1) {
     vp8_info.temporalIdx = kNoTemporalIdx;
     vp8_info.layerSync = false;
+    generic_frame_info.decode_target_indications =
+        GenericFrameInfo::DecodeTargetInfo("S");
   } else {
     int64_t unwrapped_timestamp = time_wrap_handler_.Unwrap(rtp_timestamp);
-    if (frame_config) {
-      vp8_info.temporalIdx = frame_config->packetizer_temporal_idx;
-      vp8_info.layerSync = frame_config->layer_sync;
+    if (dependency_info) {
+      vp8_info.temporalIdx =
+          dependency_info->frame_config.packetizer_temporal_idx;
+      vp8_info.layerSync = dependency_info->frame_config.layer_sync;
+      generic_frame_info.decode_target_indications =
+          dependency_info->decode_target_indications;
     } else {
       RTC_DCHECK(is_keyframe);
+      generic_frame_info.decode_target_indications =
+          GenericFrameInfo::DecodeTargetInfo("SS");
     }
 
     if (is_keyframe) {
@@ -328,13 +338,15 @@
     // Note that |frame_config| is not derefernced if |is_keyframe|,
     // meaning it's never dereferenced if the optional may be unset.
     for (int i = 0; i < static_cast<int>(Buffer::kCount); ++i) {
-      if (!is_keyframe && frame_config->References(static_cast<Buffer>(i))) {
+      if (!is_keyframe &&
+          dependency_info->frame_config.References(static_cast<Buffer>(i))) {
         RTC_DCHECK_LT(vp8_info.referencedBuffersCount,
                       arraysize(CodecSpecificInfoVP8::referencedBuffers));
         vp8_info.referencedBuffers[vp8_info.referencedBuffersCount++] = i;
       }
 
-      if (is_keyframe || frame_config->Updates(static_cast<Buffer>(i))) {
+      if (is_keyframe ||
+          dependency_info->frame_config.Updates(static_cast<Buffer>(i))) {
         RTC_DCHECK_LT(vp8_info.updatedBuffersCount,
                       arraysize(CodecSpecificInfoVP8::updatedBuffers));
         vp8_info.updatedBuffers[vp8_info.updatedBuffersCount++] = i;
diff --git a/modules/video_coding/codecs/vp8/screenshare_layers.h b/modules/video_coding/codecs/vp8/screenshare_layers.h
index 6b1bc7e..8fe5fa3 100644
--- a/modules/video_coding/codecs/vp8/screenshare_layers.h
+++ b/modules/video_coding/codecs/vp8/screenshare_layers.h
@@ -11,6 +11,7 @@
 
 #include <map>
 #include <memory>
+#include <utility>
 #include <vector>
 
 #include "api/video_codecs/vp8_frame_config.h"
@@ -67,6 +68,19 @@
  private:
   enum class TemporalLayerState : int { kDrop, kTl0, kTl1, kTl1Sync };
 
+  struct DependencyInfo {
+    DependencyInfo() = default;
+    DependencyInfo(absl::string_view indication_symbols,
+                   Vp8FrameConfig frame_config)
+        : decode_target_indications(
+              GenericFrameInfo::DecodeTargetInfo(indication_symbols)),
+          frame_config(frame_config) {}
+
+    absl::InlinedVector<GenericFrameInfo::DecodeTargetIndication, 10>
+        decode_target_indications;
+    Vp8FrameConfig frame_config;
+  };
+
   bool TimeToSync(int64_t timestamp) const;
   uint32_t GetCodecTargetBitrateKbps() const;
 
@@ -81,7 +95,7 @@
   int max_qp_;
   uint32_t max_debt_bytes_;
 
-  std::map<uint32_t, Vp8FrameConfig> pending_frame_configs_;
+  std::map<uint32_t, DependencyInfo> pending_frame_configs_;
 
   // Configured max framerate.
   absl::optional<uint32_t> target_framerate_;