From: Marco Date: Wed, 2 Mar 2016 22:45:41 +0000 (-0800) Subject: vp9-svc: Fix issues with svc with periodic key frames. X-Git-Tag: v1.6.0~316 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=38e401b5daa0ffb771255a3b6cafccef3146d709;p=libvpx vp9-svc: Fix issues with svc with periodic key frames. Use the superframe counter to set the key frame, and force it to the key frame on base spatial layer only. Also, update svc frame counters under frame dropping. Update unittest: add specific tests with short key frame period. https://bugs.chromium.org/p/webm/issues/detail?id=1150 Change-Id: I5b1c9a09253e6e5fbfce51b4cf603ae22d422b01 --- diff --git a/test/datarate_test.cc b/test/datarate_test.cc index d6b1b5247..c0796dff3 100644 --- a/test/datarate_test.cc +++ b/test/datarate_test.cc @@ -901,8 +901,6 @@ TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc2SpatialLayers) { svc_params_.scaling_factor_num[1] = 288; svc_params_.scaling_factor_den[1] = 288; cfg_.rc_dropframe_thresh = 10; - // TODO(marpan): another test should be added for default/small kf_max_dist - // once https://bugs.chromium.org/p/webm/issues/detail?id=1150 is fixed. cfg_.kf_max_dist = 9999; ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, 30, 1, 0, 200); @@ -918,10 +916,90 @@ TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc2SpatialLayers) { << " The datarate for the file exceeds the target by too much!"; ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.15) << " The datarate for the file is lower than the target by too much!"; - EXPECT_EQ(GetMismatchFrames(), (unsigned int) 0); + EXPECT_EQ(static_cast(0), GetMismatchFrames()); } } +// Check basic rate targeting for 1 pass CBR SVC: 2 spatial layers and +// 3 temporal layers. Run CIF clip with 1 thread. Use short key frame period. +TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc2SpatialLayersSmallKf_dist) { + cfg_.rc_buf_initial_sz = 500; + cfg_.rc_buf_optimal_sz = 500; + cfg_.rc_buf_sz = 1000; + cfg_.rc_min_quantizer = 0; + cfg_.rc_max_quantizer = 63; + cfg_.rc_end_usage = VPX_CBR; + cfg_.g_lag_in_frames = 0; + cfg_.ss_number_layers = 2; + cfg_.ts_number_layers = 3; + cfg_.ts_rate_decimator[0] = 4; + cfg_.ts_rate_decimator[1] = 2; + cfg_.ts_rate_decimator[2] = 1; + cfg_.g_error_resilient = 1; + cfg_.g_threads = 1; + cfg_.temporal_layering_mode = 3; + svc_params_.scaling_factor_num[0] = 144; + svc_params_.scaling_factor_den[0] = 288; + svc_params_.scaling_factor_num[1] = 288; + svc_params_.scaling_factor_den[1] = 288; + cfg_.rc_dropframe_thresh = 10; + cfg_.kf_max_dist = 64; + ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, + 30, 1, 0, 200); + // TODO(wonkap/marpan): Check that effective_datarate for each layer hits the + // layer target_bitrate. Also check if test can pass at lower bitrate (~200k). + for (int i = 400; i <= 800; i += 200) { + cfg_.rc_target_bitrate = i; + ResetModel(); + assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers, + cfg_.ts_number_layers, cfg_.temporal_layering_mode); + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); + ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.85) + << " The datarate for the file exceeds the target by too much!"; + ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.15) + << " The datarate for the file is lower than the target by too much!"; + EXPECT_EQ(static_cast(0), GetMismatchFrames()); + } +} + +// Check basic rate targeting for 1 pass CBR SVC: 2 spatial layers and +// 3 temporal layers. Run HD clip with 4 threads. +TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc2SpatialLayers4threads) { + cfg_.rc_buf_initial_sz = 500; + cfg_.rc_buf_optimal_sz = 500; + cfg_.rc_buf_sz = 1000; + cfg_.rc_min_quantizer = 0; + cfg_.rc_max_quantizer = 63; + cfg_.rc_end_usage = VPX_CBR; + cfg_.g_lag_in_frames = 0; + cfg_.ss_number_layers = 2; + cfg_.ts_number_layers = 3; + cfg_.ts_rate_decimator[0] = 4; + cfg_.ts_rate_decimator[1] = 2; + cfg_.ts_rate_decimator[2] = 1; + cfg_.g_error_resilient = 1; + cfg_.g_threads = 4; + cfg_.temporal_layering_mode = 3; + svc_params_.scaling_factor_num[0] = 144; + svc_params_.scaling_factor_den[0] = 288; + svc_params_.scaling_factor_num[1] = 288; + svc_params_.scaling_factor_den[1] = 288; + cfg_.rc_dropframe_thresh = 10; + cfg_.kf_max_dist = 9999; + ::libvpx_test::I420VideoSource video("niklas_1280_720_30.y4m", 1280, 720, + 30, 1, 0, 300); + cfg_.rc_target_bitrate = 800; + ResetModel(); + assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers, + cfg_.ts_number_layers, cfg_.temporal_layering_mode); + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); + ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.85) + << " The datarate for the file exceeds the target by too much!"; + ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.15) + << " The datarate for the file is lower than the target by too much!"; + EXPECT_EQ(static_cast(0), GetMismatchFrames()); +} + // Check basic rate targeting for 1 pass CBR SVC: 3 spatial layers and // 3 temporal layers. Run CIF clip with 1 thread. TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc3SpatialLayers) { @@ -959,12 +1037,12 @@ TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc3SpatialLayers) { << " The datarate for the file exceeds the target by too much!"; ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.22) << " The datarate for the file is lower than the target by too much!"; - EXPECT_EQ(GetMismatchFrames(), (unsigned int) 0); + EXPECT_EQ(static_cast(0), GetMismatchFrames()); } -// Check basic rate targeting for 1 pass CBR SVC: 2 spatial layers and -// 3 temporal layers. Run HD clip with 4 threads. -TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc2SpatialLayers4threads) { +// Check basic rate targeting for 1 pass CBR SVC: 3 spatial layers and +// 3 temporal layers. Run CIF clip with 1 thread. Use short key frame period. +TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc3SpatialLayersSmallKf) { cfg_.rc_buf_initial_sz = 500; cfg_.rc_buf_optimal_sz = 500; cfg_.rc_buf_sz = 1000; @@ -972,32 +1050,34 @@ TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc2SpatialLayers4threads) { cfg_.rc_max_quantizer = 63; cfg_.rc_end_usage = VPX_CBR; cfg_.g_lag_in_frames = 0; - cfg_.ss_number_layers = 2; + cfg_.ss_number_layers = 3; cfg_.ts_number_layers = 3; cfg_.ts_rate_decimator[0] = 4; cfg_.ts_rate_decimator[1] = 2; cfg_.ts_rate_decimator[2] = 1; cfg_.g_error_resilient = 1; - cfg_.g_threads = 4; + cfg_.g_threads = 1; cfg_.temporal_layering_mode = 3; - svc_params_.scaling_factor_num[0] = 144; + svc_params_.scaling_factor_num[0] = 72; svc_params_.scaling_factor_den[0] = 288; - svc_params_.scaling_factor_num[1] = 288; + svc_params_.scaling_factor_num[1] = 144; svc_params_.scaling_factor_den[1] = 288; + svc_params_.scaling_factor_num[2] = 288; + svc_params_.scaling_factor_den[2] = 288; cfg_.rc_dropframe_thresh = 10; - cfg_.kf_max_dist = 9999; + cfg_.kf_max_dist = 32; ::libvpx_test::I420VideoSource video("niklas_1280_720_30.y4m", 1280, 720, 30, 1, 0, 300); cfg_.rc_target_bitrate = 800; ResetModel(); assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers, - cfg_.ts_number_layers, cfg_.temporal_layering_mode); + cfg_.ts_number_layers, cfg_.temporal_layering_mode); ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.85) << " The datarate for the file exceeds the target by too much!"; - ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.15) + ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.30) << " The datarate for the file is lower than the target by too much!"; - EXPECT_EQ(GetMismatchFrames(), (unsigned int) 0); + EXPECT_EQ(static_cast(0), GetMismatchFrames()); } // Check basic rate targeting for 1 pass CBR SVC: 3 spatial layers and @@ -1037,7 +1117,7 @@ TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc3SpatialLayers4threads) { << " The datarate for the file exceeds the target by too much!"; ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.22) << " The datarate for the file is lower than the target by too much!"; - EXPECT_EQ(GetMismatchFrames(), (unsigned int) 0); + EXPECT_EQ(static_cast(0), GetMismatchFrames()); } VP8_INSTANTIATE_TEST_CASE(DatarateTestLarge, ALL_TEST_MODES); diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index 6d6915c8d..332db300c 100644 --- a/vp9/encoder/vp9_encoder.c +++ b/vp9/encoder/vp9_encoder.c @@ -3983,6 +3983,8 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, ++cm->current_video_frame; cpi->ext_refresh_frame_flags_pending = 0; cpi->svc.rc_drop_superframe = 1; + if (cpi->use_svc) + vp9_inc_frame_in_layer(cpi); return; } } diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c index d64b5c53b..7804b712a 100644 --- a/vp9/encoder/vp9_ratectrl.c +++ b/vp9/encoder/vp9_ratectrl.c @@ -1594,14 +1594,15 @@ void vp9_rc_get_svc_params(VP9_COMP *cpi) { int target = rc->avg_frame_bandwidth; int layer = LAYER_IDS_TO_IDX(cpi->svc.spatial_layer_id, cpi->svc.temporal_layer_id, cpi->svc.number_temporal_layers); - + // Periodic key frames is based on the super-frame counter + // (svc.current_superframe), also only base spatial layer is key frame. if ((cm->current_video_frame == 0) || (cpi->frame_flags & FRAMEFLAGS_KEY) || - (cpi->oxcf.auto_key && (rc->frames_since_key % - cpi->oxcf.key_freq == 0))) { + (cpi->oxcf.auto_key && + (cpi->svc.current_superframe % cpi->oxcf.key_freq == 0) && + cpi->svc.spatial_layer_id == 0)) { cm->frame_type = KEY_FRAME; rc->source_alt_ref_active = 0; - if (is_two_pass_svc(cpi)) { cpi->svc.layer_context[layer].is_key_frame = 1; cpi->ref_frame_flags &=