blob: 89be9b66c1fe6e416069f248126733d742a5b7bc [file] [log] [blame]
mikhal@webrtc.org832caca2011-12-13 21:15:05 +00001/*
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
Henrik Kjellander2557b862015-11-18 22:00:21 +010011#include "webrtc/modules/video_coding/decoding_state.h"
stefan@webrtc.org39670f62011-12-23 09:08:51 +000012
Henrik Kjellanderff761fb2015-11-04 08:31:52 +010013#include "webrtc/modules/include/module_common_types.h"
Henrik Kjellander2557b862015-11-18 22:00:21 +010014#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"
mikhal@webrtc.org832caca2011-12-13 21:15:05 +000017
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),
philipelcfc319b2015-11-10 07:17:23 -080027 in_initial_state_(true) {
28 memset(frame_decoded_, 0, sizeof(frame_decoded_));
29}
mikhal@webrtc.org832caca2011-12-13 21:15:05 +000030
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;
stefan@webrtc.orga64300a2013-03-04 15:24:40 +000041 in_initial_state_ = true;
philipelcfc319b2015-11-10 07:17:23 -080042 memset(frame_decoded_, 0, sizeof(frame_decoded_));
mikhal@webrtc.org832caca2011-12-13 21:15:05 +000043}
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);
stefan@webrtc.orga64300a2013-03-04 15:24:40 +000055 if (in_initial_state_)
mikhal@webrtc.org832caca2011-12-13 21:15:05 +000056 return false;
stefan@webrtc.org7bc465b2013-04-11 17:48:02 +000057 return !IsNewerTimestamp(frame->TimeStamp(), time_stamp_);
mikhal@webrtc.org832caca2011-12-13 21:15:05 +000058}
59
60bool VCMDecodingState::IsOldPacket(const VCMPacket* packet) const {
61 assert(packet != NULL);
stefan@webrtc.orga64300a2013-03-04 15:24:40 +000062 if (in_initial_state_)
mikhal@webrtc.org832caca2011-12-13 21:15:05 +000063 return false;
stefan@webrtc.org7bc465b2013-04-11 17:48:02 +000064 return !IsNewerTimestamp(packet->timestamp, time_stamp_);
mikhal@webrtc.org832caca2011-12-13 21:15:05 +000065}
66
67void VCMDecodingState::SetState(const VCMFrameBuffer* frame) {
68 assert(frame != NULL && frame->GetHighSeqNum() >= 0);
philipelcfc319b2015-11-10 07:17:23 -080069 if (!UsingFlexibleMode(frame))
70 UpdateSyncState(frame);
mikhal@webrtc.org832caca2011-12-13 21:15:05 +000071 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();
philipelcfc319b2015-11-10 07:17:23 -080076
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
stefan@webrtc.orga64300a2013-03-04 15:24:40 +000096 in_initial_state_ = false;
mikhal@webrtc.org832caca2011-12-13 21:15:05 +000097}
98
mikhal@webrtc.org381da4b2013-04-25 21:45:29 +000099void 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_;
philipelcfc319b2015-11-10 07:17:23 -0800107 frame_decoded_cleared_to_ = state.frame_decoded_cleared_to_;
108 memcpy(frame_decoded_, state.frame_decoded_, sizeof(frame_decoded_));
mikhal@webrtc.org381da4b2013-04-25 21:45:29 +0000109}
110
stefan@webrtc.orgc8b29a22013-06-17 07:13:16 +0000111bool 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;
stefan@webrtc.org7f3f8bc2013-05-27 07:02:45 +0000116 }
stefan@webrtc.orgc8b29a22013-06-17 07:13:16 +0000117 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;
stefan@webrtc.orgbd941d32012-11-29 14:37:18 +0000126}
127
mikhal@webrtc.org77c425b2012-01-03 20:35:25 +0000128void VCMDecodingState::UpdateOldPacket(const VCMPacket* packet) {
mikhal@webrtc.org832caca2011-12-13 21:15:05 +0000129 assert(packet != NULL);
mikhal@webrtc.org77c425b2012-01-03 20:35:25 +0000130 if (packet->timestamp == time_stamp_) {
131 // Late packet belonging to the last decoded frame - make sure we update the
132 // last decoded sequence number.
stefan@webrtc.org7bc465b2013-04-11 17:48:02 +0000133 sequence_num_ = LatestSequenceNumber(packet->seqNum, sequence_num_);
mikhal@webrtc.org832caca2011-12-13 21:15:05 +0000134 }
135}
136
137void VCMDecodingState::SetSeqNum(uint16_t new_seq_num) {
138 sequence_num_ = new_seq_num;
139}
140
stefan@webrtc.orga64300a2013-03-04 15:24:40 +0000141bool VCMDecodingState::in_initial_state() const {
142 return in_initial_state_;
mikhal@webrtc.org832caca2011-12-13 21:15:05 +0000143}
144
145bool VCMDecodingState::full_sync() const {
146 return full_sync_;
147}
148
149void VCMDecodingState::UpdateSyncState(const VCMFrameBuffer* frame) {
stefan@webrtc.orga64300a2013-03-04 15:24:40 +0000150 if (in_initial_state_)
mikhal@webrtc.org832caca2011-12-13 21:15:05 +0000151 return;
152 if (frame->TemporalId() == kNoTemporalIdx ||
153 frame->Tl0PicId() == kNoTl0PicIdx) {
154 full_sync_ = true;
mikhal@webrtc.org884d8e72011-12-19 18:53:05 +0000155 } else if (frame->FrameType() == kVideoFrameKey || frame->LayerSync()) {
mikhal@webrtc.org832caca2011-12-13 21:15:05 +0000156 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).
stefan@webrtc.orge72e9ee2012-09-19 11:08:05 +0000161 if (UsingPictureId(frame)) {
mikhal@webrtc.org0aeb22e2013-10-28 22:26:14 +0000162 // 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 }
stefan@webrtc.orge72e9ee2012-09-19 11:08:05 +0000168 } else {
philipel9d3ab612015-12-21 04:12:39 -0800169 full_sync_ =
170 ContinuousSeqNum(static_cast<uint16_t>(frame->GetLowSeqNum()));
mikhal@webrtc.org832caca2011-12-13 21:15:05 +0000171 }
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);
stefan@webrtc.orgc8b29a22013-06-17 07:13:16 +0000183 // 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.
stefan3cdfcd82016-09-30 09:06:36 -0700186 if (frame->FrameType() == kVideoFrameKey)
stefan@webrtc.orgc8b29a22013-06-17 07:13:16 +0000187 return true;
188 // When in the initial state we always require a key frame to start decoding.
189 if (in_initial_state_)
mikhal@webrtc.org8392cd92013-04-25 21:30:50 +0000190 return false;
mikhal@webrtc.org0aeb22e2013-10-28 22:26:14 +0000191 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)) {
philipelcfc319b2015-11-10 07:17:23 -0800202 if (UsingFlexibleMode(frame)) {
203 return ContinuousFrameRefs(frame);
204 } else {
205 return ContinuousPictureId(frame->PictureId());
206 }
mikhal@webrtc.org0aeb22e2013-10-28 22:26:14 +0000207 } else {
stefan3cdfcd82016-09-30 09:06:36 -0700208 return ContinuousSeqNum(static_cast<uint16_t>(frame->GetLowSeqNum()));
mikhal@webrtc.org832caca2011-12-13 21:15:05 +0000209 }
mikhal@webrtc.org832caca2011-12-13 21:15:05 +0000210}
211
212bool VCMDecodingState::ContinuousPictureId(int picture_id) const {
stefan@webrtc.org39670f62011-12-23 09:08:51 +0000213 int next_picture_id = picture_id_ + 1;
214 if (picture_id < picture_id_) {
mikhal@webrtc.org832caca2011-12-13 21:15:05 +0000215 // Wrap
stefan@webrtc.org39670f62011-12-23 09:08:51 +0000216 if (picture_id_ >= 0x80) {
mikhal@webrtc.org832caca2011-12-13 21:15:05 +0000217 // 15 bits used for picture id
stefan@webrtc.org39670f62011-12-23 09:08:51 +0000218 return ((next_picture_id & 0x7FFF) == picture_id);
mikhal@webrtc.org832caca2011-12-13 21:15:05 +0000219 } else {
220 // 7 bits used for picture id
stefan@webrtc.org39670f62011-12-23 09:08:51 +0000221 return ((next_picture_id & 0x7F) == picture_id);
mikhal@webrtc.org832caca2011-12-13 21:15:05 +0000222 }
223 }
224 // No wrap
stefan@webrtc.org39670f62011-12-23 09:08:51 +0000225 return (next_picture_id == picture_id);
mikhal@webrtc.org832caca2011-12-13 21:15:05 +0000226}
227
228bool VCMDecodingState::ContinuousSeqNum(uint16_t seq_num) const {
pbos@webrtc.org4f16c872014-11-24 09:06:48 +0000229 return seq_num == static_cast<uint16_t>(sequence_num_ + 1);
mikhal@webrtc.org832caca2011-12-13 21:15:05 +0000230}
231
philipel9d3ab612015-12-21 04:12:39 -0800232bool VCMDecodingState::ContinuousLayer(int temporal_id, int tl0_pic_id) const {
mikhal@webrtc.org832caca2011-12-13 21:15:05 +0000233 // 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
mikhal@webrtc.org884d8e72011-12-19 18:53:05 +0000242 // Current implementation: Look for base layer continuity.
mikhal@webrtc.org832caca2011-12-13 21:15:05 +0000243 if (temporal_id != 0)
244 return false;
stefan@webrtc.org39670f62011-12-23 09:08:51 +0000245 return (static_cast<uint8_t>(tl0_pic_id_ + 1) == tl0_pic_id);
mikhal@webrtc.org832caca2011-12-13 21:15:05 +0000246}
247
philipelcfc319b2015-11-10 07:17:23 -0800248bool 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
stefan@webrtc.orge72e9ee2012-09-19 11:08:05 +0000262bool VCMDecodingState::UsingPictureId(const VCMFrameBuffer* frame) const {
263 return (frame->PictureId() != kNoPictureId && picture_id_ != kNoPictureId);
264}
265
philipelcfc319b2015-11-10 07:17:23 -0800266bool 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
mikhal@webrtc.org832caca2011-12-13 21:15:05 +0000285} // namespace webrtc