Change for adding QP settings for key frames

Change-Id: I4dcabb60cb1185eb9a2efa18b50f17af272d2cd6
This commit is contained in:
Minghai Shang
2014-02-25 15:32:20 -08:00
parent 0eca2cd3c8
commit c79bd22a5f
4 changed files with 103 additions and 25 deletions

View File

@@ -54,12 +54,18 @@ static const arg_def_t kf_dist_arg =
static const arg_def_t scale_factors_arg = static const arg_def_t scale_factors_arg =
ARG_DEF("r", "scale-factors", 1, "scale factors (lowest to highest layer)"); ARG_DEF("r", "scale-factors", 1, "scale factors (lowest to highest layer)");
static const arg_def_t quantizers_arg = 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[] = { static const arg_def_t *svc_args[] = {
&encoding_mode_arg, &frames_arg, &width_arg, &height_arg, &encoding_mode_arg, &frames_arg, &width_arg, &height_arg,
&timebase_arg, &bitrate_arg, &skip_frames_arg, &layers_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 = 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)) { } else if (arg_match(&arg, &scale_factors_arg, argi)) {
vpx_svc_set_scale_factors(svc_ctx, arg.val); vpx_svc_set_scale_factors(svc_ctx, arg.val);
} else if (arg_match(&arg, &quantizers_arg, argi)) { } 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 { } else {
++argj; ++argj;
} }

View File

@@ -177,20 +177,48 @@ TEST_F(SvcTest, SetQuantizersOption) {
codec_initialized_ = true; codec_initialized_ = true;
} }
TEST_F(SvcTest, SetQuantizers) { TEST_F(SvcTest, SetKeyFrameQuantizersOption) {
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);
svc_.spatial_layers = 2; 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); EXPECT_EQ(VPX_CODEC_OK, res);
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); 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); EXPECT_EQ(VPX_CODEC_OK, res);
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_OK, res); EXPECT_EQ(VPX_CODEC_OK, res);
@@ -221,7 +249,7 @@ TEST_F(SvcTest, SetScaleFactors) {
TEST_F(SvcTest, FirstFrameHasLayers) { TEST_F(SvcTest, FirstFrameHasLayers) {
svc_.spatial_layers = 2; svc_.spatial_layers = 2;
vpx_svc_set_scale_factors(&svc_, "4/16,16/16"); 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_codec_err_t res =
vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
@@ -248,7 +276,7 @@ TEST_F(SvcTest, FirstFrameHasLayers) {
TEST_F(SvcTest, EncodeThreeFrames) { TEST_F(SvcTest, EncodeThreeFrames) {
svc_.spatial_layers = 2; svc_.spatial_layers = 2;
vpx_svc_set_scale_factors(&svc_, "4/16,16/16"); 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_codec_err_t res =
vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
@@ -301,7 +329,7 @@ TEST_F(SvcTest, EncodeThreeFrames) {
TEST_F(SvcTest, GetLayerResolution) { TEST_F(SvcTest, GetLayerResolution) {
svc_.spatial_layers = 2; svc_.spatial_layers = 2;
vpx_svc_set_scale_factors(&svc_, "4/16,8/16"); 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_codec_err_t res =
vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);

View File

@@ -47,11 +47,14 @@ static const char *DEFAULT_SCALE_FACTORS = "4/16,5/16,7/16,11/16,16/16";
typedef struct SvcInternal { typedef struct SvcInternal {
char options[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_options char options[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_options
char quantizers[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_quantizers 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 char scale_factors[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_scale_factors
// values extracted from option, quantizers // values extracted from option, quantizers
int scaling_factor_num[VPX_SS_MAX_LAYERS]; int scaling_factor_num[VPX_SS_MAX_LAYERS];
int scaling_factor_den[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]; int quantizer[VPX_SS_MAX_LAYERS];
// accumulated statistics // 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, 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 *input_string;
char *token; char *token;
const char *delim = ","; 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); SvcInternal *const si = get_svc_internal(svc_ctx);
if (quantizer_values == NULL || strlen(quantizer_values) == 0) { 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); input_string = strdup(DEFAULT_QUANTIZER_VALUES);
} else { } else {
input_string = strdup(quantizer_values); input_string = strdup(quantizer_values);
@@ -299,8 +308,13 @@ static vpx_codec_err_t parse_quantizer_values(SvcContext *svc_ctx,
} else { } else {
q = 0; q = 0;
} }
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; si->quantizer[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] = q;
} }
}
if (res == VPX_CODEC_OK && found != svc_ctx->spatial_layers) { if (res == VPX_CODEC_OK && found != svc_ctx->spatial_layers) {
svc_log(svc_ctx, SVC_LOG_ERROR, svc_log(svc_ctx, SVC_LOG_ERROR,
"svc: quantizers: %d values required, but only %d specified\n", "svc: quantizers: %d values required, but only %d specified\n",
@@ -384,6 +398,7 @@ static vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) {
char *option_name; char *option_name;
char *option_value; char *option_value;
char *input_ptr; char *input_ptr;
int is_keyframe_qaunt_set = 0;
vpx_codec_err_t res = VPX_CODEC_OK; vpx_codec_err_t res = VPX_CODEC_OK;
if (options == NULL) return 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); res = parse_scale_factors(svc_ctx, option_value);
if (res != VPX_CODEC_OK) break; if (res != VPX_CODEC_OK) break;
} else if (strcmp("quantizers", option_name) == 0) { } 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 (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 { } else {
svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name); svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name);
res = VPX_CODEC_INVALID_PARAM; 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, 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); SvcInternal *const si = get_svc_internal(svc_ctx);
if (svc_ctx == NULL || quantizers == NULL || si == NULL) { if (svc_ctx == NULL || quantizers == NULL || si == NULL) {
return VPX_CODEC_INVALID_PARAM; return VPX_CODEC_INVALID_PARAM;
} }
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)); strncpy(si->quantizers, quantizers, sizeof(si->quantizers));
si->quantizers[sizeof(si->quantizers) - 1] = '\0'; si->quantizers[sizeof(si->quantizers) - 1] = '\0';
}
return VPX_CODEC_OK; 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 // for first frame
si->layers = svc_ctx->spatial_layers; 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; 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); res = parse_scale_factors(svc_ctx, si->scale_factors);
if (res != VPX_CODEC_OK) return res; 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"); svc_log(svc_ctx, SVC_LOG_ERROR, "vpx_svc_get_layer_resolution failed\n");
} }
layer_index = layer + VPX_SS_MAX_LAYERS - si->layers; layer_index = layer + VPX_SS_MAX_LAYERS - si->layers;
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.min_quantizer = si->quantizer[layer_index];
svc_params.max_quantizer = si->quantizer[layer_index]; svc_params.max_quantizer = si->quantizer[layer_index];
}
svc_params.distance_from_i_frame = si->frame_within_gop; svc_params.distance_from_i_frame = si->frame_within_gop;
// Use buffer i for layer i LST // Use buffer i for layer i LST

View File

@@ -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" * e.g., "60,53,39,33,27"
*/ */
vpx_codec_err_t vpx_svc_set_quantizers(SvcContext *svc_ctx, 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 * Set SVC scale factors