rtc: Fix usage and allocation for source_last_TL0 Add checks to prevent source_last_TL0 from being used unallocated. In the issue below is was being passed unallocated to the scaler, which caused divide-by-zero in the resizer. Fix the logic to allocate source_last_TL0 on the very first frame, regardless of temporal_layer_id, and add additional checks for allocation.. Unittest to reproduce. Bug: 505976409 Change-Id: I6dbba45d8add65042a53981c60319d8dc4cd8a6f
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c index 2d492dd..0337baf 100644 --- a/av1/encoder/encoder.c +++ b/av1/encoder/encoder.c
@@ -2975,10 +2975,14 @@ av1_set_size_dependent_vars(cpi, &q, &bottom_index, &top_index); av1_set_mv_search_params(cpi); - if (cm->current_frame.frame_number == 0 && - (cpi->ppi->use_svc || cpi->oxcf.rc_cfg.drop_frames_water_mark > 0) && - cpi->svc.temporal_layer_id == 0) { - const SequenceHeader *seq_params = cm->seq_params; + const SequenceHeader *seq_params = cm->seq_params; + if ((cpi->svc.source_last_TL0.buffer_alloc_sz == 0 || + cpi->svc.source_last_TL0.y_width != cpi->oxcf.frm_dim_cfg.width || + cpi->svc.source_last_TL0.y_height != cpi->oxcf.frm_dim_cfg.height || + cpi->svc.source_last_TL0.subsampling_x != seq_params->subsampling_x || + cpi->svc.source_last_TL0.subsampling_y != seq_params->subsampling_y || + cpi->svc.source_last_TL0.flags != cpi->source->flags) && + (cpi->ppi->use_svc || cpi->oxcf.rc_cfg.drop_frames_water_mark > 0)) { if (aom_alloc_frame_buffer( &cpi->svc.source_last_TL0, cpi->oxcf.frm_dim_cfg.width, cpi->oxcf.frm_dim_cfg.height, seq_params->subsampling_x,
diff --git a/av1/encoder/svc_layercontext.c b/av1/encoder/svc_layercontext.c index 5d8de75..8b8d4c5 100644 --- a/av1/encoder/svc_layercontext.c +++ b/av1/encoder/svc_layercontext.c
@@ -653,6 +653,7 @@ void av1_svc_set_last_source(AV1_COMP *const cpi, EncodeFrameInput *frame_input, YV12_BUFFER_CONFIG *prev_source) { frame_input->last_source = prev_source != NULL ? prev_source : NULL; + if (cpi->svc.source_last_TL0.buffer_alloc_sz == 0) return; if (!cpi->ppi->use_svc && cpi->rc.prev_frame_is_dropped && cpi->rc.frame_number_encoded > 0) { frame_input->last_source = &cpi->svc.source_last_TL0;
diff --git a/test/encode_api_test.cc b/test/encode_api_test.cc index ba482bc..858c3a4 100644 --- a/test/encode_api_test.cc +++ b/test/encode_api_test.cc
@@ -2490,4 +2490,68 @@ } #endif // !CONFIG_REALTIME_ONLY +// Test for issue: 505976409. +TEST(EncodeAPI, SvcSourceLastTL0Uninitialized) { + aom_codec_iface_t *iface = aom_codec_av1_cx(); + aom_codec_enc_cfg_t cfg; + ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_REALTIME), + AOM_CODEC_OK); + + cfg.g_w = 64; + cfg.g_h = 64; + cfg.rc_end_usage = AOM_CBR; + cfg.g_lag_in_frames = 0; + cfg.rc_target_bitrate = 400; + + aom_codec_ctx_t codec; + ASSERT_EQ(aom_codec_enc_init(&codec, iface, &cfg, 0), AOM_CODEC_OK); + ASSERT_EQ(aom_codec_control(&codec, AOME_SET_CPUUSED, 9), AOM_CODEC_OK); + + aom_svc_params_t svc = {}; + svc.number_spatial_layers = 1; + svc.number_temporal_layers = 2; + svc.scaling_factor_num[0] = 1; + svc.scaling_factor_den[0] = 4; + for (int i = 0; i < 32; ++i) svc.layer_target_bitrate[i] = 200; + for (int i = 0; i < 8; ++i) svc.framerate_factor[i] = 1; + ASSERT_EQ(aom_codec_control(&codec, AV1E_SET_SVC_PARAMS, &svc), AOM_CODEC_OK); + + aom_image_t *img = aom_img_alloc(nullptr, AOM_IMG_FMT_I420, 64, 64, 1); + ASSERT_NE(img, nullptr); + FillImage(img, 128); + + // Frame 0: TL1 (Starts with non-zero temporal layer). + aom_svc_layer_id_t layer_id = { 0, 1 }; + ASSERT_EQ(aom_codec_control(&codec, AV1E_SET_SVC_LAYER_ID, &layer_id), + AOM_CODEC_OK); + + aom_svc_ref_frame_config_t ref_cfg = {}; + for (int r = 0; r < 7; ++r) { + ref_cfg.reference[r] = 1; + ref_cfg.ref_idx[r] = 7; + } + ref_cfg.refresh[2] = 1; + ref_cfg.refresh[6] = 1; + ASSERT_EQ(aom_codec_control(&codec, AV1E_SET_SVC_REF_FRAME_CONFIG, &ref_cfg), + AOM_CODEC_OK); + + ASSERT_EQ(aom_codec_encode(&codec, img, 0, 1, AOM_EFLAG_FORCE_KF), + AOM_CODEC_OK); + + // Frame 1: TL0. + layer_id.temporal_layer_id = 0; + ASSERT_EQ(aom_codec_control(&codec, AV1E_SET_SVC_LAYER_ID, &layer_id), + AOM_CODEC_OK); + ASSERT_EQ(aom_codec_encode(&codec, img, 1, 1, 0), AOM_CODEC_OK); + + // Frame 2: TL1 (Triggers use of source_last_TL0). + layer_id.temporal_layer_id = 1; + ASSERT_EQ(aom_codec_control(&codec, AV1E_SET_SVC_LAYER_ID, &layer_id), + AOM_CODEC_OK); + // This frame used to crash or hang before the fix. + ASSERT_EQ(aom_codec_encode(&codec, img, 2, 1, 0), AOM_CODEC_OK); + + aom_img_free(img); + ASSERT_EQ(aom_codec_destroy(&codec), AOM_CODEC_OK); +} } // namespace