Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2016 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 |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 24 OnCompleteFrameCallback* frame_callback) | 24 OnCompleteFrameCallback* frame_callback) |
| 25 : size_(start_buffer_size), | 25 : size_(start_buffer_size), |
| 26 max_size_(max_buffer_size), | 26 max_size_(max_buffer_size), |
| 27 first_seq_num_(0), | 27 first_seq_num_(0), |
| 28 last_seq_num_(0), | 28 last_seq_num_(0), |
| 29 first_packet_received_(false), | 29 first_packet_received_(false), |
| 30 data_buffer_(start_buffer_size), | 30 data_buffer_(start_buffer_size), |
| 31 sequence_buffer_(start_buffer_size), | 31 sequence_buffer_(start_buffer_size), |
| 32 frame_callback_(frame_callback), | 32 frame_callback_(frame_callback), |
| 33 last_picture_id_(-1), | 33 last_picture_id_(-1), |
| 34 last_unwrap_(-1) { | 34 last_unwrap_(-1), |
| 35 current_ss_idx_(0) { | |
| 35 RTC_DCHECK_LE(start_buffer_size, max_buffer_size); | 36 RTC_DCHECK_LE(start_buffer_size, max_buffer_size); |
| 36 // Buffer size must always be a power of 2. | 37 // Buffer size must always be a power of 2. |
| 37 RTC_DCHECK((start_buffer_size & (start_buffer_size - 1)) == 0); | 38 RTC_DCHECK((start_buffer_size & (start_buffer_size - 1)) == 0); |
| 38 RTC_DCHECK((max_buffer_size & (max_buffer_size - 1)) == 0); | 39 RTC_DCHECK((max_buffer_size & (max_buffer_size - 1)) == 0); |
| 39 } | 40 } |
| 40 | 41 |
| 41 bool PacketBuffer::InsertPacket(const VCMPacket& packet) { | 42 bool PacketBuffer::InsertPacket(const VCMPacket& packet) { |
| 42 rtc::CritScope lock(&crit_); | 43 rtc::CritScope lock(&crit_); |
| 43 uint16_t seq_num = packet.seqNum; | 44 uint16_t seq_num = packet.seqNum; |
| 44 size_t index = seq_num % size_; | 45 size_t index = seq_num % size_; |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 210 case kVideoCodecULPFEC : | 211 case kVideoCodecULPFEC : |
| 211 case kVideoCodecRED : | 212 case kVideoCodecRED : |
| 212 case kVideoCodecUnknown : { | 213 case kVideoCodecUnknown : { |
| 213 RTC_NOTREACHED(); | 214 RTC_NOTREACHED(); |
| 214 } | 215 } |
| 215 case kVideoCodecVP8 : { | 216 case kVideoCodecVP8 : { |
| 216 ManageFrameVp8(std::move(frame)); | 217 ManageFrameVp8(std::move(frame)); |
| 217 break; | 218 break; |
| 218 } | 219 } |
| 219 case kVideoCodecVP9 : { | 220 case kVideoCodecVP9 : { |
| 220 // TODO(philipel): ManageFrameVp9(std::move(frame)); | 221 ManageFrameVp9(std::move(frame)); |
| 221 break; | 222 break; |
| 222 } | 223 } |
| 223 case kVideoCodecH264 : | 224 case kVideoCodecH264 : |
| 224 case kVideoCodecI420 : | 225 case kVideoCodecI420 : |
| 225 case kVideoCodecGeneric : | 226 case kVideoCodecGeneric : |
| 226 default : { | 227 default : { |
| 227 ManageFrameGeneric(std::move(frame)); | 228 ManageFrameGeneric(std::move(frame)); |
| 228 } | 229 } |
| 229 } | 230 } |
| 230 } | 231 } |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 312 frame->picture_id = codec_header.pictureId % kPicIdLength; | 313 frame->picture_id = codec_header.pictureId % kPicIdLength; |
| 313 | 314 |
| 314 if (last_unwrap_ == -1) | 315 if (last_unwrap_ == -1) |
| 315 last_unwrap_ = codec_header.pictureId; | 316 last_unwrap_ = codec_header.pictureId; |
| 316 | 317 |
| 317 if (last_picture_id_ == -1) | 318 if (last_picture_id_ == -1) |
| 318 last_picture_id_ = frame->picture_id; | 319 last_picture_id_ = frame->picture_id; |
| 319 | 320 |
| 320 // Find if there has been a gap in fully received frames and save the picture | 321 // Find if there has been a gap in fully received frames and save the picture |
| 321 // id of those frames in |not_yet_received_frames_|. | 322 // id of those frames in |not_yet_received_frames_|. |
| 322 if (AheadOf<uint8_t, kPicIdLength>(frame->picture_id, last_picture_id_)) { | 323 if (AheadOf<uint16_t, kPicIdLength>(frame->picture_id, last_picture_id_)) { |
|
stefan-webrtc
2016/04/26 08:15:12
Do we have a unittest which would have caught this
philipel
2016/04/28 09:40:42
This was not a bug, I simply wanted to test what w
| |
| 323 last_picture_id_ = Add<kPicIdLength>(last_picture_id_, 1); | 324 last_picture_id_ = Add<kPicIdLength>(last_picture_id_, 1); |
| 324 while (last_picture_id_ != frame->picture_id) { | 325 while (last_picture_id_ != frame->picture_id) { |
| 325 not_yet_received_frames_.insert(last_picture_id_); | 326 not_yet_received_frames_.insert(last_picture_id_); |
| 326 last_picture_id_ = Add<kPicIdLength>(last_picture_id_, 1); | 327 last_picture_id_ = Add<kPicIdLength>(last_picture_id_, 1); |
| 327 } | 328 } |
| 328 } | 329 } |
| 329 | 330 |
| 330 // Clean up info for base layers that are too old. | 331 // Clean up info for base layers that are too old. |
| 331 uint8_t old_tl0_pic_idx = codec_header.tl0PicIdx - kMaxLayerInfo; | 332 uint8_t old_tl0_pic_idx = codec_header.tl0PicIdx - kMaxLayerInfo; |
| 332 auto clean_layer_info_to = layer_info_.lower_bound(old_tl0_pic_idx); | 333 auto clean_layer_info_to = layer_info_.lower_bound(old_tl0_pic_idx); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 382 // Find all references for this frame. | 383 // Find all references for this frame. |
| 383 frame->num_references = 0; | 384 frame->num_references = 0; |
| 384 for (uint8_t layer = 0; layer <= codec_header.temporalIdx; ++layer) { | 385 for (uint8_t layer = 0; layer <= codec_header.temporalIdx; ++layer) { |
| 385 RTC_DCHECK_NE(-1, layer_info_it->second[layer]); | 386 RTC_DCHECK_NE(-1, layer_info_it->second[layer]); |
| 386 | 387 |
| 387 // If we have not yet received a frame between this frame and the referenced | 388 // If we have not yet received a frame between this frame and the referenced |
| 388 // frame then we have to wait for that frame to be completed first. | 389 // frame then we have to wait for that frame to be completed first. |
| 389 auto not_received_frame_it = | 390 auto not_received_frame_it = |
| 390 not_yet_received_frames_.upper_bound(layer_info_it->second[layer]); | 391 not_yet_received_frames_.upper_bound(layer_info_it->second[layer]); |
| 391 if (not_received_frame_it != not_yet_received_frames_.end() && | 392 if (not_received_frame_it != not_yet_received_frames_.end() && |
| 392 AheadOf<uint8_t, kPicIdLength>(frame->picture_id, | 393 AheadOf<uint16_t, kPicIdLength>(frame->picture_id, |
| 393 *not_received_frame_it)) { | 394 *not_received_frame_it)) { |
| 394 stashed_frames_.emplace(std::move(frame)); | 395 stashed_frames_.emplace(std::move(frame)); |
| 395 return; | 396 return; |
| 396 } | 397 } |
| 397 | 398 |
| 398 ++frame->num_references; | 399 ++frame->num_references; |
| 399 frame->references[layer] = layer_info_it->second[layer]; | 400 frame->references[layer] = layer_info_it->second[layer]; |
| 400 } | 401 } |
| 401 | 402 |
| 402 CompletedFrameVp8(std::move(frame)); | 403 CompletedFrameVp8(std::move(frame)); |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 429 not_yet_received_frames_.erase(frame->picture_id); | 430 not_yet_received_frames_.erase(frame->picture_id); |
| 430 | 431 |
| 431 for (size_t r = 0; r < frame->num_references; ++r) | 432 for (size_t r = 0; r < frame->num_references; ++r) |
| 432 frame->references[r] = UnwrapPictureId(frame->references[r]); | 433 frame->references[r] = UnwrapPictureId(frame->references[r]); |
| 433 frame->picture_id = UnwrapPictureId(frame->picture_id); | 434 frame->picture_id = UnwrapPictureId(frame->picture_id); |
| 434 | 435 |
| 435 frame_callback_->OnCompleteFrame(std::move(frame)); | 436 frame_callback_->OnCompleteFrame(std::move(frame)); |
| 436 RetryStashedFrames(); | 437 RetryStashedFrames(); |
| 437 } | 438 } |
| 438 | 439 |
| 440 void PacketBuffer::ManageFrameVp9(std::unique_ptr<RtpFrameObject> frame) { | |
| 441 size_t index = frame->first_seq_num() % size_; | |
| 442 const VCMPacket& packet = data_buffer_[index]; | |
| 443 const RTPVideoHeaderVP9& codec_header = | |
| 444 packet.codecSpecificHeader.codecHeader.VP9; | |
| 445 | |
| 446 if (codec_header.picture_id == kNoPictureId) { | |
| 447 ManageFrameGeneric(std::move(frame)); | |
| 448 return; | |
| 449 } | |
| 450 | |
| 451 frame->spatial_layer = codec_header.spatial_idx; | |
| 452 frame->inter_layer_predicted = codec_header.inter_layer_predicted; | |
| 453 frame->picture_id = codec_header.picture_id % kPicIdLength; | |
|
stefan-webrtc
2016/04/26 08:15:12
kPictureIdLength
philipel
2016/04/28 09:40:42
I prefer not, there will be many lines that are al
| |
| 454 | |
| 455 if (last_unwrap_ == -1) | |
| 456 last_unwrap_ = codec_header.picture_id; | |
| 457 | |
| 458 if (last_picture_id_ == -1) | |
| 459 last_picture_id_ = frame->picture_id; | |
| 460 | |
| 461 // GLORIUS flexible mode! | |
|
stefan-webrtc
2016/04/26 08:15:12
I don't think we need this comment... :)
philipel
2016/04/28 09:40:42
Removed :P
| |
| 462 if (codec_header.flexible_mode) { | |
| 463 frame->num_references = codec_header.num_ref_pics; | |
| 464 for (size_t r = 0; r < frame->num_references; ++r) { | |
|
stefan-webrtc
2016/04/26 08:15:12
use index i rather than r.
philipel
2016/04/28 09:40:42
Done.
| |
| 465 frame->references[r] = Subtract<1 << 16>(frame->picture_id, | |
| 466 codec_header.pid_diff[r]); | |
| 467 } | |
| 468 | |
| 469 CompletedFrameVp9(std::move(frame)); | |
| 470 return; | |
| 471 } | |
| 472 | |
| 473 if (codec_header.ss_data_available) { | |
| 474 // Scalability structures can only be sent with tl0 frames. | |
| 475 RTC_DCHECK_EQ(0, codec_header.spatial_idx); | |
|
stefan-webrtc
2016/04/26 08:15:12
I don't think we'd want to crash if someone gives
philipel
2016/04/28 09:40:42
SS are now ignored if they are not sent on a base
| |
| 476 | |
| 477 current_ss_idx_ = Add<kMaxGofSaved>(current_ss_idx_, 1); | |
| 478 scalability_structures_[current_ss_idx_] = codec_header.gof; | |
| 479 scalability_structures_[current_ss_idx_].pid_start = frame->picture_id; | |
| 480 | |
| 481 auto pid_and_gof = std::make_pair(frame->picture_id, | |
| 482 &scalability_structures_[current_ss_idx_]); | |
| 483 gof_info_.insert(std::make_pair(codec_header.tl0_pic_idx, pid_and_gof)); | |
| 484 } | |
| 485 | |
| 486 // Clean up info for base layers that are to old. | |
|
stefan-webrtc
2016/04/26 08:15:12
too old
philipel
2016/04/28 09:40:41
Done.
| |
| 487 uint8_t old_tl0_pic_idx = codec_header.tl0_pic_idx - kMaxGofSaved; | |
| 488 auto clean_gof_info_to = gof_info_.lower_bound(old_tl0_pic_idx); | |
| 489 gof_info_.erase(gof_info_.begin(), clean_gof_info_to); | |
| 490 | |
| 491 if (packet.frameType == kVideoFrameKey) { | |
| 492 // When using GOF all keyframes must include the scalability structure. | |
| 493 RTC_DCHECK(codec_header.ss_data_available); | |
| 494 | |
| 495 frame->num_references = 0; | |
| 496 CompletedFrameVp9(std::move(frame)); | |
| 497 return; | |
| 498 } | |
| 499 | |
| 500 auto gof_info_it = gof_info_.find((codec_header.temporal_idx == 0 && | |
| 501 !codec_header.ss_data_available) | |
| 502 ? codec_header.tl0_pic_idx - 1 | |
| 503 : codec_header.tl0_pic_idx); | |
| 504 | |
| 505 // Gof info for this frame is not available yet, stash this frame. | |
| 506 if (gof_info_it == gof_info_.end()) { | |
| 507 stashed_frames_.emplace(std::move(frame)); | |
|
stefan-webrtc
2016/04/26 08:15:12
What happens if we have already deleted the ss tha
philipel
2016/04/28 09:40:42
RetryStashedFrames have built in clean up logic wh
| |
| 508 return; | |
| 509 } | |
| 510 | |
| 511 uint16_t picture_id_tl0 = gof_info_it->second.first; | |
| 512 GofInfoVP9* gof = gof_info_it->second.second; | |
| 513 | |
| 514 // If this is a base layer frame that contains a scalability structure | |
| 515 // then gof info has already been inserted earlier, so we only want to | |
| 516 // insert if we haven't done so already. | |
| 517 if (codec_header.temporal_idx == 0 && | |
| 518 !codec_header.ss_data_available) { | |
| 519 auto pid_and_gof = std::make_pair(frame->picture_id, gof); | |
| 520 gof_info_.insert(std::make_pair(codec_header.tl0_pic_idx, pid_and_gof)); | |
| 521 } | |
| 522 | |
| 523 // Sync frames only depend on their tl0_pic_idx.W | |
|
stefan-webrtc
2016/04/26 08:15:12
Erase W.
And is this comment true? I think a fram
philipel
2016/04/28 09:40:42
I was thinking of sync frames for Vp8 for some rea
| |
| 524 if (codec_header.temporal_up_switch) { | |
| 525 frame->num_references = 1; | |
| 526 frame->references[0] = picture_id_tl0; | |
| 527 CompletedFrameVp9(std::move(frame)); | |
| 528 return; | |
| 529 } | |
| 530 | |
| 531 RTC_DCHECK((AheadOrAt<uint16_t, kPicIdLength>(frame->picture_id, | |
|
stefan-webrtc
2016/04/26 08:15:12
Is this a safe DCHECK if someone produces a bit st
philipel
2016/04/28 09:40:41
What this check do is to make sure we don't select
| |
| 532 picture_id_tl0))); | |
| 533 | |
| 534 uint8_t diff = ForwardDiff<uint16_t, kPicIdLength>(gof->pid_start, | |
| 535 frame->picture_id); | |
|
stefan-webrtc
2016/04/26 08:15:12
May not be correctly indented
philipel
2016/04/28 09:40:41
Done.
| |
| 536 uint8_t gof_idx = diff % gof->num_frames_in_gof; | |
| 537 | |
| 538 // Populate references according to the scalability structure. | |
| 539 frame->num_references = gof->num_ref_pics[gof_idx]; | |
| 540 for (size_t r = 0; r < frame->num_references; ++r) { | |
|
stefan-webrtc
2016/04/26 08:15:12
index i
philipel
2016/04/28 09:40:42
Done.
| |
| 541 diff = ForwardDiff<uint16_t, kPicIdLength>(gof->pid_start, | |
| 542 frame->picture_id); | |
|
stefan-webrtc
2016/04/26 08:15:12
Indentation.
And actually, you have already compu
philipel
2016/04/28 09:40:42
Done.
| |
| 543 gof_idx = diff % gof->num_frames_in_gof; | |
|
stefan-webrtc
2016/04/26 08:15:12
This too, if I'm not mistaken
philipel
2016/04/28 09:40:42
Done.
| |
| 544 frame->references[r] = Subtract<1 << 16>(frame->picture_id, | |
| 545 gof->pid_diff[gof_idx][r]); | |
| 546 } | |
| 547 | |
| 548 CompletedFrameVp9(std::move(frame)); | |
| 549 } | |
| 550 | |
| 551 void PacketBuffer::CompletedFrameVp9(std::unique_ptr<RtpFrameObject> frame) { | |
| 552 for (size_t r = 0; r < frame->num_references; ++r) | |
| 553 frame->references[r] = UnwrapPictureId(frame->references[r]); | |
| 554 frame->picture_id = UnwrapPictureId(frame->picture_id); | |
| 555 | |
| 556 frame_callback_->OnCompleteFrame(std::move(frame)); | |
| 557 RetryStashedFrames(); | |
| 558 } | |
| 559 | |
| 560 | |
| 439 uint16_t PacketBuffer::UnwrapPictureId(uint16_t picture_id) { | 561 uint16_t PacketBuffer::UnwrapPictureId(uint16_t picture_id) { |
| 440 if (last_unwrap_ == -1) | 562 RTC_DCHECK_NE(-1, last_unwrap_); |
| 441 last_unwrap_ = picture_id; | |
| 442 | 563 |
| 443 uint16_t unwrap_truncated = last_unwrap_ % kPicIdLength; | 564 uint16_t unwrap_truncated = last_unwrap_ % kPicIdLength; |
| 444 uint16_t diff = MinDiff<uint8_t, kPicIdLength>(unwrap_truncated, picture_id); | 565 uint16_t diff = MinDiff<uint16_t, kPicIdLength>(unwrap_truncated, picture_id); |
| 445 | 566 |
| 446 if (AheadOf<uint8_t, kPicIdLength>(picture_id, unwrap_truncated)) | 567 if (AheadOf<uint16_t, kPicIdLength>(picture_id, unwrap_truncated)) |
| 447 last_unwrap_ = Add<1 << 16>(last_unwrap_, diff); | 568 last_unwrap_ = Add<1 << 16>(last_unwrap_, diff); |
| 448 else | 569 else |
| 449 last_unwrap_ = Subtract<1 << 16>(last_unwrap_, diff); | 570 last_unwrap_ = Subtract<1 << 16>(last_unwrap_, diff); |
| 450 | 571 |
| 451 return last_unwrap_; | 572 return last_unwrap_; |
| 452 } | 573 } |
| 453 | 574 |
| 454 void PacketBuffer::Flush() { | 575 void PacketBuffer::Flush() { |
| 455 rtc::CritScope lock(&crit_); | 576 rtc::CritScope lock(&crit_); |
| 456 for (size_t i = 0; i < size_; ++i) | 577 for (size_t i = 0; i < size_; ++i) |
| 457 sequence_buffer_[i].used = false; | 578 sequence_buffer_[i].used = false; |
| 458 | 579 |
| 459 last_seq_num_gop_.clear(); | 580 last_seq_num_gop_.clear(); |
| 460 while (!stashed_frames_.empty()) | 581 while (!stashed_frames_.empty()) |
| 461 stashed_frames_.pop(); | 582 stashed_frames_.pop(); |
| 462 not_yet_received_frames_.clear(); | 583 not_yet_received_frames_.clear(); |
| 463 | 584 |
| 464 first_packet_received_ = false; | 585 first_packet_received_ = false; |
| 465 } | 586 } |
| 466 | 587 |
| 467 } // namespace video_coding | 588 } // namespace video_coding |
| 468 } // namespace webrtc | 589 } // namespace webrtc |
| OLD | NEW |