xref: /aosp_15_r20/external/webrtc/modules/video_coding/decoding_state.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker 
11*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/decoding_state.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include "common_video/h264/h264_common.h"
14*d9f75844SAndroid Build Coastguard Worker #include "modules/include/module_common_types_public.h"
15*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/frame_buffer.h"
16*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/jitter_buffer_common.h"
17*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/packet.h"
18*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
19*d9f75844SAndroid Build Coastguard Worker 
20*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
21*d9f75844SAndroid Build Coastguard Worker 
VCMDecodingState()22*d9f75844SAndroid Build Coastguard Worker VCMDecodingState::VCMDecodingState()
23*d9f75844SAndroid Build Coastguard Worker     : sequence_num_(0),
24*d9f75844SAndroid Build Coastguard Worker       time_stamp_(0),
25*d9f75844SAndroid Build Coastguard Worker       picture_id_(kNoPictureId),
26*d9f75844SAndroid Build Coastguard Worker       temporal_id_(kNoTemporalIdx),
27*d9f75844SAndroid Build Coastguard Worker       tl0_pic_id_(kNoTl0PicIdx),
28*d9f75844SAndroid Build Coastguard Worker       full_sync_(true),
29*d9f75844SAndroid Build Coastguard Worker       in_initial_state_(true) {
30*d9f75844SAndroid Build Coastguard Worker   memset(frame_decoded_, 0, sizeof(frame_decoded_));
31*d9f75844SAndroid Build Coastguard Worker }
32*d9f75844SAndroid Build Coastguard Worker 
~VCMDecodingState()33*d9f75844SAndroid Build Coastguard Worker VCMDecodingState::~VCMDecodingState() {}
34*d9f75844SAndroid Build Coastguard Worker 
Reset()35*d9f75844SAndroid Build Coastguard Worker void VCMDecodingState::Reset() {
36*d9f75844SAndroid Build Coastguard Worker   // TODO(mikhal): Verify - not always would want to reset the sync
37*d9f75844SAndroid Build Coastguard Worker   sequence_num_ = 0;
38*d9f75844SAndroid Build Coastguard Worker   time_stamp_ = 0;
39*d9f75844SAndroid Build Coastguard Worker   picture_id_ = kNoPictureId;
40*d9f75844SAndroid Build Coastguard Worker   temporal_id_ = kNoTemporalIdx;
41*d9f75844SAndroid Build Coastguard Worker   tl0_pic_id_ = kNoTl0PicIdx;
42*d9f75844SAndroid Build Coastguard Worker   full_sync_ = true;
43*d9f75844SAndroid Build Coastguard Worker   in_initial_state_ = true;
44*d9f75844SAndroid Build Coastguard Worker   memset(frame_decoded_, 0, sizeof(frame_decoded_));
45*d9f75844SAndroid Build Coastguard Worker   received_sps_.clear();
46*d9f75844SAndroid Build Coastguard Worker   received_pps_.clear();
47*d9f75844SAndroid Build Coastguard Worker }
48*d9f75844SAndroid Build Coastguard Worker 
time_stamp() const49*d9f75844SAndroid Build Coastguard Worker uint32_t VCMDecodingState::time_stamp() const {
50*d9f75844SAndroid Build Coastguard Worker   return time_stamp_;
51*d9f75844SAndroid Build Coastguard Worker }
52*d9f75844SAndroid Build Coastguard Worker 
sequence_num() const53*d9f75844SAndroid Build Coastguard Worker uint16_t VCMDecodingState::sequence_num() const {
54*d9f75844SAndroid Build Coastguard Worker   return sequence_num_;
55*d9f75844SAndroid Build Coastguard Worker }
56*d9f75844SAndroid Build Coastguard Worker 
IsOldFrame(const VCMFrameBuffer * frame) const57*d9f75844SAndroid Build Coastguard Worker bool VCMDecodingState::IsOldFrame(const VCMFrameBuffer* frame) const {
58*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(frame);
59*d9f75844SAndroid Build Coastguard Worker   if (in_initial_state_)
60*d9f75844SAndroid Build Coastguard Worker     return false;
61*d9f75844SAndroid Build Coastguard Worker   return !IsNewerTimestamp(frame->Timestamp(), time_stamp_);
62*d9f75844SAndroid Build Coastguard Worker }
63*d9f75844SAndroid Build Coastguard Worker 
IsOldPacket(const VCMPacket * packet) const64*d9f75844SAndroid Build Coastguard Worker bool VCMDecodingState::IsOldPacket(const VCMPacket* packet) const {
65*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(packet);
66*d9f75844SAndroid Build Coastguard Worker   if (in_initial_state_)
67*d9f75844SAndroid Build Coastguard Worker     return false;
68*d9f75844SAndroid Build Coastguard Worker   return !IsNewerTimestamp(packet->timestamp, time_stamp_);
69*d9f75844SAndroid Build Coastguard Worker }
70*d9f75844SAndroid Build Coastguard Worker 
SetState(const VCMFrameBuffer * frame)71*d9f75844SAndroid Build Coastguard Worker void VCMDecodingState::SetState(const VCMFrameBuffer* frame) {
72*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(frame);
73*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK_GE(frame->GetHighSeqNum(), 0);
74*d9f75844SAndroid Build Coastguard Worker   if (!UsingFlexibleMode(frame))
75*d9f75844SAndroid Build Coastguard Worker     UpdateSyncState(frame);
76*d9f75844SAndroid Build Coastguard Worker   sequence_num_ = static_cast<uint16_t>(frame->GetHighSeqNum());
77*d9f75844SAndroid Build Coastguard Worker   time_stamp_ = frame->Timestamp();
78*d9f75844SAndroid Build Coastguard Worker   picture_id_ = frame->PictureId();
79*d9f75844SAndroid Build Coastguard Worker   temporal_id_ = frame->TemporalId();
80*d9f75844SAndroid Build Coastguard Worker   tl0_pic_id_ = frame->Tl0PicId();
81*d9f75844SAndroid Build Coastguard Worker 
82*d9f75844SAndroid Build Coastguard Worker   for (const NaluInfo& nalu : frame->GetNaluInfos()) {
83*d9f75844SAndroid Build Coastguard Worker     if (nalu.type == H264::NaluType::kPps) {
84*d9f75844SAndroid Build Coastguard Worker       if (nalu.pps_id < 0) {
85*d9f75844SAndroid Build Coastguard Worker         RTC_LOG(LS_WARNING) << "Received pps without pps id.";
86*d9f75844SAndroid Build Coastguard Worker       } else if (nalu.sps_id < 0) {
87*d9f75844SAndroid Build Coastguard Worker         RTC_LOG(LS_WARNING) << "Received pps without sps id.";
88*d9f75844SAndroid Build Coastguard Worker       } else {
89*d9f75844SAndroid Build Coastguard Worker         received_pps_[nalu.pps_id] = nalu.sps_id;
90*d9f75844SAndroid Build Coastguard Worker       }
91*d9f75844SAndroid Build Coastguard Worker     } else if (nalu.type == H264::NaluType::kSps) {
92*d9f75844SAndroid Build Coastguard Worker       if (nalu.sps_id < 0) {
93*d9f75844SAndroid Build Coastguard Worker         RTC_LOG(LS_WARNING) << "Received sps without sps id.";
94*d9f75844SAndroid Build Coastguard Worker       } else {
95*d9f75844SAndroid Build Coastguard Worker         received_sps_.insert(nalu.sps_id);
96*d9f75844SAndroid Build Coastguard Worker       }
97*d9f75844SAndroid Build Coastguard Worker     }
98*d9f75844SAndroid Build Coastguard Worker   }
99*d9f75844SAndroid Build Coastguard Worker 
100*d9f75844SAndroid Build Coastguard Worker   if (UsingFlexibleMode(frame)) {
101*d9f75844SAndroid Build Coastguard Worker     uint16_t frame_index = picture_id_ % kFrameDecodedLength;
102*d9f75844SAndroid Build Coastguard Worker     if (in_initial_state_) {
103*d9f75844SAndroid Build Coastguard Worker       frame_decoded_cleared_to_ = frame_index;
104*d9f75844SAndroid Build Coastguard Worker     } else if (frame->FrameType() == VideoFrameType::kVideoFrameKey) {
105*d9f75844SAndroid Build Coastguard Worker       memset(frame_decoded_, 0, sizeof(frame_decoded_));
106*d9f75844SAndroid Build Coastguard Worker       frame_decoded_cleared_to_ = frame_index;
107*d9f75844SAndroid Build Coastguard Worker     } else {
108*d9f75844SAndroid Build Coastguard Worker       if (AheadOfFramesDecodedClearedTo(frame_index)) {
109*d9f75844SAndroid Build Coastguard Worker         while (frame_decoded_cleared_to_ != frame_index) {
110*d9f75844SAndroid Build Coastguard Worker           frame_decoded_cleared_to_ =
111*d9f75844SAndroid Build Coastguard Worker               (frame_decoded_cleared_to_ + 1) % kFrameDecodedLength;
112*d9f75844SAndroid Build Coastguard Worker           frame_decoded_[frame_decoded_cleared_to_] = false;
113*d9f75844SAndroid Build Coastguard Worker         }
114*d9f75844SAndroid Build Coastguard Worker       }
115*d9f75844SAndroid Build Coastguard Worker     }
116*d9f75844SAndroid Build Coastguard Worker     frame_decoded_[frame_index] = true;
117*d9f75844SAndroid Build Coastguard Worker   }
118*d9f75844SAndroid Build Coastguard Worker 
119*d9f75844SAndroid Build Coastguard Worker   in_initial_state_ = false;
120*d9f75844SAndroid Build Coastguard Worker }
121*d9f75844SAndroid Build Coastguard Worker 
CopyFrom(const VCMDecodingState & state)122*d9f75844SAndroid Build Coastguard Worker void VCMDecodingState::CopyFrom(const VCMDecodingState& state) {
123*d9f75844SAndroid Build Coastguard Worker   sequence_num_ = state.sequence_num_;
124*d9f75844SAndroid Build Coastguard Worker   time_stamp_ = state.time_stamp_;
125*d9f75844SAndroid Build Coastguard Worker   picture_id_ = state.picture_id_;
126*d9f75844SAndroid Build Coastguard Worker   temporal_id_ = state.temporal_id_;
127*d9f75844SAndroid Build Coastguard Worker   tl0_pic_id_ = state.tl0_pic_id_;
128*d9f75844SAndroid Build Coastguard Worker   full_sync_ = state.full_sync_;
129*d9f75844SAndroid Build Coastguard Worker   in_initial_state_ = state.in_initial_state_;
130*d9f75844SAndroid Build Coastguard Worker   frame_decoded_cleared_to_ = state.frame_decoded_cleared_to_;
131*d9f75844SAndroid Build Coastguard Worker   memcpy(frame_decoded_, state.frame_decoded_, sizeof(frame_decoded_));
132*d9f75844SAndroid Build Coastguard Worker   received_sps_ = state.received_sps_;
133*d9f75844SAndroid Build Coastguard Worker   received_pps_ = state.received_pps_;
134*d9f75844SAndroid Build Coastguard Worker }
135*d9f75844SAndroid Build Coastguard Worker 
UpdateEmptyFrame(const VCMFrameBuffer * frame)136*d9f75844SAndroid Build Coastguard Worker bool VCMDecodingState::UpdateEmptyFrame(const VCMFrameBuffer* frame) {
137*d9f75844SAndroid Build Coastguard Worker   bool empty_packet = frame->GetHighSeqNum() == frame->GetLowSeqNum();
138*d9f75844SAndroid Build Coastguard Worker   if (in_initial_state_ && empty_packet) {
139*d9f75844SAndroid Build Coastguard Worker     // Drop empty packets as long as we are in the initial state.
140*d9f75844SAndroid Build Coastguard Worker     return true;
141*d9f75844SAndroid Build Coastguard Worker   }
142*d9f75844SAndroid Build Coastguard Worker   if ((empty_packet && ContinuousSeqNum(frame->GetHighSeqNum())) ||
143*d9f75844SAndroid Build Coastguard Worker       ContinuousFrame(frame)) {
144*d9f75844SAndroid Build Coastguard Worker     // Continuous empty packets or continuous frames can be dropped if we
145*d9f75844SAndroid Build Coastguard Worker     // advance the sequence number.
146*d9f75844SAndroid Build Coastguard Worker     sequence_num_ = frame->GetHighSeqNum();
147*d9f75844SAndroid Build Coastguard Worker     time_stamp_ = frame->Timestamp();
148*d9f75844SAndroid Build Coastguard Worker     return true;
149*d9f75844SAndroid Build Coastguard Worker   }
150*d9f75844SAndroid Build Coastguard Worker   return false;
151*d9f75844SAndroid Build Coastguard Worker }
152*d9f75844SAndroid Build Coastguard Worker 
UpdateOldPacket(const VCMPacket * packet)153*d9f75844SAndroid Build Coastguard Worker void VCMDecodingState::UpdateOldPacket(const VCMPacket* packet) {
154*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(packet);
155*d9f75844SAndroid Build Coastguard Worker   if (packet->timestamp == time_stamp_) {
156*d9f75844SAndroid Build Coastguard Worker     // Late packet belonging to the last decoded frame - make sure we update the
157*d9f75844SAndroid Build Coastguard Worker     // last decoded sequence number.
158*d9f75844SAndroid Build Coastguard Worker     sequence_num_ = LatestSequenceNumber(packet->seqNum, sequence_num_);
159*d9f75844SAndroid Build Coastguard Worker   }
160*d9f75844SAndroid Build Coastguard Worker }
161*d9f75844SAndroid Build Coastguard Worker 
SetSeqNum(uint16_t new_seq_num)162*d9f75844SAndroid Build Coastguard Worker void VCMDecodingState::SetSeqNum(uint16_t new_seq_num) {
163*d9f75844SAndroid Build Coastguard Worker   sequence_num_ = new_seq_num;
164*d9f75844SAndroid Build Coastguard Worker }
165*d9f75844SAndroid Build Coastguard Worker 
in_initial_state() const166*d9f75844SAndroid Build Coastguard Worker bool VCMDecodingState::in_initial_state() const {
167*d9f75844SAndroid Build Coastguard Worker   return in_initial_state_;
168*d9f75844SAndroid Build Coastguard Worker }
169*d9f75844SAndroid Build Coastguard Worker 
full_sync() const170*d9f75844SAndroid Build Coastguard Worker bool VCMDecodingState::full_sync() const {
171*d9f75844SAndroid Build Coastguard Worker   return full_sync_;
172*d9f75844SAndroid Build Coastguard Worker }
173*d9f75844SAndroid Build Coastguard Worker 
UpdateSyncState(const VCMFrameBuffer * frame)174*d9f75844SAndroid Build Coastguard Worker void VCMDecodingState::UpdateSyncState(const VCMFrameBuffer* frame) {
175*d9f75844SAndroid Build Coastguard Worker   if (in_initial_state_)
176*d9f75844SAndroid Build Coastguard Worker     return;
177*d9f75844SAndroid Build Coastguard Worker   if (frame->TemporalId() == kNoTemporalIdx ||
178*d9f75844SAndroid Build Coastguard Worker       frame->Tl0PicId() == kNoTl0PicIdx) {
179*d9f75844SAndroid Build Coastguard Worker     full_sync_ = true;
180*d9f75844SAndroid Build Coastguard Worker   } else if (frame->FrameType() == VideoFrameType::kVideoFrameKey ||
181*d9f75844SAndroid Build Coastguard Worker              frame->LayerSync()) {
182*d9f75844SAndroid Build Coastguard Worker     full_sync_ = true;
183*d9f75844SAndroid Build Coastguard Worker   } else if (full_sync_) {
184*d9f75844SAndroid Build Coastguard Worker     // Verify that we are still in sync.
185*d9f75844SAndroid Build Coastguard Worker     // Sync will be broken if continuity is true for layers but not for the
186*d9f75844SAndroid Build Coastguard Worker     // other methods (PictureId and SeqNum).
187*d9f75844SAndroid Build Coastguard Worker     if (UsingPictureId(frame)) {
188*d9f75844SAndroid Build Coastguard Worker       // First check for a valid tl0PicId.
189*d9f75844SAndroid Build Coastguard Worker       if (frame->Tl0PicId() - tl0_pic_id_ > 1) {
190*d9f75844SAndroid Build Coastguard Worker         full_sync_ = false;
191*d9f75844SAndroid Build Coastguard Worker       } else {
192*d9f75844SAndroid Build Coastguard Worker         full_sync_ = ContinuousPictureId(frame->PictureId());
193*d9f75844SAndroid Build Coastguard Worker       }
194*d9f75844SAndroid Build Coastguard Worker     } else {
195*d9f75844SAndroid Build Coastguard Worker       full_sync_ =
196*d9f75844SAndroid Build Coastguard Worker           ContinuousSeqNum(static_cast<uint16_t>(frame->GetLowSeqNum()));
197*d9f75844SAndroid Build Coastguard Worker     }
198*d9f75844SAndroid Build Coastguard Worker   }
199*d9f75844SAndroid Build Coastguard Worker }
200*d9f75844SAndroid Build Coastguard Worker 
ContinuousFrame(const VCMFrameBuffer * frame) const201*d9f75844SAndroid Build Coastguard Worker bool VCMDecodingState::ContinuousFrame(const VCMFrameBuffer* frame) const {
202*d9f75844SAndroid Build Coastguard Worker   // Check continuity based on the following hierarchy:
203*d9f75844SAndroid Build Coastguard Worker   // - Temporal layers (stop here if out of sync).
204*d9f75844SAndroid Build Coastguard Worker   // - Picture Id when available.
205*d9f75844SAndroid Build Coastguard Worker   // - Sequence numbers.
206*d9f75844SAndroid Build Coastguard Worker   // Return true when in initial state.
207*d9f75844SAndroid Build Coastguard Worker   // Note that when a method is not applicable it will return false.
208*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(frame);
209*d9f75844SAndroid Build Coastguard Worker   // A key frame is always considered continuous as it doesn't refer to any
210*d9f75844SAndroid Build Coastguard Worker   // frames and therefore won't introduce any errors even if prior frames are
211*d9f75844SAndroid Build Coastguard Worker   // missing.
212*d9f75844SAndroid Build Coastguard Worker   if (frame->FrameType() == VideoFrameType::kVideoFrameKey &&
213*d9f75844SAndroid Build Coastguard Worker       HaveSpsAndPps(frame->GetNaluInfos())) {
214*d9f75844SAndroid Build Coastguard Worker     return true;
215*d9f75844SAndroid Build Coastguard Worker   }
216*d9f75844SAndroid Build Coastguard Worker   // When in the initial state we always require a key frame to start decoding.
217*d9f75844SAndroid Build Coastguard Worker   if (in_initial_state_)
218*d9f75844SAndroid Build Coastguard Worker     return false;
219*d9f75844SAndroid Build Coastguard Worker   if (ContinuousLayer(frame->TemporalId(), frame->Tl0PicId()))
220*d9f75844SAndroid Build Coastguard Worker     return true;
221*d9f75844SAndroid Build Coastguard Worker   // tl0picId is either not used, or should remain unchanged.
222*d9f75844SAndroid Build Coastguard Worker   if (frame->Tl0PicId() != tl0_pic_id_)
223*d9f75844SAndroid Build Coastguard Worker     return false;
224*d9f75844SAndroid Build Coastguard Worker   // Base layers are not continuous or temporal layers are inactive.
225*d9f75844SAndroid Build Coastguard Worker   // In the presence of temporal layers, check for Picture ID/sequence number
226*d9f75844SAndroid Build Coastguard Worker   // continuity if sync can be restored by this frame.
227*d9f75844SAndroid Build Coastguard Worker   if (!full_sync_ && !frame->LayerSync())
228*d9f75844SAndroid Build Coastguard Worker     return false;
229*d9f75844SAndroid Build Coastguard Worker   if (UsingPictureId(frame)) {
230*d9f75844SAndroid Build Coastguard Worker     if (UsingFlexibleMode(frame)) {
231*d9f75844SAndroid Build Coastguard Worker       return ContinuousFrameRefs(frame);
232*d9f75844SAndroid Build Coastguard Worker     } else {
233*d9f75844SAndroid Build Coastguard Worker       return ContinuousPictureId(frame->PictureId());
234*d9f75844SAndroid Build Coastguard Worker     }
235*d9f75844SAndroid Build Coastguard Worker   } else {
236*d9f75844SAndroid Build Coastguard Worker     return ContinuousSeqNum(static_cast<uint16_t>(frame->GetLowSeqNum())) &&
237*d9f75844SAndroid Build Coastguard Worker            HaveSpsAndPps(frame->GetNaluInfos());
238*d9f75844SAndroid Build Coastguard Worker   }
239*d9f75844SAndroid Build Coastguard Worker }
240*d9f75844SAndroid Build Coastguard Worker 
ContinuousPictureId(int picture_id) const241*d9f75844SAndroid Build Coastguard Worker bool VCMDecodingState::ContinuousPictureId(int picture_id) const {
242*d9f75844SAndroid Build Coastguard Worker   int next_picture_id = picture_id_ + 1;
243*d9f75844SAndroid Build Coastguard Worker   if (picture_id < picture_id_) {
244*d9f75844SAndroid Build Coastguard Worker     // Wrap
245*d9f75844SAndroid Build Coastguard Worker     if (picture_id_ >= 0x80) {
246*d9f75844SAndroid Build Coastguard Worker       // 15 bits used for picture id
247*d9f75844SAndroid Build Coastguard Worker       return ((next_picture_id & 0x7FFF) == picture_id);
248*d9f75844SAndroid Build Coastguard Worker     } else {
249*d9f75844SAndroid Build Coastguard Worker       // 7 bits used for picture id
250*d9f75844SAndroid Build Coastguard Worker       return ((next_picture_id & 0x7F) == picture_id);
251*d9f75844SAndroid Build Coastguard Worker     }
252*d9f75844SAndroid Build Coastguard Worker   }
253*d9f75844SAndroid Build Coastguard Worker   // No wrap
254*d9f75844SAndroid Build Coastguard Worker   return (next_picture_id == picture_id);
255*d9f75844SAndroid Build Coastguard Worker }
256*d9f75844SAndroid Build Coastguard Worker 
ContinuousSeqNum(uint16_t seq_num) const257*d9f75844SAndroid Build Coastguard Worker bool VCMDecodingState::ContinuousSeqNum(uint16_t seq_num) const {
258*d9f75844SAndroid Build Coastguard Worker   return seq_num == static_cast<uint16_t>(sequence_num_ + 1);
259*d9f75844SAndroid Build Coastguard Worker }
260*d9f75844SAndroid Build Coastguard Worker 
ContinuousLayer(int temporal_id,int tl0_pic_id) const261*d9f75844SAndroid Build Coastguard Worker bool VCMDecodingState::ContinuousLayer(int temporal_id, int tl0_pic_id) const {
262*d9f75844SAndroid Build Coastguard Worker   // First, check if applicable.
263*d9f75844SAndroid Build Coastguard Worker   if (temporal_id == kNoTemporalIdx || tl0_pic_id == kNoTl0PicIdx)
264*d9f75844SAndroid Build Coastguard Worker     return false;
265*d9f75844SAndroid Build Coastguard Worker   // If this is the first frame to use temporal layers, make sure we start
266*d9f75844SAndroid Build Coastguard Worker   // from base.
267*d9f75844SAndroid Build Coastguard Worker   else if (tl0_pic_id_ == kNoTl0PicIdx && temporal_id_ == kNoTemporalIdx &&
268*d9f75844SAndroid Build Coastguard Worker            temporal_id == 0)
269*d9f75844SAndroid Build Coastguard Worker     return true;
270*d9f75844SAndroid Build Coastguard Worker 
271*d9f75844SAndroid Build Coastguard Worker   // Current implementation: Look for base layer continuity.
272*d9f75844SAndroid Build Coastguard Worker   if (temporal_id != 0)
273*d9f75844SAndroid Build Coastguard Worker     return false;
274*d9f75844SAndroid Build Coastguard Worker   return (static_cast<uint8_t>(tl0_pic_id_ + 1) == tl0_pic_id);
275*d9f75844SAndroid Build Coastguard Worker }
276*d9f75844SAndroid Build Coastguard Worker 
ContinuousFrameRefs(const VCMFrameBuffer * frame) const277*d9f75844SAndroid Build Coastguard Worker bool VCMDecodingState::ContinuousFrameRefs(const VCMFrameBuffer* frame) const {
278*d9f75844SAndroid Build Coastguard Worker   uint8_t num_refs = frame->CodecSpecific()->codecSpecific.VP9.num_ref_pics;
279*d9f75844SAndroid Build Coastguard Worker   for (uint8_t r = 0; r < num_refs; ++r) {
280*d9f75844SAndroid Build Coastguard Worker     uint16_t frame_ref = frame->PictureId() -
281*d9f75844SAndroid Build Coastguard Worker                          frame->CodecSpecific()->codecSpecific.VP9.p_diff[r];
282*d9f75844SAndroid Build Coastguard Worker     uint16_t frame_index = frame_ref % kFrameDecodedLength;
283*d9f75844SAndroid Build Coastguard Worker     if (AheadOfFramesDecodedClearedTo(frame_index) ||
284*d9f75844SAndroid Build Coastguard Worker         !frame_decoded_[frame_index]) {
285*d9f75844SAndroid Build Coastguard Worker       return false;
286*d9f75844SAndroid Build Coastguard Worker     }
287*d9f75844SAndroid Build Coastguard Worker   }
288*d9f75844SAndroid Build Coastguard Worker   return true;
289*d9f75844SAndroid Build Coastguard Worker }
290*d9f75844SAndroid Build Coastguard Worker 
UsingPictureId(const VCMFrameBuffer * frame) const291*d9f75844SAndroid Build Coastguard Worker bool VCMDecodingState::UsingPictureId(const VCMFrameBuffer* frame) const {
292*d9f75844SAndroid Build Coastguard Worker   return (frame->PictureId() != kNoPictureId && picture_id_ != kNoPictureId);
293*d9f75844SAndroid Build Coastguard Worker }
294*d9f75844SAndroid Build Coastguard Worker 
UsingFlexibleMode(const VCMFrameBuffer * frame) const295*d9f75844SAndroid Build Coastguard Worker bool VCMDecodingState::UsingFlexibleMode(const VCMFrameBuffer* frame) const {
296*d9f75844SAndroid Build Coastguard Worker   bool is_flexible_mode =
297*d9f75844SAndroid Build Coastguard Worker       frame->CodecSpecific()->codecType == kVideoCodecVP9 &&
298*d9f75844SAndroid Build Coastguard Worker       frame->CodecSpecific()->codecSpecific.VP9.flexible_mode;
299*d9f75844SAndroid Build Coastguard Worker   if (is_flexible_mode && frame->PictureId() == kNoPictureId) {
300*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING) << "Frame is marked as using flexible mode but no"
301*d9f75844SAndroid Build Coastguard Worker                            "picture id is set.";
302*d9f75844SAndroid Build Coastguard Worker     return false;
303*d9f75844SAndroid Build Coastguard Worker   }
304*d9f75844SAndroid Build Coastguard Worker   return is_flexible_mode;
305*d9f75844SAndroid Build Coastguard Worker }
306*d9f75844SAndroid Build Coastguard Worker 
307*d9f75844SAndroid Build Coastguard Worker // TODO(philipel): change how check work, this check practially
308*d9f75844SAndroid Build Coastguard Worker // limits the max p_diff to 64.
AheadOfFramesDecodedClearedTo(uint16_t index) const309*d9f75844SAndroid Build Coastguard Worker bool VCMDecodingState::AheadOfFramesDecodedClearedTo(uint16_t index) const {
310*d9f75844SAndroid Build Coastguard Worker   // No way of knowing for sure if we are actually ahead of
311*d9f75844SAndroid Build Coastguard Worker   // frame_decoded_cleared_to_. We just make the assumption
312*d9f75844SAndroid Build Coastguard Worker   // that we are not trying to reference back to a very old
313*d9f75844SAndroid Build Coastguard Worker   // index, but instead are referencing a newer index.
314*d9f75844SAndroid Build Coastguard Worker   uint16_t diff =
315*d9f75844SAndroid Build Coastguard Worker       index > frame_decoded_cleared_to_
316*d9f75844SAndroid Build Coastguard Worker           ? kFrameDecodedLength - (index - frame_decoded_cleared_to_)
317*d9f75844SAndroid Build Coastguard Worker           : frame_decoded_cleared_to_ - index;
318*d9f75844SAndroid Build Coastguard Worker   return diff > kFrameDecodedLength / 2;
319*d9f75844SAndroid Build Coastguard Worker }
320*d9f75844SAndroid Build Coastguard Worker 
HaveSpsAndPps(const std::vector<NaluInfo> & nalus) const321*d9f75844SAndroid Build Coastguard Worker bool VCMDecodingState::HaveSpsAndPps(const std::vector<NaluInfo>& nalus) const {
322*d9f75844SAndroid Build Coastguard Worker   std::set<int> new_sps;
323*d9f75844SAndroid Build Coastguard Worker   std::map<int, int> new_pps;
324*d9f75844SAndroid Build Coastguard Worker   for (const NaluInfo& nalu : nalus) {
325*d9f75844SAndroid Build Coastguard Worker     // Check if this nalu actually contains sps/pps information or dependencies.
326*d9f75844SAndroid Build Coastguard Worker     if (nalu.sps_id == -1 && nalu.pps_id == -1)
327*d9f75844SAndroid Build Coastguard Worker       continue;
328*d9f75844SAndroid Build Coastguard Worker     switch (nalu.type) {
329*d9f75844SAndroid Build Coastguard Worker       case H264::NaluType::kPps:
330*d9f75844SAndroid Build Coastguard Worker         if (nalu.pps_id < 0) {
331*d9f75844SAndroid Build Coastguard Worker           RTC_LOG(LS_WARNING) << "Received pps without pps id.";
332*d9f75844SAndroid Build Coastguard Worker         } else if (nalu.sps_id < 0) {
333*d9f75844SAndroid Build Coastguard Worker           RTC_LOG(LS_WARNING) << "Received pps without sps id.";
334*d9f75844SAndroid Build Coastguard Worker         } else {
335*d9f75844SAndroid Build Coastguard Worker           new_pps[nalu.pps_id] = nalu.sps_id;
336*d9f75844SAndroid Build Coastguard Worker         }
337*d9f75844SAndroid Build Coastguard Worker         break;
338*d9f75844SAndroid Build Coastguard Worker       case H264::NaluType::kSps:
339*d9f75844SAndroid Build Coastguard Worker         if (nalu.sps_id < 0) {
340*d9f75844SAndroid Build Coastguard Worker           RTC_LOG(LS_WARNING) << "Received sps without sps id.";
341*d9f75844SAndroid Build Coastguard Worker         } else {
342*d9f75844SAndroid Build Coastguard Worker           new_sps.insert(nalu.sps_id);
343*d9f75844SAndroid Build Coastguard Worker         }
344*d9f75844SAndroid Build Coastguard Worker         break;
345*d9f75844SAndroid Build Coastguard Worker       default: {
346*d9f75844SAndroid Build Coastguard Worker         int needed_sps = -1;
347*d9f75844SAndroid Build Coastguard Worker         auto pps_it = new_pps.find(nalu.pps_id);
348*d9f75844SAndroid Build Coastguard Worker         if (pps_it != new_pps.end()) {
349*d9f75844SAndroid Build Coastguard Worker           needed_sps = pps_it->second;
350*d9f75844SAndroid Build Coastguard Worker         } else {
351*d9f75844SAndroid Build Coastguard Worker           auto pps_it2 = received_pps_.find(nalu.pps_id);
352*d9f75844SAndroid Build Coastguard Worker           if (pps_it2 == received_pps_.end()) {
353*d9f75844SAndroid Build Coastguard Worker             return false;
354*d9f75844SAndroid Build Coastguard Worker           }
355*d9f75844SAndroid Build Coastguard Worker           needed_sps = pps_it2->second;
356*d9f75844SAndroid Build Coastguard Worker         }
357*d9f75844SAndroid Build Coastguard Worker         if (new_sps.find(needed_sps) == new_sps.end() &&
358*d9f75844SAndroid Build Coastguard Worker             received_sps_.find(needed_sps) == received_sps_.end()) {
359*d9f75844SAndroid Build Coastguard Worker           return false;
360*d9f75844SAndroid Build Coastguard Worker         }
361*d9f75844SAndroid Build Coastguard Worker         break;
362*d9f75844SAndroid Build Coastguard Worker       }
363*d9f75844SAndroid Build Coastguard Worker     }
364*d9f75844SAndroid Build Coastguard Worker   }
365*d9f75844SAndroid Build Coastguard Worker   return true;
366*d9f75844SAndroid Build Coastguard Worker }
367*d9f75844SAndroid Build Coastguard Worker 
368*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc
369