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
18 namespace webrtc {
19
VCMDecodingState()20 VCMDecodingState::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
~VCMDecodingState()31 VCMDecodingState::~VCMDecodingState() {}
32
Reset()33 void 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
time_stamp() const45 uint32_t VCMDecodingState::time_stamp() const {
46 return time_stamp_;
47 }
48
sequence_num() const49 uint16_t VCMDecodingState::sequence_num() const {
50 return sequence_num_;
51 }
52
IsOldFrame(const VCMFrameBuffer * frame) const53 bool 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
IsOldPacket(const VCMPacket * packet) const60 bool 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
SetState(const VCMFrameBuffer * frame)67 void 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
CopyFrom(const VCMDecodingState & state)99 void 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
UpdateEmptyFrame(const VCMFrameBuffer * frame)111 bool 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
UpdateOldPacket(const VCMPacket * packet)128 void 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
SetSeqNum(uint16_t new_seq_num)137 void VCMDecodingState::SetSeqNum(uint16_t new_seq_num) {
138 sequence_num_ = new_seq_num;
139 }
140
in_initial_state() const141 bool VCMDecodingState::in_initial_state() const {
142 return in_initial_state_;
143 }
144
full_sync() const145 bool VCMDecodingState::full_sync() const {
146 return full_sync_;
147 }
148
UpdateSyncState(const VCMFrameBuffer * frame)149 void 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
ContinuousFrame(const VCMFrameBuffer * frame) const175 bool 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
ContinuousPictureId(int picture_id) const212 bool 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
ContinuousSeqNum(uint16_t seq_num) const228 bool VCMDecodingState::ContinuousSeqNum(uint16_t seq_num) const {
229 return seq_num == static_cast<uint16_t>(sequence_num_ + 1);
230 }
231
ContinuousLayer(int temporal_id,int tl0_pic_id) const232 bool 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
ContinuousFrameRefs(const VCMFrameBuffer * frame) const248 bool 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
UsingPictureId(const VCMFrameBuffer * frame) const262 bool VCMDecodingState::UsingPictureId(const VCMFrameBuffer* frame) const {
263 return (frame->PictureId() != kNoPictureId && picture_id_ != kNoPictureId);
264 }
265
UsingFlexibleMode(const VCMFrameBuffer * frame) const266 bool 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.
AheadOfFramesDecodedClearedTo(uint16_t index) const273 bool 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