Don't update internal state of the FrameBuffer2 when an undecodable frame is inserted.

Bug: chromium:844313
Change-Id: I034bcb47092815695084e37c81150bafbfbc6b9c
Reviewed-on: https://webrtc-review.googlesource.com/79944
Commit-Queue: Philip Eliasson <philipel@webrtc.org>
Reviewed-by: Björn Terelius <terelius@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23577}
diff --git a/modules/video_coding/frame_buffer2.cc b/modules/video_coding/frame_buffer2.cc
index 2a437d7..37feae1 100644
--- a/modules/video_coding/frame_buffer2.cc
+++ b/modules/video_coding/frame_buffer2.cc
@@ -13,6 +13,7 @@
 #include <algorithm>
 #include <cstring>
 #include <queue>
+#include <vector>
 
 #include "modules/video_coding/include/video_coding_defines.h"
 #include "modules/video_coding/jitter_estimator.h"
@@ -486,20 +487,34 @@
                                                    FrameMap::iterator info) {
   TRACE_EVENT0("webrtc", "FrameBuffer::UpdateFrameInfoWithIncomingFrame");
   const VideoLayerFrameId& id = frame.id;
-  info->second.num_missing_continuous = frame.num_references;
-  info->second.num_missing_decodable = frame.num_references;
 
   RTC_DCHECK(last_decoded_frame_it_ == frames_.end() ||
              last_decoded_frame_it_->first < info->first);
 
-  // Check how many dependencies that have already been fulfilled.
+  // In this function we determine how many missing dependencies this |frame|
+  // has to become continuous/decodable. If a frame that this |frame| depend
+  // on has already been decoded then we can ignore that dependency since it has
+  // already been fulfilled.
+  //
+  // For all other frames we will register a backwards reference to this |frame|
+  // so that |num_missing_continuous| and |num_missing_decodable| can be
+  // decremented as frames become continuous/are decoded.
+  struct Dependency {
+    VideoLayerFrameId id;
+    bool continuous;
+  };
+  std::vector<Dependency> not_yet_fulfilled_dependencies;
+
+  // Find all dependencies that have not yet been fulfilled.
   for (size_t i = 0; i < frame.num_references; ++i) {
     VideoLayerFrameId ref_key(frame.references[i], frame.id.spatial_layer);
     auto ref_info = frames_.find(ref_key);
 
-    // Does |frame| depend on a frame earlier than the last decoded frame?
+    // Does |frame| depend on a frame earlier than the last decoded one?
     if (last_decoded_frame_it_ != frames_.end() &&
         ref_key <= last_decoded_frame_it_->first) {
+      // Was that frame decoded? If not, this |frame| will never become
+      // decodable.
       if (ref_info == frames_.end()) {
         int64_t now_ms = clock_->TimeInMilliseconds();
         if (last_log_non_decoded_ms_ + kLogNonDecodedIntervalMs < now_ms) {
@@ -512,57 +527,51 @@
         }
         return false;
       }
-
-      --info->second.num_missing_continuous;
-      --info->second.num_missing_decodable;
     } else {
-      if (ref_info == frames_.end())
-        ref_info = frames_.insert(std::make_pair(ref_key, FrameInfo())).first;
-
-      if (ref_info->second.continuous)
-        --info->second.num_missing_continuous;
-
-      // Add backwards reference so |frame| can be updated when new
-      // frames are inserted or decoded.
-      ref_info->second.dependent_frames[ref_info->second.num_dependent_frames] =
-          id;
-      RTC_DCHECK_LT(ref_info->second.num_dependent_frames,
-                    (FrameInfo::kMaxNumDependentFrames - 1));
-      // TODO(philipel): Look into why this could happen and handle
-      // appropriately.
-      if (ref_info->second.num_dependent_frames <
-          (FrameInfo::kMaxNumDependentFrames - 1)) {
-        ++ref_info->second.num_dependent_frames;
-      }
+      bool ref_continuous =
+          ref_info != frames_.end() && ref_info->second.continuous;
+      not_yet_fulfilled_dependencies.push_back({ref_key, ref_continuous});
     }
-    RTC_DCHECK_LE(ref_info->second.num_missing_continuous,
-                  ref_info->second.num_missing_decodable);
   }
 
-  // Check if we have the lower spatial layer frame.
+  // Does |frame| depend on the lower spatial layer?
   if (frame.inter_layer_predicted) {
-    ++info->second.num_missing_continuous;
-    ++info->second.num_missing_decodable;
-
     VideoLayerFrameId ref_key(frame.id.picture_id, frame.id.spatial_layer - 1);
-    // Gets or create the FrameInfo for the referenced frame.
-    auto ref_info = frames_.insert(std::make_pair(ref_key, FrameInfo())).first;
-    if (ref_info->second.continuous)
-      --info->second.num_missing_continuous;
+    auto ref_info = frames_.find(ref_key);
 
-    if (ref_info == last_decoded_frame_it_) {
-      --info->second.num_missing_decodable;
-    } else {
-      ref_info->second.dependent_frames[ref_info->second.num_dependent_frames] =
-          id;
-      ++ref_info->second.num_dependent_frames;
+    bool lower_layer_continuous =
+        ref_info != frames_.end() && ref_info->second.continuous;
+    bool lower_layer_decoded = last_decoded_frame_it_ != frames_.end() &&
+                               last_decoded_frame_it_->first == ref_key;
+
+    if (!lower_layer_continuous || !lower_layer_decoded) {
+      not_yet_fulfilled_dependencies.push_back(
+          {ref_key, lower_layer_continuous});
     }
-    RTC_DCHECK_LE(ref_info->second.num_missing_continuous,
-                  ref_info->second.num_missing_decodable);
   }
 
-  RTC_DCHECK_LE(info->second.num_missing_continuous,
-                info->second.num_missing_decodable);
+  info->second.num_missing_continuous = not_yet_fulfilled_dependencies.size();
+  info->second.num_missing_decodable = not_yet_fulfilled_dependencies.size();
+
+  for (const Dependency& dep : not_yet_fulfilled_dependencies) {
+    if (dep.continuous)
+      --info->second.num_missing_continuous;
+
+    // At this point we know we want to insert this frame, so here we
+    // intentionally get or create the FrameInfo for this dependency.
+    FrameInfo* dep_info = &frames_[dep.id];
+
+    if (dep_info->num_dependent_frames <
+        (FrameInfo::kMaxNumDependentFrames - 1)) {
+      dep_info->dependent_frames[dep_info->num_dependent_frames] = id;
+      ++dep_info->num_dependent_frames;
+    } else {
+      RTC_LOG(LS_WARNING) << "Frame with (picture_id:spatial_id) ("
+                          << dep.id.picture_id << ":"
+                          << static_cast<int>(dep.id.spatial_layer)
+                          << ") is referenced by too many frames.";
+    }
+  }
 
   return true;
 }