Implement Dependency Descriptor reader

Bug: webrtc:10342
Change-Id: I671bf57368016b633546966cc994646095433519
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/152823
Reviewed-by: Philip Eliasson <philipel@webrtc.org>
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29197}
diff --git a/common_video/generic_frame_descriptor/generic_frame_info.h b/common_video/generic_frame_descriptor/generic_frame_info.h
index d54e53d..3916530 100644
--- a/common_video/generic_frame_descriptor/generic_frame_info.h
+++ b/common_video/generic_frame_descriptor/generic_frame_info.h
@@ -12,6 +12,7 @@
 #define COMMON_VIDEO_GENERIC_FRAME_DESCRIPTOR_GENERIC_FRAME_INFO_H_
 
 #include <initializer_list>
+#include <memory>
 #include <vector>
 
 #include "absl/container/inlined_vector.h"
@@ -82,6 +83,9 @@
   int structure_id = 0;
   int num_decode_targets = 0;
   int num_chains = 0;
+  // If chains are used (num_chains > 0), maps decode target index into index of
+  // the chain protecting that target or |num_chains| value if decode target is
+  // not protected by a chain.
   absl::InlinedVector<int, 10> decode_target_protected_by_chain;
   absl::InlinedVector<RenderResolution, 4> resolutions;
   std::vector<FrameDependencyTemplate> templates;
@@ -90,10 +94,10 @@
 struct DependencyDescriptor {
   bool first_packet_in_frame = true;
   bool last_packet_in_frame = true;
-  bool has_structure_attached = false;
   int frame_number = 0;
   FrameDependencyTemplate frame_dependencies;
   absl::optional<RenderResolution> resolution;
+  std::unique_ptr<FrameDependencyStructure> attached_structure;
 };
 
 // Describes how a certain encoder buffer was used when encoding a frame.
diff --git a/modules/rtp_rtcp/BUILD.gn b/modules/rtp_rtcp/BUILD.gn
index c0b35cf..2f3c079 100644
--- a/modules/rtp_rtcp/BUILD.gn
+++ b/modules/rtp_rtcp/BUILD.gn
@@ -86,6 +86,7 @@
     "source/rtcp_packet/tmmbr.cc",
     "source/rtcp_packet/transport_feedback.cc",
     "source/rtp_dependency_descriptor_extension.cc",
+    "source/rtp_dependency_descriptor_reader.cc",
     "source/rtp_generic_frame_descriptor.cc",
     "source/rtp_generic_frame_descriptor_extension.cc",
     "source/rtp_header_extension_map.cc",
@@ -116,6 +117,7 @@
     "../../system_wrappers",
     "../video_coding:codec_globals_headers",
     "//third_party/abseil-cpp/absl/algorithm:container",
+    "//third_party/abseil-cpp/absl/memory",
     "//third_party/abseil-cpp/absl/strings",
     "//third_party/abseil-cpp/absl/types:optional",
     "//third_party/abseil-cpp/absl/types:variant",
diff --git a/modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.cc b/modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.cc
index db3831e..6b6a0a9 100644
--- a/modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.cc
+++ b/modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.cc
@@ -10,9 +10,24 @@
 
 #include "modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.h"
 
+#include <cstdint>
+
+#include "api/array_view.h"
+#include "common_video/generic_frame_descriptor/generic_frame_info.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.h"
+
 namespace webrtc {
 
 constexpr RTPExtensionType RtpDependencyDescriptorExtension::kId;
 constexpr char RtpDependencyDescriptorExtension::kUri[];
 
+bool RtpDependencyDescriptorExtension::Parse(
+    rtc::ArrayView<const uint8_t> data,
+    const FrameDependencyStructure* structure,
+    DependencyDescriptor* descriptor) {
+  RtpDependencyDescriptorReader reader(data, structure, descriptor);
+  return reader.ParseSuccessful();
+}
+
 }  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.h b/modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.h
index 44dd6d6..58c8e8a 100644
--- a/modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.h
+++ b/modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.h
@@ -15,7 +15,6 @@
 #include "api/array_view.h"
 #include "common_video/generic_frame_descriptor/generic_frame_info.h"
 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
-#include "modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.h"
 #include "modules/rtp_rtcp/source/rtp_dependency_descriptor_writer.h"
 
 namespace webrtc {
@@ -32,10 +31,8 @@
       "generic-frame-descriptor-02";
 
   static bool Parse(rtc::ArrayView<const uint8_t> data,
-                    RtpDependencyDescriptorReader* reader,
-                    DependencyDescriptor* descriptor) {
-    return reader->Parse(data, descriptor);
-  }
+                    const FrameDependencyStructure* structure,
+                    DependencyDescriptor* descriptor);
 
   static size_t ValueSize(RtpDependencyDescriptorWriter* writer,
                           const DependencyDescriptor& descriptor) {
diff --git a/modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.cc b/modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.cc
new file mode 100644
index 0000000..1ed0e20
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.cc
@@ -0,0 +1,256 @@
+/*
+ *  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/rtp_rtcp/source/rtp_dependency_descriptor_reader.h"
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "absl/memory/memory.h"
+#include "rtc_base/bit_buffer.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace {
+
+constexpr int kMaxTemporalId = 7;
+constexpr int kMaxSpatialId = 3;
+constexpr int kMaxTemplates = 63;
+constexpr int kMaxTemplateId = kMaxTemplates - 1;
+constexpr int kExtendedFieldsIndicator = kMaxTemplates;
+
+}  // namespace
+
+RtpDependencyDescriptorReader::RtpDependencyDescriptorReader(
+    rtc::ArrayView<const uint8_t> raw_data,
+    const FrameDependencyStructure* structure,
+    DependencyDescriptor* descriptor)
+    : descriptor_(descriptor), buffer_(raw_data.data(), raw_data.size()) {
+  RTC_DCHECK(descriptor);
+
+  ReadMandatoryFields();
+  if (frame_dependency_template_id_ == kExtendedFieldsIndicator)
+    ReadExtendedFields();
+
+  structure_ = descriptor->attached_structure
+                   ? descriptor->attached_structure.get()
+                   : structure;
+  if (structure_ == nullptr) {
+    parsing_failed_ = true;
+    return;
+  }
+  ReadFrameDependencyDefinition();
+}
+
+uint32_t RtpDependencyDescriptorReader::ReadBits(size_t bit_count) {
+  uint32_t value = 0;
+  if (!buffer_.ReadBits(&value, bit_count))
+    parsing_failed_ = true;
+  return value;
+}
+
+uint32_t RtpDependencyDescriptorReader::ReadNonSymmetric(size_t num_values) {
+  uint32_t value = 0;
+  if (!buffer_.ReadNonSymmetric(&value, num_values))
+    parsing_failed_ = true;
+  return value;
+}
+
+void RtpDependencyDescriptorReader::ReadTemplateDependencyStructure() {
+  descriptor_->attached_structure =
+      absl::make_unique<FrameDependencyStructure>();
+  descriptor_->attached_structure->structure_id = ReadBits(6);
+  descriptor_->attached_structure->num_decode_targets = ReadBits(5) + 1;
+
+  ReadTemplateLayers();
+  ReadTemplateDtis();
+  ReadTemplateFdiffs();
+  ReadTemplateChains();
+
+  uint32_t has_resolutions = ReadBits(1);
+  if (has_resolutions)
+    ReadResolutions();
+}
+
+void RtpDependencyDescriptorReader::ReadTemplateLayers() {
+  enum NextLayerIdc : uint32_t {
+    kSameLayer = 0,
+    kNextTemporalLayer = 1,
+    kNextSpatialLayer = 2,
+    kNoMoreTemplates = 3,
+  };
+  std::vector<FrameDependencyTemplate> templates;
+
+  int temporal_id = 0;
+  int spatial_id = 0;
+  NextLayerIdc next_layer_idc;
+  do {
+    if (templates.size() == kMaxTemplates) {
+      parsing_failed_ = true;
+      break;
+    }
+    templates.emplace_back();
+    FrameDependencyTemplate& last_template = templates.back();
+    last_template.temporal_id = temporal_id;
+    last_template.spatial_id = spatial_id;
+
+    next_layer_idc = static_cast<NextLayerIdc>(ReadBits(2));
+    if (next_layer_idc == kNextTemporalLayer) {
+      temporal_id++;
+      if (temporal_id > kMaxTemporalId) {
+        parsing_failed_ = true;
+        break;
+      }
+    } else if (next_layer_idc == kNextSpatialLayer) {
+      temporal_id = 0;
+      spatial_id++;
+      if (spatial_id > kMaxSpatialId) {
+        parsing_failed_ = true;
+        break;
+      }
+    }
+  } while (next_layer_idc != kNoMoreTemplates && !parsing_failed_);
+
+  descriptor_->attached_structure->templates = std::move(templates);
+}
+
+void RtpDependencyDescriptorReader::ReadTemplateDtis() {
+  FrameDependencyStructure* structure = descriptor_->attached_structure.get();
+  for (FrameDependencyTemplate& current_template : structure->templates) {
+    current_template.decode_target_indications.resize(
+        structure->num_decode_targets);
+    for (int i = 0; i < structure->num_decode_targets; ++i) {
+      current_template.decode_target_indications[i] =
+          static_cast<DecodeTargetIndication>(ReadBits(2));
+    }
+  }
+}
+
+void RtpDependencyDescriptorReader::ReadTemplateFdiffs() {
+  for (FrameDependencyTemplate& current_template :
+       descriptor_->attached_structure->templates) {
+    for (uint32_t fdiff_follows = ReadBits(1); fdiff_follows;
+         fdiff_follows = ReadBits(1)) {
+      uint32_t fdiff_minus_one = ReadBits(4);
+      current_template.frame_diffs.push_back(fdiff_minus_one + 1);
+    }
+  }
+}
+
+void RtpDependencyDescriptorReader::ReadTemplateChains() {
+  FrameDependencyStructure* structure = descriptor_->attached_structure.get();
+  structure->num_chains = ReadNonSymmetric(structure->num_decode_targets + 1);
+  if (structure->num_chains == 0)
+    return;
+  for (int i = 0; i < structure->num_decode_targets; ++i) {
+    uint32_t protected_by_chain = ReadNonSymmetric(structure->num_chains + 1);
+    structure->decode_target_protected_by_chain.push_back(protected_by_chain);
+  }
+  for (FrameDependencyTemplate& frame_template : structure->templates) {
+    for (int chain_id = 0; chain_id < structure->num_chains; ++chain_id) {
+      frame_template.chain_diffs.push_back(ReadBits(4));
+    }
+  }
+}
+
+void RtpDependencyDescriptorReader::ReadResolutions() {
+  FrameDependencyStructure* structure = descriptor_->attached_structure.get();
+  // The way templates are bitpacked, they are always ordered by spatial_id.
+  int spatial_layers = structure->templates.back().spatial_id + 1;
+  structure->resolutions.reserve(spatial_layers);
+  for (int sid = 0; sid < spatial_layers; ++sid) {
+    uint16_t width_minus_1 = ReadBits(16);
+    uint16_t height_minus_1 = ReadBits(16);
+    structure->resolutions.emplace_back(width_minus_1 + 1, height_minus_1 + 1);
+  }
+}
+
+void RtpDependencyDescriptorReader::ReadMandatoryFields() {
+  descriptor_->first_packet_in_frame = ReadBits(1);
+  descriptor_->last_packet_in_frame = ReadBits(1);
+  frame_dependency_template_id_ = ReadBits(6);
+  descriptor_->frame_number = ReadBits(16);
+}
+
+void RtpDependencyDescriptorReader::ReadExtendedFields() {
+  frame_dependency_template_id_ = ReadBits(6);
+  if (frame_dependency_template_id_ == kExtendedFieldsIndicator) {
+    parsing_failed_ = true;
+    return;
+  }
+  bool template_dependency_structure_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);
+  }
+}
+
+void RtpDependencyDescriptorReader::ReadFrameDependencyDefinition() {
+  size_t template_index = (frame_dependency_template_id_ +
+                           (kMaxTemplateId + 1) - structure_->structure_id) %
+                          (kMaxTemplateId + 1);
+
+  if (template_index >= structure_->templates.size()) {
+    parsing_failed_ = true;
+    return;
+  }
+
+  // Copy all the fields from the matching template
+  descriptor_->frame_dependencies = structure_->templates[template_index];
+
+  if (custom_dtis_flag_)
+    ReadFrameDtis();
+  if (custom_fdiffs_flag_)
+    ReadFrameFdiffs();
+  if (custom_chains_flag_)
+    ReadFrameChains();
+
+  if (structure_->resolutions.empty()) {
+    descriptor_->resolution = absl::nullopt;
+  } else {
+    // Format guarantees that if there were resolutions in the last structure,
+    // then each spatial layer got one.
+    RTC_DCHECK_LE(descriptor_->frame_dependencies.spatial_id,
+                  structure_->resolutions.size());
+    descriptor_->resolution =
+        structure_->resolutions[descriptor_->frame_dependencies.spatial_id];
+  }
+}
+
+void RtpDependencyDescriptorReader::ReadFrameDtis() {
+  RTC_DCHECK_EQ(
+      descriptor_->frame_dependencies.decode_target_indications.size(),
+      structure_->num_decode_targets);
+  for (auto& dti : descriptor_->frame_dependencies.decode_target_indications) {
+    dti = static_cast<DecodeTargetIndication>(ReadBits(2));
+  }
+}
+
+void RtpDependencyDescriptorReader::ReadFrameFdiffs() {
+  descriptor_->frame_dependencies.frame_diffs.clear();
+  for (uint32_t next_fdiff_size = ReadBits(2); next_fdiff_size > 0;
+       next_fdiff_size = ReadBits(2)) {
+    uint32_t fdiff_minus_one = ReadBits(4 * next_fdiff_size);
+    descriptor_->frame_dependencies.frame_diffs.push_back(fdiff_minus_one + 1);
+  }
+}
+
+void RtpDependencyDescriptorReader::ReadFrameChains() {
+  RTC_DCHECK_EQ(descriptor_->frame_dependencies.chain_diffs.size(),
+                structure_->num_chains);
+  for (auto& chain_diff : descriptor_->frame_dependencies.chain_diffs) {
+    chain_diff = ReadBits(8);
+  }
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.h b/modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.h
index 31ac530..e16fba8 100644
--- a/modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.h
+++ b/modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.h
@@ -11,29 +11,62 @@
 #define MODULES_RTP_RTCP_SOURCE_RTP_DEPENDENCY_DESCRIPTOR_READER_H_
 
 #include <cstdint>
+#include <memory>
+#include <vector>
 
 #include "api/array_view.h"
 #include "common_video/generic_frame_descriptor/generic_frame_info.h"
+#include "rtc_base/bit_buffer.h"
 
 namespace webrtc {
-// Keeps and updates state required to deserialize DependencyDescriptor
-// rtp header extension.
+// Deserializes DependencyDescriptor rtp header extension.
 class RtpDependencyDescriptorReader {
  public:
-  // Parses the dependency descriptor. Returns false on failure.
-  // Updates frame dependency structures if parsed descriptor has a new one.
-  // Doesn't update own state when Parse fails.
-  bool Parse(rtc::ArrayView<const uint8_t> raw_data,
-             DependencyDescriptor* descriptor) {
-    // TODO(bugs.webrtc.org/10342): Implement.
-    return false;
-  }
+  // Parses the dependency descriptor.
+  RtpDependencyDescriptorReader(rtc::ArrayView<const uint8_t> raw_data,
+                                const FrameDependencyStructure* structure,
+                                DependencyDescriptor* descriptor);
+  RtpDependencyDescriptorReader(const RtpDependencyDescriptorReader&) = delete;
+  RtpDependencyDescriptorReader& operator=(
+      const RtpDependencyDescriptorReader&) = delete;
 
-  // Returns latest valid parsed structure or nullptr if none was parsed so far.
-  const FrameDependencyStructure* GetStructure() const {
-    // TODO(bugs.webrtc.org/10342): Implement.
-    return nullptr;
-  }
+  // Returns true if parse was successful.
+  bool ParseSuccessful() { return !parsing_failed_; }
+
+ private:
+  // Reads bits from |buffer_|. If it fails, returns 0 and marks parsing as
+  // failed, but doesn't stop the parsing.
+  uint32_t ReadBits(size_t bit_count);
+  uint32_t ReadNonSymmetric(size_t num_values);
+
+  // Functions to read template dependency structure.
+  void ReadTemplateDependencyStructure();
+  void ReadTemplateLayers();
+  void ReadTemplateDtis();
+  void ReadTemplateFdiffs();
+  void ReadTemplateChains();
+  void ReadResolutions();
+
+  // Function to read details for the current frame.
+  void ReadMandatoryFields();
+  void ReadExtendedFields();
+  void ReadFrameDependencyDefinition();
+
+  void ReadFrameDtis();
+  void ReadFrameFdiffs();
+  void ReadFrameChains();
+
+  // Output.
+  bool parsing_failed_ = false;
+  DependencyDescriptor* const descriptor_;
+  // Values that are needed while reading the descriptor, but can be discarded
+  // when reading is complete.
+  rtc::BitBuffer buffer_;
+  int frame_dependency_template_id_ = 0;
+  bool custom_dtis_flag_ = false;
+  bool custom_fdiffs_flag_ = false;
+  bool custom_chains_flag_ = false;
+  const FrameDependencyStructure* structure_ = nullptr;
 };
 
 }  // namespace webrtc