From 2c6d9c574fc123b3488ac950872fb5487b429941 Mon Sep 17 00:00:00 2001 From: Marco Date: Sun, 11 Jan 2015 15:26:44 -0800 Subject: vp8: Fix to crash in pick_inter. Added unittest that triggers the crash without this fix. Issue: https://code.google.com/p/webm/issues/detail?id=911 Change-Id: If5208ceb210c821891675fdf3d9951ab83d52ae6 --- test/error_resilience_test.cc | 90 +++++++++++++++++++++++++++++++++++++------ vp8/encoder/pickinter.c | 67 ++++++++++++++++---------------- 2 files changed, 112 insertions(+), 45 deletions(-) diff --git a/test/error_resilience_test.cc b/test/error_resilience_test.cc index 182547bdf..9a99a80f8 100644 --- a/test/error_resilience_test.cc +++ b/test/error_resilience_test.cc @@ -37,6 +37,7 @@ class ErrorResilienceTestLarge : public ::libvpx_test::EncoderTest, void Reset() { error_nframes_ = 0; droppable_nframes_ = 0; + pattern_switch_ = 0; } virtual void SetUp() { @@ -62,19 +63,37 @@ class ErrorResilienceTestLarge : public ::libvpx_test::EncoderTest, // 1 3 // 0 2 ..... // LAST is updated on base/layer 0, GOLDEN updated on layer 1. - int SetFrameFlags(int frame_num, int num_temp_layers) { + // Non-zero pattern_switch parameter means pattern will switch to + // not using LAST for frame_num >= pattern_switch. + int SetFrameFlags(int frame_num, + int num_temp_layers, + int pattern_switch) { int frame_flags = 0; if (num_temp_layers == 2) { - if (frame_num % 2 == 0) { - // Layer 0: predict from L and ARF, update L. - frame_flags = VP8_EFLAG_NO_REF_GF | - VP8_EFLAG_NO_UPD_GF | - VP8_EFLAG_NO_UPD_ARF; - } else { - // Layer 1: predict from L, GF, and ARF, and update GF. - frame_flags = VP8_EFLAG_NO_UPD_ARF | - VP8_EFLAG_NO_UPD_LAST; - } + if (frame_num % 2 == 0) { + if (frame_num < pattern_switch || pattern_switch == 0) { + // Layer 0: predict from LAST and ARF, update LAST. + frame_flags = VP8_EFLAG_NO_REF_GF | + VP8_EFLAG_NO_UPD_GF | + VP8_EFLAG_NO_UPD_ARF; + } else { + // Layer 0: predict from GF and ARF, update GF. + frame_flags = VP8_EFLAG_NO_REF_LAST | + VP8_EFLAG_NO_UPD_LAST | + VP8_EFLAG_NO_UPD_ARF; + } + } else { + if (frame_num < pattern_switch || pattern_switch == 0) { + // Layer 1: predict from L, GF, and ARF, update GF. + frame_flags = VP8_EFLAG_NO_UPD_ARF | + VP8_EFLAG_NO_UPD_LAST; + } else { + // Layer 1: predict from GF and ARF, update GF. + frame_flags = VP8_EFLAG_NO_REF_LAST | + VP8_EFLAG_NO_UPD_LAST | + VP8_EFLAG_NO_UPD_ARF; + } + } } return frame_flags; } @@ -86,7 +105,9 @@ class ErrorResilienceTestLarge : public ::libvpx_test::EncoderTest, VP8_EFLAG_NO_UPD_ARF); // For temporal layer case. if (cfg_.ts_number_layers > 1) { - frame_flags_ = SetFrameFlags(video->frame(), cfg_.ts_number_layers); + frame_flags_ = SetFrameFlags(video->frame(), + cfg_.ts_number_layers, + pattern_switch_); for (unsigned int i = 0; i < droppable_nframes_; ++i) { if (droppable_frames_[i] == video->frame()) { std::cout << "Encoding droppable frame: " @@ -168,11 +189,16 @@ class ErrorResilienceTestLarge : public ::libvpx_test::EncoderTest, return mismatch_nframes_; } + void SetPatternSwitch(int frame_switch) { + pattern_switch_ = frame_switch; + } + private: double psnr_; unsigned int nframes_; unsigned int error_nframes_; unsigned int droppable_nframes_; + unsigned int pattern_switch_; double mismatch_psnr_; unsigned int mismatch_nframes_; unsigned int error_frames_[kMaxErrorFrames]; @@ -299,6 +325,7 @@ TEST_P(ErrorResilienceTestLarge, 2LayersDropEnhancement) { // Error resilient mode ON. cfg_.g_error_resilient = 1; cfg_.kf_mode = VPX_KF_DISABLED; + SetPatternSwitch(0); // The odd frames are the enhancement layer for 2 layer pattern, so set // those frames as droppable. Drop the last 7 frames. @@ -316,6 +343,45 @@ TEST_P(ErrorResilienceTestLarge, 2LayersDropEnhancement) { Reset(); } +// Check for successful decoding and no encoder/decoder mismatch +// for a two layer temporal pattern, where at some point in the +// sequence, the LAST ref is not used anymore. +TEST_P(ErrorResilienceTestLarge, 2LayersNoRefLast) { + const vpx_rational timebase = { 33333333, 1000000000 }; + cfg_.g_timebase = timebase; + cfg_.rc_target_bitrate = 500; + cfg_.g_lag_in_frames = 0; + + cfg_.rc_end_usage = VPX_CBR; + // 2 Temporal layers, no spatial layers, CBR mode. + cfg_.ss_number_layers = 1; + cfg_.ts_number_layers = 2; + cfg_.ts_rate_decimator[0] = 2; + cfg_.ts_rate_decimator[1] = 1; + cfg_.ts_periodicity = 2; + cfg_.ts_target_bitrate[0] = 60 * cfg_.rc_target_bitrate / 100; + cfg_.ts_target_bitrate[1] = cfg_.rc_target_bitrate; + + init_flags_ = VPX_CODEC_USE_PSNR; + + libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, + timebase.den, timebase.num, 0, 100); + + // Error resilient mode ON. + cfg_.g_error_resilient = 1; + cfg_.kf_mode = VPX_KF_DISABLED; + SetPatternSwitch(60); + + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); + // Test that no mismatches have been found + std::cout << " Mismatch frames: " + << GetMismatchFrames() << "\n"; + EXPECT_EQ(GetMismatchFrames(), (unsigned int) 0); + + // Reset previously set of error/droppable frames. + Reset(); +} + class ErrorResilienceTestLargeCodecControls : public ::libvpx_test::EncoderTest, public ::libvpx_test::CodecTestWithParam { protected: diff --git a/vp8/encoder/pickinter.c b/vp8/encoder/pickinter.c index fc026aa9c..d02cd30b9 100644 --- a/vp8/encoder/pickinter.c +++ b/vp8/encoder/pickinter.c @@ -753,45 +753,46 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int ref_frame_map[4]; int sign_bias = 0; int dot_artifact_candidate = 0; - // For detecting dot artifact. - unsigned char* target = x->src.y_buffer; - unsigned char* target_u = x->block[16].src + *x->block[16].base_src; - unsigned char* target_v = x->block[20].src + *x->block[20].base_src; - int stride = x->src.y_stride; - int stride_uv = x->block[16].src_stride; + get_predictor_pointers(cpi, plane, recon_yoffset, recon_uvoffset); + + // If the current frame is using LAST as a reference, check for + // biasing the mode selection for dot artifacts. + if (cpi->ref_frame_flags & VP8_LAST_FRAME) { + unsigned char* target_y = x->src.y_buffer; + unsigned char* target_u = x->block[16].src + *x->block[16].base_src; + unsigned char* target_v = x->block[20].src + *x->block[20].base_src; + int stride = x->src.y_stride; + int stride_uv = x->block[16].src_stride; #if CONFIG_TEMPORAL_DENOISING - if (cpi->oxcf.noise_sensitivity) { - int uv_denoise = (cpi->oxcf.noise_sensitivity >= 2) ? 1 : 0; - target = - cpi->denoiser.yv12_running_avg[LAST_FRAME].y_buffer + recon_yoffset; - stride = cpi->denoiser.yv12_running_avg[LAST_FRAME].y_stride; - if (uv_denoise) { - target_u = - cpi->denoiser.yv12_running_avg[LAST_FRAME].u_buffer + recon_uvoffset; - target_v = - cpi->denoiser.yv12_running_avg[LAST_FRAME].v_buffer + recon_uvoffset; - stride_uv = cpi->denoiser.yv12_running_avg[LAST_FRAME].uv_stride; + if (cpi->oxcf.noise_sensitivity) { + const int uv_denoise = (cpi->oxcf.noise_sensitivity >= 2) ? 1 : 0; + target_y = + cpi->denoiser.yv12_running_avg[LAST_FRAME].y_buffer + recon_yoffset; + stride = cpi->denoiser.yv12_running_avg[LAST_FRAME].y_stride; + if (uv_denoise) { + target_u = + cpi->denoiser.yv12_running_avg[LAST_FRAME].u_buffer + + recon_uvoffset; + target_v = + cpi->denoiser.yv12_running_avg[LAST_FRAME].v_buffer + + recon_uvoffset; + stride_uv = cpi->denoiser.yv12_running_avg[LAST_FRAME].uv_stride; + } } - } #endif - - get_predictor_pointers(cpi, plane, recon_yoffset, recon_uvoffset); - - dot_artifact_candidate = - check_dot_artifact_candidate(cpi, x, - target, stride, - plane[LAST_FRAME][0], mb_row, mb_col, 0); - // If not found in Y channel, check UV channel. - if (!dot_artifact_candidate) { dot_artifact_candidate = - check_dot_artifact_candidate(cpi, x, - target_u, stride_uv, - plane[LAST_FRAME][1], mb_row, mb_col, 1); + check_dot_artifact_candidate(cpi, x, target_y, stride, + plane[LAST_FRAME][0], mb_row, mb_col, 0); + // If not found in Y channel, check UV channel. if (!dot_artifact_candidate) { dot_artifact_candidate = - check_dot_artifact_candidate(cpi, x, - target_v, stride_uv, - plane[LAST_FRAME][2], mb_row, mb_col, 2); + check_dot_artifact_candidate(cpi, x, target_u, stride_uv, + plane[LAST_FRAME][1], mb_row, mb_col, 1); + if (!dot_artifact_candidate) { + dot_artifact_candidate = + check_dot_artifact_candidate(cpi, x, target_v, stride_uv, + plane[LAST_FRAME][2], mb_row, mb_col, 2); + } } } -- cgit v1.2.3