diff options
-rw-r--r-- | test/acm_random.h | 6 | ||||
-rw-r--r-- | test/hadamard_test.cc | 284 | ||||
-rw-r--r-- | test/svc_datarate_test.cc | 83 | ||||
-rw-r--r-- | test/vp9_datarate_test.cc | 50 | ||||
-rw-r--r-- | vp8/decoder/threading.c | 18 | ||||
-rw-r--r-- | vp8/encoder/bitstream.c | 124 | ||||
-rw-r--r-- | vp8/encoder/boolhuff.c | 4 | ||||
-rw-r--r-- | vp8/encoder/boolhuff.h | 11 | ||||
-rw-r--r-- | vp8/encoder/encodemv.c | 11 | ||||
-rw-r--r-- | vp8/encoder/mcomp.c | 98 | ||||
-rw-r--r-- | vp8/encoder/mcomp.h | 6 | ||||
-rw-r--r-- | vp8/encoder/onyx_if.c | 54 | ||||
-rw-r--r-- | vp8/encoder/ratectrl.c | 2 | ||||
-rw-r--r-- | vp8/encoder/tokenize.c | 70 | ||||
-rw-r--r-- | vp8/encoder/tokenize.h | 8 | ||||
-rw-r--r-- | vp9/encoder/vp9_encodeframe.c | 14 | ||||
-rw-r--r-- | vp9/encoder/vp9_encoder.c | 61 | ||||
-rw-r--r-- | vp9/encoder/vp9_firstpass.c | 67 | ||||
-rw-r--r-- | vp9/encoder/vp9_ratectrl.c | 44 | ||||
-rw-r--r-- | vp9/encoder/vp9_ratectrl.h | 12 | ||||
-rw-r--r-- | vp9/encoder/vp9_speed_features.c | 7 | ||||
-rw-r--r-- | vp9/encoder/vp9_svc_layercontext.c | 3 | ||||
-rw-r--r-- | vp9/vp9_cx_iface.c | 9 | ||||
-rw-r--r-- | vpx/vp8cx.h | 10 |
24 files changed, 445 insertions, 611 deletions
diff --git a/test/acm_random.h b/test/acm_random.h index f3e7d398d..5a4e6c392 100644 --- a/test/acm_random.h +++ b/test/acm_random.h @@ -34,6 +34,12 @@ class ACMRandom { return (value >> 15) & 0xffff; } + int16_t Rand13Signed(void) { + // Use 13 bits: values between 4095 and -4096. + const uint32_t value = random_.Generate(8192); + return static_cast<int16_t>(value) - 4096; + } + int16_t Rand9Signed(void) { // Use 9 bits: values between 255 (0x0FF) and -256 (0x100). const uint32_t value = random_.Generate(512); diff --git a/test/hadamard_test.cc b/test/hadamard_test.cc index 6d8d30c5e..6f9bec07b 100644 --- a/test/hadamard_test.cc +++ b/test/hadamard_test.cc @@ -25,13 +25,13 @@ using ::libvpx_test::ACMRandom; typedef void (*HadamardFunc)(const int16_t *a, ptrdiff_t a_stride, tran_low_t *b); -void hadamard_loop(const int16_t *a, int a_stride, int16_t *out) { - int16_t b[8]; +void hadamard_loop(const tran_low_t *a, tran_low_t *out) { + tran_low_t b[8]; for (int i = 0; i < 8; i += 2) { - b[i + 0] = a[i * a_stride] + a[(i + 1) * a_stride]; - b[i + 1] = a[i * a_stride] - a[(i + 1) * a_stride]; + b[i + 0] = a[i * 8] + a[(i + 1) * 8]; + b[i + 1] = a[i * 8] - a[(i + 1) * 8]; } - int16_t c[8]; + tran_low_t c[8]; for (int i = 0; i < 8; i += 4) { c[i + 0] = b[i + 0] + b[i + 2]; c[i + 1] = b[i + 1] + b[i + 3]; @@ -49,12 +49,15 @@ void hadamard_loop(const int16_t *a, int a_stride, int16_t *out) { } void reference_hadamard8x8(const int16_t *a, int a_stride, tran_low_t *b) { - int16_t buf[64]; - int16_t buf2[64]; - for (int i = 0; i < 8; ++i) hadamard_loop(a + i, a_stride, buf + i * 8); - for (int i = 0; i < 8; ++i) hadamard_loop(buf + i, 8, buf2 + i * 8); - - for (int i = 0; i < 64; ++i) b[i] = (tran_low_t)buf2[i]; + tran_low_t input[64]; + tran_low_t buf[64]; + for (int i = 0; i < 8; ++i) { + for (int j = 0; j < 8; ++j) { + input[i * 8 + j] = static_cast<tran_low_t>(a[i * a_stride + j]); + } + } + for (int i = 0; i < 8; ++i) hadamard_loop(input + i, buf + i * 8); + for (int i = 0; i < 8; ++i) hadamard_loop(buf + i, b + i * 8); } void reference_hadamard16x16(const int16_t *a, int a_stride, tran_low_t *b) { @@ -115,13 +118,23 @@ void reference_hadamard32x32(const int16_t *a, int a_stride, tran_low_t *b) { } } -class HadamardTestBase : public ::testing::TestWithParam<HadamardFunc> { +struct HadamardFuncWithSize { + HadamardFuncWithSize(HadamardFunc f, int s) : func(f), block_size(s) {} + HadamardFunc func; + int block_size; +}; + +class HadamardTestBase : public ::testing::TestWithParam<HadamardFuncWithSize> { public: virtual void SetUp() { - h_func_ = GetParam(); + h_func_ = GetParam().func; + bwh_ = GetParam().block_size; + block_size_ = bwh_ * bwh_; rnd_.Reset(ACMRandom::DeterministicSeed()); } + virtual int16_t Rand() = 0; + void ReferenceHadamard(const int16_t *a, int a_stride, tran_low_t *b, int bwh) { if (bwh == 32) @@ -132,205 +145,162 @@ class HadamardTestBase : public ::testing::TestWithParam<HadamardFunc> { reference_hadamard8x8(a, a_stride, b); } - template <int bwh> void CompareReferenceRandom() { - const int kBlockSize = bwh * bwh; - DECLARE_ALIGNED(16, int16_t, a[kBlockSize]); - DECLARE_ALIGNED(16, tran_low_t, b[kBlockSize]); - tran_low_t b_ref[kBlockSize]; - for (int i = 0; i < kBlockSize; ++i) { - a[i] = rnd_.Rand9Signed(); - } + const int kMaxBlockSize = 32 * 32; + DECLARE_ALIGNED(16, int16_t, a[kMaxBlockSize]); + DECLARE_ALIGNED(16, tran_low_t, b[kMaxBlockSize]); + memset(a, 0, sizeof(a)); memset(b, 0, sizeof(b)); + + tran_low_t b_ref[kMaxBlockSize]; memset(b_ref, 0, sizeof(b_ref)); - ReferenceHadamard(a, bwh, b_ref, bwh); - ASM_REGISTER_STATE_CHECK(h_func_(a, bwh, b)); + for (int i = 0; i < block_size_; ++i) a[i] = Rand(); + + ReferenceHadamard(a, bwh_, b_ref, bwh_); + ASM_REGISTER_STATE_CHECK(h_func_(a, bwh_, b)); // The order of the output is not important. Sort before checking. - std::sort(b, b + kBlockSize); - std::sort(b_ref, b_ref + kBlockSize); + std::sort(b, b + block_size_); + std::sort(b_ref, b_ref + block_size_); EXPECT_EQ(0, memcmp(b, b_ref, sizeof(b))); } - template <int bwh> void VaryStride() { - const int kBlockSize = bwh * bwh; - DECLARE_ALIGNED(16, int16_t, a[kBlockSize * 8]); - DECLARE_ALIGNED(16, tran_low_t, b[kBlockSize]); - tran_low_t b_ref[kBlockSize]; - for (int i = 0; i < kBlockSize * 8; ++i) { - a[i] = rnd_.Rand9Signed(); - } + const int kMaxBlockSize = 32 * 32; + DECLARE_ALIGNED(16, int16_t, a[kMaxBlockSize * 8]); + DECLARE_ALIGNED(16, tran_low_t, b[kMaxBlockSize]); + memset(a, 0, sizeof(a)); + for (int i = 0; i < block_size_ * 8; ++i) a[i] = Rand(); + tran_low_t b_ref[kMaxBlockSize]; for (int i = 8; i < 64; i += 8) { memset(b, 0, sizeof(b)); memset(b_ref, 0, sizeof(b_ref)); - ReferenceHadamard(a, i, b_ref, bwh); + ReferenceHadamard(a, i, b_ref, bwh_); ASM_REGISTER_STATE_CHECK(h_func_(a, i, b)); // The order of the output is not important. Sort before checking. - std::sort(b, b + kBlockSize); - std::sort(b_ref, b_ref + kBlockSize); + std::sort(b, b + block_size_); + std::sort(b_ref, b_ref + block_size_); EXPECT_EQ(0, memcmp(b, b_ref, sizeof(b))); } } + void SpeedTest(int times) { + const int kMaxBlockSize = 32 * 32; + DECLARE_ALIGNED(16, int16_t, input[kMaxBlockSize]); + DECLARE_ALIGNED(16, tran_low_t, output[kMaxBlockSize]); + memset(input, 1, sizeof(input)); + memset(output, 0, sizeof(output)); + + vpx_usec_timer timer; + vpx_usec_timer_start(&timer); + for (int i = 0; i < times; ++i) { + h_func_(input, bwh_, output); + } + vpx_usec_timer_mark(&timer); + + const int elapsed_time = static_cast<int>(vpx_usec_timer_elapsed(&timer)); + printf("Hadamard%dx%d[%12d runs]: %d us\n", bwh_, bwh_, times, + elapsed_time); + } + protected: + int bwh_; + int block_size_; HadamardFunc h_func_; ACMRandom rnd_; }; -void HadamardSpeedTest(const char *name, HadamardFunc const func, - const int16_t *input, int stride, tran_low_t *output, - int times) { - int i; - vpx_usec_timer timer; - - vpx_usec_timer_start(&timer); - for (i = 0; i < times; ++i) { - func(input, stride, output); - } - vpx_usec_timer_mark(&timer); - - const int elapsed_time = static_cast<int>(vpx_usec_timer_elapsed(&timer)); - printf("%s[%12d runs]: %d us\n", name, times, elapsed_time); -} - -class Hadamard8x8Test : public HadamardTestBase {}; - -void HadamardSpeedTest8x8(HadamardFunc const func, int times) { - DECLARE_ALIGNED(16, int16_t, input[64]); - DECLARE_ALIGNED(16, tran_low_t, output[64]); - memset(input, 1, sizeof(input)); - HadamardSpeedTest("Hadamard8x8", func, input, 8, output, times); -} +class HadamardLowbdTest : public HadamardTestBase { + protected: + virtual int16_t Rand() { return rnd_.Rand9Signed(); } +}; -TEST_P(Hadamard8x8Test, CompareReferenceRandom) { CompareReferenceRandom<8>(); } +TEST_P(HadamardLowbdTest, CompareReferenceRandom) { CompareReferenceRandom(); } -TEST_P(Hadamard8x8Test, VaryStride) { VaryStride<8>(); } +TEST_P(HadamardLowbdTest, VaryStride) { VaryStride(); } -TEST_P(Hadamard8x8Test, DISABLED_Speed) { - HadamardSpeedTest8x8(h_func_, 10); - HadamardSpeedTest8x8(h_func_, 10000); - HadamardSpeedTest8x8(h_func_, 10000000); +TEST_P(HadamardLowbdTest, DISABLED_Speed) { + SpeedTest(10); + SpeedTest(10000); + SpeedTest(10000000); } -INSTANTIATE_TEST_CASE_P(C, Hadamard8x8Test, - ::testing::Values(&vpx_hadamard_8x8_c)); +INSTANTIATE_TEST_CASE_P( + C, HadamardLowbdTest, + ::testing::Values(HadamardFuncWithSize(&vpx_hadamard_8x8_c, 8), + HadamardFuncWithSize(&vpx_hadamard_16x16_c, 16), + HadamardFuncWithSize(&vpx_hadamard_32x32_c, 32))); #if HAVE_SSE2 -INSTANTIATE_TEST_CASE_P(SSE2, Hadamard8x8Test, - ::testing::Values(&vpx_hadamard_8x8_sse2)); +INSTANTIATE_TEST_CASE_P( + SSE2, HadamardLowbdTest, + ::testing::Values(HadamardFuncWithSize(&vpx_hadamard_8x8_sse2, 8), + HadamardFuncWithSize(&vpx_hadamard_16x16_sse2, 16), + HadamardFuncWithSize(&vpx_hadamard_32x32_sse2, 32))); #endif // HAVE_SSE2 +#if HAVE_AVX2 +INSTANTIATE_TEST_CASE_P( + AVX2, HadamardLowbdTest, + ::testing::Values(HadamardFuncWithSize(&vpx_hadamard_16x16_avx2, 16), + HadamardFuncWithSize(&vpx_hadamard_32x32_avx2, 32))); +#endif // HAVE_AVX2 + #if HAVE_SSSE3 && ARCH_X86_64 -INSTANTIATE_TEST_CASE_P(SSSE3, Hadamard8x8Test, - ::testing::Values(&vpx_hadamard_8x8_ssse3)); +INSTANTIATE_TEST_CASE_P( + SSSE3, HadamardLowbdTest, + ::testing::Values(HadamardFuncWithSize(&vpx_hadamard_8x8_ssse3, 8))); #endif // HAVE_SSSE3 && ARCH_X86_64 #if HAVE_NEON -INSTANTIATE_TEST_CASE_P(NEON, Hadamard8x8Test, - ::testing::Values(&vpx_hadamard_8x8_neon)); +INSTANTIATE_TEST_CASE_P( + NEON, HadamardLowbdTest, + ::testing::Values(HadamardFuncWithSize(&vpx_hadamard_8x8_neon, 8), + HadamardFuncWithSize(&vpx_hadamard_16x16_neon, 16))); #endif // HAVE_NEON // TODO(jingning): Remove highbitdepth flag when the SIMD functions are // in place and turn on the unit test. #if !CONFIG_VP9_HIGHBITDEPTH #if HAVE_MSA -INSTANTIATE_TEST_CASE_P(MSA, Hadamard8x8Test, - ::testing::Values(&vpx_hadamard_8x8_msa)); +INSTANTIATE_TEST_CASE_P( + MSA, HadamardLowbdTest, + ::testing::Values(HadamardFuncWithSize(&vpx_hadamard_8x8_msa, 8), + HadamardFuncWithSize(&vpx_hadamard_16x16_msa, 16))); #endif // HAVE_MSA #endif // !CONFIG_VP9_HIGHBITDEPTH #if HAVE_VSX -INSTANTIATE_TEST_CASE_P(VSX, Hadamard8x8Test, - ::testing::Values(&vpx_hadamard_8x8_vsx)); +INSTANTIATE_TEST_CASE_P( + VSX, HadamardLowbdTest, + ::testing::Values(HadamardFuncWithSize(&vpx_hadamard_8x8_vsx, 8), + HadamardFuncWithSize(&vpx_hadamard_16x16_vsx, 16))); #endif // HAVE_VSX -class Hadamard16x16Test : public HadamardTestBase {}; - -void HadamardSpeedTest16x16(HadamardFunc const func, int times) { - DECLARE_ALIGNED(16, int16_t, input[256]); - DECLARE_ALIGNED(16, tran_low_t, output[256]); - memset(input, 1, sizeof(input)); - HadamardSpeedTest("Hadamard16x16", func, input, 16, output, times); -} - -TEST_P(Hadamard16x16Test, CompareReferenceRandom) { - CompareReferenceRandom<16>(); -} - -TEST_P(Hadamard16x16Test, VaryStride) { VaryStride<16>(); } - -TEST_P(Hadamard16x16Test, DISABLED_Speed) { - HadamardSpeedTest16x16(h_func_, 10); - HadamardSpeedTest16x16(h_func_, 10000); - HadamardSpeedTest16x16(h_func_, 10000000); -} - -INSTANTIATE_TEST_CASE_P(C, Hadamard16x16Test, - ::testing::Values(&vpx_hadamard_16x16_c)); - -#if HAVE_SSE2 -INSTANTIATE_TEST_CASE_P(SSE2, Hadamard16x16Test, - ::testing::Values(&vpx_hadamard_16x16_sse2)); -#endif // HAVE_SSE2 - -#if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P(AVX2, Hadamard16x16Test, - ::testing::Values(&vpx_hadamard_16x16_avx2)); -#endif // HAVE_AVX2 - -#if HAVE_VSX -INSTANTIATE_TEST_CASE_P(VSX, Hadamard16x16Test, - ::testing::Values(&vpx_hadamard_16x16_vsx)); -#endif // HAVE_VSX - -#if HAVE_NEON -INSTANTIATE_TEST_CASE_P(NEON, Hadamard16x16Test, - ::testing::Values(&vpx_hadamard_16x16_neon)); -#endif // HAVE_NEON - -#if !CONFIG_VP9_HIGHBITDEPTH -#if HAVE_MSA -INSTANTIATE_TEST_CASE_P(MSA, Hadamard16x16Test, - ::testing::Values(&vpx_hadamard_16x16_msa)); -#endif // HAVE_MSA -#endif // !CONFIG_VP9_HIGHBITDEPTH +#if CONFIG_VP9_HIGHBITDEPTH +class HadamardHighbdTest : public HadamardTestBase { + protected: + virtual int16_t Rand() { return rnd_.Rand13Signed(); } +}; -class Hadamard32x32Test : public HadamardTestBase {}; +TEST_P(HadamardHighbdTest, CompareReferenceRandom) { CompareReferenceRandom(); } -void HadamardSpeedTest32x32(HadamardFunc const func, int times) { - DECLARE_ALIGNED(16, int16_t, input[1024]); - DECLARE_ALIGNED(16, tran_low_t, output[1024]); - memset(input, 1, sizeof(input)); - HadamardSpeedTest("Hadamard32x32", func, input, 32, output, times); -} +TEST_P(HadamardHighbdTest, VaryStride) { VaryStride(); } -TEST_P(Hadamard32x32Test, CompareReferenceRandom) { - CompareReferenceRandom<32>(); +TEST_P(HadamardHighbdTest, DISABLED_Speed) { + SpeedTest(10); + SpeedTest(10000); + SpeedTest(10000000); } -TEST_P(Hadamard32x32Test, VaryStride) { VaryStride<32>(); } - -TEST_P(Hadamard32x32Test, DISABLED_Speed) { - HadamardSpeedTest32x32(h_func_, 10); - HadamardSpeedTest32x32(h_func_, 10000); - HadamardSpeedTest32x32(h_func_, 10000000); -} - -INSTANTIATE_TEST_CASE_P(C, Hadamard32x32Test, - ::testing::Values(&vpx_hadamard_32x32_c)); - -#if HAVE_SSE2 -INSTANTIATE_TEST_CASE_P(SSE2, Hadamard32x32Test, - ::testing::Values(&vpx_hadamard_32x32_sse2)); -#endif // HAVE_SSE2 - -#if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P(AVX2, Hadamard32x32Test, - ::testing::Values(&vpx_hadamard_32x32_avx2)); -#endif // HAVE_AVX2 +INSTANTIATE_TEST_CASE_P( + C, HadamardHighbdTest, + ::testing::Values(HadamardFuncWithSize(&vpx_highbd_hadamard_8x8_c, 8), + HadamardFuncWithSize(&vpx_highbd_hadamard_16x16_c, 16), + HadamardFuncWithSize(&vpx_highbd_hadamard_32x32_c, 32))); +#endif // CONFIG_VP9_HIGHBITDEPTH } // namespace diff --git a/test/svc_datarate_test.cc b/test/svc_datarate_test.cc index 117014fa6..c530beac6 100644 --- a/test/svc_datarate_test.cc +++ b/test/svc_datarate_test.cc @@ -60,6 +60,7 @@ class DatarateOnePassCbrSvc : public ::svc_test::OnePassCbrSvc { layer_sync_on_base_ = 0; force_intra_only_frame_ = 0; superframe_has_intra_only_ = 0; + use_post_encode_drop_ = 0; } virtual void BeginPassHook(unsigned int /*pass*/) {} @@ -174,6 +175,10 @@ class DatarateOnePassCbrSvc : public ::svc_test::OnePassCbrSvc { svc_drop_frame.max_consec_drop = 30; encoder->Control(VP9E_SET_SVC_FRAME_DROP_LAYER, &svc_drop_frame); } + + if (use_post_encode_drop_) { + encoder->Control(VP9E_SET_POSTENCODE_DROP, use_post_encode_drop_); + } } if (update_pattern_ && video->frame() >= 100) { @@ -482,6 +487,7 @@ class DatarateOnePassCbrSvc : public ::svc_test::OnePassCbrSvc { int layer_sync_on_base_; int force_intra_only_frame_; int superframe_has_intra_only_; + int use_post_encode_drop_; }; // Params: speed setting. @@ -1361,9 +1367,86 @@ TEST_P(DatarateOnePassCbrSvcSingleBR, OnePassCbrSvc2QL1TLScreen) { #endif } +// Params: speed setting. +class DatarateOnePassCbrSvcPostencodeDrop + : public DatarateOnePassCbrSvc, + public ::libvpx_test::CodecTestWithParam<int> { + public: + DatarateOnePassCbrSvcPostencodeDrop() : DatarateOnePassCbrSvc(GET_PARAM(0)) { + memset(&svc_params_, 0, sizeof(svc_params_)); + } + virtual ~DatarateOnePassCbrSvcPostencodeDrop() {} + + protected: + virtual void SetUp() { + InitializeConfig(); + SetMode(::libvpx_test::kRealTime); + speed_setting_ = GET_PARAM(1); + ResetModel(); + } +}; + +// Run SVC encoder for 2 quality layers (same resolution different, +// bitrates), 1 temporal layer, with screen content mode. +TEST_P(DatarateOnePassCbrSvcPostencodeDrop, OnePassCbrSvc2QL1TLScreen) { + cfg_.rc_buf_initial_sz = 200; + cfg_.rc_buf_optimal_sz = 200; + cfg_.rc_buf_sz = 400; + cfg_.rc_min_quantizer = 0; + cfg_.rc_max_quantizer = 52; + cfg_.rc_end_usage = VPX_CBR; + cfg_.g_lag_in_frames = 0; + cfg_.ss_number_layers = 2; + cfg_.ts_number_layers = 1; + cfg_.ts_rate_decimator[0] = 1; + cfg_.temporal_layering_mode = 0; + cfg_.g_error_resilient = 1; + cfg_.g_threads = 2; + svc_params_.scaling_factor_num[0] = 1; + svc_params_.scaling_factor_den[0] = 1; + svc_params_.scaling_factor_num[1] = 1; + svc_params_.scaling_factor_den[1] = 1; + cfg_.rc_dropframe_thresh = 30; + cfg_.kf_max_dist = 9999; + number_spatial_layers_ = cfg_.ss_number_layers; + number_temporal_layers_ = cfg_.ts_number_layers; + ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, + 30, 1, 0, 300); + top_sl_width_ = 352; + top_sl_height_ = 288; + ResetModel(); + base_speed_setting_ = speed_setting_; + tune_content_ = 1; + use_post_encode_drop_ = 1; + // Set the layer bitrates, for 2 spatial layers, 1 temporal. + cfg_.rc_target_bitrate = 400; + cfg_.ss_target_bitrate[0] = 100; + cfg_.ss_target_bitrate[1] = 300; + cfg_.layer_target_bitrate[0] = 100; + cfg_.layer_target_bitrate[1] = 300; + for (int sl = 0; sl < 2; ++sl) { + float layer_framerate = 30.0; + layer_target_avg_bandwidth_[sl] = static_cast<int>( + cfg_.layer_target_bitrate[sl] * 1000.0 / layer_framerate); + bits_in_buffer_model_[sl] = + cfg_.layer_target_bitrate[sl] * cfg_.rc_buf_initial_sz; + } + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); + CheckLayerRateTargeting(number_spatial_layers_, number_temporal_layers_, 0.73, + 1.25); +#if CONFIG_VP9_DECODER + // The non-reference frames are expected to be mismatched frames as the + // encoder will avoid loopfilter on these frames. + EXPECT_EQ(num_nonref_frames_, GetMismatchFrames()); +#endif +} + VP9_INSTANTIATE_TEST_CASE(DatarateOnePassCbrSvcSingleBR, ::testing::Range(5, 10)); +VP9_INSTANTIATE_TEST_CASE(DatarateOnePassCbrSvcPostencodeDrop, + ::testing::Range(4, 5)); + VP9_INSTANTIATE_TEST_CASE(DatarateOnePassCbrSvcInterLayerPredSingleBR, ::testing::Range(5, 10), ::testing::Range(0, 3)); diff --git a/test/vp9_datarate_test.cc b/test/vp9_datarate_test.cc index da2609181..62f2852f6 100644 --- a/test/vp9_datarate_test.cc +++ b/test/vp9_datarate_test.cc @@ -22,7 +22,9 @@ namespace { class DatarateTestVP9 : public ::libvpx_test::EncoderTest { public: explicit DatarateTestVP9(const ::libvpx_test::CodecFactory *codec) - : EncoderTest(codec) {} + : EncoderTest(codec) { + tune_content_ = 0; + } protected: virtual ~DatarateTestVP9() {} @@ -114,6 +116,7 @@ class DatarateTestVP9 : public ::libvpx_test::EncoderTest { if (video->frame() == 0) { encoder->Control(VP8E_SET_CPUUSED, set_cpu_used_); encoder->Control(VP9E_SET_AQ_MODE, aq_mode_); + encoder->Control(VP9E_SET_TUNE_CONTENT, tune_content_); } if (denoiser_offon_test_) { @@ -204,6 +207,7 @@ class DatarateTestVP9 : public ::libvpx_test::EncoderTest { vpx_codec_pts_t last_pts_; double timebase_; + int tune_content_; int frame_number_; // Counter for number of non-dropped/encoded frames. int tot_frame_number_; // Counter for total number of input frames. int64_t bits_total_[3]; @@ -713,6 +717,47 @@ TEST_P(DatarateTestVP9RealTime, RegionOfInterest) { free(roi_.roi_map); } +// Params: test mode, speed setting and index for bitrate array. +class DatarateTestVP9PostEncodeDrop + : public DatarateTestVP9, + public ::libvpx_test::CodecTestWithParam<int> { + public: + DatarateTestVP9PostEncodeDrop() : DatarateTestVP9(GET_PARAM(0)) {} + + protected: + virtual void SetUp() { + InitializeConfig(); + SetMode(::libvpx_test::kRealTime); + set_cpu_used_ = GET_PARAM(1); + ResetModel(); + } +}; + +// Check basic rate targeting for CBR mode, with 2 threads and dropped frames. +TEST_P(DatarateTestVP9PostEncodeDrop, PostEncodeDropScreenContent) { + cfg_.rc_buf_initial_sz = 500; + cfg_.rc_buf_optimal_sz = 500; + cfg_.rc_buf_sz = 1000; + cfg_.rc_dropframe_thresh = 30; + cfg_.rc_min_quantizer = 0; + cfg_.rc_max_quantizer = 56; + cfg_.rc_end_usage = VPX_CBR; + cfg_.g_lag_in_frames = 0; + // Encode using multiple threads. + cfg_.g_threads = 2; + cfg_.g_error_resilient = 0; + tune_content_ = 1; + ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, + 30, 1, 0, 300); + cfg_.rc_target_bitrate = 300; + ResetModel(); + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); + ASSERT_GE(effective_datarate_[0], cfg_.rc_target_bitrate * 0.85) + << " The datarate for the file is lower than target by too much!"; + ASSERT_LE(effective_datarate_[0], cfg_.rc_target_bitrate * 1.15) + << " The datarate for the file is greater than target by too much!"; +} + #if CONFIG_VP9_TEMPORAL_DENOISING // Params: speed setting. class DatarateTestVP9RealTimeDenoiser : public DatarateTestVP9RealTime { @@ -849,6 +894,9 @@ VP9_INSTANTIATE_TEST_CASE(DatarateTestVP9LargeVBR, VP9_INSTANTIATE_TEST_CASE(DatarateTestVP9RealTime, ::testing::Range(5, 10)); +VP9_INSTANTIATE_TEST_CASE(DatarateTestVP9PostEncodeDrop, + ::testing::Range(4, 5)); + #if CONFIG_VP9_TEMPORAL_DENOISING VP9_INSTANTIATE_TEST_CASE(DatarateTestVP9RealTimeDenoiser, ::testing::Range(5, 10)); diff --git a/vp8/decoder/threading.c b/vp8/decoder/threading.c index 8cc301d4f..90e0f4d86 100644 --- a/vp8/decoder/threading.c +++ b/vp8/decoder/threading.c @@ -415,13 +415,17 @@ static void mt_decode_mb_rows(VP8D_COMP *pbi, MACROBLOCKD *xd, "Corrupted reference frame"); } - xd->pre.y_buffer = - ref_buffer[xd->mode_info_context->mbmi.ref_frame][0] + recon_yoffset; - xd->pre.u_buffer = - ref_buffer[xd->mode_info_context->mbmi.ref_frame][1] + recon_uvoffset; - xd->pre.v_buffer = - ref_buffer[xd->mode_info_context->mbmi.ref_frame][2] + recon_uvoffset; - + if (xd->mode_info_context->mbmi.ref_frame >= LAST_FRAME) { + const MV_REFERENCE_FRAME ref = xd->mode_info_context->mbmi.ref_frame; + xd->pre.y_buffer = ref_buffer[ref][0] + recon_yoffset; + xd->pre.u_buffer = ref_buffer[ref][1] + recon_uvoffset; + xd->pre.v_buffer = ref_buffer[ref][2] + recon_uvoffset; + } else { + // ref_frame is INTRA_FRAME, pre buffer should not be used. + xd->pre.y_buffer = 0; + xd->pre.u_buffer = 0; + xd->pre.v_buffer = 0; + } mt_decode_macroblock(pbi, xd, 0); xd->left_available = 1; diff --git a/vp8/encoder/bitstream.c b/vp8/encoder/bitstream.c index 8cacb6450..8dd042775 100644 --- a/vp8/encoder/bitstream.c +++ b/vp8/encoder/bitstream.c @@ -41,13 +41,6 @@ const int vp8cx_base_skip_false_prob[128] = { unsigned __int64 Sectionbits[500]; #endif -#ifdef VP8_ENTROPY_STATS -int intra_mode_stats[10][10][10]; -static unsigned int tree_update_hist[BLOCK_TYPES][COEF_BANDS] - [PREV_COEF_CONTEXTS][ENTROPY_NODES][2]; -extern unsigned int active_section; -#endif - #ifdef MODE_STATS int count_mb_seg[4] = { 0, 0, 0, 0 }; #endif @@ -428,10 +421,6 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi) { vp8_convert_rfct_to_prob(cpi); -#ifdef VP8_ENTROPY_STATS - active_section = 1; -#endif - if (pc->mb_no_coeff_skip) { int total_mbs = pc->mb_rows * pc->mb_cols; @@ -472,10 +461,6 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi) { xd->mb_to_top_edge = -((mb_row * 16) << 3); xd->mb_to_bottom_edge = ((pc->mb_rows - 1 - mb_row) * 16) << 3; -#ifdef VP8_ENTROPY_STATS - active_section = 9; -#endif - if (cpi->mb.e_mbd.update_mb_segmentation_map) { write_mb_features(w, mi, &cpi->mb.e_mbd); } @@ -486,9 +471,6 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi) { if (rf == INTRA_FRAME) { vp8_write(w, 0, cpi->prob_intra_coded); -#ifdef VP8_ENTROPY_STATS - active_section = 6; -#endif write_ymode(w, mode, pc->fc.ymode_prob); if (mode == B_PRED) { @@ -522,28 +504,13 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi) { vp8_clamp_mv2(&best_mv, xd); vp8_mv_ref_probs(mv_ref_p, ct); - -#ifdef VP8_ENTROPY_STATS - accum_mv_refs(mode, ct); -#endif } -#ifdef VP8_ENTROPY_STATS - active_section = 3; -#endif - write_mv_ref(w, mode, mv_ref_p); switch (mode) /* new, split require MVs */ { - case NEWMV: - -#ifdef VP8_ENTROPY_STATS - active_section = 5; -#endif - - write_mv(w, &mi->mv.as_mv, &best_mv, mvc); - break; + case NEWMV: write_mv(w, &mi->mv.as_mv, &best_mv, mvc); break; case SPLITMV: { int j = 0; @@ -574,9 +541,6 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi) { write_sub_mv_ref(w, blockmode, vp8_sub_mv_ref_prob2[mv_contz]); if (blockmode == NEW4X4) { -#ifdef VP8_ENTROPY_STATS - active_section = 11; -#endif write_mv(w, &blockmv.as_mv, &best_mv, (const MV_CONTEXT *)mvc); } } while (++j < cpi->mb.partition_info->count); @@ -642,10 +606,6 @@ static void write_kfmodes(VP8_COMP *cpi) { const B_PREDICTION_MODE L = left_block_mode(m, i); const int bm = m->bmi[i].as_mode; -#ifdef VP8_ENTROPY_STATS - ++intra_mode_stats[A][L][bm]; -#endif - write_bmode(bc, bm, vp8_kf_bmode_prob[A][L]); } while (++i < 16); } @@ -973,10 +933,6 @@ void vp8_update_coef_probs(VP8_COMP *cpi) { vp8_write(w, u, upd); #endif -#ifdef VP8_ENTROPY_STATS - ++tree_update_hist[i][j][k][t][u]; -#endif - if (u) { /* send/use new probability */ @@ -990,16 +946,6 @@ void vp8_update_coef_probs(VP8_COMP *cpi) { } while (++t < ENTROPY_NODES); -/* Accum token counts for generation of default statistics */ -#ifdef VP8_ENTROPY_STATS - t = 0; - - do { - context_counters[i][j][k][t] += cpi->coef_counts[i][j][k][t]; - } while (++t < MAX_ENTROPY_TOKENS); - -#endif - } while (++k < PREV_COEF_CONTEXTS); } while (++j < COEF_BANDS); } while (++i < BLOCK_TYPES); @@ -1286,15 +1232,6 @@ void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, if (pc->frame_type != KEY_FRAME) vp8_write_bit(bc, pc->refresh_last_frame); -#ifdef VP8_ENTROPY_STATS - - if (pc->frame_type == INTER_FRAME) - active_section = 0; - else - active_section = 7; - -#endif - vpx_clear_system_state(); #if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING @@ -1308,25 +1245,13 @@ void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, vp8_update_coef_probs(cpi); #endif -#ifdef VP8_ENTROPY_STATS - active_section = 2; -#endif - /* Write out the mb_no_coeff_skip flag */ vp8_write_bit(bc, pc->mb_no_coeff_skip); if (pc->frame_type == KEY_FRAME) { write_kfmodes(cpi); - -#ifdef VP8_ENTROPY_STATS - active_section = 8; -#endif } else { pack_inter_mode_mvs(cpi); - -#ifdef VP8_ENTROPY_STATS - active_section = 1; -#endif } vp8_stop_encode(bc); @@ -1431,50 +1356,3 @@ void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, } #endif } - -#ifdef VP8_ENTROPY_STATS -void print_tree_update_probs() { - int i, j, k, l; - FILE *f = fopen("context.c", "a"); - int Sum; - fprintf(f, "\n/* Update probabilities for token entropy tree. */\n\n"); - fprintf(f, - "const vp8_prob tree_update_probs[BLOCK_TYPES] [COEF_BANDS] " - "[PREV_COEF_CONTEXTS] [ENTROPY_NODES] = {\n"); - - for (i = 0; i < BLOCK_TYPES; ++i) { - fprintf(f, " { \n"); - - for (j = 0; j < COEF_BANDS; ++j) { - fprintf(f, " {\n"); - - for (k = 0; k < PREV_COEF_CONTEXTS; ++k) { - fprintf(f, " {"); - - for (l = 0; l < ENTROPY_NODES; ++l) { - Sum = - tree_update_hist[i][j][k][l][0] + tree_update_hist[i][j][k][l][1]; - - if (Sum > 0) { - if (((tree_update_hist[i][j][k][l][0] * 255) / Sum) > 0) - fprintf(f, "%3ld, ", - (tree_update_hist[i][j][k][l][0] * 255) / Sum); - else - fprintf(f, "%3ld, ", 1); - } else - fprintf(f, "%3ld, ", 128); - } - - fprintf(f, "},\n"); - } - - fprintf(f, " },\n"); - } - - fprintf(f, " },\n"); - } - - fprintf(f, "};\n"); - fclose(f); -} -#endif diff --git a/vp8/encoder/boolhuff.c b/vp8/encoder/boolhuff.c index d1ed3c10c..819c2f22a 100644 --- a/vp8/encoder/boolhuff.c +++ b/vp8/encoder/boolhuff.c @@ -15,10 +15,6 @@ unsigned __int64 Sectionbits[500]; #endif -#ifdef VP8_ENTROPY_STATS -unsigned int active_section = 0; -#endif - const unsigned int vp8_prob_cost[256] = { 2047, 2047, 1791, 1641, 1535, 1452, 1385, 1328, 1279, 1235, 1196, 1161, 1129, 1099, 1072, 1046, 1023, 1000, 979, 959, 940, 922, 905, 889, 873, 858, diff --git a/vp8/encoder/boolhuff.h b/vp8/encoder/boolhuff.h index 029f9628a..8ac0a2cc4 100644 --- a/vp8/encoder/boolhuff.h +++ b/vp8/encoder/boolhuff.h @@ -63,17 +63,6 @@ static void vp8_encode_bool(BOOL_CODER *bc, int bit, int probability) { unsigned int lowvalue = bc->lowvalue; int shift; -#ifdef VP8_ENTROPY_STATS -#if defined(SECTIONBITS_OUTPUT) - - if (bit) - Sectionbits[active_section] += vp8_prob_cost[255 - probability]; - else - Sectionbits[active_section] += vp8_prob_cost[probability]; - -#endif -#endif - split = 1 + (((range - 1) * probability) >> 8); range = split; diff --git a/vp8/encoder/encodemv.c b/vp8/encoder/encodemv.c index ea93ccd71..04adf105b 100644 --- a/vp8/encoder/encodemv.c +++ b/vp8/encoder/encodemv.c @@ -16,10 +16,6 @@ #include <math.h> -#ifdef VP8_ENTROPY_STATS -extern unsigned int active_section; -#endif - static void encode_mvcomponent(vp8_writer *const w, const int v, const struct mv_context *mvc) { const vp8_prob *p = mvc->prob; @@ -309,9 +305,6 @@ void vp8_write_mvprobs(VP8_COMP *cpi) { vp8_writer *const w = cpi->bc; MV_CONTEXT *mvc = cpi->common.fc.mvc; int flags[2] = { 0, 0 }; -#ifdef VP8_ENTROPY_STATS - active_section = 4; -#endif write_component_probs(w, &mvc[0], &vp8_default_mv_context[0], &vp8_mv_update_probs[0], cpi->mb.MVcount[0], 0, &flags[0]); @@ -323,8 +316,4 @@ void vp8_write_mvprobs(VP8_COMP *cpi) { vp8_build_component_cost_table( cpi->mb.mvcost, (const MV_CONTEXT *)cpi->common.fc.mvc, flags); } - -#ifdef VP8_ENTROPY_STATS - active_section = 5; -#endif } diff --git a/vp8/encoder/mcomp.c b/vp8/encoder/mcomp.c index b4a49a3b1..1c3612fc3 100644 --- a/vp8/encoder/mcomp.c +++ b/vp8/encoder/mcomp.c @@ -21,11 +21,6 @@ #include "vp8/common/common.h" #include "vpx_dsp/vpx_dsp_common.h" -#ifdef VP8_ENTROPY_STATS -static int mv_ref_ct[31][4][2]; -static int mv_mode_cts[4][2]; -#endif - int vp8_mv_bit_cost(int_mv *mv, int_mv *ref, int *mvcost[2], int Weight) { /* MV costing is based on the distribution of vectors in the previous * frame and as such will tend to over state the cost of vectors. In @@ -1821,96 +1816,3 @@ int vp8_refining_search_sadx4(MACROBLOCK *x, BLOCK *b, BLOCKD *d, return fn_ptr->vf(what, what_stride, best_address, in_what_stride, &thissad) + mv_err_cost(&this_mv, center_mv, mvcost, x->errorperbit); } - -#ifdef VP8_ENTROPY_STATS -void print_mode_context(void) { - FILE *f = fopen("modecont.c", "w"); - int i, j; - - fprintf(f, "#include \"entropy.h\"\n"); - fprintf(f, "const int vp8_mode_contexts[6][4] =\n"); - fprintf(f, "{\n"); - - for (j = 0; j < 6; ++j) { - fprintf(f, " { /* %d */\n", j); - fprintf(f, " "); - - for (i = 0; i < 4; ++i) { - int overal_prob; - int this_prob; - int count; - - /* Overall probs */ - count = mv_mode_cts[i][0] + mv_mode_cts[i][1]; - - if (count) - overal_prob = 256 * mv_mode_cts[i][0] / count; - else - overal_prob = 128; - - if (overal_prob == 0) overal_prob = 1; - - /* context probs */ - count = mv_ref_ct[j][i][0] + mv_ref_ct[j][i][1]; - - if (count) - this_prob = 256 * mv_ref_ct[j][i][0] / count; - else - this_prob = 128; - - if (this_prob == 0) this_prob = 1; - - fprintf(f, "%5d, ", this_prob); - } - - fprintf(f, " },\n"); - } - - fprintf(f, "};\n"); - fclose(f); -} - -/* MV ref count VP8_ENTROPY_STATS stats code */ -#ifdef VP8_ENTROPY_STATS -void init_mv_ref_counts() { - memset(mv_ref_ct, 0, sizeof(mv_ref_ct)); - memset(mv_mode_cts, 0, sizeof(mv_mode_cts)); -} - -void accum_mv_refs(MB_PREDICTION_MODE m, const int ct[4]) { - if (m == ZEROMV) { - ++mv_ref_ct[ct[0]][0][0]; - ++mv_mode_cts[0][0]; - } else { - ++mv_ref_ct[ct[0]][0][1]; - ++mv_mode_cts[0][1]; - - if (m == NEARESTMV) { - ++mv_ref_ct[ct[1]][1][0]; - ++mv_mode_cts[1][0]; - } else { - ++mv_ref_ct[ct[1]][1][1]; - ++mv_mode_cts[1][1]; - - if (m == NEARMV) { - ++mv_ref_ct[ct[2]][2][0]; - ++mv_mode_cts[2][0]; - } else { - ++mv_ref_ct[ct[2]][2][1]; - ++mv_mode_cts[2][1]; - - if (m == NEWMV) { - ++mv_ref_ct[ct[3]][3][0]; - ++mv_mode_cts[3][0]; - } else { - ++mv_ref_ct[ct[3]][3][1]; - ++mv_mode_cts[3][1]; - } - } - } - } -} - -#endif /* END MV ref count VP8_ENTROPY_STATS stats code */ - -#endif diff --git a/vp8/encoder/mcomp.h b/vp8/encoder/mcomp.h index 397f872e2..6c77995da 100644 --- a/vp8/encoder/mcomp.h +++ b/vp8/encoder/mcomp.h @@ -18,11 +18,6 @@ extern "C" { #endif -#ifdef VP8_ENTROPY_STATS -void init_mv_ref_counts(); -void accum_mv_refs(MB_PREDICTION_MODE, const int near_mv_ref_cts[4]); -#endif - /* The maximum number of steps in a step search given the largest allowed * initial step */ @@ -34,7 +29,6 @@ void accum_mv_refs(MB_PREDICTION_MODE, const int near_mv_ref_cts[4]); /* Maximum size of the first step in full pel units */ #define MAX_FIRST_STEP (1 << (MAX_MVSEARCH_STEPS - 1)) -void print_mode_context(void); int vp8_mv_bit_cost(int_mv *mv, int_mv *ref, int *mvcost[2], int Weight); void vp8_init_dsmotion_compensation(MACROBLOCK *x, int stride); void vp8_init3smotion_compensation(MACROBLOCK *x, int stride); diff --git a/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c index ddd588294..8de8ca18e 100644 --- a/vp8/encoder/onyx_if.c +++ b/vp8/encoder/onyx_if.c @@ -65,9 +65,7 @@ extern int vp8_update_coef_context(VP8_COMP *cpi); extern void vp8_deblock_frame(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *post, int filt_lvl, int low_var_thresh, int flag); -extern void print_parms(VP8_CONFIG *ocf, char *filenam); extern unsigned int vp8_get_processor_freq(); -extern void print_tree_update_probs(); int vp8_calc_ss_err(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *dest); @@ -101,10 +99,6 @@ extern int skip_true_count; extern int skip_false_count; #endif -#ifdef VP8_ENTROPY_STATS -extern int intra_mode_stats[10][10][10]; -#endif - #ifdef SPEEDSTATS unsigned int frames_at_speed[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -1893,10 +1887,6 @@ struct VP8_COMP *vp8_create_compressor(VP8_CONFIG *oxcf) { CHECK_MEM_ERROR(cpi->consec_zero_last_mvbias, vpx_calloc((cpi->common.mb_rows * cpi->common.mb_cols), 1)); -#ifdef VP8_ENTROPY_STATS - init_context_counters(); -#endif - /*Initialize the feed-forward activity masking.*/ cpi->activity_avg = 90 << 12; @@ -2005,10 +1995,6 @@ struct VP8_COMP *vp8_create_compressor(VP8_CONFIG *oxcf) { cpi->mb.rd_thresh_mult[i] = 128; } -#ifdef VP8_ENTROPY_STATS - init_mv_ref_counts(); -#endif - #if CONFIG_MULTITHREAD if (vp8cx_create_encoder_threads(cpi)) { vp8_remove_compressor(&cpi); @@ -2120,12 +2106,6 @@ void vp8_remove_compressor(VP8_COMP **comp) { #endif -#ifdef VP8_ENTROPY_STATS - print_context_counters(); - print_tree_update_probs(); - print_mode_context(); -#endif - #if CONFIG_INTERNAL_STATS if (cpi->pass != 1) { @@ -2252,40 +2232,6 @@ void vp8_remove_compressor(VP8_COMP **comp) { } #endif -#ifdef VP8_ENTROPY_STATS - { - int i, j, k; - FILE *fmode = fopen("modecontext.c", "w"); - - fprintf(fmode, "\n#include \"entropymode.h\"\n\n"); - fprintf(fmode, "const unsigned int vp8_kf_default_bmode_counts "); - fprintf(fmode, - "[VP8_BINTRAMODES] [VP8_BINTRAMODES] [VP8_BINTRAMODES] =\n{\n"); - - for (i = 0; i < 10; ++i) { - fprintf(fmode, " { /* Above Mode : %d */\n", i); - - for (j = 0; j < 10; ++j) { - fprintf(fmode, " {"); - - for (k = 0; k < 10; ++k) { - if (!intra_mode_stats[i][j][k]) - fprintf(fmode, " %5d, ", 1); - else - fprintf(fmode, " %5d, ", intra_mode_stats[i][j][k]); - } - - fprintf(fmode, "}, /* left_mode %d */\n", j); - } - - fprintf(fmode, " },\n"); - } - - fprintf(fmode, "};\n"); - fclose(fmode); - } -#endif - #if defined(SECTIONBITS_OUTPUT) if (0) { diff --git a/vp8/encoder/ratectrl.c b/vp8/encoder/ratectrl.c index fc833bccc..ce07a6f19 100644 --- a/vp8/encoder/ratectrl.c +++ b/vp8/encoder/ratectrl.c @@ -1464,7 +1464,7 @@ int vp8_drop_encodedframe_overshoot(VP8_COMP *cpi, int Q) { (cpi->oxcf.screen_content_mode == 2 || (cpi->drop_frames_allowed && (force_drop_overshoot || - (cpi->rate_correction_factor < (4.0f * MIN_BPB_FACTOR) && + (cpi->rate_correction_factor < (8.0f * MIN_BPB_FACTOR) && cpi->frames_since_last_drop_overshoot > (int)cpi->framerate))))) { // Note: the "projected_frame_size" from encode_frame() only gives estimate // of mode/motion vector rate (in non-rd mode): so below we only require diff --git a/vp8/encoder/tokenize.c b/vp8/encoder/tokenize.c index ca5f0e3d8..c3d702660 100644 --- a/vp8/encoder/tokenize.c +++ b/vp8/encoder/tokenize.c @@ -19,10 +19,6 @@ /* Global event counters used for accumulating statistics across several compressions, then generating context.c = initial stats. */ -#ifdef VP8_ENTROPY_STATS -_int64 context_counters[BLOCK_TYPES][COEF_BANDS][PREV_COEF_CONTEXTS] - [MAX_ENTROPY_TOKENS]; -#endif void vp8_stuff_mb(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t); void vp8_fix_contexts(MACROBLOCKD *x); @@ -383,72 +379,6 @@ void vp8_tokenize_mb(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t) { tokenize1st_order_b(x, t, plane_type, cpi); } -#ifdef VP8_ENTROPY_STATS - -void init_context_counters(void) { - memset(context_counters, 0, sizeof(context_counters)); -} - -void print_context_counters() { - int type, band, pt, t; - - FILE *const f = fopen("context.c", "w"); - - fprintf(f, "#include \"entropy.h\"\n"); - - fprintf(f, "\n/* *** GENERATED FILE: DO NOT EDIT *** */\n\n"); - - fprintf(f, - "int Contexts[BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] " - "[MAX_ENTROPY_TOKENS];\n\n"); - - fprintf(f, - "const int default_contexts[BLOCK_TYPES] [COEF_BANDS] " - "[PREV_COEF_CONTEXTS] [MAX_ENTROPY_TOKENS] = {"); - -#define Comma(X) (X ? "," : "") - - type = 0; - - do { - fprintf(f, "%s\n { /* block Type %d */", Comma(type), type); - - band = 0; - - do { - fprintf(f, "%s\n { /* Coeff Band %d */", Comma(band), band); - - pt = 0; - - do { - fprintf(f, "%s\n {", Comma(pt)); - - t = 0; - - do { - const _int64 x = context_counters[type][band][pt][t]; - const int y = (int)x; - - assert(x == (_int64)y); /* no overflow handling yet */ - fprintf(f, "%s %d", Comma(t), y); - - } while (++t < MAX_ENTROPY_TOKENS); - - fprintf(f, "}"); - } while (++pt < PREV_COEF_CONTEXTS); - - fprintf(f, "\n }"); - - } while (++band < COEF_BANDS); - - fprintf(f, "\n }"); - } while (++type < BLOCK_TYPES); - - fprintf(f, "\n};\n"); - fclose(f); -} -#endif - static void stuff2nd_order_b(TOKENEXTRA **tp, ENTROPY_CONTEXT *a, ENTROPY_CONTEXT *l, VP8_COMP *cpi, MACROBLOCK *x) { int pt; /* near block/prev token context index */ diff --git a/vp8/encoder/tokenize.h b/vp8/encoder/tokenize.h index 46425ac8f..47b5be17f 100644 --- a/vp8/encoder/tokenize.h +++ b/vp8/encoder/tokenize.h @@ -34,14 +34,6 @@ typedef struct { int rd_cost_mby(MACROBLOCKD *); -#ifdef VP8_ENTROPY_STATS -void init_context_counters(); -void print_context_counters(); - -extern _int64 context_counters[BLOCK_TYPES][COEF_BANDS][PREV_COEF_CONTEXTS] - [MAX_ENTROPY_TOKENS]; -#endif - extern const short *const vp8_dct_value_cost_ptr; /* TODO: The Token field should be broken out into a separate char array to * improve cache locality, since it's needed for costing when the rest of the diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index fb25fbc5c..4aae37706 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -1378,6 +1378,20 @@ static int choose_partitioning(VP9_COMP *cpi, const TileInfo *const tile, x->sb_use_mv_part = 1; x->sb_mvcol_part = mi->mv[0].as_mv.col; x->sb_mvrow_part = mi->mv[0].as_mv.row; + if (cpi->oxcf.content == VP9E_CONTENT_SCREEN && + cpi->svc.spatial_layer_id == 0 && + cpi->rc.high_num_blocks_with_motion && !x->zero_temp_sad_source && + cm->width >= 1280 && cm->height >= 720) { + // Disable split below 16x16 block size when scroll motion is detected. + // TODO(marpan/jianj): Improve this condition: issue is that search + // range is hard-coded/limited in vp9_int_pro_motion_estimation() so + // scroll motion may not be detected here. + if ((abs(x->sb_mvrow_part) >= 48 && abs(x->sb_mvcol_part) <= 8) || + y_sad < 100000) { + compute_minmax_variance = 0; + thresholds[2] = INT64_MAX; + } + } } y_sad_last = y_sad; diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index fad492de7..40c7a626e 100644 --- a/vp9/encoder/vp9_encoder.c +++ b/vp9/encoder/vp9_encoder.c @@ -3488,6 +3488,11 @@ static void set_size_dependent_vars(VP9_COMP *cpi, int *q, int *bottom_index, // Decide q and q bounds. *q = vp9_rc_pick_q_and_bounds(cpi, bottom_index, top_index); + if (cpi->oxcf.rc_mode == VPX_CBR && cpi->rc.force_max_q) { + *q = cpi->rc.worst_quality; + cpi->rc.force_max_q = 0; + } + if (!frame_is_intra_only(cm)) { vp9_set_high_precision_mv(cpi, (*q) < HIGH_PRECISION_MV_QTHRESH); } @@ -3693,6 +3698,7 @@ static int encode_without_recode_loop(VP9_COMP *cpi, size_t *size, uint8_t *dest) { VP9_COMMON *const cm = &cpi->common; int q = 0, bottom_index = 0, top_index = 0; + int no_drop_scene_change = 0; const INTERP_FILTER filter_scaler = (is_one_pass_cbr_svc(cpi)) ? cpi->svc.downsample_filter_type[cpi->svc.spatial_layer_id] @@ -3823,9 +3829,11 @@ static int encode_without_recode_loop(VP9_COMP *cpi, size_t *size, // For 1 pass CBR, check if we are dropping this frame. // Never drop on key frame, if base layer is key for svc, // on scene change, or if superframe has layer sync. + if ((cpi->rc.high_source_sad || cpi->svc.high_source_sad_superframe) && + !(cpi->rc.use_post_encode_drop && cpi->svc.last_layer_dropped[0])) + no_drop_scene_change = 1; if (cpi->oxcf.pass == 0 && cpi->oxcf.rc_mode == VPX_CBR && - !frame_is_intra_only(cm) && !cpi->rc.high_source_sad && - !cpi->svc.high_source_sad_superframe && + !frame_is_intra_only(cm) && !no_drop_scene_change && !cpi->svc.superframe_has_layer_sync && (!cpi->use_svc || !cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame)) { @@ -3863,6 +3871,12 @@ static int encode_without_recode_loop(VP9_COMP *cpi, size_t *size, cpi->use_skin_detection = 1; } + // Enable post encode frame dropping for CBR on non key frame, when + // ext_use_post_encode_drop is specified by user. + cpi->rc.use_post_encode_drop = cpi->rc.ext_use_post_encode_drop && + cpi->oxcf.rc_mode == VPX_CBR && + cm->frame_type != KEY_FRAME; + vp9_set_quantizer(cm, q); vp9_set_variance_partition_thresholds(cpi, q, 0); @@ -3877,6 +3891,14 @@ static int encode_without_recode_loop(VP9_COMP *cpi, size_t *size, vp9_svc_assert_constraints_pattern(cpi); } + if (cpi->rc.last_post_encode_dropped_scene_change) { + cpi->rc.high_source_sad = 1; + cpi->svc.high_source_sad_superframe = 1; + // For now disable use_source_sad since Last_Source will not be the previous + // encoded but the dropped one. + cpi->sf.use_source_sad = 0; + cpi->rc.last_post_encode_dropped_scene_change = 0; + } // Check if this high_source_sad (scene/slide change) frame should be // encoded at high/max QP, and if so, set the q and adjust some rate // control parameters. @@ -4751,19 +4773,6 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, size_t *size, cm->ref_frame_map[cpi->alt_fb_idx]); } - cpi->last_frame_dropped = 0; - cpi->svc.last_layer_dropped[cpi->svc.spatial_layer_id] = 0; - // Keep track of the frame buffer index updated/refreshed for the - // current encoded TL0 superframe. - if (cpi->svc.temporal_layer_id == 0) { - if (cpi->refresh_last_frame) - cpi->svc.fb_idx_upd_tl0[cpi->svc.spatial_layer_id] = cpi->lst_fb_idx; - else if (cpi->refresh_golden_frame) - cpi->svc.fb_idx_upd_tl0[cpi->svc.spatial_layer_id] = cpi->gld_fb_idx; - else if (cpi->refresh_alt_ref_frame) - cpi->svc.fb_idx_upd_tl0[cpi->svc.spatial_layer_id] = cpi->alt_fb_idx; - } - // Disable segmentation if it decrease rate/distortion ratio if (cpi->oxcf.aq_mode == LOOKAHEAD_AQ) vp9_try_disable_lookahead_aq(cpi, size, dest); @@ -4810,9 +4819,31 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, size_t *size, // Pick the loop filter level for the frame. loopfilter_frame(cpi, cm); + if (cpi->rc.use_post_encode_drop) save_coding_context(cpi); + // build the bitstream vp9_pack_bitstream(cpi, dest, size); + if (cpi->rc.use_post_encode_drop && cm->base_qindex < cpi->rc.worst_quality && + cpi->svc.spatial_layer_id == 0 && + post_encode_drop_screen_content(cpi, size)) { + restore_coding_context(cpi); + return; + } + + cpi->last_frame_dropped = 0; + cpi->svc.last_layer_dropped[cpi->svc.spatial_layer_id] = 0; + // Keep track of the frame buffer index updated/refreshed for the + // current encoded TL0 superframe. + if (cpi->svc.temporal_layer_id == 0) { + if (cpi->refresh_last_frame) + cpi->svc.fb_idx_upd_tl0[cpi->svc.spatial_layer_id] = cpi->lst_fb_idx; + else if (cpi->refresh_golden_frame) + cpi->svc.fb_idx_upd_tl0[cpi->svc.spatial_layer_id] = cpi->gld_fb_idx; + else if (cpi->refresh_alt_ref_frame) + cpi->svc.fb_idx_upd_tl0[cpi->svc.spatial_layer_id] = cpi->alt_fb_idx; + } + if (cm->seg.update_map) update_reference_segmentation_map(cpi); if (frame_is_intra_only(cm) == 0) { diff --git a/vp9/encoder/vp9_firstpass.c b/vp9/encoder/vp9_firstpass.c index 66e6aebd2..8e8c8f7fa 100644 --- a/vp9/encoder/vp9_firstpass.c +++ b/vp9/encoder/vp9_firstpass.c @@ -1825,10 +1825,12 @@ static int detect_flash(const TWO_PASS *twopass, int offset) { // brief break in prediction (such as a flash) but subsequent frames // are reasonably well predicted by an earlier (pre flash) frame. // The recovery after a flash is indicated by a high pcnt_second_ref - // compared to pcnt_inter. + // useage or a second ref coded error notabley lower than the last + // frame coded error. return next_frame != NULL && - next_frame->pcnt_second_ref > next_frame->pcnt_inter && - next_frame->pcnt_second_ref >= 0.5; + ((next_frame->sr_coded_error < next_frame->coded_error) || + ((next_frame->pcnt_second_ref > next_frame->pcnt_inter) && + (next_frame->pcnt_second_ref >= 0.5))); } // Update the motion related elements to the GF arf boost calculation. @@ -2544,17 +2546,17 @@ static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) { &next_frame, &this_frame_mv_in_out, &mv_in_out_accumulator, &abs_mv_in_out_accumulator, &mv_ratio_accumulator); + // Monitor for static sections. + if ((rc->frames_since_key + i - 1) > 1) { + zero_motion_accumulator = VPXMIN( + zero_motion_accumulator, get_zero_motion_factor(cpi, &next_frame)); + } + // Accumulate the effect of prediction quality decay. if (!flash_detected) { last_loop_decay_rate = loop_decay_rate; loop_decay_rate = get_prediction_decay_rate(cpi, &next_frame); - // Monitor for static sections. - if ((rc->frames_since_key + i - 1) > 1) { - zero_motion_accumulator = VPXMIN( - zero_motion_accumulator, get_zero_motion_factor(cpi, &next_frame)); - } - // Break clause to detect very still sections after motion. For example, // a static image after a fade or other transition. if (detect_transition_to_still(cpi, i, 5, loop_decay_rate, @@ -2725,17 +2727,11 @@ static int slide_transition(const FIRSTPASS_STATS *this_frame, (this_frame->coded_error > (next_frame->coded_error * ERROR_SPIKE)); } -// Threshold for use of the lagging second reference frame. High second ref -// usage may point to a transient event like a flash or occlusion rather than -// a real scene cut. -#define SECOND_REF_USEAGE_THRESH 0.1 // Minimum % intra coding observed in first pass (1.0 = 100%) #define MIN_INTRA_LEVEL 0.25 -// Minimum ratio between the % of intra coding and inter coding in the first -// pass after discounting neutral blocks (discounting neutral blocks in this -// way helps catch scene cuts in clips with very flat areas or letter box -// format clips with image padding. -#define INTRA_VS_INTER_THRESH 2.0 +// Threshold for use of the lagging second reference frame. Scene cuts do not +// usually have a high second ref useage. +#define SECOND_REF_USEAGE_THRESH 0.125 // Hard threshold where the first pass chooses intra for almost all blocks. // In such a case even if the frame is not a scene cut coding a key frame // may be a good option. @@ -2743,12 +2739,6 @@ static int slide_transition(const FIRSTPASS_STATS *this_frame, // Maximum threshold for the relative ratio of intra error score vs best // inter error score. #define KF_II_ERR_THRESHOLD 2.5 -// In real scene cuts there is almost always a sharp change in the intra -// or inter error score. -#define ERR_CHANGE_THRESHOLD 0.4 -// For real scene cuts we expect an improvment in the intra inter error -// ratio in the next frame. -#define II_IMPROVEMENT_THRESHOLD 3.5 #define KF_II_MAX 128.0 #define II_FACTOR 12.5 // Test for very low intra complexity which could cause false key frames @@ -2760,30 +2750,21 @@ static int test_candidate_kf(TWO_PASS *twopass, const FIRSTPASS_STATS *next_frame) { int is_viable_kf = 0; double pcnt_intra = 1.0 - this_frame->pcnt_inter; - double modified_pcnt_inter = - this_frame->pcnt_inter - this_frame->pcnt_neutral; // Does the frame satisfy the primary criteria of a key frame? // See above for an explanation of the test criteria. // If so, then examine how well it predicts subsequent frames. - if ((this_frame->pcnt_second_ref < SECOND_REF_USEAGE_THRESH) && - (next_frame->pcnt_second_ref < SECOND_REF_USEAGE_THRESH) && + if (!detect_flash(twopass, -1) && !detect_flash(twopass, 0) && + (this_frame->pcnt_second_ref < SECOND_REF_USEAGE_THRESH) && ((this_frame->pcnt_inter < VERY_LOW_INTER_THRESH) || (slide_transition(this_frame, last_frame, next_frame)) || - ((pcnt_intra > MIN_INTRA_LEVEL) && - (pcnt_intra > (INTRA_VS_INTER_THRESH * modified_pcnt_inter)) && + (((this_frame->coded_error > (next_frame->coded_error * 1.1)) && + (this_frame->coded_error > (last_frame->coded_error * 1.1))) && + (pcnt_intra > MIN_INTRA_LEVEL) && + ((pcnt_intra + this_frame->pcnt_neutral) > 0.5) && ((this_frame->intra_error / DOUBLE_DIVIDE_CHECK(this_frame->coded_error)) < - KF_II_ERR_THRESHOLD) && - ((fabs(last_frame->coded_error - this_frame->coded_error) / - DOUBLE_DIVIDE_CHECK(this_frame->coded_error) > - ERR_CHANGE_THRESHOLD) || - (fabs(last_frame->intra_error - this_frame->intra_error) / - DOUBLE_DIVIDE_CHECK(this_frame->intra_error) > - ERR_CHANGE_THRESHOLD) || - ((next_frame->intra_error / - DOUBLE_DIVIDE_CHECK(next_frame->coded_error)) > - II_IMPROVEMENT_THRESHOLD))))) { + KF_II_ERR_THRESHOLD)))) { int i; const FIRSTPASS_STATS *start_pos = twopass->stats_in; FIRSTPASS_STATS local_next_frame = *next_frame; @@ -3224,9 +3205,9 @@ void vp9_rc_get_second_pass_params(VP9_COMP *cpi) { FILE *fpfile; fpfile = fopen("arf.stt", "a"); ++arf_count; - fprintf(fpfile, "%10d %10ld %10d %10d %10ld\n", cm->current_video_frame, - rc->frames_till_gf_update_due, rc->kf_boost, arf_count, - rc->gfu_boost); + fprintf(fpfile, "%10d %10ld %10d %10d %10ld %10ld\n", + cm->current_video_frame, rc->frames_till_gf_update_due, + rc->kf_boost, arf_count, rc->gfu_boost, cm->frame_type); fclose(fpfile); } diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c index c8931ae82..360e546e5 100644 --- a/vp9/encoder/vp9_ratectrl.c +++ b/vp9/encoder/vp9_ratectrl.c @@ -363,6 +363,7 @@ void vp9_rc_init(const VP9EncoderConfig *oxcf, int pass, RATE_CONTROL *rc) { rc->high_source_sad = 0; rc->reset_high_source_sad = 0; rc->high_source_sad_lagindex = -1; + rc->high_num_blocks_with_motion = 0; rc->hybrid_intra_scene_change = 0; rc->re_encode_maxq_scene_change = 0; rc->alt_ref_gf_group = 0; @@ -398,6 +399,11 @@ void vp9_rc_init(const VP9EncoderConfig *oxcf, int pass, RATE_CONTROL *rc) { rc->max_gf_interval = vp9_rc_get_default_max_gf_interval( oxcf->init_framerate, rc->min_gf_interval); rc->baseline_gf_interval = (rc->min_gf_interval + rc->max_gf_interval) / 2; + + rc->force_max_q = 0; + rc->last_post_encode_dropped_scene_change = 0; + rc->use_post_encode_drop = 0; + rc->ext_use_post_encode_drop = 0; } static int check_buffer_above_thresh(VP9_COMP *cpi, int drop_mark) { @@ -515,6 +521,39 @@ static int drop_frame(VP9_COMP *cpi) { } } +int post_encode_drop_screen_content(VP9_COMP *cpi, size_t *size) { + size_t frame_size = *size << 3; + int64_t new_buffer_level = + cpi->rc.buffer_level + cpi->rc.avg_frame_bandwidth - (int64_t)frame_size; + + // For now we drop if new buffer level (given the encoded frame size) goes + // below 0. + if (new_buffer_level < 0) { + *size = 0; + vp9_rc_postencode_update_drop_frame(cpi); + // Update flag to use for next frame. + if (cpi->rc.high_source_sad || + (cpi->use_svc && cpi->svc.high_source_sad_superframe)) + cpi->rc.last_post_encode_dropped_scene_change = 1; + // Force max_q on next fame. + cpi->rc.force_max_q = 1; + cpi->rc.avg_frame_qindex[INTER_FRAME] = cpi->rc.worst_quality; + cpi->last_frame_dropped = 1; + cpi->ext_refresh_frame_flags_pending = 0; + if (cpi->use_svc) { + cpi->svc.last_layer_dropped[cpi->svc.spatial_layer_id] = 1; + cpi->svc.drop_spatial_layer[cpi->svc.spatial_layer_id] = 1; + cpi->svc.drop_count[cpi->svc.spatial_layer_id]++; + cpi->svc.skip_enhancement_layer = 1; + } + return 1; + } + + cpi->rc.force_max_q = 0; + cpi->rc.last_post_encode_dropped_scene_change = 0; + return 0; +} + int vp9_rc_drop_frame(VP9_COMP *cpi) { SVC *svc = &cpi->svc; int svc_prev_layer_dropped = 0; @@ -834,7 +873,7 @@ static int calc_active_worst_quality_one_pass_cbr(const VP9_COMP *cpi) { int active_worst_quality; int ambient_qp; unsigned int num_frames_weight_key = 5 * cpi->svc.number_temporal_layers; - if (frame_is_intra_only(cm) || rc->reset_high_source_sad) + if (frame_is_intra_only(cm) || rc->reset_high_source_sad || rc->force_max_q) return rc->worst_quality; // For ambient_qp we use minimum of avg_frame_qindex[KEY_FRAME/INTER_FRAME] // for the first few frames following key frame. These are both initialized @@ -2670,6 +2709,7 @@ void vp9_scene_detection_onepass(VP9_COMP *cpi) { if (cm->use_highbitdepth) return; #endif rc->high_source_sad = 0; + rc->high_num_blocks_with_motion = 0; if (cpi->svc.spatial_layer_id == 0 && src_width == last_src_width && src_height == last_src_height) { YV12_BUFFER_CONFIG *frames[MAX_LAG_BUFFERS] = { NULL }; @@ -2788,6 +2828,8 @@ void vp9_scene_detection_onepass(VP9_COMP *cpi) { } else { rc->avg_source_sad[lagframe_idx] = avg_sad; } + if (num_zero_temp_sad < (num_samples >> 1)) + rc->high_num_blocks_with_motion = 1; } } // For CBR non-screen content mode, check if we should reset the rate diff --git a/vp9/encoder/vp9_ratectrl.h b/vp9/encoder/vp9_ratectrl.h index a9f75555e..16aa08137 100644 --- a/vp9/encoder/vp9_ratectrl.h +++ b/vp9/encoder/vp9_ratectrl.h @@ -175,6 +175,7 @@ typedef struct { uint64_t avg_source_sad[MAX_LAG_BUFFERS]; uint64_t prev_avg_source_sad_lag; int high_source_sad_lagindex; + int high_num_blocks_with_motion; int alt_ref_gf_group; int last_frame_is_src_altref; int high_source_sad; @@ -186,6 +187,14 @@ typedef struct { int force_qpmin; int reset_high_source_sad; double perc_arf_usage; + int force_max_q; + // Last frame was dropped post encode on scene change. + int last_post_encode_dropped_scene_change; + // Enable post encode frame dropping for screen content. Only enabled when + // ext_use_post_encode_drop is enabled by user. + int use_post_encode_drop; + // External flag to enable post encode frame dropping, controlled by user. + int ext_use_post_encode_drop; } RATE_CONTROL; struct VP9_COMP; @@ -247,6 +256,9 @@ void vp9_rc_postencode_update_drop_frame(struct VP9_COMP *cpi); // Changes only the rate correction factors in the rate control structure. void vp9_rc_update_rate_correction_factors(struct VP9_COMP *cpi); +// Post encode drop for CBR screen-content mode. +int post_encode_drop_screen_content(struct VP9_COMP *cpi, size_t *size); + // Decide if we should drop this frame: For 1-pass CBR. // Changes only the decimation count in the rate control structure int vp9_rc_drop_frame(struct VP9_COMP *cpi); diff --git a/vp9/encoder/vp9_speed_features.c b/vp9/encoder/vp9_speed_features.c index 1f9044265..2b0d5e146 100644 --- a/vp9/encoder/vp9_speed_features.c +++ b/vp9/encoder/vp9_speed_features.c @@ -794,6 +794,13 @@ static void set_rt_speed_feature_framesize_independent( sf->partition_search_type = FIXED_PARTITION; sf->always_this_block_size = BLOCK_64X64; } + // Special case for screen content: increase motion search when high motion + // is detected. + if (cpi->oxcf.content == VP9E_CONTENT_SCREEN && cpi->oxcf.speed > 5 && + cpi->rc.high_num_blocks_with_motion && cpi->svc.spatial_layer_id == 0) { + sf->mv.search_method = NSTEP; + sf->mv.fullpel_search_step_param = 2; + } } void vp9_set_speed_features_framesize_dependent(VP9_COMP *cpi) { diff --git a/vp9/encoder/vp9_svc_layercontext.c b/vp9/encoder/vp9_svc_layercontext.c index 1321c4575..7cab7ffb2 100644 --- a/vp9/encoder/vp9_svc_layercontext.c +++ b/vp9/encoder/vp9_svc_layercontext.c @@ -329,6 +329,7 @@ void vp9_restore_layer_context(VP9_COMP *const cpi) { LAYER_CONTEXT *const lc = get_layer_context(cpi); const int old_frame_since_key = cpi->rc.frames_since_key; const int old_frame_to_key = cpi->rc.frames_to_key; + const int old_ext_use_post_encode_drop = cpi->rc.ext_use_post_encode_drop; cpi->rc = lc->rc; cpi->twopass = lc->twopass; @@ -346,7 +347,7 @@ void vp9_restore_layer_context(VP9_COMP *const cpi) { cpi->rc.frames_since_key = old_frame_since_key; cpi->rc.frames_to_key = old_frame_to_key; } - + cpi->rc.ext_use_post_encode_drop = old_ext_use_post_encode_drop; // For spatial-svc, allow cyclic-refresh to be applied on the spatial layers, // for the base temporal layer. if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c index efe23e33d..0cc639572 100644 --- a/vp9/vp9_cx_iface.c +++ b/vp9/vp9_cx_iface.c @@ -1625,6 +1625,14 @@ static vpx_codec_err_t ctrl_set_render_size(vpx_codec_alg_priv_t *ctx, return update_extra_cfg(ctx, &extra_cfg); } +static vpx_codec_err_t ctrl_set_postencode_drop(vpx_codec_alg_priv_t *ctx, + va_list args) { + VP9_COMP *const cpi = ctx->cpi; + const unsigned int data = va_arg(args, unsigned int); + cpi->rc.ext_use_post_encode_drop = data; + return VPX_CODEC_OK; +} + static vpx_codec_ctrl_fn_map_t encoder_ctrl_maps[] = { { VP8_COPY_REFERENCE, ctrl_copy_reference }, @@ -1668,6 +1676,7 @@ static vpx_codec_ctrl_fn_map_t encoder_ctrl_maps[] = { { VP9E_SET_RENDER_SIZE, ctrl_set_render_size }, { VP9E_SET_TARGET_LEVEL, ctrl_set_target_level }, { VP9E_SET_ROW_MT, ctrl_set_row_mt }, + { VP9E_SET_POSTENCODE_DROP, ctrl_set_postencode_drop }, { VP9E_ENABLE_MOTION_VECTOR_UNIT_TEST, ctrl_enable_motion_vector_unit_test }, { VP9E_SET_SVC_INTER_LAYER_PRED, ctrl_set_svc_inter_layer_pred }, { VP9E_SET_SVC_FRAME_DROP_LAYER, ctrl_set_svc_frame_drop_layer }, diff --git a/vpx/vp8cx.h b/vpx/vp8cx.h index 1692028ea..2f54223ca 100644 --- a/vpx/vp8cx.h +++ b/vpx/vp8cx.h @@ -660,6 +660,16 @@ enum vp8e_enc_control_id { * 1. The default value is set to be 1. */ VP9E_SET_TPL, + + /*!\brief Codec control function to enable postencode frame drop. + * + * This will allow encoder to drop frame after it's encoded. + * + * 0: Off (default), 1: Enabled + * + * Supported in codecs: VP9 + */ + VP9E_SET_POSTENCODE_DROP, }; /*!\brief vpx 1-D scaling mode |