Remove temporary VP9 pid/tl0 jump fix.

Earlier the pid/tl0 was incorrectly reinitialized upon encoder reconfiguration,
and this fix was implemented to mitigate that. This fix can however guess wrong
and cause a valid stream to be interupted.

BUG=webrtc:7920

Review-Url: https://codereview.webrtc.org/2969043002
Cr-Commit-Position: refs/heads/master@{#19268}
This commit is contained in:
philipel
2017-08-08 06:18:56 -07:00
committed by Commit Bot
parent 007d56229a
commit bb992e7159
3 changed files with 0 additions and 385 deletions

View File

@ -397,11 +397,6 @@ RtpFrameReferenceFinder::FrameDecision RtpFrameReferenceFinder::ManageFrameVp9(
RTC_DCHECK(rtp_codec_header); RTC_DCHECK(rtp_codec_header);
const RTPVideoHeaderVP9& codec_header = rtp_codec_header->VP9; const RTPVideoHeaderVP9& codec_header = rtp_codec_header->VP9;
bool old_frame = Vp9PidTl0Fix(*frame, &rtp_codec_header->VP9.picture_id,
&rtp_codec_header->VP9.tl0_pic_idx);
if (old_frame)
return kDrop;
if (codec_header.picture_id == kNoPictureId || if (codec_header.picture_id == kNoPictureId ||
codec_header.temporal_idx == kNoTemporalIdx) { codec_header.temporal_idx == kNoTemporalIdx) {
return ManageFrameGeneric(std::move(frame), codec_header.picture_id); return ManageFrameGeneric(std::move(frame), codec_header.picture_id);
@ -608,148 +603,5 @@ uint16_t RtpFrameReferenceFinder::UnwrapPictureId(uint16_t picture_id) {
return last_unwrap_; return last_unwrap_;
} }
bool RtpFrameReferenceFinder::Vp9PidTl0Fix(const RtpFrameObject& frame,
int16_t* picture_id,
int16_t* tl0_pic_idx) {
const int kTl0PicIdLength = 256;
const uint8_t kMaxPidDiff = 128;
// We are currently receiving VP9 without PID, nothing to fix.
if (*picture_id == kNoPictureId)
return false;
// If |vp9_fix_jump_timestamp_| != -1 then a jump has occurred recently.
if (vp9_fix_jump_timestamp_ != -1) {
// If this frame has a timestamp older than |vp9_fix_jump_timestamp_| then
// this frame is old (more previous than the frame where we detected the
// jump) and should be dropped.
if (AheadOf<uint32_t>(vp9_fix_jump_timestamp_, frame.timestamp))
return true;
// After 60 seconds, reset |vp9_fix_jump_timestamp_| in order to not
// discard old frames when the timestamp wraps.
int diff_ms =
ForwardDiff<uint32_t>(vp9_fix_jump_timestamp_, frame.timestamp) / 90;
if (diff_ms > 60 * 1000)
vp9_fix_jump_timestamp_ = -1;
}
// Update |vp9_fix_last_timestamp_| with the most recent timestamp.
if (vp9_fix_last_timestamp_ == -1)
vp9_fix_last_timestamp_ = frame.timestamp;
if (AheadOf<uint32_t>(frame.timestamp, vp9_fix_last_timestamp_))
vp9_fix_last_timestamp_ = frame.timestamp;
uint16_t fixed_pid = Add<kPicIdLength>(*picture_id, vp9_fix_pid_offset_);
if (vp9_fix_last_picture_id_ == -1)
vp9_fix_last_picture_id_ = *picture_id;
int16_t fixed_tl0 = kNoTl0PicIdx;
if (*tl0_pic_idx != kNoTl0PicIdx) {
fixed_tl0 = Add<kTl0PicIdLength>(*tl0_pic_idx, vp9_fix_tl0_pic_idx_offset_);
// Update |vp9_fix_last_tl0_pic_idx_| with the most recent tl0 pic index.
if (vp9_fix_last_tl0_pic_idx_ == -1)
vp9_fix_last_tl0_pic_idx_ = *tl0_pic_idx;
if (AheadOf<uint8_t>(fixed_tl0, vp9_fix_last_tl0_pic_idx_))
vp9_fix_last_tl0_pic_idx_ = fixed_tl0;
}
bool has_jumped = DetectVp9PicIdJump(fixed_pid, fixed_tl0, frame.timestamp);
if (!has_jumped)
has_jumped = DetectVp9Tl0PicIdxJump(fixed_tl0, frame.timestamp);
if (has_jumped) {
// First we calculate the offset to get to the previous picture id, and then
// we add kMaxPid to avoid accidently referencing any previous
// frames that was inserted into the FrameBuffer.
vp9_fix_pid_offset_ = ForwardDiff<uint16_t, kPicIdLength>(
*picture_id, vp9_fix_last_picture_id_);
vp9_fix_pid_offset_ += kMaxPidDiff;
fixed_pid = Add<kPicIdLength>(*picture_id, vp9_fix_pid_offset_);
vp9_fix_last_picture_id_ = fixed_pid;
vp9_fix_jump_timestamp_ = frame.timestamp;
gof_info_.clear();
if (fixed_tl0 != kNoTl0PicIdx) {
vp9_fix_tl0_pic_idx_offset_ =
ForwardDiff<uint8_t>(*tl0_pic_idx, vp9_fix_last_tl0_pic_idx_);
vp9_fix_tl0_pic_idx_offset_ += kMaxGofSaved;
fixed_tl0 =
Add<kTl0PicIdLength>(*tl0_pic_idx, vp9_fix_tl0_pic_idx_offset_);
vp9_fix_last_tl0_pic_idx_ = fixed_tl0;
}
}
// Update |vp9_fix_last_picture_id_| with the most recent picture id.
if (AheadOf<uint16_t, kPicIdLength>(fixed_pid, vp9_fix_last_picture_id_))
vp9_fix_last_picture_id_ = fixed_pid;
*picture_id = fixed_pid;
*tl0_pic_idx = fixed_tl0;
return false;
}
bool RtpFrameReferenceFinder::DetectVp9PicIdJump(int fixed_pid,
int fixed_tl0,
uint32_t timestamp) const {
// Test if there has been a jump backwards in the picture id.
if (AheadOrAt<uint32_t>(timestamp, vp9_fix_last_timestamp_) &&
AheadOf<uint16_t, kPicIdLength>(vp9_fix_last_picture_id_, fixed_pid)) {
return true;
}
// Test if we have jumped forward too much. The reason we have to do this
// is because the FrameBuffer holds history of old frames and inserting
// frames with a much advanced picture id can result in the frame buffer
// holding more than half of the interval of picture ids.
if (AheadOrAt<uint32_t>(timestamp, vp9_fix_last_timestamp_) &&
ForwardDiff<uint16_t, kPicIdLength>(vp9_fix_last_picture_id_, fixed_pid) >
128) {
return true;
}
// Special case where the picture id jump forward but not by much and the
// tl0 jumps to the id of an already saved gof for that id. In order to
// detect this we check if the picture id span over the length of the GOF.
if (fixed_tl0 != kNoTl0PicIdx) {
auto info_it = gof_info_.find(fixed_tl0);
if (info_it != gof_info_.end()) {
int last_pid_gof_idx_0 =
Subtract<kPicIdLength>(info_it->second.last_picture_id,
info_it->second.last_picture_id %
info_it->second.gof->num_frames_in_gof);
int pif_gof_end = Add<kPicIdLength>(
last_pid_gof_idx_0, info_it->second.gof->num_frames_in_gof);
if (AheadOf<uint16_t, kPicIdLength>(fixed_pid, pif_gof_end))
return true;
}
}
return false;
}
bool RtpFrameReferenceFinder::DetectVp9Tl0PicIdxJump(int fixed_tl0,
uint32_t timestamp) const {
if (fixed_tl0 != kNoTl0PicIdx) {
// Test if there has been a jump backwards in tl0 pic index.
if (AheadOrAt<uint32_t>(timestamp, vp9_fix_last_timestamp_) &&
AheadOf<uint8_t>(vp9_fix_last_tl0_pic_idx_, fixed_tl0)) {
return true;
}
// Test if there has been a jump forward. If the jump forward results
// in the tl0 pic index for this frame to be considered smaller than the
// smallest item in |gof_info_| then we have jumped forward far enough to
// wrap.
if (!gof_info_.empty() &&
AheadOf<uint8_t>(gof_info_.begin()->first, fixed_tl0)) {
return true;
}
}
return false;
}
} // namespace video_coding } // namespace video_coding
} // namespace webrtc } // namespace webrtc

View File

@ -213,15 +213,6 @@ class RtpFrameReferenceFinder {
int cleared_to_seq_num_ GUARDED_BY(crit_); int cleared_to_seq_num_ GUARDED_BY(crit_);
OnCompleteFrameCallback* frame_callback_; OnCompleteFrameCallback* frame_callback_;
// Vp9PidFix variables
// TODO(philipel): Remove when VP9 PID does not jump mid-stream.
int vp9_fix_last_timestamp_ = -1;
int vp9_fix_jump_timestamp_ = -1;
int vp9_fix_last_picture_id_ = -1;
int vp9_fix_pid_offset_ = 0;
int vp9_fix_last_tl0_pic_idx_ = -1;
int vp9_fix_tl0_pic_idx_offset_ = 0;
}; };
} // namespace video_coding } // namespace video_coding

View File

@ -1308,233 +1308,5 @@ TEST_F(TestRtpFrameReferenceFinder, Vp9FlexibleModeTwoSpatialLayersReordered) {
CheckReferencesVp9(pid + 8, 1, pid + 7); CheckReferencesVp9(pid + 8, 1, pid + 7);
} }
// TODO(philipel): Remove when VP9 PID/TL0 does not jump mid-stream (should be
// around M59).
TEST_F(TestRtpFrameReferenceFinder, Vp9PidFix_PidJumpsForwardNoTl0PicIdx) {
GofInfoVP9 ss;
ss.SetGofInfoVP9(kTemporalStructureMode1);
VCMPacket packet;
packet.timestamp = 0;
packet.codec = kVideoCodecVP9;
packet.frameType = kVideoFrameKey;
packet.markerBit = true;
packet.video_header.codecHeader.VP9.flexible_mode = false;
packet.video_header.codecHeader.VP9.picture_id = 0;
packet.video_header.codecHeader.VP9.temporal_idx = kNoTemporalIdx;
packet.video_header.codecHeader.VP9.spatial_idx = kNoSpatialIdx;
packet.video_header.codecHeader.VP9.tl0_pic_idx = kNoTl0PicIdx;
packet.video_header.codecHeader.VP9.temporal_up_switch = true;
packet.video_header.codecHeader.VP9.ss_data_available = true;
packet.video_header.codecHeader.VP9.gof = ss;
ref_packet_buffer_->InsertPacket(&packet);
reference_finder_->ManageFrame(std::unique_ptr<RtpFrameObject>(
new RtpFrameObject(ref_packet_buffer_, 0, 0, 0, 0, 0)));
packet.timestamp = 1;
packet.video_header.codecHeader.VP9.picture_id = 5000;
ref_packet_buffer_->InsertPacket(&packet);
reference_finder_->ManageFrame(std::unique_ptr<RtpFrameObject>(
new RtpFrameObject(ref_packet_buffer_, 0, 0, 0, 0, 0)));
ASSERT_EQ(2UL, frames_from_callback_.size());
CheckReferencesVp9(0, 0);
CheckReferencesVp9(128, 0);
}
// TODO(philipel): Remove when VP9 PID/TL0 does not jump mid-stream (should be
// around M59).
TEST_F(TestRtpFrameReferenceFinder, Vp9PidFix_PidJumpsBackwardThenForward) {
GofInfoVP9 ss;
ss.SetGofInfoVP9(kTemporalStructureMode1);
VCMPacket packet;
packet.timestamp = 0;
packet.codec = kVideoCodecVP9;
packet.frameType = kVideoFrameKey;
packet.markerBit = true;
packet.video_header.codecHeader.VP9.flexible_mode = false;
packet.video_header.codecHeader.VP9.picture_id = 1;
packet.video_header.codecHeader.VP9.temporal_idx = 0;
packet.video_header.codecHeader.VP9.spatial_idx = 0;
packet.video_header.codecHeader.VP9.tl0_pic_idx = 0;
packet.video_header.codecHeader.VP9.temporal_up_switch = true;
packet.video_header.codecHeader.VP9.ss_data_available = true;
packet.video_header.codecHeader.VP9.gof = ss;
ref_packet_buffer_->InsertPacket(&packet);
reference_finder_->ManageFrame(std::unique_ptr<RtpFrameObject>(
new RtpFrameObject(ref_packet_buffer_, 0, 0, 0, 0, 0)));
// Timestamp goes forward but pid goes backwards.
packet.timestamp = 1;
packet.video_header.codecHeader.VP9.picture_id = 0;
ref_packet_buffer_->InsertPacket(&packet);
reference_finder_->ManageFrame(std::unique_ptr<RtpFrameObject>(
new RtpFrameObject(ref_packet_buffer_, 0, 0, 0, 0, 0)));
packet.timestamp = 2;
packet.video_header.codecHeader.VP9.picture_id = 5000;
ref_packet_buffer_->InsertPacket(&packet);
reference_finder_->ManageFrame(std::unique_ptr<RtpFrameObject>(
new RtpFrameObject(ref_packet_buffer_, 0, 0, 0, 0, 0)));
ASSERT_EQ(3UL, frames_from_callback_.size());
CheckReferencesVp9(1, 0);
CheckReferencesVp9(129, 0);
CheckReferencesVp9(257, 0);
}
// TODO(philipel): Remove when VP9 PID/TL0 does not jump mid-stream (should be
// around M59).
TEST_F(TestRtpFrameReferenceFinder, Vp9PidFix_Tl0JumpsBackwardThenForward) {
GofInfoVP9 ss;
ss.SetGofInfoVP9(kTemporalStructureMode1);
VCMPacket packet;
packet.timestamp = 0;
packet.codec = kVideoCodecVP9;
packet.frameType = kVideoFrameKey;
packet.markerBit = true;
packet.video_header.codecHeader.VP9.flexible_mode = false;
packet.video_header.codecHeader.VP9.picture_id = 0;
packet.video_header.codecHeader.VP9.temporal_idx = 0;
packet.video_header.codecHeader.VP9.spatial_idx = 0;
packet.video_header.codecHeader.VP9.tl0_pic_idx = 1;
packet.video_header.codecHeader.VP9.temporal_up_switch = true;
packet.video_header.codecHeader.VP9.ss_data_available = true;
packet.video_header.codecHeader.VP9.gof = ss;
ref_packet_buffer_->InsertPacket(&packet);
reference_finder_->ManageFrame(std::unique_ptr<RtpFrameObject>(
new RtpFrameObject(ref_packet_buffer_, 0, 0, 0, 0, 0)));
packet.timestamp = 1;
packet.video_header.codecHeader.VP9.picture_id = 1;
packet.video_header.codecHeader.VP9.tl0_pic_idx = 0;
ref_packet_buffer_->InsertPacket(&packet);
reference_finder_->ManageFrame(std::unique_ptr<RtpFrameObject>(
new RtpFrameObject(ref_packet_buffer_, 0, 0, 0, 0, 0)));
packet.timestamp = 2;
packet.frameType = kVideoFrameDelta;
packet.video_header.codecHeader.VP9.picture_id = 2;
packet.video_header.codecHeader.VP9.tl0_pic_idx = 2;
ref_packet_buffer_->InsertPacket(&packet);
reference_finder_->ManageFrame(std::unique_ptr<RtpFrameObject>(
new RtpFrameObject(ref_packet_buffer_, 0, 0, 0, 0, 0)));
packet.timestamp = 3;
packet.frameType = kVideoFrameKey;
packet.video_header.codecHeader.VP9.ss_data_available = true;
packet.video_header.codecHeader.VP9.picture_id = 3;
packet.video_header.codecHeader.VP9.tl0_pic_idx = 129;
ref_packet_buffer_->InsertPacket(&packet);
reference_finder_->ManageFrame(std::unique_ptr<RtpFrameObject>(
new RtpFrameObject(ref_packet_buffer_, 0, 0, 0, 0, 0)));
ASSERT_EQ(4UL, frames_from_callback_.size());
CheckReferencesVp9(0, 0);
CheckReferencesVp9(128, 0);
CheckReferencesVp9(129, 0, 128);
CheckReferencesVp9(257, 0);
}
// TODO(philipel): Remove when VP9 PID/TL0 does not jump mid-stream (should be
// around M59).
TEST_F(TestRtpFrameReferenceFinder, Vp9PidFix_PidSmallJumpForward) {
GofInfoVP9 ss;
ss.SetGofInfoVP9(kTemporalStructureMode1);
VCMPacket packet;
packet.timestamp = 0;
packet.codec = kVideoCodecVP9;
packet.frameType = kVideoFrameKey;
packet.markerBit = true;
packet.video_header.codecHeader.VP9.flexible_mode = false;
packet.video_header.codecHeader.VP9.picture_id = 1;
packet.video_header.codecHeader.VP9.temporal_idx = 0;
packet.video_header.codecHeader.VP9.spatial_idx = 0;
packet.video_header.codecHeader.VP9.tl0_pic_idx = 1;
packet.video_header.codecHeader.VP9.temporal_up_switch = true;
packet.video_header.codecHeader.VP9.ss_data_available = true;
packet.video_header.codecHeader.VP9.gof = ss;
ref_packet_buffer_->InsertPacket(&packet);
reference_finder_->ManageFrame(std::unique_ptr<RtpFrameObject>(
new RtpFrameObject(ref_packet_buffer_, 0, 0, 0, 0, 0)));
packet.timestamp = 1;
packet.video_header.codecHeader.VP9.picture_id = 2;
packet.video_header.codecHeader.VP9.tl0_pic_idx = 2;
ref_packet_buffer_->InsertPacket(&packet);
reference_finder_->ManageFrame(std::unique_ptr<RtpFrameObject>(
new RtpFrameObject(ref_packet_buffer_, 0, 0, 0, 0, 0)));
packet.timestamp = 2;
packet.video_header.codecHeader.VP9.picture_id = 3;
packet.video_header.codecHeader.VP9.tl0_pic_idx = 2;
ref_packet_buffer_->InsertPacket(&packet);
reference_finder_->ManageFrame(std::unique_ptr<RtpFrameObject>(
new RtpFrameObject(ref_packet_buffer_, 0, 0, 0, 0, 0)));
packet.timestamp = 2;
packet.video_header.codecHeader.VP9.picture_id = 4;
packet.video_header.codecHeader.VP9.tl0_pic_idx = 1;
ref_packet_buffer_->InsertPacket(&packet);
reference_finder_->ManageFrame(std::unique_ptr<RtpFrameObject>(
new RtpFrameObject(ref_packet_buffer_, 0, 0, 0, 0, 0)));
ASSERT_EQ(4UL, frames_from_callback_.size());
CheckReferencesVp9(1, 0);
CheckReferencesVp9(2, 0);
CheckReferencesVp9(3, 0);
CheckReferencesVp9(131, 0);
}
// TODO(philipel): Remove when VP9 PID/TL0 does not jump mid-stream (should be
// around M59).
TEST_F(TestRtpFrameReferenceFinder, Vp9PidFix_DropOldFrame) {
GofInfoVP9 ss;
ss.SetGofInfoVP9(kTemporalStructureMode1);
VCMPacket packet;
packet.timestamp = 0;
packet.codec = kVideoCodecVP9;
packet.frameType = kVideoFrameKey;
packet.markerBit = true;
packet.video_header.codecHeader.VP9.flexible_mode = false;
packet.video_header.codecHeader.VP9.picture_id = 1;
packet.video_header.codecHeader.VP9.temporal_idx = 0;
packet.video_header.codecHeader.VP9.spatial_idx = 0;
packet.video_header.codecHeader.VP9.tl0_pic_idx = 1;
packet.video_header.codecHeader.VP9.temporal_up_switch = true;
packet.video_header.codecHeader.VP9.ss_data_available = true;
packet.video_header.codecHeader.VP9.gof = ss;
ref_packet_buffer_->InsertPacket(&packet);
reference_finder_->ManageFrame(std::unique_ptr<RtpFrameObject>(
new RtpFrameObject(ref_packet_buffer_, 0, 0, 0, 0, 0)));
packet.timestamp = 1;
packet.video_header.codecHeader.VP9.picture_id = 0;
packet.video_header.codecHeader.VP9.tl0_pic_idx = 2;
ref_packet_buffer_->InsertPacket(&packet);
reference_finder_->ManageFrame(std::unique_ptr<RtpFrameObject>(
new RtpFrameObject(ref_packet_buffer_, 0, 0, 0, 0, 0)));
packet.timestamp = 0;
packet.video_header.codecHeader.VP9.picture_id = 3;
packet.video_header.codecHeader.VP9.tl0_pic_idx = 2;
ref_packet_buffer_->InsertPacket(&packet);
reference_finder_->ManageFrame(std::unique_ptr<RtpFrameObject>(
new RtpFrameObject(ref_packet_buffer_, 0, 0, 0, 0, 0)));
ASSERT_EQ(2UL, frames_from_callback_.size());
CheckReferencesVp9(1, 0);
CheckReferencesVp9(129, 0);
}
} // namespace video_coding } // namespace video_coding
} // namespace webrtc } // namespace webrtc