summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--test/acm_random.h6
-rw-r--r--test/hadamard_test.cc284
-rw-r--r--test/svc_datarate_test.cc83
-rw-r--r--test/vp9_datarate_test.cc50
-rw-r--r--vp8/decoder/threading.c18
-rw-r--r--vp8/encoder/bitstream.c124
-rw-r--r--vp8/encoder/boolhuff.c4
-rw-r--r--vp8/encoder/boolhuff.h11
-rw-r--r--vp8/encoder/encodemv.c11
-rw-r--r--vp8/encoder/mcomp.c98
-rw-r--r--vp8/encoder/mcomp.h6
-rw-r--r--vp8/encoder/onyx_if.c54
-rw-r--r--vp8/encoder/ratectrl.c2
-rw-r--r--vp8/encoder/tokenize.c70
-rw-r--r--vp8/encoder/tokenize.h8
-rw-r--r--vp9/encoder/vp9_encodeframe.c14
-rw-r--r--vp9/encoder/vp9_encoder.c61
-rw-r--r--vp9/encoder/vp9_firstpass.c67
-rw-r--r--vp9/encoder/vp9_ratectrl.c44
-rw-r--r--vp9/encoder/vp9_ratectrl.h12
-rw-r--r--vp9/encoder/vp9_speed_features.c7
-rw-r--r--vp9/encoder/vp9_svc_layercontext.c3
-rw-r--r--vp9/vp9_cx_iface.c9
-rw-r--r--vpx/vp8cx.h10
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