In dependency descritpor add active decode targets bitmask field

to follow spec draft change.

Bug: webrtc:10342
Change-Id: I8cd9f26a2061ecd62a3a7826c4086141203ee5cd
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/159022
Reviewed-by: Sam Zackrisson <saza@webrtc.org>
Reviewed-by: Philip Eliasson <philipel@webrtc.org>
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29726}
diff --git a/common_video/generic_frame_descriptor/generic_frame_info.h b/common_video/generic_frame_descriptor/generic_frame_info.h
index 3916530..2aff0e3 100644
--- a/common_video/generic_frame_descriptor/generic_frame_info.h
+++ b/common_video/generic_frame_descriptor/generic_frame_info.h
@@ -97,6 +97,7 @@
   int frame_number = 0;
   FrameDependencyTemplate frame_dependencies;
   absl::optional<RenderResolution> resolution;
+  absl::optional<uint32_t> active_decode_targets_bitmask;
   std::unique_ptr<FrameDependencyStructure> attached_structure;
 };
 
diff --git a/modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.cc b/modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.cc
index 5170578..5103d7f 100644
--- a/modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.cc
+++ b/modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.cc
@@ -41,10 +41,15 @@
   structure_ = descriptor->attached_structure
                    ? descriptor->attached_structure.get()
                    : structure;
-  if (structure_ == nullptr) {
+  if (structure_ == nullptr || parsing_failed_) {
     parsing_failed_ = true;
     return;
   }
+  if (active_decode_targets_present_flag_) {
+    descriptor->active_decode_targets_bitmask =
+        ReadBits(structure_->num_decode_targets);
+  }
+
   ReadFrameDependencyDefinition();
 }
 
@@ -190,12 +195,16 @@
     return;
   }
   bool template_dependency_structure_present_flag = ReadBits(1);
+  active_decode_targets_present_flag_ = ReadBits(1);
   custom_dtis_flag_ = ReadBits(1);
   custom_fdiffs_flag_ = ReadBits(1);
   custom_chains_flag_ = ReadBits(1);
   if (template_dependency_structure_present_flag) {
     ReadTemplateDependencyStructure();
     RTC_DCHECK(descriptor_->attached_structure);
+    descriptor_->active_decode_targets_bitmask =
+        (uint64_t{1} << descriptor_->attached_structure->num_decode_targets) -
+        1;
   }
 }
 
diff --git a/modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.h b/modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.h
index e16fba8..11df2f4 100644
--- a/modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.h
+++ b/modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.h
@@ -63,6 +63,7 @@
   // when reading is complete.
   rtc::BitBuffer buffer_;
   int frame_dependency_template_id_ = 0;
+  bool active_decode_targets_present_flag_ = false;
   bool custom_dtis_flag_ = false;
   bool custom_fdiffs_flag_ = false;
   bool custom_chains_flag_ = false;
diff --git a/modules/rtp_rtcp/source/rtp_dependency_descriptor_writer.cc b/modules/rtp_rtcp/source/rtp_dependency_descriptor_writer.cc
index ea10e37..1190acf 100644
--- a/modules/rtp_rtcp/source/rtp_dependency_descriptor_writer.cc
+++ b/modules/rtp_rtcp/source/rtp_dependency_descriptor_writer.cc
@@ -80,8 +80,13 @@
 int RtpDependencyDescriptorWriter::ValueSizeBits() const {
   static constexpr int kMandatoryFields = 1 + 1 + 6 + 16;
   int value_size_bits = kMandatoryFields + best_template_.extra_size_bits;
-  if (descriptor_.attached_structure)
-    value_size_bits += 10 + StructureSizeBits();
+  if (HasExtendedFields()) {
+    value_size_bits += 11;
+    if (descriptor_.attached_structure)
+      value_size_bits += StructureSizeBits();
+    if (ShouldWriteActiveDecodeTargetsBitmask())
+      value_size_bits += structure_.num_decode_targets;
+  }
   return value_size_bits;
 }
 
@@ -124,15 +129,7 @@
   result.need_custom_chains =
       descriptor_.frame_dependencies.chain_diffs != frame_template->chain_diffs;
 
-  if (!result.need_custom_fdiffs && !result.need_custom_dtis &&
-      !result.need_custom_chains) {
-    // Perfect match.
-    result.extra_size_bits = 0;
-    return result;
-  }
-  // If structure should be attached, then there will be ExtendedFields anyway,
-  // so do not count 10 bits for them as extra.
-  result.extra_size_bits = descriptor_.attached_structure ? 0 : 10;
+  result.extra_size_bits = 0;
   if (result.need_custom_fdiffs) {
     result.extra_size_bits +=
         2 * (1 + descriptor_.frame_dependencies.frame_diffs.size());
@@ -176,8 +173,21 @@
   }
 }
 
+bool RtpDependencyDescriptorWriter::ShouldWriteActiveDecodeTargetsBitmask()
+    const {
+  if (!descriptor_.active_decode_targets_bitmask)
+    return false;
+  const uint64_t all_decode_targets_bitmask =
+      (uint64_t{1} << structure_.num_decode_targets) - 1;
+  if (descriptor_.attached_structure &&
+      descriptor_.active_decode_targets_bitmask == all_decode_targets_bitmask)
+    return false;
+  return true;
+}
+
 bool RtpDependencyDescriptorWriter::HasExtendedFields() const {
-  return best_template_.extra_size_bits > 0 || descriptor_.attached_structure;
+  return best_template_.extra_size_bits > 0 || descriptor_.attached_structure ||
+         descriptor_.active_decode_targets_bitmask;
 }
 
 uint64_t RtpDependencyDescriptorWriter::TemplateId() const {
@@ -306,11 +316,17 @@
   uint64_t template_dependency_structure_present_flag =
       descriptor_.attached_structure ? 1u : 0u;
   WriteBits(template_dependency_structure_present_flag, 1);
+  uint64_t active_decode_targets_present_flag =
+      ShouldWriteActiveDecodeTargetsBitmask() ? 1u : 0u;
+  WriteBits(active_decode_targets_present_flag, 1);
   WriteBits(best_template_.need_custom_dtis, 1);
   WriteBits(best_template_.need_custom_fdiffs, 1);
   WriteBits(best_template_.need_custom_chains, 1);
-  if (descriptor_.attached_structure)
+  if (template_dependency_structure_present_flag)
     WriteTemplateDependencyStructure();
+  if (active_decode_targets_present_flag)
+    WriteBits(*descriptor_.active_decode_targets_bitmask,
+              structure_.num_decode_targets);
 }
 
 void RtpDependencyDescriptorWriter::WriteFrameDependencyDefinition() {
diff --git a/modules/rtp_rtcp/source/rtp_dependency_descriptor_writer.h b/modules/rtp_rtcp/source/rtp_dependency_descriptor_writer.h
index 750c7ed..5274f2d 100644
--- a/modules/rtp_rtcp/source/rtp_dependency_descriptor_writer.h
+++ b/modules/rtp_rtcp/source/rtp_dependency_descriptor_writer.h
@@ -50,6 +50,7 @@
   int StructureSizeBits() const;
   TemplateMatch CalculateMatch(TemplateIterator frame_template) const;
   void FindBestTemplate();
+  bool ShouldWriteActiveDecodeTargetsBitmask() const;
   bool HasExtendedFields() const;
   uint64_t TemplateId() const;
 
diff --git a/test/fuzzers/rtp_dependency_descriptor_fuzzer.cc b/test/fuzzers/rtp_dependency_descriptor_fuzzer.cc
index fbe7ac3..0736bba 100644
--- a/test/fuzzers/rtp_dependency_descriptor_fuzzer.cc
+++ b/test/fuzzers/rtp_dependency_descriptor_fuzzer.cc
@@ -21,19 +21,6 @@
 #include "test/fuzzers/fuzz_data_helper.h"
 
 namespace webrtc {
-namespace {
-
-bool AreSame(const DependencyDescriptor& lhs, const DependencyDescriptor& rhs) {
-  return lhs.first_packet_in_frame == rhs.first_packet_in_frame &&
-         lhs.last_packet_in_frame == rhs.last_packet_in_frame &&
-         (lhs.attached_structure != nullptr) ==
-             (rhs.attached_structure != nullptr) &&
-         lhs.frame_number == rhs.frame_number &&
-         lhs.resolution == rhs.resolution &&
-         lhs.frame_dependencies == rhs.frame_dependencies;
-}
-
-}  // namespace
 
 void FuzzOneInput(const uint8_t* data, size_t size) {
   FrameDependencyStructure structure1;
@@ -80,7 +67,23 @@
     DependencyDescriptor descriptor2;
     RTC_CHECK(RtpDependencyDescriptorExtension::Parse(
         write_buffer, structure2.get(), &descriptor2));
-    RTC_CHECK(AreSame(descriptor1, descriptor2));
+    // Check descriptor1 and descriptor2 have same values.
+    RTC_CHECK_EQ(descriptor1.first_packet_in_frame,
+                 descriptor2.first_packet_in_frame);
+    RTC_CHECK_EQ(descriptor1.last_packet_in_frame,
+                 descriptor2.last_packet_in_frame);
+    RTC_CHECK_EQ(descriptor1.attached_structure != nullptr,
+                 descriptor2.attached_structure != nullptr);
+    // Using value_or would miss invalid corner case when one value is nullopt
+    // while another one is 0, but for other errors would produce much nicer
+    // error message than using RTC_CHECK(optional1 == optional2);
+    // If logger would support pretty printing optional values, value_or can be
+    // removed.
+    RTC_CHECK_EQ(descriptor1.active_decode_targets_bitmask.value_or(0),
+                 descriptor2.active_decode_targets_bitmask.value_or(0));
+    RTC_CHECK_EQ(descriptor1.frame_number, descriptor2.frame_number);
+    RTC_CHECK(descriptor1.resolution == descriptor2.resolution);
+    RTC_CHECK(descriptor1.frame_dependencies == descriptor2.frame_dependencies);
 
     if (descriptor2.attached_structure) {
       structure2 = std::move(descriptor2.attached_structure);