rtc: Fixes for resize when scalemode is used
Make sure sb_size is based on config width/height
(in case scalemode resize is done on first frame),
and add check in variance partition to avoid
computing variance when reference is different resoln.
Also add return in calculate_next_size_params when
not in superres mode, and fix to CBR rate control
on resize.
Added unittest for resize via scalemode.
Change-Id: I9421ee9efccd5094072bb89a5e909b44692fe665
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 1c9170c..a7984e5 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -252,8 +252,10 @@
assert(oxcf->superblock_size == AOM_SUPERBLOCK_SIZE_DYNAMIC);
- if (cpi->svc.number_spatial_layers > 1) {
- // Use the configured size (top resolution) for spatial layers.
+ if (cpi->svc.number_spatial_layers > 1 ||
+ oxcf->resize_cfg.resize_mode != RESIZE_NONE) {
+ // Use the configured size (top resolution) for spatial layers or
+ // on resize.
return AOMMIN(oxcf->frm_dim_cfg.width, oxcf->frm_dim_cfg.height) > 480
? BLOCK_128X128
: BLOCK_64X64;
@@ -4546,6 +4548,8 @@
resize_pending_params->width = (hs - 1 + oxcf->frm_dim_cfg.width * hr) / hs;
resize_pending_params->height = (vs - 1 + oxcf->frm_dim_cfg.height * vr) / vs;
+ if (horiz_mode != NORMAL || vert_mode != NORMAL)
+ oxcf->resize_cfg.resize_mode = RESIZE_FIXED;
return 0;
}
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index 43311f1..03b94dd 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -1638,10 +1638,11 @@
rc->this_frame_target = target;
// Modify frame size target when down-scaled.
- if (av1_frame_scaled(cm))
+ if (av1_frame_scaled(cm) && cpi->oxcf.rc_cfg.mode != AOM_CBR) {
rc->this_frame_target =
(int)(rc->this_frame_target *
resize_rate_factor(&cpi->oxcf.frm_dim_cfg, width, height));
+ }
// Target rate per SB64 (including partial SB64s.
rc->sb64_target_rate =
diff --git a/av1/encoder/superres_scale.c b/av1/encoder/superres_scale.c
index 2d79c95..7c6f840 100644
--- a/av1/encoder/superres_scale.c
+++ b/av1/encoder/superres_scale.c
@@ -359,6 +359,7 @@
rsz.resize_width = resize_pending_params->width;
rsz.resize_height = resize_pending_params->height;
resize_pending_params->width = resize_pending_params->height = 0;
+ if (oxcf->superres_cfg.superres_mode == AOM_SUPERRES_NONE) return rsz;
} else {
resize_denom = calculate_next_resize_scale(cpi);
rsz.resize_width = frm_dim_cfg->width;
diff --git a/av1/encoder/var_based_part.c b/av1/encoder/var_based_part.c
index d8fd4f4..6fc0c38 100644
--- a/av1/encoder/var_based_part.c
+++ b/av1/encoder/var_based_part.c
@@ -824,7 +824,7 @@
int sp;
int dp;
- const int is_key_frame =
+ int is_key_frame =
(frame_is_intra_only(cm) ||
(cpi->use_svc &&
cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame));
@@ -875,6 +875,21 @@
memset(x->part_search_info.variance_low, 0,
sizeof(x->part_search_info.variance_low));
+ // Check if LAST frame is NULL or if the resolution of LAST is
+ // different than the current frame resolution, and if so, treat this frame
+ // as a key frame, for the purpose of the superblock partitioning.
+ // LAST == NULL can happen in cases where enhancement spatial layers are
+ // enabled dyanmically and the only reference is the spatial(GOLDEN).
+ // TODO(marpan): Check se of scaled references for the different resoln.
+ if (!frame_is_intra_only(cm)) {
+ const YV12_BUFFER_CONFIG *const ref =
+ get_ref_frame_yv12_buf(cm, LAST_FRAME);
+ if (ref == NULL || ref->y_crop_height != cm->height ||
+ ref->y_crop_width != cm->width) {
+ is_key_frame = 1;
+ }
+ }
+
if (!is_key_frame) {
setup_planes(cpi, x, &y_sad, &y_sad_g, &ref_frame_partition, mi_row,
mi_col);
diff --git a/test/resize_test.cc b/test/resize_test.cc
index bcf6794..1c12715 100644
--- a/test/resize_test.cc
+++ b/test/resize_test.cc
@@ -19,6 +19,7 @@
#include "test/i420_video_source.h"
#include "test/video_source.h"
#include "test/util.h"
+#include "test/y4m_video_source.h"
// Enable(1) or Disable(0) writing of the compressed bitstream.
#define WRITE_COMPRESSED_STREAM 0
@@ -377,6 +378,16 @@
encoder->Control(AOME_SET_CPUUSED, set_cpu_used_);
encoder->Control(AV1E_SET_FRAME_PARALLEL_DECODING, 1);
}
+ if (set_scale_mode_) {
+ struct aom_scaling_mode mode;
+ if (video->frame() <= 20)
+ mode = { AOME_ONETWO, AOME_ONETWO };
+ else if (video->frame() <= 40)
+ mode = { AOME_ONEFOUR, AOME_ONEFOUR };
+ else if (video->frame() > 40)
+ mode = { AOME_NORMAL, AOME_NORMAL };
+ encoder->Control(AOME_SET_SCALEMODE, &mode);
+ }
if (change_bitrate_ && video->frame() == 120) {
change_bitrate_ = false;
@@ -426,6 +437,11 @@
// the width and height of the frame are swapped
cfg_.g_forced_max_frame_width = cfg_.g_forced_max_frame_height =
AOMMAX(kInitialWidth, kInitialHeight);
+ if (set_scale_mode_) {
+ cfg_.rc_dropframe_thresh = 0;
+ cfg_.g_forced_max_frame_width = 1280;
+ cfg_.g_forced_max_frame_height = 1280;
+ }
}
std::vector<FrameInfo> frame_info_list_;
@@ -433,13 +449,48 @@
bool change_bitrate_;
double mismatch_psnr_;
int mismatch_nframes_;
+ bool set_scale_mode_;
};
+// Check the AOME_SET_SCALEMODE control by downsizing to
+// 1/2, then 1/4, and then back up to originsal.
+TEST_P(ResizeRealtimeTest, TestInternalResizeSetScaleMode) {
+ ::libaom_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 60);
+ cfg_.g_w = 1280;
+ cfg_.g_h = 720;
+ set_scale_mode_ = true;
+ DefaultConfig();
+ change_bitrate_ = false;
+ mismatch_nframes_ = 0;
+ ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+ // Check we decoded the same number of frames as we attempted to encode
+ ASSERT_EQ(frame_info_list_.size(), video.limit());
+ for (std::vector<FrameInfo>::const_iterator info = frame_info_list_.begin();
+ info != frame_info_list_.end(); ++info) {
+ const unsigned int frame = static_cast<unsigned>(info->pts);
+ unsigned int expected_w = 1280 >> 1;
+ unsigned int expected_h = 720 >> 1;
+ if (frame > 40) {
+ expected_w = 1280;
+ expected_h = 720;
+ } else if (frame > 20 && frame <= 40) {
+ expected_w = 1280 >> 2;
+ expected_h = 720 >> 2;
+ }
+ EXPECT_EQ(expected_w, info->w)
+ << "Frame " << frame << " had unexpected width";
+ EXPECT_EQ(expected_h, info->h)
+ << "Frame " << frame << " had unexpected height";
+ EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames());
+ }
+}
+
TEST_P(ResizeRealtimeTest, TestExternalResizeWorks) {
ResizingVideoSource video;
video.flag_codec_ = 1;
DefaultConfig();
change_bitrate_ = false;
+ set_scale_mode_ = false;
mismatch_psnr_ = 0.0;
mismatch_nframes_ = 0;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));