From c79bd22a5f83ce2a2a2a9d9fe37d409c098c41d7 Mon Sep 17 00:00:00 2001 From: Minghai Shang Date: Tue, 25 Feb 2014 15:32:20 -0800 Subject: [PATCH] Change for adding QP settings for key frames Change-Id: I4dcabb60cb1185eb9a2efa18b50f17af272d2cd6 --- examples/vp9_spatial_scalable_encoder.c | 14 ++++-- test/svc_test.cc | 52 +++++++++++++++++----- vpx/src/svc_encodeframe.c | 59 +++++++++++++++++++++---- vpx/svc_context.h | 3 +- 4 files changed, 103 insertions(+), 25 deletions(-) diff --git a/examples/vp9_spatial_scalable_encoder.c b/examples/vp9_spatial_scalable_encoder.c index 9f526b0a4..98dc3f5f9 100644 --- a/examples/vp9_spatial_scalable_encoder.c +++ b/examples/vp9_spatial_scalable_encoder.c @@ -54,12 +54,18 @@ static const arg_def_t kf_dist_arg = static const arg_def_t scale_factors_arg = ARG_DEF("r", "scale-factors", 1, "scale factors (lowest to highest layer)"); static const arg_def_t quantizers_arg = - ARG_DEF("q", "quantizers", 1, "quantizers (lowest to highest layer)"); + ARG_DEF("q", "quantizers", 1, "quantizers for non key frames, also will " + "be applied to key frames if -qn is not specified (lowest to " + "highest layer)"); +static const arg_def_t quantizers_keyframe_arg = + ARG_DEF("qn", "quantizers-keyframe", 1, "quantizers for key frames (lowest " + "to highest layer)"); static const arg_def_t *svc_args[] = { &encoding_mode_arg, &frames_arg, &width_arg, &height_arg, &timebase_arg, &bitrate_arg, &skip_frames_arg, &layers_arg, - &kf_dist_arg, &scale_factors_arg, &quantizers_arg, NULL + &kf_dist_arg, &scale_factors_arg, &quantizers_arg, + &quantizers_keyframe_arg, NULL }; static const SVC_ENCODING_MODE default_encoding_mode = @@ -150,7 +156,9 @@ static void parse_command_line(int argc, const char **argv_, } else if (arg_match(&arg, &scale_factors_arg, argi)) { vpx_svc_set_scale_factors(svc_ctx, arg.val); } else if (arg_match(&arg, &quantizers_arg, argi)) { - vpx_svc_set_quantizers(svc_ctx, arg.val); + vpx_svc_set_quantizers(svc_ctx, arg.val, 0); + } else if (arg_match(&arg, &quantizers_keyframe_arg, argi)) { + vpx_svc_set_quantizers(svc_ctx, arg.val, 1); } else { ++argj; } diff --git a/test/svc_test.cc b/test/svc_test.cc index 75659d50d..2e5653424 100644 --- a/test/svc_test.cc +++ b/test/svc_test.cc @@ -177,20 +177,48 @@ TEST_F(SvcTest, SetQuantizersOption) { codec_initialized_ = true; } -TEST_F(SvcTest, SetQuantizers) { - vpx_codec_err_t res = vpx_svc_set_quantizers(NULL, "40,30"); - EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); - - res = vpx_svc_set_quantizers(&svc_, NULL); - EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); - +TEST_F(SvcTest, SetKeyFrameQuantizersOption) { svc_.spatial_layers = 2; - res = vpx_svc_set_quantizers(&svc_, "40"); + vpx_codec_err_t res = vpx_svc_set_options(&svc_, + "quantizers-keyframe=not-quantizers"); EXPECT_EQ(VPX_CODEC_OK, res); res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); - res = vpx_svc_set_quantizers(&svc_, "40,30"); + vpx_svc_set_options(&svc_, "quantizers-keyframe=40,45"); + res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); + EXPECT_EQ(VPX_CODEC_OK, res); + codec_initialized_ = true; +} + +TEST_F(SvcTest, SetQuantizers) { + vpx_codec_err_t res = vpx_svc_set_quantizers(NULL, "40,30", 0); + EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); + + res = vpx_svc_set_quantizers(&svc_, NULL, 0); + EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); + + svc_.spatial_layers = 2; + res = vpx_svc_set_quantizers(&svc_, "40", 0); + EXPECT_EQ(VPX_CODEC_OK, res); + res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); + EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); + + res = vpx_svc_set_quantizers(&svc_, "40,30", 0); + EXPECT_EQ(VPX_CODEC_OK, res); + res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); + EXPECT_EQ(VPX_CODEC_OK, res); + codec_initialized_ = true; +} + +TEST_F(SvcTest, SetKeyFrameQuantizers) { + vpx_codec_err_t res = vpx_svc_set_quantizers(NULL, "40,31", 1); + EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); + + res = vpx_svc_set_quantizers(&svc_, NULL, 1); + EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); + + res = vpx_svc_set_quantizers(&svc_, "40,30", 1); EXPECT_EQ(VPX_CODEC_OK, res); res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); EXPECT_EQ(VPX_CODEC_OK, res); @@ -221,7 +249,7 @@ TEST_F(SvcTest, SetScaleFactors) { TEST_F(SvcTest, FirstFrameHasLayers) { svc_.spatial_layers = 2; vpx_svc_set_scale_factors(&svc_, "4/16,16/16"); - vpx_svc_set_quantizers(&svc_, "40,30"); + vpx_svc_set_quantizers(&svc_, "40,30", 0); vpx_codec_err_t res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); @@ -248,7 +276,7 @@ TEST_F(SvcTest, FirstFrameHasLayers) { TEST_F(SvcTest, EncodeThreeFrames) { svc_.spatial_layers = 2; vpx_svc_set_scale_factors(&svc_, "4/16,16/16"); - vpx_svc_set_quantizers(&svc_, "40,30"); + vpx_svc_set_quantizers(&svc_, "40,30", 0); vpx_codec_err_t res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); @@ -301,7 +329,7 @@ TEST_F(SvcTest, EncodeThreeFrames) { TEST_F(SvcTest, GetLayerResolution) { svc_.spatial_layers = 2; vpx_svc_set_scale_factors(&svc_, "4/16,8/16"); - vpx_svc_set_quantizers(&svc_, "40,30"); + vpx_svc_set_quantizers(&svc_, "40,30", 0); vpx_codec_err_t res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); diff --git a/vpx/src/svc_encodeframe.c b/vpx/src/svc_encodeframe.c index adce47637..c12d8a3b0 100644 --- a/vpx/src/svc_encodeframe.c +++ b/vpx/src/svc_encodeframe.c @@ -47,11 +47,14 @@ static const char *DEFAULT_SCALE_FACTORS = "4/16,5/16,7/16,11/16,16/16"; typedef struct SvcInternal { char options[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_options char quantizers[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_quantizers + char quantizers_keyframe[OPTION_BUFFER_SIZE]; // set by + // vpx_svc_set_quantizers char scale_factors[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_scale_factors // values extracted from option, quantizers int scaling_factor_num[VPX_SS_MAX_LAYERS]; int scaling_factor_den[VPX_SS_MAX_LAYERS]; + int quantizer_keyframe[VPX_SS_MAX_LAYERS]; int quantizer[VPX_SS_MAX_LAYERS]; // accumulated statistics @@ -268,7 +271,8 @@ static vpx_codec_err_t set_option_encoding_mode(SvcContext *svc_ctx, } static vpx_codec_err_t parse_quantizer_values(SvcContext *svc_ctx, - const char *quantizer_values) { + const char *quantizer_values, + const int is_keyframe) { char *input_string; char *token; const char *delim = ","; @@ -279,6 +283,11 @@ static vpx_codec_err_t parse_quantizer_values(SvcContext *svc_ctx, SvcInternal *const si = get_svc_internal(svc_ctx); if (quantizer_values == NULL || strlen(quantizer_values) == 0) { + if (is_keyframe) { + // If there non settings for key frame, we will apply settings from + // non key frame. So just simply return here. + return VPX_CODEC_INVALID_PARAM; + } input_string = strdup(DEFAULT_QUANTIZER_VALUES); } else { input_string = strdup(quantizer_values); @@ -299,7 +308,12 @@ static vpx_codec_err_t parse_quantizer_values(SvcContext *svc_ctx, } else { q = 0; } - si->quantizer[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] = q; + if (is_keyframe) { + si->quantizer_keyframe[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] + = q; + } else { + si->quantizer[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] = q; + } } if (res == VPX_CODEC_OK && found != svc_ctx->spatial_layers) { svc_log(svc_ctx, SVC_LOG_ERROR, @@ -384,6 +398,7 @@ static vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) { char *option_name; char *option_value; char *input_ptr; + int is_keyframe_qaunt_set = 0; vpx_codec_err_t res = VPX_CODEC_OK; if (options == NULL) return VPX_CODEC_OK; @@ -409,8 +424,17 @@ static vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) { res = parse_scale_factors(svc_ctx, option_value); if (res != VPX_CODEC_OK) break; } else if (strcmp("quantizers", option_name) == 0) { - res = parse_quantizer_values(svc_ctx, option_value); + res = parse_quantizer_values(svc_ctx, option_value, 0); if (res != VPX_CODEC_OK) break; + if (!is_keyframe_qaunt_set) { + SvcInternal *const si = get_svc_internal(svc_ctx); + memcpy(get_svc_internal(svc_ctx)->quantizer_keyframe, si->quantizer, + sizeof(si->quantizer)); + } + } else if (strcmp("quantizers-keyframe", option_name) == 0) { + res = parse_quantizer_values(svc_ctx, option_value, 1); + if (res != VPX_CODEC_OK) break; + is_keyframe_qaunt_set = 1; } else { svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name); res = VPX_CODEC_INVALID_PARAM; @@ -433,13 +457,19 @@ vpx_codec_err_t vpx_svc_set_options(SvcContext *svc_ctx, const char *options) { } vpx_codec_err_t vpx_svc_set_quantizers(SvcContext *svc_ctx, - const char *quantizers) { + const char *quantizers, + const int is_for_keyframe) { SvcInternal *const si = get_svc_internal(svc_ctx); if (svc_ctx == NULL || quantizers == NULL || si == NULL) { return VPX_CODEC_INVALID_PARAM; } - strncpy(si->quantizers, quantizers, sizeof(si->quantizers)); - si->quantizers[sizeof(si->quantizers) - 1] = '\0'; + if (is_for_keyframe) { + strncpy(si->quantizers_keyframe, quantizers, sizeof(si->quantizers)); + si->quantizers_keyframe[sizeof(si->quantizers_keyframe) - 1] = '\0'; + } else { + strncpy(si->quantizers, quantizers, sizeof(si->quantizers)); + si->quantizers[sizeof(si->quantizers) - 1] = '\0'; + } return VPX_CODEC_OK; } @@ -490,9 +520,13 @@ vpx_codec_err_t vpx_svc_init(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx, // for first frame si->layers = svc_ctx->spatial_layers; - res = parse_quantizer_values(svc_ctx, si->quantizers); + res = parse_quantizer_values(svc_ctx, si->quantizers, 0); if (res != VPX_CODEC_OK) return res; + res = parse_quantizer_values(svc_ctx, si->quantizers_keyframe, 1); + if (res != VPX_CODEC_OK) + memcpy(si->quantizer_keyframe, si->quantizer, sizeof(si->quantizer)); + res = parse_scale_factors(svc_ctx, si->scale_factors); if (res != VPX_CODEC_OK) return res; @@ -713,8 +747,15 @@ static void set_svc_parameters(SvcContext *svc_ctx, svc_log(svc_ctx, SVC_LOG_ERROR, "vpx_svc_get_layer_resolution failed\n"); } layer_index = layer + VPX_SS_MAX_LAYERS - si->layers; - svc_params.min_quantizer = si->quantizer[layer_index]; - svc_params.max_quantizer = si->quantizer[layer_index]; + + if (vpx_svc_is_keyframe(svc_ctx)) { + svc_params.min_quantizer = si->quantizer_keyframe[layer_index]; + svc_params.max_quantizer = si->quantizer_keyframe[layer_index]; + } else { + svc_params.min_quantizer = si->quantizer[layer_index]; + svc_params.max_quantizer = si->quantizer[layer_index]; + } + svc_params.distance_from_i_frame = si->frame_within_gop; // Use buffer i for layer i LST diff --git a/vpx/svc_context.h b/vpx/svc_context.h index f675fb684..98474ca91 100644 --- a/vpx/svc_context.h +++ b/vpx/svc_context.h @@ -64,7 +64,8 @@ vpx_codec_err_t vpx_svc_set_options(SvcContext *svc_ctx, const char *options); * e.g., "60,53,39,33,27" */ vpx_codec_err_t vpx_svc_set_quantizers(SvcContext *svc_ctx, - const char *quantizer_values); + const char *quantizer_values, + const int is_for_keyframe); /** * Set SVC scale factors