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 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
364 } | 364 } |
365 | 365 |
366 void RtpFrameReferenceFinder::ManageFrameVp9( | 366 void RtpFrameReferenceFinder::ManageFrameVp9( |
367 std::unique_ptr<RtpFrameObject> frame) { | 367 std::unique_ptr<RtpFrameObject> frame) { |
368 rtc::Optional<RTPVideoTypeHeader> rtp_codec_header = frame->GetCodecHeader(); | 368 rtc::Optional<RTPVideoTypeHeader> rtp_codec_header = frame->GetCodecHeader(); |
369 if (!rtp_codec_header) | 369 if (!rtp_codec_header) |
370 return; | 370 return; |
371 | 371 |
372 const RTPVideoHeaderVP9& codec_header = rtp_codec_header->VP9; | 372 const RTPVideoHeaderVP9& codec_header = rtp_codec_header->VP9; |
373 | 373 |
| 374 bool old_frame = Vp9PidTl0Fix(*frame, &rtp_codec_header->VP9.picture_id, |
| 375 &rtp_codec_header->VP9.tl0_pic_idx); |
| 376 if (old_frame) |
| 377 return; |
| 378 |
374 if (codec_header.picture_id == kNoPictureId || | 379 if (codec_header.picture_id == kNoPictureId || |
375 codec_header.temporal_idx == kNoTemporalIdx) { | 380 codec_header.temporal_idx == kNoTemporalIdx) { |
376 ManageFrameGeneric(std::move(frame), codec_header.picture_id); | 381 ManageFrameGeneric(std::move(frame), codec_header.picture_id); |
377 return; | 382 return; |
378 } | 383 } |
379 | 384 |
380 frame->spatial_layer = codec_header.spatial_idx; | 385 frame->spatial_layer = codec_header.spatial_idx; |
381 frame->inter_layer_predicted = codec_header.inter_layer_predicted; | 386 frame->inter_layer_predicted = codec_header.inter_layer_predicted; |
382 frame->picture_id = codec_header.picture_id % kPicIdLength; | 387 frame->picture_id = codec_header.picture_id % kPicIdLength; |
383 | 388 |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
578 uint16_t diff = MinDiff<uint16_t, kPicIdLength>(unwrap_truncated, picture_id); | 583 uint16_t diff = MinDiff<uint16_t, kPicIdLength>(unwrap_truncated, picture_id); |
579 | 584 |
580 if (AheadOf<uint16_t, kPicIdLength>(picture_id, unwrap_truncated)) | 585 if (AheadOf<uint16_t, kPicIdLength>(picture_id, unwrap_truncated)) |
581 last_unwrap_ = Add<1 << 16>(last_unwrap_, diff); | 586 last_unwrap_ = Add<1 << 16>(last_unwrap_, diff); |
582 else | 587 else |
583 last_unwrap_ = Subtract<1 << 16>(last_unwrap_, diff); | 588 last_unwrap_ = Subtract<1 << 16>(last_unwrap_, diff); |
584 | 589 |
585 return last_unwrap_; | 590 return last_unwrap_; |
586 } | 591 } |
587 | 592 |
| 593 bool RtpFrameReferenceFinder::Vp9PidTl0Fix(const RtpFrameObject& frame, |
| 594 int16_t* picture_id, |
| 595 int16_t* tl0_pic_idx) { |
| 596 const int kTl0PicIdLength = 256; |
| 597 const uint8_t kMaxPidDiff = 128; |
| 598 |
| 599 // We are currently receiving VP9 without PID, nothing to fix. |
| 600 if (*picture_id == kNoPictureId) |
| 601 return false; |
| 602 |
| 603 // If |vp9_fix_jump_timestamp_| != -1 then a jump has occurred recently. |
| 604 if (vp9_fix_jump_timestamp_ != -1) { |
| 605 // If this frame has a timestamp older than |vp9_fix_jump_timestamp_| then |
| 606 // this frame is old (more previous than the frame where we detected the |
| 607 // jump) and should be dropped. |
| 608 if (AheadOf<uint32_t>(vp9_fix_jump_timestamp_, frame.timestamp)) |
| 609 return true; |
| 610 |
| 611 // After 60 seconds, reset |vp9_fix_jump_timestamp_| in order to not |
| 612 // discard old frames when the timestamp wraps. |
| 613 int diff_ms = |
| 614 ForwardDiff<uint32_t>(vp9_fix_jump_timestamp_, frame.timestamp) / 90; |
| 615 if (diff_ms > 60 * 1000) |
| 616 vp9_fix_jump_timestamp_ = -1; |
| 617 } |
| 618 |
| 619 // Update |vp9_fix_last_timestamp_| with the most recent timestamp. |
| 620 if (vp9_fix_last_timestamp_ == -1) |
| 621 vp9_fix_last_timestamp_ = frame.timestamp; |
| 622 if (AheadOf<uint32_t>(frame.timestamp, vp9_fix_last_timestamp_)) |
| 623 vp9_fix_last_timestamp_ = frame.timestamp; |
| 624 |
| 625 uint16_t fixed_pid = Add<kPicIdLength>(*picture_id, vp9_fix_pid_offset_); |
| 626 if (vp9_fix_last_picture_id_ == -1) |
| 627 vp9_fix_last_picture_id_ = *picture_id; |
| 628 |
| 629 int16_t fixed_tl0 = kNoTl0PicIdx; |
| 630 if (*tl0_pic_idx != kNoTl0PicIdx) { |
| 631 fixed_tl0 = Add<kTl0PicIdLength>(*tl0_pic_idx, vp9_fix_tl0_pic_idx_offset_); |
| 632 // Update |vp9_fix_last_tl0_pic_idx_| with the most recent tl0 pic index. |
| 633 if (vp9_fix_last_tl0_pic_idx_ == -1) |
| 634 vp9_fix_last_tl0_pic_idx_ = *tl0_pic_idx; |
| 635 if (AheadOf<uint8_t>(fixed_tl0, vp9_fix_last_tl0_pic_idx_)) |
| 636 vp9_fix_last_tl0_pic_idx_ = fixed_tl0; |
| 637 } |
| 638 |
| 639 bool has_jumped = DetectVp9PicIdJump(fixed_pid, fixed_tl0, frame.timestamp); |
| 640 if (!has_jumped) |
| 641 has_jumped = DetectVp9Tl0PicIdxJump(fixed_tl0, frame.timestamp); |
| 642 |
| 643 if (has_jumped) { |
| 644 // First we calculate the offset to get to the previous picture id, and then |
| 645 // we add kMaxPid to avoid accidently referencing any previous |
| 646 // frames that was inserted into the FrameBuffer. |
| 647 vp9_fix_pid_offset_ = ForwardDiff<uint16_t, kPicIdLength>( |
| 648 *picture_id, vp9_fix_last_picture_id_); |
| 649 vp9_fix_pid_offset_ += kMaxPidDiff; |
| 650 |
| 651 fixed_pid = Add<kPicIdLength>(*picture_id, vp9_fix_pid_offset_); |
| 652 vp9_fix_last_picture_id_ = fixed_pid; |
| 653 vp9_fix_jump_timestamp_ = frame.timestamp; |
| 654 gof_info_.clear(); |
| 655 |
| 656 vp9_fix_tl0_pic_idx_offset_ = |
| 657 ForwardDiff<uint8_t>(*tl0_pic_idx, vp9_fix_last_tl0_pic_idx_); |
| 658 vp9_fix_tl0_pic_idx_offset_ += kMaxGofSaved; |
| 659 fixed_tl0 = Add<kTl0PicIdLength>(*tl0_pic_idx, vp9_fix_tl0_pic_idx_offset_); |
| 660 vp9_fix_last_tl0_pic_idx_ = fixed_tl0; |
| 661 } |
| 662 |
| 663 // Update |vp9_fix_last_picture_id_| with the most recent picture id. |
| 664 if (AheadOf<uint16_t, kPicIdLength>(fixed_pid, vp9_fix_last_picture_id_)) |
| 665 vp9_fix_last_picture_id_ = fixed_pid; |
| 666 |
| 667 *picture_id = fixed_pid; |
| 668 *tl0_pic_idx = fixed_tl0; |
| 669 |
| 670 return false; |
| 671 } |
| 672 |
| 673 bool RtpFrameReferenceFinder::DetectVp9PicIdJump(int fixed_pid, |
| 674 int fixed_tl0, |
| 675 uint32_t timestamp) const { |
| 676 // Test if there has been a jump backwards in the picture id. |
| 677 if (AheadOrAt<uint32_t>(timestamp, vp9_fix_last_timestamp_) && |
| 678 AheadOf<uint16_t, kPicIdLength>(vp9_fix_last_picture_id_, fixed_pid)) { |
| 679 return true; |
| 680 } |
| 681 |
| 682 // Test if we have jumped forward too much. The reason we have to do this |
| 683 // is because the FrameBuffer holds history of old frames and inserting |
| 684 // frames with a much advanced picture id can result in the frame buffer |
| 685 // holding more than half of the interval of picture ids. |
| 686 if (AheadOrAt<uint32_t>(timestamp, vp9_fix_last_timestamp_) && |
| 687 ForwardDiff<uint16_t, kPicIdLength>(vp9_fix_last_picture_id_, fixed_pid) > |
| 688 128) { |
| 689 return true; |
| 690 } |
| 691 |
| 692 // Special case where the picture id jump forward but not by much and the |
| 693 // tl0 jumps to the id of an already saved gof for that id. In order to |
| 694 // detect this we check if the picture id span over the length of the GOF. |
| 695 if (fixed_tl0 != kNoTl0PicIdx) { |
| 696 auto info_it = gof_info_.find(fixed_tl0); |
| 697 if (info_it != gof_info_.end()) { |
| 698 int last_pid_gof_idx_0 = |
| 699 Subtract<kPicIdLength>(info_it->second.last_picture_id, |
| 700 info_it->second.last_picture_id % |
| 701 info_it->second.gof->num_frames_in_gof); |
| 702 int pif_gof_end = Add<kPicIdLength>( |
| 703 last_pid_gof_idx_0, info_it->second.gof->num_frames_in_gof); |
| 704 if (AheadOf<uint16_t, kPicIdLength>(fixed_pid, pif_gof_end)) |
| 705 return true; |
| 706 } |
| 707 } |
| 708 |
| 709 return false; |
| 710 } |
| 711 |
| 712 bool RtpFrameReferenceFinder::DetectVp9Tl0PicIdxJump(int fixed_tl0, |
| 713 uint32_t timestamp) const { |
| 714 if (fixed_tl0 != kNoTl0PicIdx) { |
| 715 // Test if there has been a jump backwards in tl0 pic index. |
| 716 if (AheadOrAt<uint32_t>(timestamp, vp9_fix_last_timestamp_) && |
| 717 AheadOf<uint8_t>(vp9_fix_last_tl0_pic_idx_, fixed_tl0)) { |
| 718 return true; |
| 719 } |
| 720 |
| 721 // Test if there has been a jump forward. If the jump forward results |
| 722 // in the tl0 pic index for this frame to be considered smaller than the |
| 723 // smallest item in |gof_info_| then we have jumped forward far enough to |
| 724 // wrap. |
| 725 if (!gof_info_.empty() && |
| 726 AheadOf<uint8_t>(gof_info_.begin()->first, fixed_tl0)) { |
| 727 return true; |
| 728 } |
| 729 } |
| 730 return false; |
| 731 } |
| 732 |
588 } // namespace video_coding | 733 } // namespace video_coding |
589 } // namespace webrtc | 734 } // namespace webrtc |
OLD | NEW |