diff --git a/test/decode_test_driver.h b/test/decode_test_driver.h index 5daa1657b..ed7069004 100644 --- a/test/decode_test_driver.h +++ b/test/decode_test_driver.h @@ -81,7 +81,7 @@ class Decoder { // Common test functionality for all Decoder tests. class DecoderTest { public: - // Main loop. + // Main decoding loop virtual void RunLoop(CompressedVideoSource *video); // Hook to be called on every decompressed frame. diff --git a/test/encode_test_driver.cc b/test/encode_test_driver.cc index 9475ee9c7..b2b6e0d6d 100644 --- a/test/encode_test_driver.cc +++ b/test/encode_test_driver.cc @@ -7,6 +7,7 @@ * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ + #include "vpx_config.h" #include "test/codec_factory.h" #include "test/encode_test_driver.h" @@ -129,6 +130,11 @@ static bool compare_img(const vpx_image_t *img1, return match; } +void EncoderTest::MismatchHook(const vpx_image_t *img1, + const vpx_image_t *img2) { + ASSERT_TRUE(0) << "Encode/Decode mismatch found"; +} + void EncoderTest::RunLoop(VideoSource *video) { vpx_codec_dec_cfg_t dec_cfg = {0}; @@ -149,7 +155,6 @@ void EncoderTest::RunLoop(VideoSource *video) { &stats_); ASSERT_TRUE(encoder != NULL); Decoder* const decoder = codec_->CreateDecoder(dec_cfg, 0); - bool has_cxdata = false; bool again; for (again = true, video->Begin(); again; video->Next()) { again = video->img() != NULL; @@ -160,15 +165,18 @@ void EncoderTest::RunLoop(VideoSource *video) { CxDataIterator iter = encoder->GetCxData(); + bool has_cxdata = false; + bool has_dxdata = false; while (const vpx_codec_cx_pkt_t *pkt = iter.Next()) { again = true; - switch (pkt->kind) { case VPX_CODEC_CX_FRAME_PKT: has_cxdata = true; - if (decoder) + if (decoder && DoDecode()) { decoder->DecodeFrame((const uint8_t*)pkt->data.frame.buf, pkt->data.frame.sz); + has_dxdata = true; + } ASSERT_GE(pkt->data.frame.pts, last_pts_); last_pts_ = pkt->data.frame.pts; FramePktHook(pkt); @@ -183,16 +191,17 @@ void EncoderTest::RunLoop(VideoSource *video) { } } - if (decoder && has_cxdata) { + if (has_dxdata && has_cxdata) { const vpx_image_t *img_enc = encoder->GetPreviewFrame(); DxDataIterator dec_iter = decoder->GetDxData(); const vpx_image_t *img_dec = dec_iter.Next(); - if(img_enc && img_dec) { + if (img_enc && img_dec) { const bool res = compare_img(img_enc, img_dec); - ASSERT_TRUE(res)<< "Encoder/Decoder mismatch found."; + if (!res) { // Mismatch + MismatchHook(img_enc, img_dec); + } } } - if (!Continue()) break; } @@ -207,4 +216,5 @@ void EncoderTest::RunLoop(VideoSource *video) { break; } } + } // namespace libvpx_test diff --git a/test/encode_test_driver.h b/test/encode_test_driver.h index 618257212..0944dc2c6 100644 --- a/test/encode_test_driver.h +++ b/test/encode_test_driver.h @@ -9,6 +9,8 @@ */ #ifndef TEST_ENCODE_TEST_DRIVER_H_ #define TEST_ENCODE_TEST_DRIVER_H_ + +#include "./vpx_config.h" #include #include #include "third_party/googletest/src/include/gtest/gtest.h" @@ -162,7 +164,7 @@ class EncoderTest { // Map the TestMode enum to the deadline_ and passes_ variables. void SetMode(TestMode mode); - // Main loop. + // Main loop virtual void RunLoop(VideoSource *video); // Hook to be called at the beginning of a pass. @@ -185,6 +187,13 @@ class EncoderTest { virtual bool Continue() const { return !abort_; } const CodecFactory *codec_; + // Hook to determine whether to decode frame after encoding + virtual bool DoDecode() const { return 1; } + + // Hook to handle encode/decode mismatch + virtual void MismatchHook(const vpx_image_t *img1, + const vpx_image_t *img2); + bool abort_; vpx_codec_enc_cfg_t cfg_; unsigned int passes_; diff --git a/test/error_resilience_test.cc b/test/error_resilience_test.cc index be9043964..f33c722d8 100644 --- a/test/error_resilience_test.cc +++ b/test/error_resilience_test.cc @@ -7,6 +7,7 @@ in the file PATENTS. All contributing project authors may be found in the AUTHORS file in the root of the source tree. */ + #include "third_party/googletest/src/include/gtest/gtest.h" #include "test/codec_factory.h" #include "test/encode_test_driver.h" @@ -15,14 +16,28 @@ namespace { +const int kMaxErrorFrames = 8; +const int kMaxDroppableFrames = 8; + class ErrorResilienceTest : public ::libvpx_test::EncoderTest, public ::libvpx_test::CodecTestWithParam { protected: - ErrorResilienceTest() : EncoderTest(GET_PARAM(0)), psnr_(0.0), nframes_(0), - encoding_mode_(GET_PARAM(1)) {} + ErrorResilienceTest() : EncoderTest(GET_PARAM(0)), + psnr_(0.0), + nframes_(0), + mismatch_psnr_(0.0), + mismatch_nframes_(0), + encoding_mode_(GET_PARAM(1)) { + Reset(); + } virtual ~ErrorResilienceTest() {} + void Reset() { + error_nframes_ = 0; + droppable_nframes_ = 0; + } + virtual void SetUp() { InitializeConfig(); SetMode(encoding_mode_); @@ -31,6 +46,8 @@ class ErrorResilienceTest : public ::libvpx_test::EncoderTest, virtual void BeginPassHook(unsigned int /*pass*/) { psnr_ = 0.0; nframes_ = 0; + mismatch_psnr_ = 0.0; + mismatch_nframes_ = 0; } virtual bool Continue() const { @@ -42,15 +59,92 @@ class ErrorResilienceTest : public ::libvpx_test::EncoderTest, nframes_++; } + virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video) { + frame_flags_ &= ~(VP8_EFLAG_NO_UPD_LAST | + VP8_EFLAG_NO_UPD_GF | + VP8_EFLAG_NO_UPD_ARF); + if (droppable_nframes_ > 0 && + (cfg_.g_pass == VPX_RC_LAST_PASS || cfg_.g_pass == VPX_RC_ONE_PASS)) { + for (unsigned int i = 0; i < droppable_nframes_; ++i) { + if (droppable_frames_[i] == nframes_) { + std::cout << " Encoding droppable frame: " + << droppable_frames_[i] << "\n"; + frame_flags_ |= (VP8_EFLAG_NO_UPD_LAST | + VP8_EFLAG_NO_UPD_GF | + VP8_EFLAG_NO_UPD_ARF); + return; + } + } + } + } + double GetAveragePsnr() const { if (nframes_) return psnr_ / nframes_; return 0.0; } + double GetAverageMismatchPsnr() const { + if (mismatch_nframes_) + return mismatch_psnr_ / mismatch_nframes_; + return 0.0; + } + + virtual bool DoDecode() const { + if (error_nframes_ > 0 && + (cfg_.g_pass == VPX_RC_LAST_PASS || cfg_.g_pass == VPX_RC_ONE_PASS)) { + for (unsigned int i = 0; i < error_nframes_; ++i) { + if (error_frames_[i] == nframes_ - 1) { + std::cout << " Skipping decoding frame: " + << error_frames_[i] << "\n"; + return 0; + } + } + } + return 1; + } + + virtual void MismatchHook(const vpx_image_t *img1, + const vpx_image_t *img2) { + double mismatch_psnr = compute_psnr(img1, img2); + mismatch_psnr_ += mismatch_psnr; + ++mismatch_nframes_; + // std::cout << "Mismatch frame psnr: " << mismatch_psnr << "\n"; + } + + void SetErrorFrames(int num, unsigned int *list) { + if (num > kMaxErrorFrames) + num = kMaxErrorFrames; + else if (num < 0) + num = 0; + error_nframes_ = num; + for (unsigned int i = 0; i < error_nframes_; ++i) + error_frames_[i] = list[i]; + } + + void SetDroppableFrames(int num, unsigned int *list) { + if (num > kMaxDroppableFrames) + num = kMaxDroppableFrames; + else if (num < 0) + num = 0; + droppable_nframes_ = num; + for (unsigned int i = 0; i < droppable_nframes_; ++i) + droppable_frames_[i] = list[i]; + } + + unsigned int GetMismatchFrames() { + return mismatch_nframes_; + } + private: double psnr_; unsigned int nframes_; + unsigned int error_nframes_; + unsigned int droppable_nframes_; + double mismatch_psnr_; + unsigned int mismatch_nframes_; + unsigned int error_frames_[kMaxErrorFrames]; + unsigned int droppable_frames_[kMaxDroppableFrames]; libvpx_test::TestMode encoding_mode_; }; @@ -85,5 +179,50 @@ TEST_P(ErrorResilienceTest, OnVersusOff) { } } +TEST_P(ErrorResilienceTest, DropFramesWithoutRecovery) { + const vpx_rational timebase = { 33333333, 1000000000 }; + cfg_.g_timebase = timebase; + cfg_.rc_target_bitrate = 2000; + cfg_.g_lag_in_frames = 5; + + init_flags_ = VPX_CODEC_USE_PSNR; + + libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, + timebase.den, timebase.num, 0, 30); + + // Error resilient mode ON. + cfg_.g_error_resilient = 1; + + // Set an arbitrary set of error frames same as droppable frames + unsigned int num_droppable_frames = 2; + unsigned int droppable_frame_list[] = {5, 16}; + SetDroppableFrames(num_droppable_frames, droppable_frame_list); + SetErrorFrames(num_droppable_frames, droppable_frame_list); + 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 error/droppable frames + Reset(); + + // Now set an arbitrary set of error frames that are non-droppable + unsigned int num_error_frames = 3; + unsigned int error_frame_list[] = {3, 10, 20}; + SetErrorFrames(num_error_frames, error_frame_list); + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); + // Test that dropping an arbitrary set of inter frames does not hurt too much + // Note the Average Mismatch PSNR is the average of the PSNR between + // decoded frame and encoder's version of the same frame for all frames + // with mismatch. + const double psnr_resilience_mismatch = GetAverageMismatchPsnr(); + std::cout << " Mismatch PSNR: " + << psnr_resilience_mismatch << "\n"; + EXPECT_GT(psnr_resilience_mismatch, 20.0); +} + VP8_INSTANTIATE_TEST_CASE(ErrorResilienceTest, ONE_PASS_TEST_MODES); +VP9_INSTANTIATE_TEST_CASE(ErrorResilienceTest, ONE_PASS_TEST_MODES); + } // namespace diff --git a/test/test.mk b/test/test.mk index e3667da2e..f275a47f2 100644 --- a/test/test.mk +++ b/test/test.mk @@ -15,9 +15,10 @@ LIBVPX_TEST_SRCS-$(CONFIG_VP8_ENCODER) += altref_test.cc LIBVPX_TEST_SRCS-$(CONFIG_VP8_ENCODER) += config_test.cc LIBVPX_TEST_SRCS-$(CONFIG_VP8_ENCODER) += cq_test.cc LIBVPX_TEST_SRCS-$(CONFIG_VP8_ENCODER) += datarate_test.cc + LIBVPX_TEST_SRCS-yes += encode_test_driver.cc LIBVPX_TEST_SRCS-yes += encode_test_driver.h -LIBVPX_TEST_SRCS-$(CONFIG_VP8_ENCODER) += error_resilience_test.cc +LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += error_resilience_test.cc LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += i420_video_source.h LIBVPX_TEST_SRCS-$(CONFIG_VP8_ENCODER) += keyframe_test.cc LIBVPX_TEST_SRCS-$(CONFIG_VP8_ENCODER) += resize_test.cc @@ -26,6 +27,8 @@ LIBVPX_TEST_SRCS-$(CONFIG_DECODERS) += ../md5_utils.h ../md5_utils.c LIBVPX_TEST_SRCS-yes += decode_test_driver.cc LIBVPX_TEST_SRCS-yes += decode_test_driver.h LIBVPX_TEST_SRCS-$(CONFIG_DECODERS) += ivf_video_source.h + + LIBVPX_TEST_SRCS-$(CONFIG_VP8_DECODER) += test_vector_test.cc ## ## WHITE BOX TESTS @@ -70,6 +73,7 @@ LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += fdct8x8_test.cc #LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += dct16x16_test.cc LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += variance_test.cc LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += dct32x32_test.cc + endif # VP9 @@ -79,7 +83,8 @@ endif ## ## TEST DATA ## -LIBVPX_TEST_DATA-$(CONFIG_VP8_ENCODER) += hantro_collage_w352h288.yuv +LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += hantro_collage_w352h288.yuv + LIBVPX_TEST_DATA-$(CONFIG_VP8_DECODER) += vp80-00-comprehensive-001.ivf LIBVPX_TEST_DATA-$(CONFIG_VP8_DECODER) += vp80-00-comprehensive-002.ivf LIBVPX_TEST_DATA-$(CONFIG_VP8_DECODER) += vp80-00-comprehensive-003.ivf diff --git a/test/util.h b/test/util.h index 06a70cc8e..533a1db5c 100644 --- a/test/util.h +++ b/test/util.h @@ -11,8 +11,38 @@ #ifndef TEST_UTIL_H_ #define TEST_UTIL_H_ +#include +#include +#include "third_party/googletest/src/include/gtest/gtest.h" +#include "vpx/vpx_image.h" + // Macros #define PARAMS(...) ::testing::TestWithParam< std::tr1::tuple< __VA_ARGS__ > > #define GET_PARAM(k) std::tr1::get< k >(GetParam()) +static double compute_psnr(const vpx_image_t *img1, + const vpx_image_t *img2) { + assert((img1->fmt == img2->fmt) && + (img1->d_w == img2->d_w) && + (img1->d_h == img2->d_h)); + + const unsigned int width_y = img1->d_w; + const unsigned int height_y = img1->d_h; + unsigned int i, j; + + int64_t sqrerr = 0; + for (i = 0; i < height_y; ++i) + for (j = 0; j < width_y; ++j) { + int64_t d = img1->planes[VPX_PLANE_Y][i * img1->stride[VPX_PLANE_Y] + j] - + img2->planes[VPX_PLANE_Y][i * img2->stride[VPX_PLANE_Y] + j]; + sqrerr += d * d; + } + double mse = sqrerr / (width_y * height_y); + double psnr = 100.0; + if (mse > 0.0) { + psnr = 10 * log10(255.0 * 255.0 / mse); + } + return psnr; +} + #endif // TEST_UTIL_H_ diff --git a/vp9/common/vp9_alloccommon.c b/vp9/common/vp9_alloccommon.c index f2107d7aa..2b7ab2e98 100644 --- a/vp9/common/vp9_alloccommon.c +++ b/vp9/common/vp9_alloccommon.c @@ -146,6 +146,7 @@ int vp9_alloc_frame_buffers(VP9_COMMON *oci, int width, int height) { return 0; } + void vp9_setup_version(VP9_COMMON *cm) { if (cm->version & 0x4) { if (!CONFIG_EXPERIMENTAL) diff --git a/vp9/common/vp9_entropymode.c b/vp9/common/vp9_entropymode.c index ecae5e057..30e5336a2 100644 --- a/vp9/common/vp9_entropymode.c +++ b/vp9/common/vp9_entropymode.c @@ -11,9 +11,10 @@ #include "vp9/common/vp9_onyxc_int.h" #include "vp9/common/vp9_modecont.h" +#include "vp9/common/vp9_seg_common.h" +#include "vp9/common/vp9_alloccommon.h" #include "vpx_mem/vpx_mem.h" - static const unsigned int kf_y_mode_cts[8][VP9_YMODES] = { /* DC V H D45 135 117 153 D27 D63 TM i8x8 BPRED */ {12, 6, 5, 5, 5, 5, 5, 5, 5, 2, 22, 200}, @@ -344,6 +345,9 @@ void vp9_init_mbmode_probs(VP9_COMMON *x) { #if CONFIG_COMP_INTERINTRA_PRED x->fc.interintra_prob = VP9_DEF_INTERINTRA_PROB; #endif + x->ref_pred_probs[0] = 120; + x->ref_pred_probs[1] = 80; + x->ref_pred_probs[2] = 40; } @@ -480,7 +484,7 @@ void vp9_accum_mv_refs(VP9_COMMON *pc, #define MVREF_COUNT_SAT 20 #define MVREF_MAX_UPDATE_FACTOR 128 -void vp9_update_mode_context(VP9_COMMON *pc) { +void vp9_adapt_mode_context(VP9_COMMON *pc) { int i, j; unsigned int (*mv_ref_ct)[4][2]; int (*mode_context)[4]; @@ -631,3 +635,65 @@ void vp9_adapt_mode_probs(VP9_COMMON *cm) { } #endif } + +static void set_default_lf_deltas(MACROBLOCKD *xd) { + xd->mode_ref_lf_delta_enabled = 1; + xd->mode_ref_lf_delta_update = 1; + + xd->ref_lf_deltas[INTRA_FRAME] = 2; + xd->ref_lf_deltas[LAST_FRAME] = 0; + xd->ref_lf_deltas[GOLDEN_FRAME] = -2; + xd->ref_lf_deltas[ALTREF_FRAME] = -2; + + xd->mode_lf_deltas[0] = 4; // BPRED + xd->mode_lf_deltas[1] = -2; // Zero + xd->mode_lf_deltas[2] = 2; // New mv + xd->mode_lf_deltas[3] = 4; // Split mv +} + +void vp9_setup_past_independence(VP9_COMMON *cm, MACROBLOCKD *xd) { + // Reset the segment feature data to the default stats: + // Features disabled, 0, with delta coding (Default state). + int i; + vp9_clearall_segfeatures(xd); + xd->mb_segment_abs_delta = SEGMENT_DELTADATA; + if (cm->last_frame_seg_map) + vpx_memset(cm->last_frame_seg_map, 0, (cm->mb_rows * cm->mb_cols)); + + /* reset the mode ref deltas for loop filter */ + vpx_memset(xd->last_ref_lf_deltas, 0, sizeof(xd->last_ref_lf_deltas)); + vpx_memset(xd->last_mode_lf_deltas, 0, sizeof(xd->last_mode_lf_deltas)); + set_default_lf_deltas(xd); + + vp9_default_coef_probs(cm); + vp9_init_mbmode_probs(cm); + vp9_default_bmode_probs(cm->fc.bmode_prob); + vp9_kf_default_bmode_probs(cm->kf_bmode_prob); + vp9_init_mv_probs(cm); + // To force update of the sharpness + cm->last_sharpness_level = -1; + + vp9_init_mode_contexts(cm); + + for (i = 0; i < NUM_FRAME_CONTEXTS; i++) { + vpx_memcpy(&cm->frame_contexts[i], &cm->fc, sizeof(cm->fc)); + } + + vpx_memset(cm->prev_mip, 0, + (cm->mb_cols + 1) * (cm->mb_rows + 1)* sizeof(MODE_INFO)); + vpx_memset(cm->mip, 0, + (cm->mb_cols + 1) * (cm->mb_rows + 1)* sizeof(MODE_INFO)); + + vp9_update_mode_info_border(cm, cm->mip); + vp9_update_mode_info_in_image(cm, cm->mi); + +#if CONFIG_NEW_MVREF + // Defaults probabilities for encoding the MV ref id signal + vpx_memset(xd->mb_mv_ref_probs, VP9_DEFAULT_MV_REF_PROB, + sizeof(xd->mb_mv_ref_probs)); +#endif + cm->ref_frame_sign_bias[GOLDEN_FRAME] = 0; + cm->ref_frame_sign_bias[ALTREF_FRAME] = 0; + + cm->frame_context_idx = 0; +} diff --git a/vp9/common/vp9_entropymode.h b/vp9/common/vp9_entropymode.h index e03c6fe6d..aa06e49c6 100644 --- a/vp9/common/vp9_entropymode.h +++ b/vp9/common/vp9_entropymode.h @@ -76,11 +76,14 @@ void vp9_entropy_mode_init(void); struct VP9Common; +/* sets up common features to forget past dependence */ +void vp9_setup_past_independence(struct VP9Common *cm, MACROBLOCKD *xd); + void vp9_init_mbmode_probs(struct VP9Common *x); extern void vp9_init_mode_contexts(struct VP9Common *pc); -extern void vp9_update_mode_context(struct VP9Common *pc); +extern void vp9_adapt_mode_context(struct VP9Common *pc); extern void vp9_accum_mv_refs(struct VP9Common *pc, MB_PREDICTION_MODE m, diff --git a/vp9/common/vp9_findnearmv.c b/vp9/common/vp9_findnearmv.c index 41d18dbfb..88f2ea9c1 100644 --- a/vp9/common/vp9_findnearmv.c +++ b/vp9/common/vp9_findnearmv.c @@ -141,130 +141,136 @@ void vp9_find_best_ref_mvs(MACROBLOCKD *xd, int_mv sorted_mvs[MAX_MV_REF_CANDIDATES]; int zero_seen = FALSE; - // Default all to 0,0 if nothing else available - nearest->as_int = near->as_int = 0; - vpx_memset(sorted_mvs, 0, sizeof(sorted_mvs)); + if (ref_y_buffer) { - above_src = xd->dst.y_buffer - xd->dst.y_stride * 2; - above_ref = ref_y_buffer - ref_y_stride * 2; + // Default all to 0,0 if nothing else available + nearest->as_int = near->as_int = 0; + vpx_memset(sorted_mvs, 0, sizeof(sorted_mvs)); + + above_src = xd->dst.y_buffer - xd->dst.y_stride * 2; + above_ref = ref_y_buffer - ref_y_stride * 2; #if CONFIG_ABOVESPREFMV - above_src -= 4; - above_ref -= 4; + above_src -= 4; + above_ref -= 4; #else - left_src = xd->dst.y_buffer - 2; - left_ref = ref_y_buffer - 2; + left_src = xd->dst.y_buffer - 2; + left_ref = ref_y_buffer - 2; #endif - // Limit search to the predicted best few candidates - for(i = 0; i < MAX_MV_REF_CANDIDATES; ++i) { - int_mv this_mv; - int offset = 0; - int row_offset, col_offset; + // Limit search to the predicted best few candidates + for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i) { + int_mv this_mv; + int offset = 0; + int row_offset, col_offset; - this_mv.as_int = mvlist[i].as_int; + this_mv.as_int = mvlist[i].as_int; - // If we see a 0,0 vector for a second time we have reached the end of - // the list of valid candidate vectors. - if (!this_mv.as_int && zero_seen) - break; - - zero_seen = zero_seen || !this_mv.as_int; - -#if !CONFIG_ABOVESPREFMV - clamp_mv(&this_mv, - xd->mb_to_left_edge - LEFT_TOP_MARGIN + 24, - xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN, - xd->mb_to_top_edge - LEFT_TOP_MARGIN + 24, - xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN); -#else - clamp_mv(&this_mv, - xd->mb_to_left_edge - LEFT_TOP_MARGIN + 32, - xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN, - xd->mb_to_top_edge - LEFT_TOP_MARGIN + 24, - xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN); -#endif - - row_offset = this_mv.as_mv.row >> 3; - col_offset = this_mv.as_mv.col >> 3; - offset = ref_y_stride * row_offset + col_offset; - score = 0; - if (xd->up_available) { - vp9_sub_pixel_variance16x2(above_ref + offset, ref_y_stride, - SP(this_mv.as_mv.col), - SP(this_mv.as_mv.row), - above_src, xd->dst.y_stride, &sse); - score += sse; - if (xd->mode_info_context->mbmi.sb_type >= BLOCK_SIZE_SB32X32) { - vp9_sub_pixel_variance16x2(above_ref + offset + 16, - ref_y_stride, - SP(this_mv.as_mv.col), - SP(this_mv.as_mv.row), - above_src + 16, xd->dst.y_stride, &sse); - score += sse; - } - if (xd->mode_info_context->mbmi.sb_type >= BLOCK_SIZE_SB64X64) { - vp9_sub_pixel_variance16x2(above_ref + offset + 32, - ref_y_stride, - SP(this_mv.as_mv.col), - SP(this_mv.as_mv.row), - above_src + 32, xd->dst.y_stride, &sse); - score += sse; - vp9_sub_pixel_variance16x2(above_ref + offset + 48, - ref_y_stride, - SP(this_mv.as_mv.col), - SP(this_mv.as_mv.row), - above_src + 48, xd->dst.y_stride, &sse); - score += sse; - } - } -#if !CONFIG_ABOVESPREFMV - if (xd->left_available) { - vp9_sub_pixel_variance2x16_c(left_ref + offset, ref_y_stride, - SP(this_mv.as_mv.col), - SP(this_mv.as_mv.row), - left_src, xd->dst.y_stride, &sse); - score += sse; - if (xd->mode_info_context->mbmi.sb_type >= BLOCK_SIZE_SB32X32) { - vp9_sub_pixel_variance2x16_c(left_ref + offset + ref_y_stride * 16, - ref_y_stride, - SP(this_mv.as_mv.col), - SP(this_mv.as_mv.row), - left_src + xd->dst.y_stride * 16, - xd->dst.y_stride, &sse); - score += sse; - } - if (xd->mode_info_context->mbmi.sb_type >= BLOCK_SIZE_SB64X64) { - vp9_sub_pixel_variance2x16_c(left_ref + offset + ref_y_stride * 32, - ref_y_stride, - SP(this_mv.as_mv.col), - SP(this_mv.as_mv.row), - left_src + xd->dst.y_stride * 32, - xd->dst.y_stride, &sse); - score += sse; - vp9_sub_pixel_variance2x16_c(left_ref + offset + ref_y_stride * 48, - ref_y_stride, - SP(this_mv.as_mv.col), - SP(this_mv.as_mv.row), - left_src + xd->dst.y_stride * 48, - xd->dst.y_stride, &sse); - score += sse; - } - } -#endif - // Add the entry to our list and then resort the list on score. - ref_scores[i] = score; - sorted_mvs[i].as_int = this_mv.as_int; - j = i; - while (j > 0) { - if (ref_scores[j] < ref_scores[j-1]) { - ref_scores[j] = ref_scores[j-1]; - sorted_mvs[j].as_int = sorted_mvs[j-1].as_int; - ref_scores[j-1] = score; - sorted_mvs[j-1].as_int = this_mv.as_int; - j--; - } else + // If we see a 0,0 vector for a second time we have reached the end of + // the list of valid candidate vectors. + if (!this_mv.as_int && zero_seen) break; + + zero_seen = zero_seen || !this_mv.as_int; + +#if !CONFIG_ABOVESPREFMV + clamp_mv(&this_mv, + xd->mb_to_left_edge - LEFT_TOP_MARGIN + 24, + xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN, + xd->mb_to_top_edge - LEFT_TOP_MARGIN + 24, + xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN); +#else + clamp_mv(&this_mv, + xd->mb_to_left_edge - LEFT_TOP_MARGIN + 32, + xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN, + xd->mb_to_top_edge - LEFT_TOP_MARGIN + 24, + xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN); +#endif + + row_offset = this_mv.as_mv.row >> 3; + col_offset = this_mv.as_mv.col >> 3; + offset = ref_y_stride * row_offset + col_offset; + score = 0; + if (xd->up_available) { + vp9_sub_pixel_variance16x2(above_ref + offset, ref_y_stride, + SP(this_mv.as_mv.col), + SP(this_mv.as_mv.row), + above_src, xd->dst.y_stride, &sse); + score += sse; + if (xd->mode_info_context->mbmi.sb_type >= BLOCK_SIZE_SB32X32) { + vp9_sub_pixel_variance16x2(above_ref + offset + 16, + ref_y_stride, + SP(this_mv.as_mv.col), + SP(this_mv.as_mv.row), + above_src + 16, xd->dst.y_stride, &sse); + score += sse; + } + if (xd->mode_info_context->mbmi.sb_type >= BLOCK_SIZE_SB64X64) { + vp9_sub_pixel_variance16x2(above_ref + offset + 32, + ref_y_stride, + SP(this_mv.as_mv.col), + SP(this_mv.as_mv.row), + above_src + 32, xd->dst.y_stride, &sse); + score += sse; + vp9_sub_pixel_variance16x2(above_ref + offset + 48, + ref_y_stride, + SP(this_mv.as_mv.col), + SP(this_mv.as_mv.row), + above_src + 48, xd->dst.y_stride, &sse); + score += sse; + } + } +#if !CONFIG_ABOVESPREFMV + if (xd->left_available) { + vp9_sub_pixel_variance2x16_c(left_ref + offset, ref_y_stride, + SP(this_mv.as_mv.col), + SP(this_mv.as_mv.row), + left_src, xd->dst.y_stride, &sse); + score += sse; + if (xd->mode_info_context->mbmi.sb_type >= BLOCK_SIZE_SB32X32) { + vp9_sub_pixel_variance2x16_c(left_ref + offset + ref_y_stride * 16, + ref_y_stride, + SP(this_mv.as_mv.col), + SP(this_mv.as_mv.row), + left_src + xd->dst.y_stride * 16, + xd->dst.y_stride, &sse); + score += sse; + } + if (xd->mode_info_context->mbmi.sb_type >= BLOCK_SIZE_SB64X64) { + vp9_sub_pixel_variance2x16_c(left_ref + offset + ref_y_stride * 32, + ref_y_stride, + SP(this_mv.as_mv.col), + SP(this_mv.as_mv.row), + left_src + xd->dst.y_stride * 32, + xd->dst.y_stride, &sse); + score += sse; + vp9_sub_pixel_variance2x16_c(left_ref + offset + ref_y_stride * 48, + ref_y_stride, + SP(this_mv.as_mv.col), + SP(this_mv.as_mv.row), + left_src + xd->dst.y_stride * 48, + xd->dst.y_stride, &sse); + score += sse; + } + } +#endif + // Add the entry to our list and then resort the list on score. + ref_scores[i] = score; + sorted_mvs[i].as_int = this_mv.as_int; + j = i; + while (j > 0) { + if (ref_scores[j] < ref_scores[j-1]) { + ref_scores[j] = ref_scores[j-1]; + sorted_mvs[j].as_int = sorted_mvs[j-1].as_int; + ref_scores[j-1] = score; + sorted_mvs[j-1].as_int = this_mv.as_int; + j--; + } else { + break; + } + } } + } else { + vpx_memcpy(sorted_mvs, mvlist, sizeof(sorted_mvs)); } // Make sure all the candidates are properly clamped etc diff --git a/vp9/common/vp9_findnearmv.h b/vp9/common/vp9_findnearmv.h index a66a7de27..de0648291 100644 --- a/vp9/common/vp9_findnearmv.h +++ b/vp9/common/vp9_findnearmv.h @@ -28,7 +28,8 @@ void vp9_find_best_ref_mvs(MACROBLOCKD *xd, int_mv *nearest, int_mv *near); -static void mv_bias(int refmb_ref_frame_sign_bias, int refframe, int_mv *mvp, const int *ref_frame_sign_bias) { +static void mv_bias(int refmb_ref_frame_sign_bias, int refframe, + int_mv *mvp, const int *ref_frame_sign_bias) { MV xmv; xmv = mvp->as_mv; diff --git a/vp9/common/vp9_loopfilter.c b/vp9/common/vp9_loopfilter.c index fb0505588..418210408 100644 --- a/vp9/common/vp9_loopfilter.c +++ b/vp9/common/vp9_loopfilter.c @@ -109,6 +109,9 @@ void vp9_loop_filter_frame_init(VP9_COMMON *cm, loop_filter_info_n *lfi = &cm->lf_info; /* update limits if sharpness has changed */ + // printf("vp9_loop_filter_frame_init %d\n", default_filt_lvl); + // printf("sharpness level: %d [%d]\n", + // cm->sharpness_level, cm->last_sharpness_level); if (cm->last_sharpness_level != cm->sharpness_level) { vp9_loop_filter_update_sharpness(lfi, cm->sharpness_level); cm->last_sharpness_level = cm->sharpness_level; @@ -202,6 +205,7 @@ static int sb_mb_lf_skip(const MODE_INFO *const mip0, mbmi1->mv[mbmi1->ref_frame].as_int) && mbmi0->ref_frame != INTRA_FRAME; } + void vp9_loop_filter_frame(VP9_COMMON *cm, MACROBLOCKD *xd, int frame_filter_level, @@ -271,7 +275,6 @@ void vp9_loop_filter_frame(VP9_COMMON *cm, vp9_loop_filter_bv(y_ptr, u_ptr, v_ptr, post->y_stride, post->uv_stride, &lfi); } - } /* don't apply across umv border */ if (mb_row > 0 && diff --git a/vp9/common/vp9_mvref_common.c b/vp9/common/vp9_mvref_common.c index 786b02188..8d4980f08 100644 --- a/vp9/common/vp9_mvref_common.c +++ b/vp9/common/vp9_mvref_common.c @@ -259,12 +259,14 @@ void vp9_find_mv_refs( split_count += (candidate_mi->mbmi.mode == SPLITMV); } } - // Look in the last frame - candidate_mi = lf_here; - if (get_matching_candidate(candidate_mi, ref_frame, &c_refmv)) { - clamp_mv(xd, &c_refmv); - addmv_and_shuffle(candidate_mvs, candidate_scores, - &index, c_refmv, 18); + // Look in the last frame if it exists + if (lf_here) { + candidate_mi = lf_here; + if (get_matching_candidate(candidate_mi, ref_frame, &c_refmv)) { + clamp_mv(xd, &c_refmv); + addmv_and_shuffle(candidate_mvs, candidate_scores, + &index, c_refmv, 18); + } } // More distant neigbours for (i = 2; (i < MVREF_NEIGHBOURS) && @@ -316,8 +318,8 @@ void vp9_find_mv_refs( } } } - // Look at the last frame - if (index < (MAX_MV_REF_CANDIDATES - 1)) { + // Look at the last frame if it exists + if (index < (MAX_MV_REF_CANDIDATES - 1) && lf_here) { candidate_mi = lf_here; get_non_matching_candidates(candidate_mi, ref_frame, &c_ref_frame, &c_refmv, @@ -366,7 +368,7 @@ void vp9_find_mv_refs( // 0,0 is always a valid reference. for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i) { - if (candidate_mvs[i].as_int == 0) + if (candidate_mvs[i].as_int == 0) break; } if (i == MAX_MV_REF_CANDIDATES) { diff --git a/vp9/common/vp9_onyx.h b/vp9/common/vp9_onyx.h index e4ad72f21..46ae2f0f4 100644 --- a/vp9/common/vp9_onyx.h +++ b/vp9/common/vp9_onyx.h @@ -159,6 +159,12 @@ extern "C" int encode_breakout; // early breakout encode threshold : for video conf recommend 800 + /* Bitfield defining the error resiliency features to enable. + * Can provide decodable frames after losses in previous + * frames and decodable partitions after losses in the same frame. + */ + unsigned int error_resilient_mode; + int arnr_max_frames; int arnr_strength; int arnr_type; diff --git a/vp9/common/vp9_onyxc_int.h b/vp9/common/vp9_onyxc_int.h index 0f40e9faa..4e2fa3799 100644 --- a/vp9/common/vp9_onyxc_int.h +++ b/vp9/common/vp9_onyxc_int.h @@ -276,6 +276,7 @@ typedef struct VP9Common { int use_interintra; #endif + int error_resilient_mode; } VP9_COMMON; static int get_free_fb(VP9_COMMON *cm) { diff --git a/vp9/decoder/vp9_decodemv.c b/vp9/decoder/vp9_decodemv.c index eef9e6e60..31ae257dc 100644 --- a/vp9/decoder/vp9_decodemv.c +++ b/vp9/decoder/vp9_decodemv.c @@ -293,7 +293,10 @@ static void read_nmv_fp(vp9_reader *r, MV *mv, const MV *ref, mv->col = read_nmv_component_fp(r, mv->col, ref->col, &mvctx->comps[1], usehp); } - //printf(" %d: %d %d ref: %d %d\n", usehp, mv->row, mv-> col, ref->row, ref->col); + /* + printf("MV: %d %d REF: %d %d\n", mv->row + ref->row, mv->col + ref->col, + ref->row, ref->col); + */ } static void update_nmv(vp9_reader *bc, vp9_prob *const p, @@ -716,6 +719,11 @@ static void read_mb_modes_mv(VP9D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi, else mbmi->ref_frame = read_ref_frame(pbi, bc, mbmi->segment_id); + /* + if (pbi->common.current_video_frame == 1) + printf("ref frame: %d [%d %d]\n", mbmi->ref_frame, mb_row, mb_col); + */ + // If reference frame is an Inter frame if (mbmi->ref_frame) { int_mv nearest, nearby, best_mv; @@ -747,12 +755,25 @@ static void read_mb_modes_mv(VP9D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi, printf("%d %d\n", xd->mode_info_context->mbmi.mv[0].as_mv.row, xd->mode_info_context->mbmi.mv[0].as_mv.col); #endif - vp9_find_mv_refs(xd, mi, prev_mi, + // if (cm->current_video_frame == 1 && mb_row == 4 && mb_col == 5) + // printf("Dello\n"); + vp9_find_mv_refs(xd, mi, cm->error_resilient_mode ? 0 : prev_mi, ref_frame, mbmi->ref_mvs[ref_frame], cm->ref_frame_sign_bias); vp9_mv_ref_probs(&pbi->common, mv_ref_p, mbmi->mb_mode_context[ref_frame]); + /* + if (pbi->common.current_video_frame == 1) { + int k = mbmi->mb_mode_context[ref_frame]; + printf("vp9_mode_contexts: [%d %d %d %d] %d %d %d %d\n", + mb_row, mb_col, ref_frame, k, + cm->fc.vp9_mode_contexts[k][0], + cm->fc.vp9_mode_contexts[k][1], + cm->fc.vp9_mode_contexts[k][2], + cm->fc.vp9_mode_contexts[k][3]); + } + */ // Is the segment level mode feature enabled for this segment if (vp9_segfeature_active(xd, mbmi->segment_id, SEG_LVL_MODE)) { @@ -770,7 +791,8 @@ static void read_mb_modes_mv(VP9D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi, if (mbmi->mode != ZEROMV) { vp9_find_best_ref_mvs(xd, - xd->pre.y_buffer, + pbi->common.error_resilient_mode ? + 0 : xd->pre.y_buffer, recon_y_stride, mbmi->ref_mvs[ref_frame], &nearest, &nearby); @@ -822,14 +844,15 @@ static void read_mb_modes_mv(VP9D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi, xd->second_pre.v_buffer = cm->yv12_fb[second_ref_fb_idx].v_buffer + recon_uvoffset; - vp9_find_mv_refs(xd, mi, prev_mi, + vp9_find_mv_refs(xd, mi, cm->error_resilient_mode ? 0 : prev_mi, mbmi->second_ref_frame, mbmi->ref_mvs[mbmi->second_ref_frame], cm->ref_frame_sign_bias); if (mbmi->mode != ZEROMV) { vp9_find_best_ref_mvs(xd, - xd->second_pre.y_buffer, + pbi->common.error_resilient_mode ? + 0 : xd->second_pre.y_buffer, recon_y_stride, mbmi->ref_mvs[mbmi->second_ref_frame], &nearest_second, @@ -1136,6 +1159,10 @@ static void read_mb_modes_mv(VP9D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi, pbi->common.fc.uv_mode_counts[mbmi->mode][mbmi->uv_mode]++; } } + /* + if (pbi->common.current_video_frame == 1) + printf("mode: %d skip: %d\n", mbmi->mode, mbmi->mb_skip_coeff); + */ if (cm->txfm_mode == TX_MODE_SELECT && mbmi->mb_skip_coeff == 0 && ((mbmi->ref_frame == INTRA_FRAME && mbmi->mode <= I8X8_PRED) || @@ -1177,6 +1204,7 @@ void vp9_decode_mode_mvs_init(VP9D_COMP* const pbi, BOOL_DECODER* const bc) { mb_mode_mv_init(pbi, bc); } + void vp9_decode_mb_mode_mv(VP9D_COMP* const pbi, MACROBLOCKD* const xd, int mb_row, diff --git a/vp9/decoder/vp9_decodframe.c b/vp9/decoder/vp9_decodframe.c index 18e09e4c4..10bcbf953 100644 --- a/vp9/decoder/vp9_decodframe.c +++ b/vp9/decoder/vp9_decodframe.c @@ -32,7 +32,6 @@ #include "vp9/decoder/vp9_dboolhuff.h" #include "vp9/common/vp9_seg_common.h" -#include "vp9/common/vp9_entropy.h" #include "vp9_rtcd.h" #include @@ -1255,54 +1254,14 @@ static void init_frame(VP9D_COMP *pbi) { MACROBLOCKD *const xd = &pbi->mb; if (pc->frame_type == KEY_FRAME) { - int i; - - if (pc->last_frame_seg_map) - vpx_memset(pc->last_frame_seg_map, 0, (pc->mb_rows * pc->mb_cols)); - - vp9_init_mv_probs(pc); - - vp9_init_mbmode_probs(pc); - vp9_default_bmode_probs(pc->fc.bmode_prob); - - vp9_default_coef_probs(pc); - vp9_kf_default_bmode_probs(pc->kf_bmode_prob); - - // Reset the segment feature data to the default stats: - // Features disabled, 0, with delta coding (Default state). - vp9_clearall_segfeatures(xd); - - xd->mb_segment_abs_delta = SEGMENT_DELTADATA; - - /* reset the mode ref deltasa for loop filter */ - vpx_memset(xd->ref_lf_deltas, 0, sizeof(xd->ref_lf_deltas)); - vpx_memset(xd->mode_lf_deltas, 0, sizeof(xd->mode_lf_deltas)); - + vp9_setup_past_independence(pc, xd); /* All buffers are implicitly updated on key frames. */ pbi->refresh_frame_flags = (1 << NUM_REF_FRAMES) - 1; + } else if (pc->error_resilient_mode) { + vp9_setup_past_independence(pc, xd); + } - /* Note that Golden and Altref modes cannot be used on a key frame so - * ref_frame_sign_bias[] is undefined and meaningless - */ - pc->ref_frame_sign_bias[GOLDEN_FRAME] = 0; - pc->ref_frame_sign_bias[ALTREF_FRAME] = 0; - - vp9_init_mode_contexts(&pbi->common); - - for (i = 0; i < NUM_FRAME_CONTEXTS; i++) - vpx_memcpy(&pc->frame_contexts[i], &pc->fc, sizeof(pc->fc)); - - vpx_memset(pc->prev_mip, 0, - (pc->mb_cols + 1) * (pc->mb_rows + 1)* sizeof(MODE_INFO)); - vpx_memset(pc->mip, 0, - (pc->mb_cols + 1) * (pc->mb_rows + 1)* sizeof(MODE_INFO)); - - vp9_update_mode_info_border(pc, pc->mip); - vp9_update_mode_info_in_image(pc, pc->mi); - - - } else { - + if (pc->frame_type != KEY_FRAME) { if (!pc->use_bilinear_mc_filter) pc->mcomp_filter_type = EIGHTTAP; else @@ -1322,7 +1281,6 @@ static void init_frame(VP9D_COMP *pbi) { xd->fullpixel_mask = 0xffffffff; if (pc->full_pixel) xd->fullpixel_mask = 0xfffffff8; - } static void read_coef_probs_common(BOOL_DECODER* const bc, @@ -1383,6 +1341,7 @@ int vp9_decode_frame(VP9D_COMP *pbi, const unsigned char **p_data_end) { int i, j; int corrupt_tokens = 0; + // printf("Decoding frame %d\n", pc->current_video_frame); /* start with no corruption of current frame */ xd->corrupted = 0; pc->yv12_fb[pc->new_fb_idx].corrupted = 0; @@ -1452,9 +1411,6 @@ int vp9_decode_frame(VP9D_COMP *pbi, const unsigned char **p_data_end) { } } } -#ifdef DEC_DEBUG - printf("Decode frame %d\n", pc->current_video_frame); -#endif if ((!pbi->decoded_key_frame && pc->frame_type != KEY_FRAME) || pc->Width == 0 || pc->Height == 0) { @@ -1472,6 +1428,7 @@ int vp9_decode_frame(VP9D_COMP *pbi, const unsigned char **p_data_end) { pc->clamp_type = (CLAMP_TYPE)vp9_read_bit(&header_bc); } + pc->error_resilient_mode = vp9_read_bit(&header_bc); /* Is segmentation enabled */ xd->segmentation_enabled = (unsigned char)vp9_read_bit(&header_bc); @@ -1687,11 +1644,7 @@ int vp9_decode_frame(VP9D_COMP *pbi, const unsigned char **p_data_end) { #if CONFIG_NEW_MVREF // If Key frame reset mv ref id probabilities to defaults - if (pc->frame_type == KEY_FRAME) { - // Defaults probabilities for encoding the MV ref id signal - vpx_memset(xd->mb_mv_ref_probs, VP9_DEFAULT_MV_REF_PROB, - sizeof(xd->mb_mv_ref_probs)); - } else { + if (pc->frame_type != KEY_FRAME) { // Read any mv_ref index probability updates int i, j; @@ -1818,11 +1771,14 @@ int vp9_decode_frame(VP9D_COMP *pbi, const unsigned char **p_data_end) { "A stream must start with a complete key frame"); } - vp9_adapt_coef_probs(pc); + if (!pc->error_resilient_mode) + vp9_adapt_coef_probs(pc); if (pc->frame_type != KEY_FRAME) { - vp9_adapt_mode_probs(pc); - vp9_adapt_nmv_probs(pc, xd->allow_high_precision_mv); - vp9_update_mode_context(&pbi->common); + if (!pc->error_resilient_mode) { + vp9_adapt_mode_probs(pc); + vp9_adapt_nmv_probs(pc, xd->allow_high_precision_mv); + vp9_adapt_mode_context(&pbi->common); + } } if (pc->refresh_entropy_probs) { @@ -1839,7 +1795,6 @@ int vp9_decode_frame(VP9D_COMP *pbi, const unsigned char **p_data_end) { fclose(f); } #endif - // printf("Frame %d Done\n", frame_count++); /* Find the end of the coded buffer */ while (residual_bc.count > CHAR_BIT diff --git a/vp9/encoder/vp9_bitstream.c b/vp9/encoder/vp9_bitstream.c index 1a9d33dae..34d27d1be 100644 --- a/vp9/encoder/vp9_bitstream.c +++ b/vp9/encoder/vp9_bitstream.c @@ -189,15 +189,7 @@ static void update_refpred_stats(VP9_COMP *cpi) { int old_cost, new_cost; // Set the prediction probability structures to defaults - if (cm->frame_type == KEY_FRAME) { - // Set the prediction probabilities to defaults - cm->ref_pred_probs[0] = 120; - cm->ref_pred_probs[1] = 80; - cm->ref_pred_probs[2] = 40; - - vpx_memset(cpi->ref_pred_probs_update, 0, - sizeof(cpi->ref_pred_probs_update)); - } else { + if (cm->frame_type != KEY_FRAME) { // From the prediction counts set the probabilities for each context for (i = 0; i < PREDICTION_PROBS; i++) { new_pred_probs[i] = get_binary_prob(cpi->ref_pred_count[i][0], @@ -219,7 +211,6 @@ static void update_refpred_stats(VP9_COMP *cpi) { cm->ref_pred_probs[i] = new_pred_probs[i]; } else cpi->ref_pred_probs_update[i] = 0; - } } } @@ -508,7 +499,8 @@ static void write_sub_mv_ref vp9_sub_mv_ref_encoding_array - LEFT4X4 + m); } -static void write_nmv(vp9_writer *bc, const MV *mv, const int_mv *ref, +static void write_nmv(VP9_COMP *cpi, vp9_writer *bc, + const MV *mv, const int_mv *ref, const nmv_context *nmvc, int usehp) { MV e; e.row = mv->row - ref->as_mv.row; @@ -801,7 +793,6 @@ static void pack_inter_mode_mvs(VP9_COMP *cpi, MODE_INFO *m, vp9_mv_ref_probs(&cpi->common, mv_ref_p, mi->mb_mode_context[rf]); - // #ifdef ENTROPY_STATS #ifdef ENTROPY_STATS accum_mv_refs(mode, ct); active_section = 3; @@ -878,12 +869,12 @@ static void pack_inter_mode_mvs(VP9_COMP *cpi, MODE_INFO *m, #ifdef ENTROPY_STATS active_section = 5; #endif - write_nmv(bc, &mi->mv[0].as_mv, &mi->best_mv, + write_nmv(cpi, bc, &mi->mv[0].as_mv, &mi->best_mv, (const nmv_context*) nmvc, xd->allow_high_precision_mv); if (mi->second_ref_frame > 0) { - write_nmv(bc, &mi->mv[1].as_mv, &mi->best_second_mv, + write_nmv(cpi, bc, &mi->mv[1].as_mv, &mi->best_second_mv, (const nmv_context*) nmvc, xd->allow_high_precision_mv); } @@ -926,12 +917,12 @@ static void pack_inter_mode_mvs(VP9_COMP *cpi, MODE_INFO *m, #ifdef ENTROPY_STATS active_section = 11; #endif - write_nmv(bc, &blockmv.as_mv, &mi->best_mv, + write_nmv(cpi, bc, &blockmv.as_mv, &mi->best_mv, (const nmv_context*) nmvc, xd->allow_high_precision_mv); if (mi->second_ref_frame > 0) { - write_nmv(bc, + write_nmv(cpi, bc, &cpi->mb.partition_info->bmi[j].second_mv.as_mv, &mi->best_second_mv, (const nmv_context*) nmvc, @@ -1551,6 +1542,9 @@ void vp9_pack_bitstream(VP9_COMP *cpi, unsigned char *dest, vp9_start_encode(&header_bc, cx_data); } + // error resilient mode + vp9_write_bit(&header_bc, pc->error_resilient_mode); + // Signal whether or not Segmentation is enabled vp9_write_bit(&header_bc, (xd->segmentation_enabled) ? 1 : 0); @@ -1967,7 +1961,7 @@ void vp9_pack_bitstream(VP9_COMP *cpi, unsigned char *dest, if (pc->mcomp_filter_type == SWITCHABLE) update_switchable_interp_probs(cpi, &header_bc); - #if CONFIG_COMP_INTERINTRA_PRED +#if CONFIG_COMP_INTERINTRA_PRED if (pc->use_interintra) { vp9_cond_prob_update(&header_bc, &pc->fc.interintra_prob, @@ -2030,7 +2024,8 @@ void vp9_pack_bitstream(VP9_COMP *cpi, unsigned char *dest, // if (!cpi->dummy_packing) vp9_zero(cpi->NMVcount); write_modes(cpi, &residual_bc); - vp9_update_mode_context(&cpi->common); + if (!cpi->common.error_resilient_mode) + vp9_adapt_mode_context(&cpi->common); } vp9_stop_encode(&residual_bc); diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index 0d33edc06..8a4b7e662 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -646,6 +646,10 @@ static void set_offsets(VP9_COMP *cpi, const int idx_map = mb_row * cm->mb_cols + mb_col; const int idx_str = xd->mode_info_stride * mb_row + mb_col; +#ifdef ENC_DEBUG + enc_debug = (cpi->common.current_video_frame == 2 && + mb_row == 4 && mb_col == 5); +#endif // entropy context structures xd->above_context = cm->above_context + mb_col; xd->left_context = cm->left_context + (mb_row & 3); @@ -2007,8 +2011,8 @@ static void encode_macroblock(VP9_COMP *cpi, TOKENEXTRA **t, assert(!xd->mode_info_context->mbmi.sb_type); #ifdef ENC_DEBUG - enc_debug = (cpi->common.current_video_frame == 46 && - mb_row == 5 && mb_col == 2); + enc_debug = (cpi->common.current_video_frame == 2 && + mb_row == 5 && mb_col == 18); if (enc_debug) printf("Encode MB %d %d output %d\n", mb_row, mb_col, output_enabled); #endif @@ -2150,7 +2154,7 @@ static void encode_macroblock(VP9_COMP *cpi, TOKENEXTRA **t, } if (!x->skip) { -#ifdef ENC_DEBUG +#if 0 // def ENC_DEBUG if (enc_debug) { int i, j; printf("\n"); diff --git a/vp9/encoder/vp9_onyx_if.c b/vp9/encoder/vp9_onyx_if.c index c288f93ef..a14165752 100644 --- a/vp9/encoder/vp9_onyx_if.c +++ b/vp9/encoder/vp9_onyx_if.c @@ -1355,7 +1355,6 @@ void vp9_change_config(VP9_PTR ptr, VP9_CONFIG *oxcf) { if (cpi->oxcf.cpu_used > 5) cpi->oxcf.cpu_used = 5; - break; case MODE_SECONDPASS_BEST: @@ -2823,6 +2822,8 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, for (i = 0; i < MAX_MODES; i++) { cpi->rd_thresh_mult[i] = 128; } + + cm->error_resilient_mode = (cpi->oxcf.error_resilient_mode != 0); } // Test code for new segment features @@ -3100,10 +3101,21 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, } // Set up entropy depending on frame type. - if (cm->frame_type == KEY_FRAME) + if (cm->frame_type == KEY_FRAME) { + /* Choose which entropy context to use. When using a forward reference + * frame, it immediately follows the keyframe, and thus benefits from + * using the same entropy context established by the keyframe. Otherwise, + * use the default context 0. + */ + cm->frame_context_idx = cpi->oxcf.play_alternate; vp9_setup_key_frame(cpi); - else + } else { + /* Choose which entropy context to use. Currently there are only two + * contexts used, one for normal frames and one for alt ref frames. + */ + cpi->common.frame_context_idx = cpi->refresh_alt_ref_frame; vp9_setup_inter_frame(cpi); + } } // transform / motion compensation build reconstruction frame @@ -3437,7 +3449,8 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, vp9_copy(cpi->common.fc.hybrid_coef_counts_16x16, cpi->hybrid_coef_counts_16x16); vp9_copy(cpi->common.fc.coef_counts_32x32, cpi->coef_counts_32x32); - vp9_adapt_coef_probs(&cpi->common); + if (!cpi->common.error_resilient_mode) + vp9_adapt_coef_probs(&cpi->common); if (cpi->common.frame_type != KEY_FRAME) { vp9_copy(cpi->common.fc.sb_ymode_counts, cpi->sb_ymode_count); vp9_copy(cpi->common.fc.ymode_counts, cpi->ymode_count); @@ -3449,14 +3462,12 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, #if CONFIG_COMP_INTERINTRA_PRED vp9_copy(cpi->common.fc.interintra_counts, cpi->interintra_count); #endif - vp9_adapt_mode_probs(&cpi->common); + if (!cpi->common.error_resilient_mode) + vp9_adapt_mode_probs(&cpi->common); cpi->common.fc.NMVcount = cpi->NMVcount; - /* - printf("2: %d %d %d %d\n", cpi->NMVcount.joints[0], cpi->NMVcount.joints[1], - cpi->NMVcount.joints[2], cpi->NMVcount.joints[3]); - */ - vp9_adapt_nmv_probs(&cpi->common, cpi->mb.e_mbd.allow_high_precision_mv); + if (!cpi->common.error_resilient_mode) + vp9_adapt_nmv_probs(&cpi->common, cpi->mb.e_mbd.allow_high_precision_mv); } #if CONFIG_COMP_INTERINTRA_PRED if (cm->frame_type != KEY_FRAME) diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c index be87326a0..bb608ab37 100644 --- a/vp9/encoder/vp9_ratectrl.c +++ b/vp9/encoder/vp9_ratectrl.c @@ -25,6 +25,7 @@ #include "vp9/common/vp9_systemdependent.h" #include "vp9/encoder/vp9_encodemv.h" #include "vp9/common/vp9_quant_common.h" +#include "vp9/common/vp9_seg_common.h" #define MIN_BPB_FACTOR 0.005 #define MAX_BPB_FACTOR 50 @@ -238,76 +239,30 @@ void vp9_restore_coding_context(VP9_COMP *cpi) { #endif } - void vp9_setup_key_frame(VP9_COMP *cpi) { VP9_COMMON *cm = &cpi->common; - int i; + MACROBLOCKD *xd = &cpi->mb.e_mbd; - // Setup for Key frame: - vp9_default_coef_probs(& cpi->common); - vp9_kf_default_bmode_probs(cpi->common.kf_bmode_prob); - vp9_init_mbmode_probs(& cpi->common); - vp9_default_bmode_probs(cm->fc.bmode_prob); - - if(cm->last_frame_seg_map) - vpx_memset(cm->last_frame_seg_map, 0, (cm->mb_rows * cm->mb_cols)); - - vp9_init_mv_probs(& cpi->common); - - // cpi->common.filter_level = 0; // Reset every key frame. - cpi->common.filter_level = cpi->common.base_qindex * 3 / 8; + vp9_setup_past_independence(cm, xd); // interval before next GF cpi->frames_till_gf_update_due = cpi->baseline_gf_interval; - + /* All buffers are implicitly updated on key frames. */ cpi->refresh_golden_frame = TRUE; cpi->refresh_alt_ref_frame = TRUE; - - vp9_init_mode_contexts(&cpi->common); - - for (i = 0; i < NUM_FRAME_CONTEXTS; i++) - vpx_memcpy(&cpi->common.frame_contexts[i], &cpi->common.fc, - sizeof(cpi->common.fc)); - - vpx_memset(cm->prev_mip, 0, - (cm->mb_cols + 1) * (cm->mb_rows + 1)* sizeof(MODE_INFO)); - vpx_memset(cm->mip, 0, - (cm->mb_cols + 1) * (cm->mb_rows + 1)* sizeof(MODE_INFO)); - - vp9_update_mode_info_border(cm, cm->mip); - vp9_update_mode_info_in_image(cm, cm->mi); - -#if CONFIG_NEW_MVREF - if (1) { - MACROBLOCKD *xd = &cpi->mb.e_mbd; - - // Defaults probabilities for encoding the MV ref id signal - vpx_memset(xd->mb_mv_ref_probs, VP9_DEFAULT_MV_REF_PROB, - sizeof(xd->mb_mv_ref_probs)); - } -#endif - - /* Choose which entropy context to use. When using a forward reference - * frame, it immediately follows the keyframe, and thus benefits from - * using the same entropy context established by the keyframe. Otherwise, - * use the default context 0. - */ - cm->frame_context_idx = cpi->oxcf.play_alternate; } void vp9_setup_inter_frame(VP9_COMP *cpi) { - /* Choose which entropy context to use. Currently there are only two - * contexts used, one for normal frames and one for alt ref frames. - */ - cpi->common.frame_context_idx = cpi->refresh_alt_ref_frame; - - assert(cpi->common.frame_context_idx < NUM_FRAME_CONTEXTS); - vpx_memcpy(&cpi->common.fc, - &cpi->common.frame_contexts[cpi->common.frame_context_idx], - sizeof(cpi->common.fc)); + VP9_COMMON *cm = &cpi->common; + MACROBLOCKD *xd = &cpi->mb.e_mbd; + if (cm->error_resilient_mode) { + vp9_setup_past_independence(cm, xd); + } + assert(cm->frame_context_idx < NUM_FRAME_CONTEXTS); + vpx_memcpy(&cm->fc, &cm->frame_contexts[cm->frame_context_idx], + sizeof(cm->fc)); } - static int estimate_bits_at_q(int frame_kind, int Q, int MBs, double correction_factor) { int Bpm = (int)(.5 + correction_factor * vp9_bits_per_mb(frame_kind, Q)); diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c index 5252bfd41..f860e94ca 100644 --- a/vp9/encoder/vp9_rdopt.c +++ b/vp9/encoder/vp9_rdopt.c @@ -3177,19 +3177,21 @@ static void setup_buffer_inter(VP9_COMP *cpi, MACROBLOCK *x, // Gets an initial list of candidate vectors from neighbours and orders them vp9_find_mv_refs(xd, xd->mode_info_context, - xd->prev_mode_info_context, + cpi->common.error_resilient_mode ? + 0 : xd->prev_mode_info_context, frame_type, mbmi->ref_mvs[frame_type], cpi->common.ref_frame_sign_bias); // Candidate refinement carried out at encoder and decoder - vp9_find_best_ref_mvs(xd, y_buffer[frame_type], + vp9_find_best_ref_mvs(xd, + cpi->common.error_resilient_mode ? + 0 : y_buffer[frame_type], yv12->y_stride, mbmi->ref_mvs[frame_type], &frame_nearest_mv[frame_type], &frame_near_mv[frame_type]); - // Further refinement that is encode side only to test the top few candidates // in full and choose the best as the centre point for subsequent searches. mv_pred(cpi, x, y_buffer[frame_type], yv12->y_stride, diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c index 1ef5ff19e..0c82d067c 100644 --- a/vp9/vp9_cx_iface.c +++ b/vp9/vp9_cx_iface.c @@ -313,33 +313,35 @@ static vpx_codec_err_t set_vp8e_config(VP9_CONFIG *oxcf, oxcf->lossless = vp8_cfg.lossless; #endif + oxcf->error_resilient_mode = cfg.g_error_resilient; /* - printf("Current VP8 Settings: \n"); - printf("target_bandwidth: %d\n", oxcf->target_bandwidth); - printf("noise_sensitivity: %d\n", oxcf->noise_sensitivity); - printf("Sharpness: %d\n", oxcf->Sharpness); - printf("cpu_used: %d\n", oxcf->cpu_used); - printf("Mode: %d\n", oxcf->Mode); - printf("delete_first_pass_file: %d\n", oxcf->delete_first_pass_file); - printf("auto_key: %d\n", oxcf->auto_key); - printf("key_freq: %d\n", oxcf->key_freq); - printf("end_usage: %d\n", oxcf->end_usage); - printf("under_shoot_pct: %d\n", oxcf->under_shoot_pct); - printf("over_shoot_pct: %d\n", oxcf->over_shoot_pct); - printf("starting_buffer_level: %d\n", oxcf->starting_buffer_level); - printf("optimal_buffer_level: %d\n", oxcf->optimal_buffer_level); - printf("maximum_buffer_size: %d\n", oxcf->maximum_buffer_size); - printf("fixed_q: %d\n", oxcf->fixed_q); - printf("worst_allowed_q: %d\n", oxcf->worst_allowed_q); - printf("best_allowed_q: %d\n", oxcf->best_allowed_q); - printf("two_pass_vbrbias: %d\n", oxcf->two_pass_vbrbias); - printf("two_pass_vbrmin_section: %d\n", oxcf->two_pass_vbrmin_section); - printf("two_pass_vbrmax_section: %d\n", oxcf->two_pass_vbrmax_section); - printf("allow_lag: %d\n", oxcf->allow_lag); - printf("lag_in_frames: %d\n", oxcf->lag_in_frames); - printf("play_alternate: %d\n", oxcf->play_alternate); - printf("Version: %d\n", oxcf->Version); - printf("encode_breakout: %d\n", oxcf->encode_breakout); + printf("Current VP9 Settings: \n"); + printf("target_bandwidth: %d\n", oxcf->target_bandwidth); + printf("noise_sensitivity: %d\n", oxcf->noise_sensitivity); + printf("Sharpness: %d\n", oxcf->Sharpness); + printf("cpu_used: %d\n", oxcf->cpu_used); + printf("Mode: %d\n", oxcf->Mode); + // printf("delete_first_pass_file: %d\n", oxcf->delete_first_pass_file); + printf("auto_key: %d\n", oxcf->auto_key); + printf("key_freq: %d\n", oxcf->key_freq); + printf("end_usage: %d\n", oxcf->end_usage); + printf("under_shoot_pct: %d\n", oxcf->under_shoot_pct); + printf("over_shoot_pct: %d\n", oxcf->over_shoot_pct); + printf("starting_buffer_level: %d\n", oxcf->starting_buffer_level); + printf("optimal_buffer_level: %d\n", oxcf->optimal_buffer_level); + printf("maximum_buffer_size: %d\n", oxcf->maximum_buffer_size); + printf("fixed_q: %d\n", oxcf->fixed_q); + printf("worst_allowed_q: %d\n", oxcf->worst_allowed_q); + printf("best_allowed_q: %d\n", oxcf->best_allowed_q); + printf("two_pass_vbrbias: %d\n", oxcf->two_pass_vbrbias); + printf("two_pass_vbrmin_section: %d\n", oxcf->two_pass_vbrmin_section); + printf("two_pass_vbrmax_section: %d\n", oxcf->two_pass_vbrmax_section); + printf("allow_lag: %d\n", oxcf->allow_lag); + printf("lag_in_frames: %d\n", oxcf->lag_in_frames); + printf("play_alternate: %d\n", oxcf->play_alternate); + printf("Version: %d\n", oxcf->Version); + printf("encode_breakout: %d\n", oxcf->encode_breakout); + printf("error resilient: %d\n", oxcf->error_resilient_mode); */ return VPX_CODEC_OK; } diff --git a/vp9/vp9_dx_iface.c b/vp9/vp9_dx_iface.c index 05d4edbe8..293df2ea2 100644 --- a/vp9/vp9_dx_iface.c +++ b/vp9/vp9_dx_iface.c @@ -431,7 +431,7 @@ static vpx_codec_err_t vp9_decode(vpx_codec_alg_priv_t *ctx, long deadline) { const uint8_t *data_start = data; const uint8_t *data_end = data + data_sz; - vpx_codec_err_t res; + vpx_codec_err_t res = 0; do { res = decode_one(ctx, &data_start, data_sz, user_priv, deadline); diff --git a/vpxenc.c b/vpxenc.c index 3fc8da1fe..7b784f324 100644 --- a/vpxenc.c +++ b/vpxenc.c @@ -1449,14 +1449,16 @@ static void show_rate_histogram(struct rate_hist *hist, #define mmin(a, b) ((a) < (b) ? (a) : (b)) static void find_mismatch(vpx_image_t *img1, vpx_image_t *img2, int yloc[2], int uloc[2], int vloc[2]) { + static const int bsize = 64; + static const int bsize2 = bsize >> 1; int match = 1; int i, j; yloc[0] = yloc[1] = -1; - for (i = 0, match = 1; match && i < img1->d_h; i+=32) { - for (j = 0; match && j < img1->d_w; j+=32) { + for (i = 0, match = 1; match && i < img1->d_h; i += bsize) { + for (j = 0; match && j < img1->d_w; j += bsize) { int k, l; - int si = mmin(i + 32, img1->d_h) - i; - int sj = mmin(j + 32, img1->d_w) - j; + int si = mmin(i + bsize, img1->d_h) - i; + int sj = mmin(j + bsize, img1->d_w) - j; for (k = 0; match && k < si; k++) for (l = 0; match && l < sj; l++) { if (*(img1->planes[VPX_PLANE_Y] + @@ -1472,11 +1474,11 @@ static void find_mismatch(vpx_image_t *img1, vpx_image_t *img2, } } uloc[0] = uloc[1] = -1; - for (i = 0, match = 1; match && i < (img1->d_h + 1) / 2; i+=16) { - for (j = 0; j < match && (img1->d_w + 1) / 2; j+=16) { + for (i = 0, match = 1; match && i < (img1->d_h + 1) / 2; i += bsize2) { + for (j = 0; j < match && (img1->d_w + 1) / 2; j += bsize2) { int k, l; - int si = mmin(i + 16, (img1->d_h + 1) / 2) - i; - int sj = mmin(j + 16, (img1->d_w + 1) / 2) - j; + int si = mmin(i + bsize2, (img1->d_h + 1) / 2) - i; + int sj = mmin(j + bsize2, (img1->d_w + 1) / 2) - j; for (k = 0; match && k < si; k++) for (l = 0; match && l < sj; l++) { if (*(img1->planes[VPX_PLANE_U] + @@ -1492,11 +1494,11 @@ static void find_mismatch(vpx_image_t *img1, vpx_image_t *img2, } } vloc[0] = vloc[1] = -1; - for (i = 0, match = 1; match && i < (img1->d_h + 1) / 2; i+=16) { - for (j = 0; j < match && (img1->d_w + 1) / 2; j+=16) { + for (i = 0, match = 1; match && i < (img1->d_h + 1) / 2; i += bsize2) { + for (j = 0; j < match && (img1->d_w + 1) / 2; j += bsize2) { int k, l; - int si = mmin(i + 16, (img1->d_h + 1) / 2) - i; - int sj = mmin(j + 16, (img1->d_w + 1) / 2) - j; + int si = mmin(i + bsize2, (img1->d_h + 1) / 2) - i; + int sj = mmin(j + bsize2, (img1->d_w + 1) / 2) - j; for (k = 0; match && k < si; k++) for (l = 0; match && l < sj; l++) { if (*(img1->planes[VPX_PLANE_V] +