From 01cafaab1d99018c48c54178987101b490343a01 Mon Sep 17 00:00:00 2001 From: Deb Mukherjee Date: Tue, 15 Jan 2013 06:43:35 -0800 Subject: [PATCH] Adds an error-resilient mode with test Adds an error-resilient mode where frames can be continued to be decoded even when there are errors (due to network losses) on a prior frame. Specifically, backward updates are turned off and probabilities of various symbols are reset to defaults at the beginning of each frame. Further, the last frame's mvs are not used for the mv reference list, and the sorting of the initial list based on search on previous frames is turned off as well. Also adds a test where an arbitrary set of frames are skipped from decoding to simulate errors. The test verifies (1) that if the error frames are droppable - i.e. frame buffer updates have been turned off - there are no mismatch errors for the remaining frames after the error frames; and (2) if the error-frames are non droppable, there are not only no decoding errors but the mismatch PSNR between the decoder's version of the post-error frames and the encoder's version is at least 20 dB. Change-Id: Ie6e2bcd436b1e8643270356d3a930e8989ff52a5 --- test/decode_test_driver.h | 2 +- test/encode_test_driver.cc | 24 +++-- test/encode_test_driver.h | 11 +- test/error_resilience_test.cc | 143 ++++++++++++++++++++++++- test/test.mk | 9 +- test/util.h | 30 ++++++ vp9/common/vp9_alloccommon.c | 1 + vp9/common/vp9_entropymode.c | 70 +++++++++++- vp9/common/vp9_entropymode.h | 5 +- vp9/common/vp9_findnearmv.c | 196 ++++++++++++++++++---------------- vp9/common/vp9_findnearmv.h | 3 +- vp9/common/vp9_loopfilter.c | 5 +- vp9/common/vp9_mvref_common.c | 20 ++-- vp9/common/vp9_onyx.h | 6 ++ vp9/common/vp9_onyxc_int.h | 1 + vp9/decoder/vp9_decodemv.c | 38 ++++++- vp9/decoder/vp9_decodframe.c | 75 +++---------- vp9/encoder/vp9_bitstream.c | 31 +++--- vp9/encoder/vp9_encodeframe.c | 10 +- vp9/encoder/vp9_onyx_if.c | 31 ++++-- vp9/encoder/vp9_ratectrl.c | 69 +++--------- vp9/encoder/vp9_rdopt.c | 8 +- vp9/vp9_cx_iface.c | 54 +++++----- vp9/vp9_dx_iface.c | 2 +- vpxenc.c | 26 ++--- 25 files changed, 553 insertions(+), 317 deletions(-) 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; + // 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; + 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); + 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); + 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, + 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 + 16, xd->dst.y_stride, &sse); + above_src, 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, + 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), - 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, + 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), - 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, + 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), - left_src + xd->dst.y_stride * 48, - xd->dst.y_stride, &sse); + 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; + // 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; - - // 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); + MACROBLOCKD *xd = &cpi->mb.e_mbd; - // 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] + -- 2.50.1