From b54d5aa91fecaef218c7a5a4174cd0797575b464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arttu=20Yl=C3=A4-Outinen?= Date: Wed, 6 May 2015 14:08:18 +0300 Subject: [PATCH] Select GOP picture weights according to bitrate. Pictures in same layer have equal weights. At low bitrates, the difference between low and high layers is greater than at high bitrates. --- src/config.c | 24 ++++++++-------------- src/config.h | 3 --- src/rate_control.c | 51 +++++++++++++++++++++++++++++++++++++++------- 3 files changed, 52 insertions(+), 26 deletions(-) diff --git a/src/config.c b/src/config.c index 0fbdcdb5..ea51b871 100644 --- a/src/config.c +++ b/src/config.c @@ -537,45 +537,37 @@ static int config_parse(config_t *cfg, const char *name, const char *value) if(atoi(value) == 8) { // GOP cfg->gop_len = 8; - cfg->gop[0].poc_offset = 8; cfg->gop[0].qp_offset = 1; cfg->gop[0].layer = 1; cfg->gop[0].qp_factor = 0.442; cfg->gop[0].is_ref = 1; + cfg->gop[0].poc_offset = 8; cfg->gop[0].layer = 1; cfg->gop[0].is_ref = 1; cfg->gop[0].ref_pos_count = 0; cfg->gop[0].ref_neg_count = 3; cfg->gop[0].ref_neg[0] = 8; cfg->gop[0].ref_neg[1] = 12; cfg->gop[0].ref_neg[2] = 16; - cfg->gop[0].weight = 6; - cfg->gop[1].poc_offset = 4; cfg->gop[1].qp_offset = 2; cfg->gop[1].layer = 2; cfg->gop[1].qp_factor = 0.3536; cfg->gop[1].is_ref = 1; + cfg->gop[1].poc_offset = 4; cfg->gop[1].layer = 2; cfg->gop[1].is_ref = 1; cfg->gop[1].ref_neg_count = 2; cfg->gop[1].ref_neg[0] = 4; cfg->gop[1].ref_neg[1] = 8; cfg->gop[1].ref_pos_count = 1; cfg->gop[1].ref_pos[0] = 4; - cfg->gop[1].weight = 6; - cfg->gop[2].poc_offset = 2; cfg->gop[2].qp_offset = 3; cfg->gop[2].layer = 3; cfg->gop[2].qp_factor = 0.3536; cfg->gop[2].is_ref = 1; + cfg->gop[2].poc_offset = 2; cfg->gop[2].layer = 3; cfg->gop[2].is_ref = 1; cfg->gop[2].ref_neg_count = 2; cfg->gop[2].ref_neg[0] = 2; cfg->gop[2].ref_neg[1] = 6; cfg->gop[2].ref_pos_count = 2; cfg->gop[2].ref_pos[0] = 2; cfg->gop[2].ref_pos[1] = 6; - cfg->gop[2].weight = 3; - cfg->gop[3].poc_offset = 1; cfg->gop[3].qp_offset = 4; cfg->gop[3].layer = 4; cfg->gop[3].qp_factor = 0.68; cfg->gop[3].is_ref = 0; + cfg->gop[3].poc_offset = 1; cfg->gop[3].layer = 4; cfg->gop[3].is_ref = 0; cfg->gop[3].ref_neg_count = 1; cfg->gop[3].ref_neg[0] = 1; cfg->gop[3].ref_pos_count = 3; cfg->gop[3].ref_pos[0] = 1; cfg->gop[3].ref_pos[1] = 3; cfg->gop[3].ref_pos[2] = 7; - cfg->gop[3].weight = 2; - cfg->gop[4].poc_offset = 3; cfg->gop[4].qp_offset = 4; cfg->gop[4].layer = 4; cfg->gop[4].qp_factor = 0.68; cfg->gop[4].is_ref = 0; + cfg->gop[4].poc_offset = 3; cfg->gop[4].layer = 4; cfg->gop[4].is_ref = 0; cfg->gop[4].ref_neg_count = 2; cfg->gop[4].ref_neg[0] = 1; cfg->gop[4].ref_neg[1] = 3; cfg->gop[4].ref_pos_count = 2; cfg->gop[4].ref_pos[0] = 1; cfg->gop[4].ref_pos[1] = 5; - cfg->gop[4].weight = 2; - cfg->gop[5].poc_offset = 6; cfg->gop[5].qp_offset = 3; cfg->gop[5].layer = 3; cfg->gop[5].qp_factor = 0.3536; cfg->gop[5].is_ref = 1; + cfg->gop[5].poc_offset = 6; cfg->gop[5].layer = 3; cfg->gop[5].is_ref = 1; cfg->gop[5].ref_neg_count = 2; cfg->gop[5].ref_neg[0] = 2; cfg->gop[5].ref_neg[1] = 6; cfg->gop[5].ref_pos_count = 1; cfg->gop[5].ref_pos[0] = 2; - cfg->gop[5].weight = 3; - cfg->gop[6].poc_offset = 5; cfg->gop[6].qp_offset = 4; cfg->gop[6].layer = 4; cfg->gop[6].qp_factor = 0.68; cfg->gop[6].is_ref = 0; + cfg->gop[6].poc_offset = 5; cfg->gop[6].layer = 4; cfg->gop[6].is_ref = 0; cfg->gop[6].ref_neg_count = 2; cfg->gop[6].ref_neg[0] = 1; cfg->gop[6].ref_neg[1] = 5; cfg->gop[6].ref_pos_count = 2; cfg->gop[6].ref_pos[0] = 1; cfg->gop[6].ref_pos[1] = 3; - cfg->gop[6].weight = 2; - cfg->gop[7].poc_offset = 7; cfg->gop[7].qp_offset = 4; cfg->gop[7].layer = 4; cfg->gop[7].qp_factor = 0.68; cfg->gop[7].is_ref = 0; + cfg->gop[7].poc_offset = 7; cfg->gop[7].layer = 4; cfg->gop[7].is_ref = 0; cfg->gop[7].ref_neg_count = 3; cfg->gop[7].ref_neg[0] = 1; cfg->gop[7].ref_neg[1] = 3; cfg->gop[7].ref_neg[2] = 7; cfg->gop[7].ref_pos_count = 1; cfg->gop[7].ref_pos[0] = 1; - cfg->gop[7].weight = 2; } else if(atoi(value)) { fprintf(stderr, "Input error: goplen must be 8\n"); return 0; diff --git a/src/config.h b/src/config.h index d2e3655f..20b64741 100644 --- a/src/config.h +++ b/src/config.h @@ -29,9 +29,6 @@ typedef struct { - double qp_factor; - int8_t qp_offset; /*!< \brief QP offset */ - int8_t weight; int8_t poc_offset; /*!< \brief POC offset */ int8_t layer; /*!< \brief Current layer */ int8_t is_ref; /*!< \brief Flag if this picture is used as a reference */ diff --git a/src/rate_control.c b/src/rate_control.c index df190bf0..59418c01 100644 --- a/src/rate_control.c +++ b/src/rate_control.c @@ -59,6 +59,47 @@ static void gop_allocate_bits(encoder_state_t * const state) state->global->cur_gop_target_bits = MAX(200, gop_target_bits); } +/** + * Allocate bits for the current picture. + * \param state the main encoder state + * \return target number of bits + */ +double pic_allocate_bits(const encoder_state_t * const state) { + const encoder_control_t * const encoder = state->encoder_control; + + if (encoder->cfg->gop_len <= 0) { + return state->global->cur_gop_target_bits; + } + + const double avg_bits_per_picture = + encoder->cfg->target_bitrate / encoder->cfg->framerate; + const int pixels_per_picture = encoder->in.width * encoder->in.height; + const double avg_bits_per_pixel = avg_bits_per_picture / pixels_per_picture; + + int layer_weights[4]; +#define SET_ARRAY(array, x0, x1, x2, x3) \ + do { array[0] = x0; array[1] = x1; array[2] = x2; array[3] = x3; } while(0) + + if (avg_bits_per_pixel <= 0.05) { + SET_ARRAY(layer_weights, 30, 8, 4, 1); + } else if (avg_bits_per_pixel <= 0.1) { + SET_ARRAY(layer_weights, 25, 7, 4, 1); + } else if (avg_bits_per_pixel <= 0.2) { + SET_ARRAY(layer_weights, 20, 6, 4, 1); + } else { + SET_ARRAY(layer_weights, 15, 5, 4, 1); + } +#undef SET_ARRAY + + const int pic_weight = layer_weights[encoder->cfg->gop[state->global->gop_offset].layer - 1]; + int sum_weights = 0; + for (int i = 0; i < encoder->cfg->gop_len; ++i) { + sum_weights += layer_weights[encoder->cfg->gop[i].layer - 1]; + } + + return state->global->cur_gop_target_bits * pic_weight / sum_weights; +} + /** * \brief Select a lambda value for encoding the next picture * \param state the main encoder state @@ -81,15 +122,11 @@ double select_picture_lambda(encoder_state_t * const state) state->previous_encoder_state->global->cur_gop_target_bits; } - const double target_bits_current_picture = (encoder->cfg->gop_len > 0) - ? (state->global->cur_gop_target_bits * encoder->cfg->gop[state->global->gop_offset].weight / 22.0) - : state->global->cur_gop_target_bits - ; - // TODO: take the picture headers into account const int pixels_per_picture = encoder->in.width * encoder->in.height; - const double target_bits_per_pixel = target_bits_current_picture / pixels_per_picture; - + const double target_bits_current_picture = pic_allocate_bits(state); + const double target_bits_per_pixel = + target_bits_current_picture / pixels_per_picture; const double lambda = 3.2003 * pow(target_bits_per_pixel, -1.367); return CLIP(0.1, 10000, lambda); }