• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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