Fix source buffer access in rc_scene_detection_onepass_rt()
In rc_scene_detection_onepass_rt(), source buffers of current
and last input frames were accessed using cpi->unscaled_source
and cpi->unscaled_last_source. These pointers were initialized
in av1_encode(), which is called after
rc_scene_detection_onepass_rt(). Hence the local pointer
unscaled_src in rc_scene_detection_onepass_rt() points to last
frame and vice versa. Though the SAD was computed for last
source frame w.r.t current source frame, the metrics like
cpi->rc.frame_source_sad etc. are seen to be correct for all
frames except first inter frame. For first inter frame, SAD
values were not computed as unscaled_last_src was NULL and
cpi->rc.frame_source_sad is considered as zero in this case.
This CL fixes the issue by initializing these local pointers
from frame_input which is initialized correctly.
For rtc-screen,
Instruction Count BD-Rate Loss(%)
cpu-used Reduction(%) avg.psnr ovr.psnr ssim
7 -0.543 -0.2794 0.5159 0.7707
8 0.139 0.0810 -0.0130 0.1490
9 0.445 -0.4881 -0.1066 -0.0806
10 0.051 -0.0661 0.0410 0.0473
STATS_CHANGED for rt
Change-Id: Ie620d3a89c3b9f8a9f6528bdf020780a295520e9
diff --git a/av1/encoder/encode_strategy.c b/av1/encoder/encode_strategy.c
index c2b8c51..e8badea 100644
--- a/av1/encoder/encode_strategy.c
+++ b/av1/encoder/encode_strategy.c
@@ -1373,12 +1373,12 @@
start_timing(cpi, av1_get_one_pass_rt_params_time);
#endif
#if CONFIG_REALTIME_ONLY
- av1_get_one_pass_rt_params(cpi, &frame_params, *frame_flags);
+ av1_get_one_pass_rt_params(cpi, &frame_params, &frame_input, *frame_flags);
if (use_one_pass_rt_reference_structure(cpi))
av1_set_reference_structure_one_pass_rt(cpi, cpi->gf_frame_index == 0);
#else
if (use_one_pass_rt_params) {
- av1_get_one_pass_rt_params(cpi, &frame_params, *frame_flags);
+ av1_get_one_pass_rt_params(cpi, &frame_params, &frame_input, *frame_flags);
if (use_one_pass_rt_reference_structure(cpi))
av1_set_reference_structure_one_pass_rt(cpi, cpi->gf_frame_index == 0);
}
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index eac1d3f..a7d309e 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -2701,15 +2701,17 @@
*
* \ingroup rate_control
* \param[in] cpi Top level encoder structure
+ * \param[in] frame_input Current and last input source frames
*
* \return Nothing is returned. Instead the flag \c cpi->rc.high_source_sad
* is set if scene change is detected, and \c cpi->rc.avg_source_sad is updated.
*/
-static void rc_scene_detection_onepass_rt(AV1_COMP *cpi) {
+static void rc_scene_detection_onepass_rt(AV1_COMP *cpi,
+ const EncodeFrameInput *frame_input) {
AV1_COMMON *const cm = &cpi->common;
RATE_CONTROL *const rc = &cpi->rc;
- YV12_BUFFER_CONFIG const *unscaled_src = cpi->unscaled_source;
- YV12_BUFFER_CONFIG const *unscaled_last_src = cpi->unscaled_last_source;
+ YV12_BUFFER_CONFIG const *const unscaled_src = frame_input->source;
+ YV12_BUFFER_CONFIG const *const unscaled_last_src = frame_input->last_source;
uint8_t *src_y;
int src_ystride;
int src_width;
@@ -2719,14 +2721,14 @@
int last_src_width;
int last_src_height;
if (cm->spatial_layer_id != 0 || cm->width != cm->render_width ||
- cm->height != cm->render_height || cpi->unscaled_source == NULL ||
- cpi->unscaled_last_source == NULL) {
+ cm->height != cm->render_height || unscaled_src == NULL ||
+ unscaled_last_src == NULL) {
if (cpi->src_sad_blk_64x64) {
aom_free(cpi->src_sad_blk_64x64);
cpi->src_sad_blk_64x64 = NULL;
}
}
- if (cpi->unscaled_source == NULL || cpi->unscaled_last_source == NULL) return;
+ if (unscaled_src == NULL || unscaled_last_src == NULL) return;
src_y = unscaled_src->y_buffer;
src_ystride = unscaled_src->y_stride;
src_width = unscaled_src->y_width;
@@ -3042,6 +3044,7 @@
void av1_get_one_pass_rt_params(AV1_COMP *cpi,
EncodeFrameParams *const frame_params,
+ const EncodeFrameInput *frame_input,
unsigned int frame_flags) {
RATE_CONTROL *const rc = &cpi->rc;
PRIMARY_RATE_CONTROL *const p_rc = &cpi->ppi->p_rc;
@@ -3106,7 +3109,7 @@
}
// Check for scene change: for SVC check on base spatial layer only.
if (cpi->sf.rt_sf.check_scene_detection && svc->spatial_layer_id == 0)
- rc_scene_detection_onepass_rt(cpi);
+ rc_scene_detection_onepass_rt(cpi, frame_input);
// Check for dynamic resize, for single spatial layer for now.
// For temporal layers only check on base temporal layer.
if (cpi->oxcf.resize_cfg.resize_mode == RESIZE_DYNAMIC) {
diff --git a/av1/encoder/ratectrl.h b/av1/encoder/ratectrl.h
index 486fda3..6dc5baf 100644
--- a/av1/encoder/ratectrl.h
+++ b/av1/encoder/ratectrl.h
@@ -583,6 +583,7 @@
// Functions to set parameters for encoding before the actual
// encode_frame_to_data_rate() function.
struct EncodeFrameParams;
+struct EncodeFrameInput;
// Post encode update of the rate control parameters based
// on bytes used
@@ -766,6 +767,7 @@
* \ingroup rate_control
* \param[in] cpi Top level encoder structure
* \param[in] frame_params Encoder frame parameters
+ * \param[in] frame_input Current and last input source frames
* \param[in] frame_flags Emcoder frame flags
*
* \return Nothing is returned. Instead the settings computed in this
@@ -773,6 +775,7 @@
*/
void av1_get_one_pass_rt_params(struct AV1_COMP *cpi,
struct EncodeFrameParams *const frame_params,
+ const struct EncodeFrameInput *frame_input,
unsigned int frame_flags);
/*!\brief Increase q on expected encoder overshoot, for CBR mode.
diff --git a/test/rt_end_to_end_test.cc b/test/rt_end_to_end_test.cc
index 6e9711e..79a89fd 100644
--- a/test/rt_end_to_end_test.cc
+++ b/test/rt_end_to_end_test.cc
@@ -42,7 +42,7 @@
{ { 5, { { 0, 36.2 }, { 3, 36.7 } } },
{ 6, { { 0, 36.1 }, { 3, 36.48 } } },
{ 7, { { 0, 35.5 }, { 3, 36.0 } } },
- { 8, { { 0, 35.98 }, { 3, 36.48 } } },
+ { 8, { { 0, 35.8 }, { 3, 36.48 } } },
{ 9, { { 0, 35.5 }, { 3, 36.0 } } },
{ 10, { { 0, 35.3 }, { 3, 35.9 } } } } },
{ "niklas_1280_720_30.y4m",