rtc: Fix setting of intra-only frame for set_ref_frame_config
When setting the reference structure with
SET_REF_FRAME_CONFIG: if no references are set
for delta frames then that frame should be set internally
to an intra-only frame. But this check was only being
done if layers are used (number_temporal > 1 or number_spatial > 1)
(i.e., use_svc is set). So single layer was not being checked.
Fix here is to check and set to intra-only regardless of layers.
Added unittest, based on:
https://chromium-review.googlesource.com/c/chromium/src/+/5809671
Bug: 363016123
Change-Id: Ie9d9ce190dc407a50e592a5f8bf47c2a26779e9b
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index 007812d..5aa38a3 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -3715,23 +3715,24 @@
svc->spatial_layer_id == 0
? 0
: svc->layer_context[svc->temporal_layer_id].is_key_frame;
- // If the user is setting the reference structure with
- // set_ref_frame_config and did not set any references, set the
- // frame type to Intra-only.
- if (cpi->ppi->rtc_ref.set_ref_frame_config) {
- int no_references_set = 1;
- for (int i = 0; i < INTER_REFS_PER_FRAME; i++) {
- if (cpi->ppi->rtc_ref.reference[i]) {
- no_references_set = 0;
- break;
- }
+ }
+ // If the user is setting the reference structure with
+ // set_ref_frame_config and did not set any references, set the
+ // frame type to Intra-only.
+ if (cpi->ppi->rtc_ref.set_ref_frame_config) {
+ int no_references_set = 1;
+ for (int i = 0; i < INTER_REFS_PER_FRAME; i++) {
+ if (cpi->ppi->rtc_ref.reference[i]) {
+ no_references_set = 0;
+ break;
}
- // Set to intra_only_frame if no references are set.
- // The stream can start decoding on INTRA_ONLY_FRAME so long as the
- // layer with the intra_only_frame doesn't signal a reference to a slot
- // that hasn't been set yet.
- if (no_references_set) *frame_type = INTRA_ONLY_FRAME;
}
+
+ // Set to intra_only_frame if no references are set.
+ // The stream can start decoding on INTRA_ONLY_FRAME so long as the
+ // layer with the intra_only_frame doesn't signal a reference to a slot
+ // that hasn't been set yet.
+ if (no_references_set) *frame_type = INTRA_ONLY_FRAME;
}
}
if (cpi->active_map.enabled && cpi->rc.percent_blocks_inactive == 100) {
diff --git a/test/svc_datarate_test.cc b/test/svc_datarate_test.cc
index 7da2160..a1b7136 100644
--- a/test/svc_datarate_test.cc
+++ b/test/svc_datarate_test.cc
@@ -86,6 +86,7 @@
comp_pred_ = 0;
dynamic_enable_disable_mode_ = 0;
intra_only_ = 0;
+ intra_only_single_layer_ = false;
frame_to_start_decoding_ = 0;
layer_to_decode_ = 0;
frame_sync_ = 0;
@@ -675,9 +676,20 @@
// Always reference LAST.
ref_frame_config->reference[0] = 1;
if (number_temporal_layers_ == 1 && number_spatial_layers_ == 1) {
+ layer_id->temporal_layer_id = 0;
ref_frame_config->refresh[0] = 1;
if (rps_mode)
ref_config_rps(ref_frame_config, frame_cnt, rps_recovery_frame);
+ if (intra_only_single_layer_) {
+ // This repros the crash in Bug: 363016123.
+ ref_frame_config->ref_idx[0] = 0;
+ ref_frame_config->ref_idx[3] = 1;
+ ref_frame_config->ref_idx[6] = 2;
+ if (frame_cnt == 1) {
+ for (int i = 0; i < INTER_REFS_PER_FRAME; i++)
+ ref_frame_config->reference[i] = 0;
+ }
+ }
}
if (number_temporal_layers_ == 2 && number_spatial_layers_ == 1) {
// 2-temporal layer.
@@ -1369,6 +1381,32 @@
}
}
+ virtual void BasicRateTargetingSVC1TL1SLIntraOnlyTest() {
+ cfg_.rc_buf_initial_sz = 500;
+ cfg_.rc_buf_optimal_sz = 500;
+ cfg_.rc_buf_sz = 1000;
+ cfg_.rc_dropframe_thresh = 0;
+ cfg_.rc_min_quantizer = 0;
+ cfg_.rc_max_quantizer = 63;
+ cfg_.rc_end_usage = AOM_CBR;
+ cfg_.g_lag_in_frames = 0;
+ cfg_.g_error_resilient = 0;
+
+ ::libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352,
+ 288, 30, 1, 0, 300);
+ const int bitrate_array[2] = { 300, 600 };
+ cfg_.rc_target_bitrate = bitrate_array[GET_PARAM(4)];
+ ResetModel();
+ intra_only_single_layer_ = true;
+ number_temporal_layers_ = 1;
+ number_spatial_layers_ = 1;
+ ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+ ASSERT_GE(effective_datarate_tl[0], cfg_.rc_target_bitrate * 0.80)
+ << " The datarate for the file is lower than target by too much!";
+ ASSERT_LE(effective_datarate_tl[0], cfg_.rc_target_bitrate * 1.60)
+ << " The datarate for the file is greater than target by too much!";
+ }
+
virtual void BasicRateTargetingSVC1TL3SLTest() {
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
@@ -2442,6 +2480,7 @@
int comp_pred_;
int dynamic_enable_disable_mode_;
int intra_only_;
+ int intra_only_single_layer_;
unsigned int frame_to_start_decoding_;
unsigned int layer_to_decode_;
unsigned int frame_sync_;
@@ -2532,6 +2571,12 @@
BasicRateTargetingSVC1TL2SLIntraOnlyTest();
}
+// Check basic rate targeting for CBR, for 1 spatial layers, 1 temporal,
+// with Intra-only frame (frame with no references) inserted in the stream.
+TEST_P(DatarateTestSVC, BasicRateTargetingSVC1TL1SLIntraOnly) {
+ BasicRateTargetingSVC1TL1SLIntraOnlyTest();
+}
+
// Check basic rate targeting for CBR, for 3 spatial layers, 1 temporal.
TEST_P(DatarateTestSVC, BasicRateTargetingSVC1TL3SL) {
BasicRateTargetingSVC1TL3SLTest();