Bug fixes to only use rec_sse in CBR mode.
cpi->rec_sse is only calculated in AOM_CBR mode, such that we gate the
usage of it in AOM_CBR mode only.
BUG=b/310457427
BUG=b/310766628
Change-Id: Ic1185f968759eb3ec55f52645cab814dfa63430d
(cherry picked from commit 57a8fff10cc3e5fc429a35c1dad1bf063a151cb3)
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index de0f596..83c5944 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -187,7 +187,8 @@
assert(correction_factor <= MAX_BPB_FACTOR &&
correction_factor >= MIN_BPB_FACTOR);
- if (frame_type != KEY_FRAME && accurate_estimate) {
+ if (cpi->oxcf.rc_cfg.mode == AOM_CBR && frame_type != KEY_FRAME &&
+ accurate_estimate) {
assert(cpi->rec_sse != UINT64_MAX);
const int mbs = cm->mi_params.MBs;
const double sse_sqrt =
@@ -2247,7 +2248,8 @@
av1_rc_update_rate_correction_factors(cpi, 0, cm->width, cm->height);
// Update bit estimation ratio.
- if (cm->current_frame.frame_type != KEY_FRAME &&
+ if (cpi->oxcf.rc_cfg.mode == AOM_CBR &&
+ cm->current_frame.frame_type != KEY_FRAME &&
cpi->sf.hl_sf.accurate_bit_estimate) {
const double q = av1_convert_qindex_to_q(cm->quant_params.base_qindex,
cm->seq_params->bit_depth);
diff --git a/test/encode_api_test.cc b/test/encode_api_test.cc
index e6ef4c2..07b2fc8 100644
--- a/test/encode_api_test.cc
+++ b/test/encode_api_test.cc
@@ -303,6 +303,191 @@
ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK);
}
+aom_image_t *CreateGrayImage(aom_img_fmt_t fmt, unsigned int w,
+ unsigned int h) {
+ aom_image_t *const image = aom_img_alloc(nullptr, fmt, w, h, 1);
+ if (!image) return image;
+
+ for (unsigned int i = 0; i < image->d_h; ++i) {
+ memset(image->planes[0] + i * image->stride[0], 128, image->d_w);
+ }
+ const unsigned int uv_h = (image->d_h + 1) / 2;
+ const unsigned int uv_w = (image->d_w + 1) / 2;
+ for (unsigned int i = 0; i < uv_h; ++i) {
+ memset(image->planes[1] + i * image->stride[1], 128, uv_w);
+ memset(image->planes[2] + i * image->stride[2], 128, uv_w);
+ }
+ return image;
+}
+
+// Run this test to reproduce the bug in fuzz test: ASSERT: cpi->rec_sse !=
+// UINT64_MAX in av1_rc_bits_per_mb.
+TEST(EncodeAPI, Buganizer310766628) {
+ aom_codec_iface_t *const iface = aom_codec_av1_cx();
+ aom_codec_enc_cfg_t cfg;
+
+ struct Config {
+ unsigned int thread;
+ unsigned int width;
+ unsigned int height;
+ aom_rc_mode end_usage;
+ };
+
+ struct Config init_config = { 16, 759, 383, AOM_CBR };
+ const unsigned int usage = AOM_USAGE_REALTIME;
+ ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, usage), AOM_CODEC_OK);
+
+ cfg.g_threads = init_config.thread;
+ cfg.g_w = init_config.width;
+ cfg.g_h = init_config.height;
+ cfg.g_timebase.num = 1;
+ cfg.g_timebase.den = 1000 * 1000; // microseconds
+ cfg.g_pass = AOM_RC_ONE_PASS;
+ cfg.g_lag_in_frames = 0;
+ cfg.rc_end_usage = init_config.end_usage;
+ cfg.rc_min_quantizer = 2;
+ cfg.rc_max_quantizer = 58;
+
+ aom_codec_ctx_t enc;
+ const int speed = 7;
+ ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AOME_SET_CPUUSED, speed), AOM_CODEC_OK);
+
+ const aom_enc_frame_flags_t flags = 0;
+ int frame_index = 0;
+
+ // Encode a frame.
+ aom_image_t *image = CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h);
+ ASSERT_NE(image, nullptr);
+ ASSERT_EQ(aom_codec_encode(&enc, image, frame_index, 1, flags), AOM_CODEC_OK);
+ frame_index++;
+ const aom_codec_cx_pkt_t *pkt;
+ aom_codec_iter_t iter = nullptr;
+ while ((pkt = aom_codec_get_cx_data(&enc, &iter)) != nullptr) {
+ ASSERT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
+ }
+ aom_img_free(image);
+
+ struct Config encode_config = { 2, 759, 383, AOM_VBR };
+
+ cfg.g_threads = encode_config.thread;
+ cfg.g_w = encode_config.width;
+ cfg.g_h = encode_config.height;
+ cfg.rc_end_usage = encode_config.end_usage;
+
+ ASSERT_EQ(aom_codec_enc_config_set(&enc, &cfg), AOM_CODEC_OK)
+ << aom_codec_error_detail(&enc);
+
+ // Encode a frame. This will trigger the assertion failure.
+ image = CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h);
+ ASSERT_NE(image, nullptr);
+ ASSERT_EQ(aom_codec_encode(&enc, image, frame_index, 1, flags), AOM_CODEC_OK);
+ frame_index++;
+ iter = nullptr;
+ while ((pkt = aom_codec_get_cx_data(&enc, &iter)) != nullptr) {
+ ASSERT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
+ }
+ aom_img_free(image);
+
+ // Flush the encoder.
+ bool got_data;
+ do {
+ ASSERT_EQ(aom_codec_encode(&enc, nullptr, 0, 0, 0), AOM_CODEC_OK);
+ got_data = false;
+ iter = nullptr;
+ while ((pkt = aom_codec_get_cx_data(&enc, &iter)) != nullptr) {
+ ASSERT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
+ got_data = true;
+ }
+ } while (got_data);
+
+ ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK);
+}
+
+// Run this test to reproduce the bug in fuzz test: Float-cast-overflow in
+// av1_rc_bits_per_mb.
+TEST(EncodeAPI, Buganizer310457427) {
+ aom_codec_iface_t *const iface = aom_codec_av1_cx();
+ aom_codec_enc_cfg_t cfg;
+
+ struct Config {
+ unsigned int thread;
+ unsigned int width;
+ unsigned int height;
+ aom_rc_mode end_usage;
+ };
+
+ struct Config init_config = { 12, 896, 1076, AOM_CBR };
+ const unsigned int usage = AOM_USAGE_REALTIME;
+ ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, usage), AOM_CODEC_OK);
+
+ cfg.g_threads = init_config.thread;
+ cfg.g_w = init_config.width;
+ cfg.g_h = init_config.height;
+ cfg.g_timebase.num = 1;
+ cfg.g_timebase.den = 1000 * 1000; // microseconds
+ cfg.g_pass = AOM_RC_ONE_PASS;
+ cfg.g_lag_in_frames = 0;
+ cfg.rc_end_usage = init_config.end_usage;
+ cfg.rc_min_quantizer = 2;
+ cfg.rc_max_quantizer = 58;
+
+ aom_codec_ctx_t enc;
+ const int speed = 7;
+ ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AOME_SET_CPUUSED, speed), AOM_CODEC_OK);
+
+ struct Config encode_config = { 6, 609, 1076, AOM_VBR };
+ cfg.g_threads = encode_config.thread;
+ cfg.g_w = encode_config.width;
+ cfg.g_h = encode_config.height;
+ cfg.rc_end_usage = encode_config.end_usage;
+
+ ASSERT_EQ(aom_codec_enc_config_set(&enc, &cfg), AOM_CODEC_OK)
+ << aom_codec_error_detail(&enc);
+
+ const aom_enc_frame_flags_t flags = 0;
+ int frame_index = 0;
+
+ // Encode a frame.
+ aom_image_t *image = CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h);
+ ASSERT_NE(image, nullptr);
+ ASSERT_EQ(aom_codec_encode(&enc, image, frame_index, 1, flags), AOM_CODEC_OK);
+ frame_index++;
+ const aom_codec_cx_pkt_t *pkt;
+ aom_codec_iter_t iter = nullptr;
+ while ((pkt = aom_codec_get_cx_data(&enc, &iter)) != nullptr) {
+ ASSERT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
+ }
+ aom_img_free(image);
+
+ // Encode a frame. This will trigger the float-cast-overflow bug which was
+ // caused by division by zero.
+ image = CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h);
+ ASSERT_NE(image, nullptr);
+ ASSERT_EQ(aom_codec_encode(&enc, image, frame_index, 1, flags), AOM_CODEC_OK);
+ frame_index++;
+ iter = nullptr;
+ while ((pkt = aom_codec_get_cx_data(&enc, &iter)) != nullptr) {
+ ASSERT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
+ }
+ aom_img_free(image);
+
+ // Flush the encoder.
+ bool got_data;
+ do {
+ ASSERT_EQ(aom_codec_encode(&enc, nullptr, 0, 0, 0), AOM_CODEC_OK);
+ got_data = false;
+ iter = nullptr;
+ while ((pkt = aom_codec_get_cx_data(&enc, &iter)) != nullptr) {
+ ASSERT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
+ got_data = true;
+ }
+ } while (got_data);
+
+ ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK);
+}
+
class EncodeAPIParameterized
: public testing::TestWithParam<std::tuple<
/*usage=*/unsigned int, /*speed=*/int, /*aq_mode=*/unsigned int>> {};