xref: /aosp_15_r20/external/webrtc/modules/video_coding/rtp_seq_num_only_ref_finder.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "modules/video_coding/rtp_seq_num_only_ref_finder.h"
12 
13 #include <utility>
14 
15 #include "rtc_base/logging.h"
16 
17 namespace webrtc {
18 
ManageFrame(std::unique_ptr<RtpFrameObject> frame)19 RtpFrameReferenceFinder::ReturnVector RtpSeqNumOnlyRefFinder::ManageFrame(
20     std::unique_ptr<RtpFrameObject> frame) {
21   FrameDecision decision = ManageFrameInternal(frame.get());
22 
23   RtpFrameReferenceFinder::ReturnVector res;
24   switch (decision) {
25     case kStash:
26       if (stashed_frames_.size() > kMaxStashedFrames)
27         stashed_frames_.pop_back();
28       stashed_frames_.push_front(std::move(frame));
29       return res;
30     case kHandOff:
31       res.push_back(std::move(frame));
32       RetryStashedFrames(res);
33       return res;
34     case kDrop:
35       return res;
36   }
37 
38   return res;
39 }
40 
41 RtpSeqNumOnlyRefFinder::FrameDecision
ManageFrameInternal(RtpFrameObject * frame)42 RtpSeqNumOnlyRefFinder::ManageFrameInternal(RtpFrameObject* frame) {
43   if (frame->frame_type() == VideoFrameType::kVideoFrameKey) {
44     last_seq_num_gop_.insert(std::make_pair(
45         frame->last_seq_num(),
46         std::make_pair(frame->last_seq_num(), frame->last_seq_num())));
47   }
48 
49   // We have received a frame but not yet a keyframe, stash this frame.
50   if (last_seq_num_gop_.empty())
51     return kStash;
52 
53   // Clean up info for old keyframes but make sure to keep info
54   // for the last keyframe.
55   auto clean_to = last_seq_num_gop_.lower_bound(frame->last_seq_num() - 100);
56   for (auto it = last_seq_num_gop_.begin();
57        it != clean_to && last_seq_num_gop_.size() > 1;) {
58     it = last_seq_num_gop_.erase(it);
59   }
60 
61   // Find the last sequence number of the last frame for the keyframe
62   // that this frame indirectly references.
63   auto seq_num_it = last_seq_num_gop_.upper_bound(frame->last_seq_num());
64   if (seq_num_it == last_seq_num_gop_.begin()) {
65     RTC_LOG(LS_WARNING) << "Generic frame with packet range ["
66                         << frame->first_seq_num() << ", "
67                         << frame->last_seq_num()
68                         << "] has no GoP, dropping frame.";
69     return kDrop;
70   }
71   seq_num_it--;
72 
73   // Make sure the packet sequence numbers are continuous, otherwise stash
74   // this frame.
75   uint16_t last_picture_id_gop = seq_num_it->second.first;
76   uint16_t last_picture_id_with_padding_gop = seq_num_it->second.second;
77   if (frame->frame_type() == VideoFrameType::kVideoFrameDelta) {
78     uint16_t prev_seq_num = frame->first_seq_num() - 1;
79 
80     if (prev_seq_num != last_picture_id_with_padding_gop)
81       return kStash;
82   }
83 
84   RTC_DCHECK(AheadOrAt(frame->last_seq_num(), seq_num_it->first));
85 
86   // Since keyframes can cause reordering we can't simply assign the
87   // picture id according to some incrementing counter.
88   frame->SetId(frame->last_seq_num());
89   frame->num_references =
90       frame->frame_type() == VideoFrameType::kVideoFrameDelta;
91   frame->references[0] = rtp_seq_num_unwrapper_.Unwrap(last_picture_id_gop);
92   if (AheadOf<uint16_t>(frame->Id(), last_picture_id_gop)) {
93     seq_num_it->second.first = frame->Id();
94     seq_num_it->second.second = frame->Id();
95   }
96 
97   UpdateLastPictureIdWithPadding(frame->Id());
98   frame->SetSpatialIndex(0);
99   frame->SetId(rtp_seq_num_unwrapper_.Unwrap(frame->Id()));
100   return kHandOff;
101 }
102 
RetryStashedFrames(RtpFrameReferenceFinder::ReturnVector & res)103 void RtpSeqNumOnlyRefFinder::RetryStashedFrames(
104     RtpFrameReferenceFinder::ReturnVector& res) {
105   bool complete_frame = false;
106   do {
107     complete_frame = false;
108     for (auto frame_it = stashed_frames_.begin();
109          frame_it != stashed_frames_.end();) {
110       FrameDecision decision = ManageFrameInternal(frame_it->get());
111 
112       switch (decision) {
113         case kStash:
114           ++frame_it;
115           break;
116         case kHandOff:
117           complete_frame = true;
118           res.push_back(std::move(*frame_it));
119           [[fallthrough]];
120         case kDrop:
121           frame_it = stashed_frames_.erase(frame_it);
122       }
123     }
124   } while (complete_frame);
125 }
126 
UpdateLastPictureIdWithPadding(uint16_t seq_num)127 void RtpSeqNumOnlyRefFinder::UpdateLastPictureIdWithPadding(uint16_t seq_num) {
128   auto gop_seq_num_it = last_seq_num_gop_.upper_bound(seq_num);
129 
130   // If this padding packet "belongs" to a group of pictures that we don't track
131   // anymore, do nothing.
132   if (gop_seq_num_it == last_seq_num_gop_.begin())
133     return;
134   --gop_seq_num_it;
135 
136   // Calculate the next contiuous sequence number and search for it in
137   // the padding packets we have stashed.
138   uint16_t next_seq_num_with_padding = gop_seq_num_it->second.second + 1;
139   auto padding_seq_num_it =
140       stashed_padding_.lower_bound(next_seq_num_with_padding);
141 
142   // While there still are padding packets and those padding packets are
143   // continuous, then advance the "last-picture-id-with-padding" and remove
144   // the stashed padding packet.
145   while (padding_seq_num_it != stashed_padding_.end() &&
146          *padding_seq_num_it == next_seq_num_with_padding) {
147     gop_seq_num_it->second.second = next_seq_num_with_padding;
148     ++next_seq_num_with_padding;
149     padding_seq_num_it = stashed_padding_.erase(padding_seq_num_it);
150   }
151 
152   // In the case where the stream has been continuous without any new keyframes
153   // for a while there is a risk that new frames will appear to be older than
154   // the keyframe they belong to due to wrapping sequence number. In order
155   // to prevent this we advance the picture id of the keyframe every so often.
156   if (ForwardDiff(gop_seq_num_it->first, seq_num) > 10000) {
157     auto save = gop_seq_num_it->second;
158     last_seq_num_gop_.clear();
159     last_seq_num_gop_[seq_num] = save;
160   }
161 }
162 
PaddingReceived(uint16_t seq_num)163 RtpFrameReferenceFinder::ReturnVector RtpSeqNumOnlyRefFinder::PaddingReceived(
164     uint16_t seq_num) {
165   auto clean_padding_to =
166       stashed_padding_.lower_bound(seq_num - kMaxPaddingAge);
167   stashed_padding_.erase(stashed_padding_.begin(), clean_padding_to);
168   stashed_padding_.insert(seq_num);
169   UpdateLastPictureIdWithPadding(seq_num);
170   RtpFrameReferenceFinder::ReturnVector res;
171   RetryStashedFrames(res);
172   return res;
173 }
174 
ClearTo(uint16_t seq_num)175 void RtpSeqNumOnlyRefFinder::ClearTo(uint16_t seq_num) {
176   auto it = stashed_frames_.begin();
177   while (it != stashed_frames_.end()) {
178     if (AheadOf<uint16_t>(seq_num, (*it)->first_seq_num())) {
179       it = stashed_frames_.erase(it);
180     } else {
181       ++it;
182     }
183   }
184 }
185 
186 }  // namespace webrtc
187