Unwrap TL0 pic index to avoid having to work with a wrapped number.

This is to avoid clearing the |gof_info_| map when there are jumps in the
tl0 pic index.

Bug: chromium:855211
Change-Id: I762557070d65b3c535cb9a49498975bcd9c2c485
Reviewed-on: https://webrtc-review.googlesource.com/86943
Reviewed-by: Björn Terelius <terelius@webrtc.org>
Commit-Queue: Philip Eliasson <philipel@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23872}
diff --git a/modules/video_coding/rtp_frame_reference_finder.cc b/modules/video_coding/rtp_frame_reference_finder.cc
index 396935c..109d506 100644
--- a/modules/video_coding/rtp_frame_reference_finder.cc
+++ b/modules/video_coding/rtp_frame_reference_finder.cc
@@ -272,8 +272,10 @@
     } while (last_picture_id_ != frame->id.picture_id);
   }
 
+  int64_t unwrapped_tl0 = tl0_unwrapper_.Unwrap(codec_header.tl0PicIdx);
+
   // Clean up info for base layers that are too old.
-  uint8_t old_tl0_pic_idx = codec_header.tl0PicIdx - kMaxLayerInfo;
+  int64_t old_tl0_pic_idx = unwrapped_tl0 - kMaxLayerInfo;
   auto clean_layer_info_to = layer_info_.lower_bound(old_tl0_pic_idx);
   layer_info_.erase(layer_info_.begin(), clean_layer_info_to);
 
@@ -286,14 +288,13 @@
 
   if (frame->frame_type() == kVideoFrameKey) {
     frame->num_references = 0;
-    layer_info_[codec_header.tl0PicIdx].fill(-1);
-    UpdateLayerInfoVp8(frame, codec_header);
+    layer_info_[unwrapped_tl0].fill(-1);
+    UpdateLayerInfoVp8(frame, unwrapped_tl0, codec_header.temporalIdx);
     return kHandOff;
   }
 
-  auto layer_info_it = layer_info_.find(codec_header.temporalIdx == 0
-                                            ? codec_header.tl0PicIdx - 1
-                                            : codec_header.tl0PicIdx);
+  auto layer_info_it = layer_info_.find(
+      codec_header.temporalIdx == 0 ? unwrapped_tl0 - 1 : unwrapped_tl0);
 
   // If we don't have the base layer frame yet, stash this frame.
   if (layer_info_it == layer_info_.end())
@@ -304,11 +305,10 @@
   // base layer frame.
   if (codec_header.temporalIdx == 0) {
     layer_info_it =
-        layer_info_.emplace(codec_header.tl0PicIdx, layer_info_it->second)
-            .first;
+        layer_info_.emplace(unwrapped_tl0, layer_info_it->second).first;
     frame->num_references = 1;
     frame->references[0] = layer_info_it->second[0];
-    UpdateLayerInfoVp8(frame, codec_header);
+    UpdateLayerInfoVp8(frame, unwrapped_tl0, codec_header.temporalIdx);
     return kHandOff;
   }
 
@@ -317,7 +317,7 @@
     frame->num_references = 1;
     frame->references[0] = layer_info_it->second[0];
 
-    UpdateLayerInfoVp8(frame, codec_header);
+    UpdateLayerInfoVp8(frame, unwrapped_tl0, codec_header.temporalIdx);
     return kHandOff;
   }
 
@@ -361,30 +361,28 @@
     frame->references[layer] = layer_info_it->second[layer];
   }
 
-  UpdateLayerInfoVp8(frame, codec_header);
+  UpdateLayerInfoVp8(frame, unwrapped_tl0, codec_header.temporalIdx);
   return kHandOff;
 }
 
-void RtpFrameReferenceFinder::UpdateLayerInfoVp8(
-    RtpFrameObject* frame,
-    const RTPVideoHeaderVP8& codec_header) {
-  uint8_t tl0_pic_idx = codec_header.tl0PicIdx;
-  uint8_t temporal_index = codec_header.temporalIdx;
-  auto layer_info_it = layer_info_.find(tl0_pic_idx);
+void RtpFrameReferenceFinder::UpdateLayerInfoVp8(RtpFrameObject* frame,
+                                                 int64_t unwrapped_tl0,
+                                                 uint8_t temporal_idx) {
+  auto layer_info_it = layer_info_.find(unwrapped_tl0);
 
   // Update this layer info and newer.
   while (layer_info_it != layer_info_.end()) {
-    if (layer_info_it->second[temporal_index] != -1 &&
-        AheadOf<uint16_t, kPicIdLength>(layer_info_it->second[temporal_index],
+    if (layer_info_it->second[temporal_idx] != -1 &&
+        AheadOf<uint16_t, kPicIdLength>(layer_info_it->second[temporal_idx],
                                         frame->id.picture_id)) {
       // The frame was not newer, then no subsequent layer info have to be
       // update.
       break;
     }
 
-    layer_info_it->second[codec_header.temporalIdx] = frame->id.picture_id;
-    ++tl0_pic_idx;
-    layer_info_it = layer_info_.find(tl0_pic_idx);
+    layer_info_it->second[temporal_idx] = frame->id.picture_id;
+    ++unwrapped_tl0;
+    layer_info_it = layer_info_.find(unwrapped_tl0);
   }
   not_yet_received_frames_.erase(frame->id.picture_id);
 
@@ -403,7 +401,8 @@
   const RTPVideoHeaderVP9& codec_header = rtp_codec_header->VP9;
 
   if (codec_header.picture_id == kNoPictureId ||
-      codec_header.temporal_idx == kNoTemporalIdx) {
+      codec_header.temporal_idx == kNoTemporalIdx ||
+      codec_header.tl0_pic_idx == kNoTl0PicIdx) {
     return ManageFrameGeneric(std::move(frame), codec_header.picture_id);
   }
 
@@ -429,6 +428,7 @@
   }
 
   GofInfo* info;
+  int64_t unwrapped_tl0 = tl0_unwrapper_.Unwrap(codec_header.tl0_pic_idx);
   if (codec_header.ss_data_available) {
     if (codec_header.temporal_idx != 0) {
       RTC_LOG(LS_WARNING) << "Received scalability structure on a non base "
@@ -442,12 +442,12 @@
 
       scalability_structures_[current_ss_idx_] = codec_header.gof;
       scalability_structures_[current_ss_idx_].pid_start = frame->id.picture_id;
-      gof_info_.emplace(codec_header.tl0_pic_idx,
+      gof_info_.emplace(unwrapped_tl0,
                         GofInfo(&scalability_structures_[current_ss_idx_],
                                 frame->id.picture_id));
     }
 
-    const auto gof_info_it = gof_info_.find(codec_header.tl0_pic_idx);
+    const auto gof_info_it = gof_info_.find(unwrapped_tl0);
     if (gof_info_it == gof_info_.end())
       return kStash;
 
@@ -465,27 +465,25 @@
       return kDrop;
     }
 
-    auto gof_info_it = gof_info_.find((codec_header.temporal_idx == 0)
-                                          ? codec_header.tl0_pic_idx - 1
-                                          : codec_header.tl0_pic_idx);
+    auto gof_info_it = gof_info_.find(
+        (codec_header.temporal_idx == 0) ? unwrapped_tl0 - 1 : unwrapped_tl0);
 
     // Gof info for this frame is not available yet, stash this frame.
     if (gof_info_it == gof_info_.end())
       return kStash;
 
     if (codec_header.temporal_idx == 0) {
-      gof_info_it =
-          gof_info_
-              .emplace(codec_header.tl0_pic_idx,
-                       GofInfo(gof_info_it->second.gof, frame->id.picture_id))
-              .first;
+      gof_info_it = gof_info_
+                        .emplace(unwrapped_tl0, GofInfo(gof_info_it->second.gof,
+                                                        frame->id.picture_id))
+                        .first;
     }
 
     info = &gof_info_it->second;
   }
 
   // Clean up info for base layers that are too old.
-  uint8_t old_tl0_pic_idx = codec_header.tl0_pic_idx - kMaxGofSaved;
+  int64_t old_tl0_pic_idx = unwrapped_tl0 - kMaxGofSaved;
   auto clean_gof_info_to = gof_info_.lower_bound(old_tl0_pic_idx);
   gof_info_.erase(gof_info_.begin(), clean_gof_info_to);
 
diff --git a/modules/video_coding/rtp_frame_reference_finder.h b/modules/video_coding/rtp_frame_reference_finder.h
index f0344f1..ceceeca 100644
--- a/modules/video_coding/rtp_frame_reference_finder.h
+++ b/modules/video_coding/rtp_frame_reference_finder.h
@@ -100,7 +100,8 @@
   // Updates necessary layer info state used to determine frame references for
   // Vp8.
   void UpdateLayerInfoVp8(RtpFrameObject* frame,
-                          const RTPVideoHeaderVP8& codec_header)
+                          int64_t unwrapped_tl0,
+                          uint8_t temporal_idx)
       RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
 
   // Find references for Vp9 frames
@@ -162,11 +163,9 @@
       RTC_GUARDED_BY(crit_);
 
   // Holds the information about the last completed frame for a given temporal
-  // layer given a Tl0 picture index.
-  std::map<uint8_t,
-           std::array<int16_t, kMaxTemporalLayers>,
-           DescendingSeqNumComp<uint8_t>>
-      layer_info_ RTC_GUARDED_BY(crit_);
+  // layer given an unwrapped Tl0 picture index.
+  std::map<int64_t, std::array<int16_t, kMaxTemporalLayers>> layer_info_
+      RTC_GUARDED_BY(crit_);
 
   // Where the current scalability structure is in the
   // |scalability_structures_| array.
@@ -176,9 +175,8 @@
   std::array<GofInfoVP9, kMaxGofSaved> scalability_structures_
       RTC_GUARDED_BY(crit_);
 
-  // Holds the the Gof information for a given TL0 picture index.
-  std::map<uint8_t, GofInfo, DescendingSeqNumComp<uint8_t>> gof_info_
-      RTC_GUARDED_BY(crit_);
+  // Holds the the Gof information for a given unwrapped TL0 picture index.
+  std::map<int64_t, GofInfo> gof_info_ RTC_GUARDED_BY(crit_);
 
   // Keep track of which picture id and which temporal layer that had the
   // up switch flag set.
@@ -204,6 +202,8 @@
   // Unwrapper used to unwrap VP8/VP9 streams which have their picture id
   // specified.
   SeqNumUnwrapper<uint16_t, kPicIdLength> unwrapper_ RTC_GUARDED_BY(crit_);
+
+  SeqNumUnwrapper<uint8_t> tl0_unwrapper_ RTC_GUARDED_BY(crit_);
 };
 
 }  // namespace video_coding
diff --git a/modules/video_coding/rtp_frame_reference_finder_unittest.cc b/modules/video_coding/rtp_frame_reference_finder_unittest.cc
index 0d63a1d..83454eb 100644
--- a/modules/video_coding/rtp_frame_reference_finder_unittest.cc
+++ b/modules/video_coding/rtp_frame_reference_finder_unittest.cc
@@ -1331,6 +1331,16 @@
   InsertVp9Gof(sn + 1, sn + 1, false, pid + 1000, 0, 0, 1);
 }
 
+TEST_F(TestRtpFrameReferenceFinder, Vp9GofTl0Jump) {
+  uint16_t pid = Rand();
+  uint16_t sn = Rand();
+  GofInfoVP9 ss;
+  ss.SetGofInfoVP9(kTemporalStructureMode3);
+
+  InsertVp9Gof(sn, sn, true, pid + 0, 0, 0, 125, true, &ss);
+  InsertVp9Gof(sn + 1, sn + 1, false, pid + 1, 0, 0, 0, false, &ss);
+}
+
 TEST_F(TestRtpFrameReferenceFinder, Vp9GofTidTooHigh) {
   // Same as RtpFrameReferenceFinder::kMaxTemporalLayers.
   const int kMaxTemporalLayers = 5;