Generic Frame Descriptor (GFD) VP8 templates.

In this CL:
 - Updated Vp8TemporalLayers::OnEncodeDone to take a CodecSpecificInfo
   instead of a CodecSpecificInfoVP8, so that both the VP8 specific and
   generic information can be populated.
 - Added structs to represent the GFD template structure.
 - Added code to generate templates for video/screensharing.

Bug: webrtc:10342
Change-Id: I978f9d708597a6f86bbdc494e62acf7a7b400db3
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/123422
Commit-Queue: Philip Eliasson <philipel@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26987}
diff --git a/modules/video_coding/BUILD.gn b/modules/video_coding/BUILD.gn
index ffd58a2..fb67178 100644
--- a/modules/video_coding/BUILD.gn
+++ b/modules/video_coding/BUILD.gn
@@ -185,6 +185,7 @@
 rtc_source_set("video_codec_interface") {
   visibility = [ "*" ]
   sources = [
+    "include/video_codec_interface.cc",
     "include/video_codec_interface.h",
     "include/video_coding_defines.h",
     "include/video_error_codes.h",
@@ -196,6 +197,7 @@
     "../../api/video:video_frame",
     "../../api/video_codecs:video_codecs_api",
     "../../common_video:common_video",
+    "../../common_video/generic_frame_descriptor:generic_frame_descriptor",
     "//third_party/abseil-cpp/absl/types:optional",
   ]
 }
diff --git a/modules/video_coding/codecs/vp8/default_temporal_layers.cc b/modules/video_coding/codecs/vp8/default_temporal_layers.cc
index 47b1bef..61dca09 100644
--- a/modules/video_coding/codecs/vp8/default_temporal_layers.cc
+++ b/modules/video_coding/codecs/vp8/default_temporal_layers.cc
@@ -444,7 +444,7 @@
                                          size_t size_bytes,
                                          bool is_keyframe,
                                          int qp,
-                                         CodecSpecificInfoVP8* vp8_info) {
+                                         CodecSpecificInfo* info) {
   RTC_DCHECK_GT(num_layers_, 0);
 
   auto pending_frame = pending_frames_.find(rtp_timestamp);
@@ -463,15 +463,16 @@
   }
 #endif
 
+  CodecSpecificInfoVP8& vp8_info = info->codecSpecific.VP8;
   if (num_layers_ == 1) {
-    vp8_info->temporalIdx = kNoTemporalIdx;
-    vp8_info->layerSync = false;
+    vp8_info.temporalIdx = kNoTemporalIdx;
+    vp8_info.layerSync = false;
   } else {
     if (is_keyframe) {
       // Restart the temporal pattern on keyframes.
       pattern_idx_ = 0;
-      vp8_info->temporalIdx = 0;
-      vp8_info->layerSync = true;  // Keyframes are always sync frames.
+      vp8_info.temporalIdx = 0;
+      vp8_info.layerSync = true;  // Keyframes are always sync frames.
 
       for (Vp8BufferReference buffer : kAllBuffers) {
         if (kf_buffers_.find(buffer) != kf_buffers_.end()) {
@@ -486,29 +487,35 @@
       }
     } 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.frame_config.packetizer_temporal_idx;
+      vp8_info.layerSync = frame.frame_config.layer_sync;
     }
   }
 
-  vp8_info->useExplicitDependencies = true;
-  RTC_DCHECK_EQ(vp8_info->referencedBuffersCount, 0u);
-  RTC_DCHECK_EQ(vp8_info->updatedBuffersCount, 0u);
+  vp8_info.useExplicitDependencies = true;
+  RTC_DCHECK_EQ(vp8_info.referencedBuffersCount, 0u);
+  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))) {
-      RTC_DCHECK_LT(vp8_info->referencedBuffersCount,
+      RTC_DCHECK_LT(vp8_info.referencedBuffersCount,
                     arraysize(CodecSpecificInfoVP8::referencedBuffers));
-      vp8_info->referencedBuffers[vp8_info->referencedBuffersCount++] = i;
+      vp8_info.referencedBuffers[vp8_info.referencedBuffersCount++] = i;
     }
 
     if (is_keyframe || frame.frame_config.Updates(static_cast<Buffer>(i))) {
-      RTC_DCHECK_LT(vp8_info->updatedBuffersCount,
+      RTC_DCHECK_LT(vp8_info.updatedBuffersCount,
                     arraysize(CodecSpecificInfoVP8::updatedBuffers));
-      vp8_info->updatedBuffers[vp8_info->updatedBuffersCount++] = i;
+      vp8_info.updatedBuffers[vp8_info.updatedBuffersCount++] = i;
     }
   }
 
+  // The templates are always present on keyframes, and then refered to by
+  // subsequent frames.
+  if (is_keyframe) {
+    info->template_structure = GetTemplateStructure(num_layers_);
+  }
+
   if (!frame.expired) {
     for (Vp8BufferReference buffer : kAllBuffers) {
       if (frame.updated_buffer_mask & static_cast<uint8_t>(buffer)) {
@@ -518,6 +525,65 @@
   }
 }
 
+TemplateStructure DefaultTemporalLayers::GetTemplateStructure(
+    int num_layers) const {
+  RTC_CHECK_LT(num_layers, 5);
+  RTC_CHECK_GT(num_layers, 0);
+
+  TemplateStructure template_structure;
+  template_structure.num_operating_points = num_layers;
+
+  using Builder = GenericFrameInfo::Builder;
+  switch (num_layers) {
+    case 1: {
+      template_structure.templates = {
+          Builder().T(0).Dtis("S").Build(),
+          Builder().T(0).Dtis("S").Fdiffs({1}).Build(),
+      };
+      return template_structure;
+    }
+    case 2: {
+      template_structure.templates = {
+          Builder().T(0).Dtis("SS").Build(),
+          Builder().T(0).Dtis("SS").Fdiffs({2}).Build(),
+          Builder().T(0).Dtis("SR").Fdiffs({2}).Build(),
+          Builder().T(1).Dtis("-S").Fdiffs({1}).Build(),
+          Builder().T(1).Dtis("-D").Fdiffs({1, 2}).Build(),
+      };
+      return template_structure;
+    }
+    case 3: {
+      template_structure.templates = {
+          Builder().T(0).Dtis("SSS").Build(),
+          Builder().T(0).Dtis("SSS").Fdiffs({4}).Build(),
+          Builder().T(0).Dtis("SRR").Fdiffs({4}).Build(),
+          Builder().T(1).Dtis("-SR").Fdiffs({2}).Build(),
+          Builder().T(1).Dtis("-DR").Fdiffs({2, 4}).Build(),
+          Builder().T(2).Dtis("--D").Fdiffs({1}).Build(),
+          Builder().T(2).Dtis("--D").Fdiffs({1, 3}).Build(),
+      };
+      return template_structure;
+    }
+    case 4: {
+      template_structure.templates = {
+          Builder().T(0).Dtis("SSSS").Build(),
+          Builder().T(0).Dtis("SSSS").Fdiffs({8}).Build(),
+          Builder().T(1).Dtis("-SRR").Fdiffs({4}).Build(),
+          Builder().T(1).Dtis("-SRR").Fdiffs({4, 8}).Build(),
+          Builder().T(2).Dtis("--SR").Fdiffs({2}).Build(),
+          Builder().T(2).Dtis("--SR").Fdiffs({2, 4}).Build(),
+          Builder().T(3).Dtis("---D").Fdiffs({1}).Build(),
+          Builder().T(3).Dtis("---D").Fdiffs({1, 3}).Build(),
+      };
+      return template_structure;
+    }
+    default:
+      RTC_NOTREACHED();
+      // To make the compiler happy!
+      return template_structure;
+  }
+}
+
 // Returns list of temporal dependencies for each frame in the temporal pattern.
 // Values are lists of indecies in the pattern.
 std::vector<std::set<uint8_t>> GetTemporalDependencies(
diff --git a/modules/video_coding/codecs/vp8/default_temporal_layers.h b/modules/video_coding/codecs/vp8/default_temporal_layers.h
index d04e4f4..8deeb40 100644
--- a/modules/video_coding/codecs/vp8/default_temporal_layers.h
+++ b/modules/video_coding/codecs/vp8/default_temporal_layers.h
@@ -49,7 +49,7 @@
                     size_t size_bytes,
                     bool is_keyframe,
                     int qp,
-                    CodecSpecificInfoVP8* vp8_info) override;
+                    CodecSpecificInfo* info) override;
 
  private:
   static constexpr size_t kKeyframeBuffer = std::numeric_limits<size_t>::max();
@@ -64,6 +64,7 @@
   const std::vector<Vp8FrameConfig> temporal_pattern_;
   // Set of buffers that are never updated except by keyframes.
   const std::set<Vp8FrameConfig::Vp8BufferReference> kf_buffers_;
+  TemplateStructure GetTemplateStructure(int num_layers) const;
 
   uint8_t pattern_idx_;
   // Updated cumulative bitrates, per temporal layer.
diff --git a/modules/video_coding/codecs/vp8/default_temporal_layers_unittest.cc b/modules/video_coding/codecs/vp8/default_temporal_layers_unittest.cc
index ae72ec9..37e6620 100644
--- a/modules/video_coding/codecs/vp8/default_temporal_layers_unittest.cc
+++ b/modules/video_coding/codecs/vp8/default_temporal_layers_unittest.cc
@@ -107,9 +107,9 @@
  public:
   ~TemporalLayersTest() override = default;
 
-  CodecSpecificInfoVP8* IgnoredCodecSpecificInfoVp8() {
+  CodecSpecificInfo* IgnoredCodecSpecificInfo() {
     codec_specific_info_ = absl::make_unique<CodecSpecificInfo>();
-    return &codec_specific_info_->codecSpecific.VP8;
+    return codec_specific_info_.get();
   }
 
  private:
@@ -142,17 +142,17 @@
   for (size_t i = 0; i < kPatternSize * kRepetitions; ++i) {
     const size_t ind = i % kPatternSize;
     CodecSpecificInfo info;
-    CodecSpecificInfoVP8& vp8_info = info.codecSpecific.VP8;
     Vp8FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
     EXPECT_EQ(expected_flags[ind], LibvpxVp8Encoder::EncodeFlags(tl_config))
         << i;
     tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, i == 0, kDefaultQp,
-                    &vp8_info);
+                    &info);
     EXPECT_TRUE(checker.CheckTemporalConfig(i == 0, tl_config));
-    EXPECT_EQ(expected_temporal_idx[ind], vp8_info.temporalIdx);
+    EXPECT_EQ(expected_temporal_idx[ind], info.codecSpecific.VP8.temporalIdx);
     EXPECT_EQ(expected_temporal_idx[ind], tl_config.packetizer_temporal_idx);
     EXPECT_EQ(expected_temporal_idx[ind], tl_config.encoder_layer_id);
-    EXPECT_EQ(i == 0 || expected_layer_sync[ind], vp8_info.layerSync);
+    EXPECT_EQ(i == 0 || expected_layer_sync[ind],
+              info.codecSpecific.VP8.layerSync);
     EXPECT_EQ(expected_layer_sync[ind], tl_config.layer_sync);
     timestamp += 3000;
   }
@@ -196,16 +196,16 @@
   unsigned int timestamp = 0;
   for (int i = 0; i < 16; ++i) {
     CodecSpecificInfo info;
-    CodecSpecificInfoVP8& vp8_info = info.codecSpecific.VP8;
     Vp8FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
     EXPECT_EQ(expected_flags[i], LibvpxVp8Encoder::EncodeFlags(tl_config)) << i;
     tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, i == 0, kDefaultQp,
-                    &vp8_info);
+                    &info);
     EXPECT_TRUE(checker.CheckTemporalConfig(i == 0, tl_config));
-    EXPECT_EQ(expected_temporal_idx[i], vp8_info.temporalIdx);
+    EXPECT_EQ(expected_temporal_idx[i], info.codecSpecific.VP8.temporalIdx);
     EXPECT_EQ(expected_temporal_idx[i], tl_config.packetizer_temporal_idx);
     EXPECT_EQ(expected_temporal_idx[i], tl_config.encoder_layer_id);
-    EXPECT_EQ(i == 0 || expected_layer_sync[i], vp8_info.layerSync);
+    EXPECT_EQ(i == 0 || expected_layer_sync[i],
+              info.codecSpecific.VP8.layerSync);
     EXPECT_EQ(expected_layer_sync[i], tl_config.layer_sync);
     timestamp += 3000;
   }
@@ -238,16 +238,16 @@
   unsigned int timestamp = 0;
   for (int i = 0; i < 8; ++i) {
     CodecSpecificInfo info;
-    CodecSpecificInfoVP8& vp8_info = info.codecSpecific.VP8;
     Vp8FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
     EXPECT_EQ(expected_flags[i], LibvpxVp8Encoder::EncodeFlags(tl_config)) << i;
     tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, i == 0, kDefaultQp,
-                    &vp8_info);
+                    &info);
     EXPECT_TRUE(checker.CheckTemporalConfig(i == 0, tl_config));
-    EXPECT_EQ(expected_temporal_idx[i], vp8_info.temporalIdx);
+    EXPECT_EQ(expected_temporal_idx[i], info.codecSpecific.VP8.temporalIdx);
     EXPECT_EQ(expected_temporal_idx[i], tl_config.packetizer_temporal_idx);
     EXPECT_EQ(expected_temporal_idx[i], tl_config.encoder_layer_id);
-    EXPECT_EQ(i == 0 || expected_layer_sync[i], vp8_info.layerSync);
+    EXPECT_EQ(i == 0 || expected_layer_sync[i],
+              info.codecSpecific.VP8.layerSync);
     EXPECT_EQ(expected_layer_sync[i], tl_config.layer_sync);
     timestamp += 3000;
   }
@@ -271,19 +271,19 @@
   uint32_t timestamp = 0;
   Vp8FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
   tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, true, kDefaultQp,
-                  IgnoredCodecSpecificInfoVp8());
+                  IgnoredCodecSpecificInfo());
 
   // TL2 frame. First one only references TL0. Updates altref.
   tl_config = tl.UpdateLayerConfig(++timestamp);
   tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
-                  IgnoredCodecSpecificInfoVp8());
+                  IgnoredCodecSpecificInfo());
   EXPECT_EQ(tl_config.first_reference, Vp8BufferReference::kLast);
   EXPECT_EQ(tl_config.second_reference, Vp8BufferReference::kNone);
 
   // TL1 frame. Can only reference TL0. Updated golden.
   tl_config = tl.UpdateLayerConfig(++timestamp);
   tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
-                  IgnoredCodecSpecificInfoVp8());
+                  IgnoredCodecSpecificInfo());
   EXPECT_EQ(tl_config.first_reference, Vp8BufferReference::kLast);
   EXPECT_EQ(tl_config.second_reference, Vp8BufferReference::kNone);
 
@@ -291,7 +291,7 @@
   // updated, the next to last was altref.
   tl_config = tl.UpdateLayerConfig(++timestamp);
   tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
-                  IgnoredCodecSpecificInfoVp8());
+                  IgnoredCodecSpecificInfo());
   EXPECT_EQ(tl_config.first_reference, Vp8BufferReference::kGolden);
   EXPECT_EQ(tl_config.second_reference, Vp8BufferReference::kAltref);
 }
@@ -314,12 +314,12 @@
   uint32_t timestamp = 0;
   Vp8FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
   tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, true, kDefaultQp,
-                  IgnoredCodecSpecificInfoVp8());
+                  IgnoredCodecSpecificInfo());
 
   // TL2 frame. First one only references TL0. Updates altref.
   tl_config = tl.UpdateLayerConfig(++timestamp);
   tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
-                  IgnoredCodecSpecificInfoVp8());
+                  IgnoredCodecSpecificInfo());
   EXPECT_EQ(tl_config.first_reference, Vp8BufferReference::kLast);
   EXPECT_EQ(tl_config.second_reference, Vp8BufferReference::kNone);
 
@@ -331,7 +331,7 @@
   // been populated this cycle. Altref was last to be updated, before that last.
   tl_config = tl.UpdateLayerConfig(++timestamp);
   tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
-                  IgnoredCodecSpecificInfoVp8());
+                  IgnoredCodecSpecificInfo());
   EXPECT_EQ(tl_config.first_reference, Vp8BufferReference::kAltref);
   EXPECT_EQ(tl_config.second_reference, Vp8BufferReference::kLast);
 }
@@ -373,16 +373,16 @@
   uint32_t timestamp = 0;
   for (int i = 0; i < 16; ++i) {
     CodecSpecificInfo info;
-    CodecSpecificInfoVP8& vp8_info = info.codecSpecific.VP8;
     Vp8FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
     EXPECT_EQ(expected_flags[i], LibvpxVp8Encoder::EncodeFlags(tl_config)) << i;
     tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, i == 0, kDefaultQp,
-                    &vp8_info);
+                    &info);
     EXPECT_TRUE(checker.CheckTemporalConfig(i == 0, tl_config));
-    EXPECT_EQ(expected_temporal_idx[i], vp8_info.temporalIdx);
+    EXPECT_EQ(expected_temporal_idx[i], info.codecSpecific.VP8.temporalIdx);
     EXPECT_EQ(expected_temporal_idx[i], tl_config.packetizer_temporal_idx);
     EXPECT_EQ(expected_temporal_idx[i], tl_config.encoder_layer_id);
-    EXPECT_EQ(i == 0 || expected_layer_sync[i], vp8_info.layerSync);
+    EXPECT_EQ(i == 0 || expected_layer_sync[i],
+              info.codecSpecific.VP8.layerSync);
     EXPECT_EQ(expected_layer_sync[i], tl_config.layer_sync);
     timestamp += 3000;
   }
@@ -405,7 +405,7 @@
   uint32_t timestamp = 0;
   Vp8FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
   tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, true, kDefaultQp,
-                  IgnoredCodecSpecificInfoVp8());
+                  IgnoredCodecSpecificInfo());
 
   // Dropped TL2 frame.
   tl_config = tl.UpdateLayerConfig(++timestamp);
@@ -419,7 +419,7 @@
   // both contain the last keyframe.
   tl_config = tl.UpdateLayerConfig(++timestamp);
   tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
-                  IgnoredCodecSpecificInfoVp8());
+                  IgnoredCodecSpecificInfo());
   EXPECT_TRUE(tl_config.last_buffer_flags & BufferFlags::kReference);
   EXPECT_TRUE(tl_config.golden_buffer_flags & BufferFlags::kReference);
   EXPECT_TRUE(tl_config.arf_buffer_flags & BufferFlags::kReference);
@@ -429,23 +429,23 @@
   // TL0 base layer frame, updating and referencing last.
   tl_config = tl.UpdateLayerConfig(++timestamp);
   tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
-                  IgnoredCodecSpecificInfoVp8());
+                  IgnoredCodecSpecificInfo());
 
   // TL2 frame, updating altref.
   tl_config = tl.UpdateLayerConfig(++timestamp);
   tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
-                  IgnoredCodecSpecificInfoVp8());
+                  IgnoredCodecSpecificInfo());
 
   // TL1 frame, updating golden.
   tl_config = tl.UpdateLayerConfig(++timestamp);
   tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
-                  IgnoredCodecSpecificInfoVp8());
+                  IgnoredCodecSpecificInfo());
 
   // TL2 frame. Can still reference all buffer since they have been update this
   // cycle.
   tl_config = tl.UpdateLayerConfig(++timestamp);
   tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
-                  IgnoredCodecSpecificInfoVp8());
+                  IgnoredCodecSpecificInfo());
   EXPECT_TRUE(tl_config.last_buffer_flags & BufferFlags::kReference);
   EXPECT_TRUE(tl_config.golden_buffer_flags & BufferFlags::kReference);
   EXPECT_TRUE(tl_config.arf_buffer_flags & BufferFlags::kReference);
@@ -455,7 +455,7 @@
   // TL0 base layer frame, updating and referencing last.
   tl_config = tl.UpdateLayerConfig(++timestamp);
   tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
-                  IgnoredCodecSpecificInfoVp8());
+                  IgnoredCodecSpecificInfo());
 
   // Dropped TL2 frame.
   tl_config = tl.UpdateLayerConfig(++timestamp);
@@ -469,7 +469,7 @@
   // and cannot be referenced.
   tl_config = tl.UpdateLayerConfig(++timestamp);
   tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
-                  IgnoredCodecSpecificInfoVp8());
+                  IgnoredCodecSpecificInfo());
   EXPECT_TRUE(tl_config.last_buffer_flags & BufferFlags::kReference);
   EXPECT_FALSE(tl_config.golden_buffer_flags & BufferFlags::kReference);
   EXPECT_FALSE(tl_config.arf_buffer_flags & BufferFlags::kReference);
@@ -491,24 +491,24 @@
   uint32_t timestamp = 0;
   Vp8FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
   tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, true, kDefaultQp,
-                  IgnoredCodecSpecificInfoVp8());
+                  IgnoredCodecSpecificInfo());
 
   // Do a full cycle of the pattern.
   for (int i = 0; i < 7; ++i) {
     tl_config = tl.UpdateLayerConfig(++timestamp);
     tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
-                    IgnoredCodecSpecificInfoVp8());
+                    IgnoredCodecSpecificInfo());
   }
 
   // TL0 base layer frame, starting the cycle over.
   tl_config = tl.UpdateLayerConfig(++timestamp);
   tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
-                  IgnoredCodecSpecificInfoVp8());
+                  IgnoredCodecSpecificInfo());
 
   // TL2 frame.
   tl_config = tl.UpdateLayerConfig(++timestamp);
   tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
-                  IgnoredCodecSpecificInfoVp8());
+                  IgnoredCodecSpecificInfo());
 
   // Encoder has a hiccup and builds a queue, so frame encoding is delayed.
   // TL1 frame, updating golden.
@@ -528,13 +528,13 @@
   // buffers are now OK to reference.
   // Enqueued TL1 frame ready.
   tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
-                  IgnoredCodecSpecificInfoVp8());
+                  IgnoredCodecSpecificInfo());
   // Enqueued TL2 frame.
   tl.OnEncodeDone(++timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
-                  IgnoredCodecSpecificInfoVp8());
+                  IgnoredCodecSpecificInfo());
   // Enqueued TL0 frame.
   tl.OnEncodeDone(++timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
-                  IgnoredCodecSpecificInfoVp8());
+                  IgnoredCodecSpecificInfo());
 
   // TL2 frame, all buffers are now in a known good state, OK to reference.
   tl_config = tl.UpdateLayerConfig(++timestamp + 1);
@@ -560,24 +560,24 @@
   uint32_t timestamp = 0;
   Vp8FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
   tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, true, kDefaultQp,
-                  IgnoredCodecSpecificInfoVp8());
+                  IgnoredCodecSpecificInfo());
 
   // Do a full cycle of the pattern.
   for (int i = 0; i < 3; ++i) {
     tl_config = tl.UpdateLayerConfig(++timestamp);
     tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
-                    IgnoredCodecSpecificInfoVp8());
+                    IgnoredCodecSpecificInfo());
   }
 
   // TL0 base layer frame, starting the cycle over.
   tl_config = tl.UpdateLayerConfig(++timestamp);
   tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
-                  IgnoredCodecSpecificInfoVp8());
+                  IgnoredCodecSpecificInfo());
 
   // TL2 frame.
   tl_config = tl.UpdateLayerConfig(++timestamp);
   tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
-                  IgnoredCodecSpecificInfoVp8());
+                  IgnoredCodecSpecificInfo());
 
   // Encoder has a hiccup and builds a queue, so frame encoding is delayed.
   // Encoded, but delayed frames in TL 1, 2.
@@ -592,10 +592,10 @@
 
   // TL1 frame from last cycle is ready.
   tl.OnEncodeDone(timestamp + 1, kDefaultBytesPerFrame, false, kDefaultQp,
-                  IgnoredCodecSpecificInfoVp8());
+                  IgnoredCodecSpecificInfo());
   // TL2 frame from last cycle is ready.
   tl.OnEncodeDone(timestamp + 2, kDefaultBytesPerFrame, false, kDefaultQp,
-                  IgnoredCodecSpecificInfoVp8());
+                  IgnoredCodecSpecificInfo());
 
   // TL2 frame, that should be referencing all buffers, but altref and golden
   // haven not been updated this cycle. (Don't be fooled by the late frames from
@@ -641,7 +641,7 @@
       EXPECT_EQ(expected_flags[j], LibvpxVp8Encoder::EncodeFlags(tl_config))
           << j;
       tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, false, kDefaultQp,
-                      IgnoredCodecSpecificInfoVp8());
+                      IgnoredCodecSpecificInfo());
       EXPECT_TRUE(checker.CheckTemporalConfig(false, tl_config));
       EXPECT_EQ(expected_temporal_idx[j], tl_config.packetizer_temporal_idx);
       EXPECT_EQ(expected_temporal_idx[j], tl_config.encoder_layer_id);
@@ -650,12 +650,11 @@
     }
 
     CodecSpecificInfo info;
-    CodecSpecificInfoVP8& vp8_info = info.codecSpecific.VP8;
     Vp8FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
-    tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, true, kDefaultQp,
-                    &vp8_info);
-    EXPECT_TRUE(vp8_info.layerSync) << "Key frame should be marked layer sync.";
-    EXPECT_EQ(0, vp8_info.temporalIdx)
+    tl.OnEncodeDone(timestamp, kDefaultBytesPerFrame, true, kDefaultQp, &info);
+    EXPECT_TRUE(info.codecSpecific.VP8.layerSync)
+        << "Key frame should be marked layer sync.";
+    EXPECT_EQ(0, info.codecSpecific.VP8.temporalIdx)
         << "Key frame should always be packetized as layer 0";
     EXPECT_TRUE(checker.CheckTemporalConfig(true, tl_config));
   }
@@ -741,7 +740,7 @@
   for (int i = 0; i < kMaxPatternLength; ++i) {
     Vp8FrameConfig tl_config = tl.UpdateLayerConfig(timestamp_);
     tl.OnEncodeDone(timestamp_, kDefaultBytesPerFrame, i == 0, kDefaultQp,
-                    IgnoredCodecSpecificInfoVp8());
+                    IgnoredCodecSpecificInfo());
     ++timestamp_;
     EXPECT_FALSE(tl_config.drop_frame);
     tl_configs.push_back(tl_config);
diff --git a/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc
index 1dc0837..e8a6d25 100644
--- a/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc
+++ b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc
@@ -850,15 +850,16 @@
                                              uint32_t timestamp) {
   assert(codec_specific != NULL);
   codec_specific->codecType = kVideoCodecVP8;
-  CodecSpecificInfoVP8* vp8Info = &(codec_specific->codecSpecific.VP8);
-  vp8Info->keyIdx = kNoKeyIdx;  // TODO(hlundin) populate this
-  vp8Info->nonReference = (pkt.data.frame.flags & VPX_FRAME_IS_DROPPABLE) != 0;
+  codec_specific->codecSpecific.VP8.keyIdx =
+      kNoKeyIdx;  // TODO(hlundin) populate this
+  codec_specific->codecSpecific.VP8.nonReference =
+      (pkt.data.frame.flags & VPX_FRAME_IS_DROPPABLE) != 0;
 
   int qp = 0;
   vpx_codec_control(&encoders_[encoder_idx], VP8E_GET_LAST_QUANTIZER_64, &qp);
   temporal_layers_[stream_idx]->OnEncodeDone(
       timestamp, encoded_images_[encoder_idx].size(),
-      (pkt.data.frame.flags & VPX_FRAME_IS_KEY) != 0, qp, vp8Info);
+      (pkt.data.frame.flags & VPX_FRAME_IS_KEY) != 0, qp, codec_specific);
 }
 
 int LibvpxVp8Encoder::GetEncodedPartitions(const VideoFrame& input_image) {
diff --git a/modules/video_coding/codecs/vp8/screenshare_layers.cc b/modules/video_coding/codecs/vp8/screenshare_layers.cc
index d3f4d42..17b1aed 100644
--- a/modules/video_coding/codecs/vp8/screenshare_layers.cc
+++ b/modules/video_coding/codecs/vp8/screenshare_layers.cc
@@ -265,7 +265,7 @@
                                      size_t size_bytes,
                                      bool is_keyframe,
                                      int qp,
-                                     CodecSpecificInfoVP8* vp8_info) {
+                                     CodecSpecificInfo* info) {
   if (size_bytes == 0) {
     layers_[active_layer_].state = TemporalLayer::State::kDropped;
     ++stats_.num_overshoots_;
@@ -283,44 +283,47 @@
     }
   }
 
+  CodecSpecificInfoVP8& vp8_info = info->codecSpecific.VP8;
   if (number_of_temporal_layers_ == 1) {
-    vp8_info->temporalIdx = kNoTemporalIdx;
-    vp8_info->layerSync = false;
+    vp8_info.temporalIdx = kNoTemporalIdx;
+    vp8_info.layerSync = false;
   } 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;
+      vp8_info.temporalIdx = frame_config->packetizer_temporal_idx;
+      vp8_info.layerSync = frame_config->layer_sync;
     } else {
       RTC_DCHECK(is_keyframe);
     }
 
     if (is_keyframe) {
-      vp8_info->temporalIdx = 0;
+      vp8_info.temporalIdx = 0;
       last_sync_timestamp_ = unwrapped_timestamp;
-      vp8_info->layerSync = true;
+      vp8_info.layerSync = true;
       layers_[0].state = TemporalLayer::State::kKeyFrame;
       layers_[1].state = TemporalLayer::State::kKeyFrame;
       active_layer_ = 1;
+      info->template_structure =
+          GetTemplateStructure(number_of_temporal_layers_);
     }
 
-    vp8_info->useExplicitDependencies = true;
-    RTC_DCHECK_EQ(vp8_info->referencedBuffersCount, 0u);
-    RTC_DCHECK_EQ(vp8_info->updatedBuffersCount, 0u);
+    vp8_info.useExplicitDependencies = true;
+    RTC_DCHECK_EQ(vp8_info.referencedBuffersCount, 0u);
+    RTC_DCHECK_EQ(vp8_info.updatedBuffersCount, 0u);
 
     // 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))) {
-        RTC_DCHECK_LT(vp8_info->referencedBuffersCount,
+        RTC_DCHECK_LT(vp8_info.referencedBuffersCount,
                       arraysize(CodecSpecificInfoVP8::referencedBuffers));
-        vp8_info->referencedBuffers[vp8_info->referencedBuffersCount++] = i;
+        vp8_info.referencedBuffers[vp8_info.referencedBuffersCount++] = i;
       }
 
       if (is_keyframe || frame_config->Updates(static_cast<Buffer>(i))) {
-        RTC_DCHECK_LT(vp8_info->updatedBuffersCount,
+        RTC_DCHECK_LT(vp8_info.updatedBuffersCount,
                       arraysize(CodecSpecificInfoVP8::updatedBuffers));
-        vp8_info->updatedBuffers[vp8_info->updatedBuffersCount++] = i;
+        vp8_info.updatedBuffers[vp8_info.updatedBuffersCount++] = i;
       }
     }
   }
@@ -352,6 +355,38 @@
   }
 }
 
+TemplateStructure ScreenshareLayers::GetTemplateStructure(
+    int num_layers) const {
+  RTC_CHECK_LT(num_layers, 3);
+  RTC_CHECK_GT(num_layers, 0);
+
+  TemplateStructure template_structure;
+  template_structure.num_operating_points = num_layers;
+
+  using Builder = GenericFrameInfo::Builder;
+  switch (num_layers) {
+    case 1: {
+      template_structure.templates = {
+          Builder().T(0).Dtis("S").Build(),
+          Builder().T(0).Dtis("S").Fdiffs({1}).Build(),
+      };
+      return template_structure;
+    }
+    case 2: {
+      template_structure.templates = {
+          Builder().T(0).Dtis("SS").Build(),
+          Builder().T(0).Dtis("SS").Fdiffs({1}).Build(),
+          Builder().T(1).Dtis("-S").Fdiffs({1}).Build(),
+      };
+      return template_structure;
+    }
+    default:
+      RTC_NOTREACHED();
+      // To make the compiler happy!
+      return template_structure;
+  }
+}
+
 bool ScreenshareLayers::TimeToSync(int64_t timestamp) const {
   RTC_DCHECK_EQ(1, active_layer_);
   RTC_DCHECK_NE(-1, layers_[0].last_qp);
diff --git a/modules/video_coding/codecs/vp8/screenshare_layers.h b/modules/video_coding/codecs/vp8/screenshare_layers.h
index b1dbde8..1c96796 100644
--- a/modules/video_coding/codecs/vp8/screenshare_layers.h
+++ b/modules/video_coding/codecs/vp8/screenshare_layers.h
@@ -16,6 +16,7 @@
 #include "api/video_codecs/vp8_frame_config.h"
 #include "api/video_codecs/vp8_temporal_layers.h"
 #include "modules/video_coding/codecs/vp8/include/temporal_layers_checker.h"
+#include "modules/video_coding/include/video_codec_interface.h"
 #include "modules/video_coding/utility/frame_dropper.h"
 #include "rtc_base/rate_statistics.h"
 #include "rtc_base/time_utils.h"
@@ -52,7 +53,7 @@
                     size_t size_bytes,
                     bool is_keyframe,
                     int qp,
-                    CodecSpecificInfoVP8* vp8_info) override;
+                    CodecSpecificInfo* info) override;
 
  private:
   enum class TemporalLayerState : int { kDrop, kTl0, kTl1, kTl1Sync };
@@ -77,6 +78,7 @@
   absl::optional<uint32_t> target_framerate_;
   // Incoming framerate from capturer.
   absl::optional<uint32_t> capture_framerate_;
+
   // Tracks what framerate we actually encode, and drops frames on overshoot.
   RateStatistics encode_framerate_;
   bool bitrate_updated_;
@@ -107,6 +109,8 @@
   } layers_[kMaxNumTemporalLayers];
 
   void UpdateHistograms();
+  TemplateStructure GetTemplateStructure(int num_layers) const;
+
   // Data for histogram statistics.
   struct Stats {
     int64_t first_frame_time_ms_ = -1;
diff --git a/modules/video_coding/codecs/vp8/screenshare_layers_unittest.cc b/modules/video_coding/codecs/vp8/screenshare_layers_unittest.cc
index 5f4f9af..16e4d46 100644
--- a/modules/video_coding/codecs/vp8/screenshare_layers_unittest.cc
+++ b/modules/video_coding/codecs/vp8/screenshare_layers_unittest.cc
@@ -80,8 +80,7 @@
     int flags = ConfigureFrame(base_sync);
     if (flags != -1)
       layers_->OnEncodeDone(timestamp_, frame_size_, base_sync, kDefaultQp,
-                            &info->codecSpecific.VP8);
-
+                            info);
     return flags;
   }
 
@@ -133,10 +132,9 @@
     bool got_tl1 = false;
     for (int i = 0; i < 10; ++i) {
       CodecSpecificInfo info;
-      const CodecSpecificInfoVP8& vp8_info = info.codecSpecific.VP8;
       EXPECT_NE(-1, EncodeFrame(false, &info));
       timestamp_ += kTimestampDelta5Fps;
-      if (vp8_info.temporalIdx == 0) {
+      if (info.codecSpecific.VP8.temporalIdx == 0) {
         got_tl0 = true;
       } else {
         got_tl1 = true;
@@ -164,9 +162,8 @@
       if (tl_config_.packetizer_temporal_idx != layer ||
           (sync && *sync != tl_config_.layer_sync)) {
         CodecSpecificInfo info;
-        CodecSpecificInfoVP8* vp8_info = &info.codecSpecific.VP8;
         layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp,
-                              vp8_info);
+                              &info);
         timestamp_ += kTimestampDelta5Fps;
       } else {
         // Found frame from sought after layer.
@@ -188,9 +185,9 @@
   Vp8EncoderConfig cfg_;
   bool config_updated_;
 
-  CodecSpecificInfoVP8* IgnoredCodecSpecificInfoVp8() {
+  CodecSpecificInfo* IgnoredCodecSpecificInfo() {
     ignored_codec_specific_info_ = absl::make_unique<CodecSpecificInfo>();
-    return &ignored_codec_specific_info_->codecSpecific.VP8;
+    return ignored_codec_specific_info_.get();
   }
 
  private:
@@ -223,10 +220,10 @@
   const int kNumFrames = kSyncPeriodSeconds * kFrameRate * 2 - 1;
   for (int i = 0; i < kNumFrames; ++i) {
     CodecSpecificInfo info;
-    const CodecSpecificInfoVP8& vp8_info = info.codecSpecific.VP8;
     EncodeFrame(false, &info);
     timestamp_ += kTimestampDelta5Fps;
-    if (vp8_info.temporalIdx == 1 && vp8_info.layerSync) {
+    if (info.codecSpecific.VP8.temporalIdx == 1 &&
+        info.codecSpecific.VP8.layerSync) {
       sync_times.push_back(timestamp_);
     }
   }
@@ -240,21 +237,20 @@
   const int kNumFrames = kMaxSyncPeriodSeconds * kFrameRate * 2 - 1;
   for (int i = 0; i < kNumFrames; ++i) {
     CodecSpecificInfo info;
-    CodecSpecificInfoVP8* vp8_info = &info.codecSpecific.VP8;
 
     tl_config_ = UpdateLayerConfig(timestamp_);
     config_updated_ = layers_->UpdateConfiguration(&cfg_);
 
     // Simulate TL1 being at least 8 qp steps better.
     if (tl_config_.packetizer_temporal_idx == 0) {
-      layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp,
-                            vp8_info);
+      layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp, &info);
     } else {
       layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp - 8,
-                            vp8_info);
+                            &info);
     }
 
-    if (vp8_info->temporalIdx == 1 && vp8_info->layerSync)
+    if (info.codecSpecific.VP8.temporalIdx == 1 &&
+        info.codecSpecific.VP8.layerSync)
       sync_times.push_back(timestamp_);
 
     timestamp_ += kTimestampDelta5Fps;
@@ -272,20 +268,19 @@
                          kFrameRate;
   for (int i = 0; i < kNumFrames; ++i) {
     CodecSpecificInfo info;
-    CodecSpecificInfoVP8* vp8_info = &info.codecSpecific.VP8;
 
     ConfigureFrame(false);
 
     // Simulate TL1 being at least 8 qp steps better.
     if (tl_config_.packetizer_temporal_idx == 0) {
-      layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp,
-                            vp8_info);
+      layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp, &info);
     } else {
       layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp - 8,
-                            vp8_info);
+                            &info);
     }
 
-    if (vp8_info->temporalIdx == 1 && vp8_info->layerSync)
+    if (info.codecSpecific.VP8.temporalIdx == 1 &&
+        info.codecSpecific.VP8.layerSync)
       sync_times.push_back(timestamp_);
 
     timestamp_ += kTimestampDelta5Fps;
@@ -296,17 +291,16 @@
   bool bumped_tl0_quality = false;
   for (int i = 0; i < 3; ++i) {
     CodecSpecificInfo info;
-    CodecSpecificInfoVP8* vp8_info = &info.codecSpecific.VP8;
 
     int flags = ConfigureFrame(false);
     layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp - 8,
-                          vp8_info);
-    if (vp8_info->temporalIdx == 0) {
+                          &info);
+    if (info.codecSpecific.VP8.temporalIdx == 0) {
       // Bump TL0 to same quality as TL1.
       bumped_tl0_quality = true;
     } else {
       if (bumped_tl0_quality) {
-        EXPECT_TRUE(vp8_info->layerSync);
+        EXPECT_TRUE(info.codecSpecific.VP8.layerSync);
         EXPECT_EQ(kTl1SyncFlags, flags);
         return;
       }
@@ -324,10 +318,9 @@
   int tl1_frames = 0;
   for (int i = 0; i < 50; ++i) {
     CodecSpecificInfo info;
-    const CodecSpecificInfoVP8& vp8_info = info.codecSpecific.VP8;
     EncodeFrame(false, &info);
     timestamp_ += kTimestampDelta5Fps;
-    switch (vp8_info.temporalIdx) {
+    switch (info.codecSpecific.VP8.temporalIdx) {
       case 0:
         ++tl0_frames;
         break;
@@ -348,11 +341,10 @@
   // Insert 50 frames, small enough that all fits in TL0.
   for (int i = 0; i < 50; ++i) {
     CodecSpecificInfo info;
-    const CodecSpecificInfoVP8& vp8_info = info.codecSpecific.VP8;
     int flags = EncodeFrame(false, &info);
     timestamp_ += kTimestampDelta5Fps;
     EXPECT_EQ(kTl0Flags, flags);
-    EXPECT_EQ(0, vp8_info.temporalIdx);
+    EXPECT_EQ(0, info.codecSpecific.VP8.temporalIdx);
   }
 }
 
@@ -365,13 +357,12 @@
   int dropped_frames = 0;
   for (int i = 0; i < 100; ++i) {
     CodecSpecificInfo info;
-    const CodecSpecificInfoVP8& vp8_info = info.codecSpecific.VP8;
     int flags = EncodeFrame(false, &info);
     timestamp_ += kTimestampDelta5Fps;
     if (flags == -1) {
       ++dropped_frames;
     } else {
-      switch (vp8_info.temporalIdx) {
+      switch (info.codecSpecific.VP8.temporalIdx) {
         case 0:
           ++tl0_frames;
           break;
@@ -428,7 +419,7 @@
   SkipUntilTl(0);
 
   // Size 0 indicates dropped frame.
-  layers_->OnEncodeDone(timestamp_, 0, false, 0, IgnoredCodecSpecificInfoVp8());
+  layers_->OnEncodeDone(timestamp_, 0, false, 0, IgnoredCodecSpecificInfo());
 
   // Re-encode frame (so don't advance timestamp).
   int flags = EncodeFrame(false);
@@ -441,19 +432,19 @@
   EXPECT_TRUE(config_updated_);
   EXPECT_LT(cfg_.rc_max_quantizer, static_cast<unsigned int>(kDefaultQp));
   layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp,
-                        IgnoredCodecSpecificInfoVp8());
+                        IgnoredCodecSpecificInfo());
   timestamp_ += kTimestampDelta5Fps;
 
   // ...then back to standard setup.
   SkipUntilTl(0);
   layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp,
-                        IgnoredCodecSpecificInfoVp8());
+                        IgnoredCodecSpecificInfo());
   timestamp_ += kTimestampDelta5Fps;
   EXPECT_EQ(cfg_.rc_max_quantizer, static_cast<unsigned int>(kDefaultQp));
 
   // Next drop in TL1.
   SkipUntilTl(1);
-  layers_->OnEncodeDone(timestamp_, 0, false, 0, IgnoredCodecSpecificInfoVp8());
+  layers_->OnEncodeDone(timestamp_, 0, false, 0, IgnoredCodecSpecificInfo());
 
   // Re-encode frame (so don't advance timestamp).
   flags = EncodeFrame(false);
@@ -466,14 +457,14 @@
   EXPECT_TRUE(config_updated_);
   EXPECT_LT(cfg_.rc_max_quantizer, static_cast<unsigned int>(kDefaultQp));
   layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp,
-                        IgnoredCodecSpecificInfoVp8());
+                        IgnoredCodecSpecificInfo());
   timestamp_ += kTimestampDelta5Fps;
 
   // ...and back to normal.
   SkipUntilTl(1);
   EXPECT_EQ(cfg_.rc_max_quantizer, static_cast<unsigned int>(kDefaultQp));
   layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp,
-                        IgnoredCodecSpecificInfoVp8());
+                        IgnoredCodecSpecificInfo());
   timestamp_ += kTimestampDelta5Fps;
 }
 
@@ -489,7 +480,7 @@
   EXPECT_EQ(kTl0Flags,
             LibvpxVp8Encoder::EncodeFlags(UpdateLayerConfig(kStartTimestamp)));
   layers_->OnEncodeDone(kStartTimestamp, kLargeFrameSizeBytes, false,
-                        kDefaultQp, IgnoredCodecSpecificInfoVp8());
+                        kDefaultQp, IgnoredCodecSpecificInfo());
 
   const uint32_t kTwoSecondsLater =
       kStartTimestamp + (ScreenshareLayers::kMaxFrameIntervalMs * 90);
@@ -539,15 +530,15 @@
       if (timestamp >= kTimestampDelta5Fps * 20 && !trigger_drop) {
         // Simulate a too large frame, to cause frame drop.
         layers_->OnEncodeDone(timestamp, frame_size_ * 10, false, kTl0Qp,
-                              IgnoredCodecSpecificInfoVp8());
+                              IgnoredCodecSpecificInfo());
         trigger_drop = true;
       } else {
         layers_->OnEncodeDone(timestamp, frame_size_, false, kTl0Qp,
-                              IgnoredCodecSpecificInfoVp8());
+                              IgnoredCodecSpecificInfo());
       }
     } else if (flags == kTl1Flags || flags == kTl1SyncFlags) {
       layers_->OnEncodeDone(timestamp, frame_size_, false, kTl1Qp,
-                            IgnoredCodecSpecificInfoVp8());
+                            IgnoredCodecSpecificInfo());
     } else if (flags == -1) {
       dropped_frame = true;
     } else {
@@ -614,7 +605,7 @@
     } else {
       size_t frame_size_bytes = kDefaultTl0BitrateKbps * kFrameIntervalsMs / 8;
       layers_->OnEncodeDone(timestamp, frame_size_bytes, false, kDefaultQp,
-                            IgnoredCodecSpecificInfoVp8());
+                            IgnoredCodecSpecificInfo());
     }
     timestamp += kFrameIntervalsMs * 90;
     clock_.AdvanceTime(TimeDelta::ms(kFrameIntervalsMs));
@@ -632,7 +623,7 @@
     } else {
       size_t frame_size_bytes = kDefaultTl0BitrateKbps * kFrameIntervalsMs / 8;
       layers_->OnEncodeDone(timestamp, frame_size_bytes, false, kDefaultQp,
-                            IgnoredCodecSpecificInfoVp8());
+                            IgnoredCodecSpecificInfo());
     }
     timestamp += kFrameIntervalsMs * 90 / 2;
     clock_.AdvanceTime(TimeDelta::ms(kFrameIntervalsMs));
@@ -657,10 +648,9 @@
   config_updated_ = layers_->UpdateConfiguration(&cfg_);
   EXPECT_EQ(kTl1SyncFlags, LibvpxVp8Encoder::EncodeFlags(tl_config_));
 
-  CodecSpecificInfo info;
-  CodecSpecificInfoVP8* vp8_info = &info.codecSpecific.VP8;
-  layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp, vp8_info);
-  EXPECT_TRUE(vp8_info->layerSync);
+  CodecSpecificInfo new_info;
+  layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp, &new_info);
+  EXPECT_TRUE(new_info.codecSpecific.VP8.layerSync);
 }
 
 TEST_F(ScreenshareLayerTest, DropOnTooShortFrameInterval) {
@@ -671,7 +661,7 @@
   timestamp_ += kTimestampDelta5Fps * 3;
   EXPECT_FALSE(UpdateLayerConfig(timestamp_).drop_frame);
   layers_->OnEncodeDone(timestamp_, frame_size_, false, kDefaultQp,
-                        IgnoredCodecSpecificInfoVp8());
+                        IgnoredCodecSpecificInfo());
 
   // Frame interval below 90% if desired time is not allowed, try inserting
   // frame just before this limit.
@@ -735,7 +725,7 @@
 
   // Simulate re-encoded frame.
   layers_->OnEncodeDone(timestamp_, 1, false, max_qp_,
-                        IgnoredCodecSpecificInfoVp8());
+                        IgnoredCodecSpecificInfo());
 
   // Next frame, expect boosted quality.
   // Slightly alter bitrate between each frame.
@@ -752,7 +742,7 @@
 
   // Simulate re-encoded frame.
   layers_->OnEncodeDone(timestamp_, frame_size_, false, max_qp_,
-                        IgnoredCodecSpecificInfoVp8());
+                        IgnoredCodecSpecificInfo());
 
   // A third frame, expect boosted quality.
   layers_->OnRatesUpdated(kDefault2TlBitratesBps, kFrameRate);
@@ -763,7 +753,7 @@
 
   // Frame encoded.
   layers_->OnEncodeDone(timestamp_, frame_size_, false, max_qp_,
-                        IgnoredCodecSpecificInfoVp8());
+                        IgnoredCodecSpecificInfo());
 
   // A fourth frame, max qp should be restored.
   layers_->OnRatesUpdated(kDefault2TlBitratesBpsAlt, kFrameRate);
diff --git a/modules/video_coding/include/video_codec_interface.cc b/modules/video_coding/include/video_codec_interface.cc
new file mode 100644
index 0000000..bd033b6
--- /dev/null
+++ b/modules/video_coding/include/video_codec_interface.cc
@@ -0,0 +1,20 @@
+/*
+ *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "modules/video_coding/include/video_codec_interface.h"
+
+namespace webrtc {
+CodecSpecificInfo::CodecSpecificInfo() : codecType(kVideoCodecGeneric) {
+  memset(&codecSpecific, 0, sizeof(codecSpecific));
+}
+
+CodecSpecificInfo::CodecSpecificInfo(const CodecSpecificInfo&) = default;
+CodecSpecificInfo::~CodecSpecificInfo() = default;
+
+}  // namespace webrtc
diff --git a/modules/video_coding/include/video_codec_interface.h b/modules/video_coding/include/video_codec_interface.h
index cde5512..fb440be 100644
--- a/modules/video_coding/include/video_codec_interface.h
+++ b/modules/video_coding/include/video_codec_interface.h
@@ -13,10 +13,12 @@
 
 #include <vector>
 
+#include "absl/types/optional.h"
 #include "api/video/video_frame.h"
 #include "api/video_codecs/video_decoder.h"
 #include "api/video_codecs/video_encoder.h"
 #include "common_types.h"  // NOLINT(build/include)
+#include "common_video/generic_frame_descriptor/generic_frame_info.h"
 #include "modules/include/module_common_types.h"
 #include "modules/video_coding/include/video_error_codes.h"
 
@@ -96,16 +98,18 @@
 };
 static_assert(std::is_pod<CodecSpecificInfoUnion>::value, "");
 
-// Note: If any pointers are added to this struct or its sub-structs, it
+// Note: if any pointers are added to this struct or its sub-structs, it
 // must be fitted with a copy-constructor. This is because it is copied
 // in the copy-constructor of VCMEncodedFrame.
 struct CodecSpecificInfo {
-  CodecSpecificInfo() : codecType(kVideoCodecGeneric) {
-    memset(&codecSpecific, 0, sizeof(codecSpecific));
-  }
+  CodecSpecificInfo();
+  CodecSpecificInfo(const CodecSpecificInfo&);
+  ~CodecSpecificInfo();
 
   VideoCodecType codecType;
   CodecSpecificInfoUnion codecSpecific;
+  absl::optional<GenericFrameInfo> generic_frame_info;
+  absl::optional<TemplateStructure> template_structure;
 };
 
 }  // namespace webrtc
diff --git a/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc b/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc
index 690c3fa..4744e38 100644
--- a/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc
+++ b/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc
@@ -41,7 +41,7 @@
   MOCK_METHOD2(OnRatesUpdated, void(const std::vector<uint32_t>&, int));
   MOCK_METHOD1(UpdateConfiguration, bool(Vp8EncoderConfig*));
   MOCK_METHOD5(OnEncodeDone,
-               void(uint32_t, size_t, bool, int, CodecSpecificInfoVP8*));
+               void(uint32_t, size_t, bool, int, CodecSpecificInfo*));
   MOCK_METHOD3(FrameEncoded, void(uint32_t, size_t, int));
   MOCK_CONST_METHOD0(Tl0PicIdx, uint8_t());
   MOCK_CONST_METHOD1(GetTemporalLayerId, int(const Vp8FrameConfig&));