diff --git a/src/config.c b/src/config.c index ea51b871..d1c0236f 100644 --- a/src/config.c +++ b/src/config.c @@ -537,35 +537,35 @@ 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].layer = 1; cfg->gop[0].is_ref = 1; + 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].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[1].poc_offset = 4; cfg->gop[1].layer = 2; cfg->gop[1].is_ref = 1; + 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].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[2].poc_offset = 2; cfg->gop[2].layer = 3; cfg->gop[2].is_ref = 1; + 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].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[3].poc_offset = 1; cfg->gop[3].layer = 4; cfg->gop[3].is_ref = 0; + 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].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[4].poc_offset = 3; cfg->gop[4].layer = 4; cfg->gop[4].is_ref = 0; + 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].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[5].poc_offset = 6; cfg->gop[5].layer = 3; cfg->gop[5].is_ref = 1; + 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].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[6].poc_offset = 5; cfg->gop[6].layer = 4; cfg->gop[6].is_ref = 0; + 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].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[7].poc_offset = 7; cfg->gop[7].layer = 4; cfg->gop[7].is_ref = 0; + 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].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; } else if(atoi(value)) { diff --git a/src/config.h b/src/config.h index 20b64741..65da7243 100644 --- a/src/config.h +++ b/src/config.h @@ -29,6 +29,8 @@ typedef struct { + double qp_factor; + int8_t qp_offset; /*!< \brief QP offset */ 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/encoderstate.c b/src/encoderstate.c index 5d70c30e..a90e987e 100644 --- a/src/encoderstate.c +++ b/src/encoderstate.c @@ -45,10 +45,6 @@ #include "rdo.h" #include "rate_control.h" -#ifndef LMBD -# define LMBD 1.0 -#endif - int encoder_state_match_children_of_previous_frame(encoder_state_t * const state) { int i; for (i = 0; state->children[i].encoder_control; ++i) { @@ -771,10 +767,24 @@ static void encoder_state_new_frame(encoder_state_t * const state) { encoder_state_ref_sort(state); } - double lambda = select_picture_lambda(state); + double lambda; + if (encoder->cfg->target_bitrate > 0) { + // Rate control enabled. + lambda = select_picture_lambda(state); + state->global->QP = lambda_to_QP(lambda); + } else { + if (encoder->cfg->gop_len > 0 && state->global->slicetype != SLICE_I) { + gop_config_t const * const gop = + encoder->cfg->gop + state->global->gop_offset; + state->global->QP = encoder->cfg->qp + gop->qp_offset; + state->global->QP_factor = gop->qp_factor; + } else { + state->global->QP = encoder->cfg->qp; + } + lambda = select_picture_lambda_from_qp(state); + } state->global->cur_lambda_cost = lambda; state->global->cur_lambda_cost_sqrt = sqrt(lambda); - state->global->QP = lambda_to_QP(lambda); } else { //Clear the bitstream if it's not the main encoder diff --git a/src/rate_control.c b/src/rate_control.c index fc7cb5f4..5b267499 100644 --- a/src/rate_control.c +++ b/src/rate_control.c @@ -108,22 +108,23 @@ static double pic_allocate_bits(const encoder_state_t * const state) * \brief Select a lambda value for encoding the next picture * \param state the main encoder state * \return lambda for the next picture + * + * Rate control must be enabled (i.e. cfg->target_bitrate > 0) when this + * function is called. */ double select_picture_lambda(encoder_state_t * const state) { const encoder_control_t * const encoder = state->encoder_control; - if (encoder->cfg->target_bitrate <= 0) { - // Rate control disabled. - return exp((encoder->cfg->qp - 13.7223 - 0.5) / 4.2005); - } + assert(encoder->cfg->target_bitrate > 0); if (state->global->frame > encoder->cfg->owf) { + // At least one frame has been written. update_rc_parameters(state); } if (encoder->cfg->gop_len == 0 || state->global->gop_offset == 0) { - // a new GOP begins at this frame + // A new GOP begins at this frame. gop_allocate_bits(state); } else { state->global->cur_gop_target_bits = @@ -141,6 +142,34 @@ double select_picture_lambda(encoder_state_t * const state) int8_t lambda_to_QP(const double lambda) { - int8_t qp = 4.2005 * log(lambda) + 13.7223 + 0.5; + const int8_t qp = 4.2005 * log(lambda) + 13.7223 + 0.5; return CLIP(0, 51, qp); } + +/** + * \brief Select a lambda value according to current QP value + * \param state the main encoder state + * \return lambda for the next picture + * + * This function should be used to select lambda when rate control is + * disabled. + */ +double select_picture_lambda_from_qp(encoder_state_t const * const state) +{ + const int gop_len = state->encoder_control->cfg->gop_len; + const double qp_temp = state->global->QP - 12; + + double qp_factor; + if (state->global->slicetype == SLICE_I) { + const double lambda_scale = 1.0 - CLIP(0.0, 0.5, 0.05 * gop_len); + qp_factor = 0.57 * lambda_scale; + } else if (gop_len > 0) { + qp_factor = 0.95 * state->global->QP_factor; + } else { + // default QP factor from HM config + qp_factor = 0.95 * 0.4624; + } + + const double lambda = qp_factor * pow(2.0, qp_temp / 3.0); + return lambda; +} diff --git a/src/rate_control.h b/src/rate_control.h index 45ab0791..073a838d 100644 --- a/src/rate_control.h +++ b/src/rate_control.h @@ -31,4 +31,6 @@ double select_picture_lambda(encoder_state_t * const state); int8_t lambda_to_QP(const double lambda); +double select_picture_lambda_from_qp(encoder_state_t const * const state); + #endif // RATE_CONTROL_H_