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