1/*
2 *  Copyright (c) 2011 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 "webrtc/modules/video_coding/decoding_state.h"
12
13#include "webrtc/modules/include/module_common_types.h"
14#include "webrtc/modules/video_coding/frame_buffer.h"
15#include "webrtc/modules/video_coding/jitter_buffer_common.h"
16#include "webrtc/modules/video_coding/packet.h"
17
18namespace webrtc {
19
20VCMDecodingState::VCMDecodingState()
21    : sequence_num_(0),
22      time_stamp_(0),
23      picture_id_(kNoPictureId),
24      temporal_id_(kNoTemporalIdx),
25      tl0_pic_id_(kNoTl0PicIdx),
26      full_sync_(true),
27      in_initial_state_(true) {
28  memset(frame_decoded_, 0, sizeof(frame_decoded_));
29}
30
31VCMDecodingState::~VCMDecodingState() {}
32
33void VCMDecodingState::Reset() {
34  // TODO(mikhal): Verify - not always would want to reset the sync
35  sequence_num_ = 0;
36  time_stamp_ = 0;
37  picture_id_ = kNoPictureId;
38  temporal_id_ = kNoTemporalIdx;
39  tl0_pic_id_ = kNoTl0PicIdx;
40  full_sync_ = true;
41  in_initial_state_ = true;
42  memset(frame_decoded_, 0, sizeof(frame_decoded_));
43}
44
45uint32_t VCMDecodingState::time_stamp() const {
46  return time_stamp_;
47}
48
49uint16_t VCMDecodingState::sequence_num() const {
50  return sequence_num_;
51}
52
53bool VCMDecodingState::IsOldFrame(const VCMFrameBuffer* frame) const {
54  assert(frame != NULL);
55  if (in_initial_state_)
56    return false;
57  return !IsNewerTimestamp(frame->TimeStamp(), time_stamp_);
58}
59
60bool VCMDecodingState::IsOldPacket(const VCMPacket* packet) const {
61  assert(packet != NULL);
62  if (in_initial_state_)
63    return false;
64  return !IsNewerTimestamp(packet->timestamp, time_stamp_);
65}
66
67void VCMDecodingState::SetState(const VCMFrameBuffer* frame) {
68  assert(frame != NULL && frame->GetHighSeqNum() >= 0);
69  if (!UsingFlexibleMode(frame))
70    UpdateSyncState(frame);
71  sequence_num_ = static_cast<uint16_t>(frame->GetHighSeqNum());
72  time_stamp_ = frame->TimeStamp();
73  picture_id_ = frame->PictureId();
74  temporal_id_ = frame->TemporalId();
75  tl0_pic_id_ = frame->Tl0PicId();
76
77  if (UsingFlexibleMode(frame)) {
78    uint16_t frame_index = picture_id_ % kFrameDecodedLength;
79    if (in_initial_state_) {
80      frame_decoded_cleared_to_ = frame_index;
81    } else if (frame->FrameType() == kVideoFrameKey) {
82      memset(frame_decoded_, 0, sizeof(frame_decoded_));
83      frame_decoded_cleared_to_ = frame_index;
84    } else {
85      if (AheadOfFramesDecodedClearedTo(frame_index)) {
86        while (frame_decoded_cleared_to_ != frame_index) {
87          frame_decoded_cleared_to_ =
88              (frame_decoded_cleared_to_ + 1) % kFrameDecodedLength;
89          frame_decoded_[frame_decoded_cleared_to_] = false;
90        }
91      }
92    }
93    frame_decoded_[frame_index] = true;
94  }
95
96  in_initial_state_ = false;
97}
98
99void VCMDecodingState::CopyFrom(const VCMDecodingState& state) {
100  sequence_num_ = state.sequence_num_;
101  time_stamp_ = state.time_stamp_;
102  picture_id_ = state.picture_id_;
103  temporal_id_ = state.temporal_id_;
104  tl0_pic_id_ = state.tl0_pic_id_;
105  full_sync_ = state.full_sync_;
106  in_initial_state_ = state.in_initial_state_;
107  frame_decoded_cleared_to_ = state.frame_decoded_cleared_to_;
108  memcpy(frame_decoded_, state.frame_decoded_, sizeof(frame_decoded_));
109}
110
111bool VCMDecodingState::UpdateEmptyFrame(const VCMFrameBuffer* frame) {
112  bool empty_packet = frame->GetHighSeqNum() == frame->GetLowSeqNum();
113  if (in_initial_state_ && empty_packet) {
114    // Drop empty packets as long as we are in the initial state.
115    return true;
116  }
117  if ((empty_packet && ContinuousSeqNum(frame->GetHighSeqNum())) ||
118      ContinuousFrame(frame)) {
119    // Continuous empty packets or continuous frames can be dropped if we
120    // advance the sequence number.
121    sequence_num_ = frame->GetHighSeqNum();
122    time_stamp_ = frame->TimeStamp();
123    return true;
124  }
125  return false;
126}
127
128void VCMDecodingState::UpdateOldPacket(const VCMPacket* packet) {
129  assert(packet != NULL);
130  if (packet->timestamp == time_stamp_) {
131    // Late packet belonging to the last decoded frame - make sure we update the
132    // last decoded sequence number.
133    sequence_num_ = LatestSequenceNumber(packet->seqNum, sequence_num_);
134  }
135}
136
137void VCMDecodingState::SetSeqNum(uint16_t new_seq_num) {
138  sequence_num_ = new_seq_num;
139}
140
141bool VCMDecodingState::in_initial_state() const {
142  return in_initial_state_;
143}
144
145bool VCMDecodingState::full_sync() const {
146  return full_sync_;
147}
148
149void VCMDecodingState::UpdateSyncState(const VCMFrameBuffer* frame) {
150  if (in_initial_state_)
151    return;
152  if (frame->TemporalId() == kNoTemporalIdx ||
153      frame->Tl0PicId() == kNoTl0PicIdx) {
154    full_sync_ = true;
155  } else if (frame->FrameType() == kVideoFrameKey || frame->LayerSync()) {
156    full_sync_ = true;
157  } else if (full_sync_) {
158    // Verify that we are still in sync.
159    // Sync will be broken if continuity is true for layers but not for the
160    // other methods (PictureId and SeqNum).
161    if (UsingPictureId(frame)) {
162      // First check for a valid tl0PicId.
163      if (frame->Tl0PicId() - tl0_pic_id_ > 1) {
164        full_sync_ = false;
165      } else {
166        full_sync_ = ContinuousPictureId(frame->PictureId());
167      }
168    } else {
169      full_sync_ =
170          ContinuousSeqNum(static_cast<uint16_t>(frame->GetLowSeqNum()));
171    }
172  }
173}
174
175bool VCMDecodingState::ContinuousFrame(const VCMFrameBuffer* frame) const {
176  // Check continuity based on the following hierarchy:
177  // - Temporal layers (stop here if out of sync).
178  // - Picture Id when available.
179  // - Sequence numbers.
180  // Return true when in initial state.
181  // Note that when a method is not applicable it will return false.
182  assert(frame != NULL);
183  // A key frame is always considered continuous as it doesn't refer to any
184  // frames and therefore won't introduce any errors even if prior frames are
185  // missing.
186  if (frame->FrameType() == kVideoFrameKey)
187    return true;
188  // When in the initial state we always require a key frame to start decoding.
189  if (in_initial_state_)
190    return false;
191  if (ContinuousLayer(frame->TemporalId(), frame->Tl0PicId()))
192    return true;
193  // tl0picId is either not used, or should remain unchanged.
194  if (frame->Tl0PicId() != tl0_pic_id_)
195    return false;
196  // Base layers are not continuous or temporal layers are inactive.
197  // In the presence of temporal layers, check for Picture ID/sequence number
198  // continuity if sync can be restored by this frame.
199  if (!full_sync_ && !frame->LayerSync())
200    return false;
201  if (UsingPictureId(frame)) {
202    if (UsingFlexibleMode(frame)) {
203      return ContinuousFrameRefs(frame);
204    } else {
205      return ContinuousPictureId(frame->PictureId());
206    }
207  } else {
208    return ContinuousSeqNum(static_cast<uint16_t>(frame->GetLowSeqNum()));
209  }
210}
211
212bool VCMDecodingState::ContinuousPictureId(int picture_id) const {
213  int next_picture_id = picture_id_ + 1;
214  if (picture_id < picture_id_) {
215    // Wrap
216    if (picture_id_ >= 0x80) {
217      // 15 bits used for picture id
218      return ((next_picture_id & 0x7FFF) == picture_id);
219    } else {
220      // 7 bits used for picture id
221      return ((next_picture_id & 0x7F) == picture_id);
222    }
223  }
224  // No wrap
225  return (next_picture_id == picture_id);
226}
227
228bool VCMDecodingState::ContinuousSeqNum(uint16_t seq_num) const {
229  return seq_num == static_cast<uint16_t>(sequence_num_ + 1);
230}
231
232bool VCMDecodingState::ContinuousLayer(int temporal_id, int tl0_pic_id) const {
233  // First, check if applicable.
234  if (temporal_id == kNoTemporalIdx || tl0_pic_id == kNoTl0PicIdx)
235    return false;
236  // If this is the first frame to use temporal layers, make sure we start
237  // from base.
238  else if (tl0_pic_id_ == kNoTl0PicIdx && temporal_id_ == kNoTemporalIdx &&
239           temporal_id == 0)
240    return true;
241
242  // Current implementation: Look for base layer continuity.
243  if (temporal_id != 0)
244    return false;
245  return (static_cast<uint8_t>(tl0_pic_id_ + 1) == tl0_pic_id);
246}
247
248bool VCMDecodingState::ContinuousFrameRefs(const VCMFrameBuffer* frame) const {
249  uint8_t num_refs = frame->CodecSpecific()->codecSpecific.VP9.num_ref_pics;
250  for (uint8_t r = 0; r < num_refs; ++r) {
251    uint16_t frame_ref = frame->PictureId() -
252                         frame->CodecSpecific()->codecSpecific.VP9.p_diff[r];
253    uint16_t frame_index = frame_ref % kFrameDecodedLength;
254    if (AheadOfFramesDecodedClearedTo(frame_index) ||
255        !frame_decoded_[frame_index]) {
256      return false;
257    }
258  }
259  return true;
260}
261
262bool VCMDecodingState::UsingPictureId(const VCMFrameBuffer* frame) const {
263  return (frame->PictureId() != kNoPictureId && picture_id_ != kNoPictureId);
264}
265
266bool VCMDecodingState::UsingFlexibleMode(const VCMFrameBuffer* frame) const {
267  return frame->CodecSpecific()->codecType == kVideoCodecVP9 &&
268         frame->CodecSpecific()->codecSpecific.VP9.flexible_mode;
269}
270
271// TODO(philipel): change how check work, this check practially
272// limits the max p_diff to 64.
273bool VCMDecodingState::AheadOfFramesDecodedClearedTo(uint16_t index) const {
274  // No way of knowing for sure if we are actually ahead of
275  // frame_decoded_cleared_to_. We just make the assumption
276  // that we are not trying to reference back to a very old
277  // index, but instead are referencing a newer index.
278  uint16_t diff =
279      index > frame_decoded_cleared_to_
280          ? kFrameDecodedLength - (index - frame_decoded_cleared_to_)
281          : frame_decoded_cleared_to_ - index;
282  return diff > kFrameDecodedLength / 2;
283}
284
285}  // namespace webrtc
286