Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #include "webrtc/modules/video_coding/decoding_state.h" | 11 #include "webrtc/modules/video_coding/decoding_state.h" |
| 12 | 12 |
| 13 #include "webrtc/base/logging.h" | |
| 14 #include "webrtc/common_video/h264/h264_common.h" | |
| 13 #include "webrtc/modules/include/module_common_types.h" | 15 #include "webrtc/modules/include/module_common_types.h" |
| 14 #include "webrtc/modules/video_coding/frame_buffer.h" | 16 #include "webrtc/modules/video_coding/frame_buffer.h" |
| 15 #include "webrtc/modules/video_coding/jitter_buffer_common.h" | 17 #include "webrtc/modules/video_coding/jitter_buffer_common.h" |
| 16 #include "webrtc/modules/video_coding/packet.h" | 18 #include "webrtc/modules/video_coding/packet.h" |
| 17 | 19 |
| 18 namespace webrtc { | 20 namespace webrtc { |
| 19 | 21 |
| 20 VCMDecodingState::VCMDecodingState() | 22 VCMDecodingState::VCMDecodingState() |
| 21 : sequence_num_(0), | 23 : sequence_num_(0), |
| 22 time_stamp_(0), | 24 time_stamp_(0), |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 33 void VCMDecodingState::Reset() { | 35 void VCMDecodingState::Reset() { |
| 34 // TODO(mikhal): Verify - not always would want to reset the sync | 36 // TODO(mikhal): Verify - not always would want to reset the sync |
| 35 sequence_num_ = 0; | 37 sequence_num_ = 0; |
| 36 time_stamp_ = 0; | 38 time_stamp_ = 0; |
| 37 picture_id_ = kNoPictureId; | 39 picture_id_ = kNoPictureId; |
| 38 temporal_id_ = kNoTemporalIdx; | 40 temporal_id_ = kNoTemporalIdx; |
| 39 tl0_pic_id_ = kNoTl0PicIdx; | 41 tl0_pic_id_ = kNoTl0PicIdx; |
| 40 full_sync_ = true; | 42 full_sync_ = true; |
| 41 in_initial_state_ = true; | 43 in_initial_state_ = true; |
| 42 memset(frame_decoded_, 0, sizeof(frame_decoded_)); | 44 memset(frame_decoded_, 0, sizeof(frame_decoded_)); |
| 45 received_sps_.clear(); | |
| 46 received_pps_.clear(); | |
| 43 } | 47 } |
| 44 | 48 |
| 45 uint32_t VCMDecodingState::time_stamp() const { | 49 uint32_t VCMDecodingState::time_stamp() const { |
| 46 return time_stamp_; | 50 return time_stamp_; |
| 47 } | 51 } |
| 48 | 52 |
| 49 uint16_t VCMDecodingState::sequence_num() const { | 53 uint16_t VCMDecodingState::sequence_num() const { |
| 50 return sequence_num_; | 54 return sequence_num_; |
| 51 } | 55 } |
| 52 | 56 |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 67 void VCMDecodingState::SetState(const VCMFrameBuffer* frame) { | 71 void VCMDecodingState::SetState(const VCMFrameBuffer* frame) { |
| 68 assert(frame != NULL && frame->GetHighSeqNum() >= 0); | 72 assert(frame != NULL && frame->GetHighSeqNum() >= 0); |
| 69 if (!UsingFlexibleMode(frame)) | 73 if (!UsingFlexibleMode(frame)) |
| 70 UpdateSyncState(frame); | 74 UpdateSyncState(frame); |
| 71 sequence_num_ = static_cast<uint16_t>(frame->GetHighSeqNum()); | 75 sequence_num_ = static_cast<uint16_t>(frame->GetHighSeqNum()); |
| 72 time_stamp_ = frame->TimeStamp(); | 76 time_stamp_ = frame->TimeStamp(); |
| 73 picture_id_ = frame->PictureId(); | 77 picture_id_ = frame->PictureId(); |
| 74 temporal_id_ = frame->TemporalId(); | 78 temporal_id_ = frame->TemporalId(); |
| 75 tl0_pic_id_ = frame->Tl0PicId(); | 79 tl0_pic_id_ = frame->Tl0PicId(); |
| 76 | 80 |
| 81 std::vector<NaluInfo> nalus = frame->GetNaluInfos(); | |
| 82 for (const NaluInfo& nalu : nalus) { | |
|
philipel
2016/09/15 12:52:46
Maybe clean up old sps/pps? How many sps/pps can w
philipel
2016/09/15 12:52:46
"const NaluInfo& nalu : frame->GetNaluInfos()" to
stefan-webrtc
2016/09/30 09:36:02
It must be able to track all of them according to
stefan-webrtc
2016/09/30 09:36:02
Done.
philipel
2016/09/30 10:52:52
Acknowledged.
| |
| 83 if (nalu.type == H264::NaluType::kPps) { | |
| 84 if (nalu.pps_id < 0) { | |
| 85 LOG(LS_WARNING) << "Received pps without pps id."; | |
| 86 } else if (nalu.sps_id < 0) { | |
| 87 LOG(LS_WARNING) << "Received pps without sps id."; | |
| 88 } else { | |
| 89 received_pps_[nalu.pps_id] = nalu.sps_id; | |
| 90 } | |
| 91 } else if (nalu.type == H264::NaluType::kSps) { | |
| 92 if (nalu.sps_id < 0) { | |
| 93 LOG(LS_WARNING) << "Received sps without sps id."; | |
| 94 } else { | |
| 95 received_sps_.insert(nalu.sps_id); | |
| 96 } | |
| 97 } | |
| 98 } | |
| 99 | |
| 77 if (UsingFlexibleMode(frame)) { | 100 if (UsingFlexibleMode(frame)) { |
| 78 uint16_t frame_index = picture_id_ % kFrameDecodedLength; | 101 uint16_t frame_index = picture_id_ % kFrameDecodedLength; |
| 79 if (in_initial_state_) { | 102 if (in_initial_state_) { |
| 80 frame_decoded_cleared_to_ = frame_index; | 103 frame_decoded_cleared_to_ = frame_index; |
| 81 } else if (frame->FrameType() == kVideoFrameKey) { | 104 } else if (frame->FrameType() == kVideoFrameKey) { |
| 82 memset(frame_decoded_, 0, sizeof(frame_decoded_)); | 105 memset(frame_decoded_, 0, sizeof(frame_decoded_)); |
| 83 frame_decoded_cleared_to_ = frame_index; | 106 frame_decoded_cleared_to_ = frame_index; |
| 84 } else { | 107 } else { |
| 85 if (AheadOfFramesDecodedClearedTo(frame_index)) { | 108 if (AheadOfFramesDecodedClearedTo(frame_index)) { |
| 86 while (frame_decoded_cleared_to_ != frame_index) { | 109 while (frame_decoded_cleared_to_ != frame_index) { |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 99 void VCMDecodingState::CopyFrom(const VCMDecodingState& state) { | 122 void VCMDecodingState::CopyFrom(const VCMDecodingState& state) { |
| 100 sequence_num_ = state.sequence_num_; | 123 sequence_num_ = state.sequence_num_; |
| 101 time_stamp_ = state.time_stamp_; | 124 time_stamp_ = state.time_stamp_; |
| 102 picture_id_ = state.picture_id_; | 125 picture_id_ = state.picture_id_; |
| 103 temporal_id_ = state.temporal_id_; | 126 temporal_id_ = state.temporal_id_; |
| 104 tl0_pic_id_ = state.tl0_pic_id_; | 127 tl0_pic_id_ = state.tl0_pic_id_; |
| 105 full_sync_ = state.full_sync_; | 128 full_sync_ = state.full_sync_; |
| 106 in_initial_state_ = state.in_initial_state_; | 129 in_initial_state_ = state.in_initial_state_; |
| 107 frame_decoded_cleared_to_ = state.frame_decoded_cleared_to_; | 130 frame_decoded_cleared_to_ = state.frame_decoded_cleared_to_; |
| 108 memcpy(frame_decoded_, state.frame_decoded_, sizeof(frame_decoded_)); | 131 memcpy(frame_decoded_, state.frame_decoded_, sizeof(frame_decoded_)); |
| 132 received_sps_ = state.received_sps_; | |
| 133 received_pps_ = state.received_pps_; | |
| 109 } | 134 } |
| 110 | 135 |
| 111 bool VCMDecodingState::UpdateEmptyFrame(const VCMFrameBuffer* frame) { | 136 bool VCMDecodingState::UpdateEmptyFrame(const VCMFrameBuffer* frame) { |
| 112 bool empty_packet = frame->GetHighSeqNum() == frame->GetLowSeqNum(); | 137 bool empty_packet = frame->GetHighSeqNum() == frame->GetLowSeqNum(); |
| 113 if (in_initial_state_ && empty_packet) { | 138 if (in_initial_state_ && empty_packet) { |
| 114 // Drop empty packets as long as we are in the initial state. | 139 // Drop empty packets as long as we are in the initial state. |
| 115 return true; | 140 return true; |
| 116 } | 141 } |
| 117 if ((empty_packet && ContinuousSeqNum(frame->GetHighSeqNum())) || | 142 if ((empty_packet && ContinuousSeqNum(frame->GetHighSeqNum())) || |
| 118 ContinuousFrame(frame)) { | 143 ContinuousFrame(frame)) { |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 176 // Check continuity based on the following hierarchy: | 201 // Check continuity based on the following hierarchy: |
| 177 // - Temporal layers (stop here if out of sync). | 202 // - Temporal layers (stop here if out of sync). |
| 178 // - Picture Id when available. | 203 // - Picture Id when available. |
| 179 // - Sequence numbers. | 204 // - Sequence numbers. |
| 180 // Return true when in initial state. | 205 // Return true when in initial state. |
| 181 // Note that when a method is not applicable it will return false. | 206 // Note that when a method is not applicable it will return false. |
| 182 assert(frame != NULL); | 207 assert(frame != NULL); |
| 183 // A key frame is always considered continuous as it doesn't refer to any | 208 // 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 | 209 // frames and therefore won't introduce any errors even if prior frames are |
| 185 // missing. | 210 // missing. |
| 186 if (frame->FrameType() == kVideoFrameKey) | 211 if (frame->FrameType() == kVideoFrameKey && |
| 212 HaveSpsAndPps(frame->GetNaluInfos())) { | |
| 187 return true; | 213 return true; |
| 214 } | |
| 188 // When in the initial state we always require a key frame to start decoding. | 215 // When in the initial state we always require a key frame to start decoding. |
| 189 if (in_initial_state_) | 216 if (in_initial_state_) |
| 190 return false; | 217 return false; |
| 191 if (ContinuousLayer(frame->TemporalId(), frame->Tl0PicId())) | 218 if (ContinuousLayer(frame->TemporalId(), frame->Tl0PicId())) |
| 192 return true; | 219 return true; |
| 193 // tl0picId is either not used, or should remain unchanged. | 220 // tl0picId is either not used, or should remain unchanged. |
| 194 if (frame->Tl0PicId() != tl0_pic_id_) | 221 if (frame->Tl0PicId() != tl0_pic_id_) |
| 195 return false; | 222 return false; |
| 196 // Base layers are not continuous or temporal layers are inactive. | 223 // Base layers are not continuous or temporal layers are inactive. |
| 197 // In the presence of temporal layers, check for Picture ID/sequence number | 224 // In the presence of temporal layers, check for Picture ID/sequence number |
| 198 // continuity if sync can be restored by this frame. | 225 // continuity if sync can be restored by this frame. |
| 199 if (!full_sync_ && !frame->LayerSync()) | 226 if (!full_sync_ && !frame->LayerSync()) |
| 200 return false; | 227 return false; |
| 201 if (UsingPictureId(frame)) { | 228 if (UsingPictureId(frame)) { |
| 202 if (UsingFlexibleMode(frame)) { | 229 if (UsingFlexibleMode(frame)) { |
| 203 return ContinuousFrameRefs(frame); | 230 return ContinuousFrameRefs(frame); |
| 204 } else { | 231 } else { |
| 205 return ContinuousPictureId(frame->PictureId()); | 232 return ContinuousPictureId(frame->PictureId()); |
| 206 } | 233 } |
| 207 } else { | 234 } else { |
| 208 return ContinuousSeqNum(static_cast<uint16_t>(frame->GetLowSeqNum())); | 235 return ContinuousSeqNum(static_cast<uint16_t>(frame->GetLowSeqNum())) && |
| 236 HaveSpsAndPps(frame->GetNaluInfos()); | |
| 209 } | 237 } |
| 210 } | 238 } |
| 211 | 239 |
| 212 bool VCMDecodingState::ContinuousPictureId(int picture_id) const { | 240 bool VCMDecodingState::ContinuousPictureId(int picture_id) const { |
| 213 int next_picture_id = picture_id_ + 1; | 241 int next_picture_id = picture_id_ + 1; |
| 214 if (picture_id < picture_id_) { | 242 if (picture_id < picture_id_) { |
| 215 // Wrap | 243 // Wrap |
| 216 if (picture_id_ >= 0x80) { | 244 if (picture_id_ >= 0x80) { |
| 217 // 15 bits used for picture id | 245 // 15 bits used for picture id |
| 218 return ((next_picture_id & 0x7FFF) == picture_id); | 246 return ((next_picture_id & 0x7FFF) == picture_id); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 275 // frame_decoded_cleared_to_. We just make the assumption | 303 // frame_decoded_cleared_to_. We just make the assumption |
| 276 // that we are not trying to reference back to a very old | 304 // that we are not trying to reference back to a very old |
| 277 // index, but instead are referencing a newer index. | 305 // index, but instead are referencing a newer index. |
| 278 uint16_t diff = | 306 uint16_t diff = |
| 279 index > frame_decoded_cleared_to_ | 307 index > frame_decoded_cleared_to_ |
| 280 ? kFrameDecodedLength - (index - frame_decoded_cleared_to_) | 308 ? kFrameDecodedLength - (index - frame_decoded_cleared_to_) |
| 281 : frame_decoded_cleared_to_ - index; | 309 : frame_decoded_cleared_to_ - index; |
| 282 return diff > kFrameDecodedLength / 2; | 310 return diff > kFrameDecodedLength / 2; |
| 283 } | 311 } |
| 284 | 312 |
| 313 bool VCMDecodingState::HaveSpsAndPps(const std::vector<NaluInfo>& nalus) const { | |
| 314 std::set<int> new_sps; | |
|
philipel
2016/09/15 12:52:46
Remove |new_sps| and insert new sps into |received
stefan-webrtc
2016/09/30 09:36:02
We can't insert them now since the frame hasn't be
philipel
2016/09/30 10:52:52
Acknowledged.
| |
| 315 std::map<int, int> new_pps; | |
|
philipel
2016/09/15 12:52:46
Remove |new_pps| and insert new pps into |received
| |
| 316 for (const NaluInfo& nalu : nalus) { | |
| 317 switch (nalu.type) { | |
| 318 case H264::NaluType::kPps: | |
| 319 if (nalu.pps_id < 0) { | |
| 320 LOG(LS_WARNING) << "Received pps without pps id."; | |
| 321 } else if (nalu.sps_id < 0) { | |
| 322 LOG(LS_WARNING) << "Received pps without sps id."; | |
| 323 } else { | |
| 324 new_pps[nalu.pps_id] = nalu.sps_id; | |
| 325 } | |
| 326 break; | |
| 327 case H264::NaluType::kSps: | |
| 328 if (nalu.sps_id < 0) { | |
| 329 LOG(LS_WARNING) << "Received sps without sps id."; | |
| 330 } else { | |
| 331 new_sps.insert(nalu.sps_id); | |
| 332 } | |
| 333 break; | |
| 334 default: { | |
| 335 int sps_needed = -1; | |
| 336 auto pps_it = new_pps.find(nalu.pps_id); | |
| 337 if (pps_it != new_pps.end()) { | |
| 338 sps_needed = pps_it->second; | |
| 339 } else { | |
| 340 auto pps_it2 = received_pps_.find(nalu.pps_id); | |
| 341 if (pps_it2 == received_pps_.end()) { | |
| 342 return false; | |
| 343 } | |
| 344 sps_needed = pps_it2->second; | |
| 345 } | |
| 346 if (new_sps.find(sps_needed) == new_sps.end() && | |
| 347 received_sps_.find(sps_needed) == received_sps_.end()) { | |
| 348 return false; | |
| 349 } | |
| 350 break; | |
| 351 } | |
| 352 } | |
| 353 } | |
| 354 return true; | |
| 355 } | |
| 356 | |
| 285 } // namespace webrtc | 357 } // namespace webrtc |
| OLD | NEW |