Fix lambda and qp calcualtion for intra frames

also fixes a bug with selecting the clip neighbor lambda and clip neighbor qp
selection for inter frames
This commit is contained in:
Joose Sainio 2019-11-05 10:42:07 +02:00
parent 372934c7db
commit 408fd4ccb6
2 changed files with 81 additions and 51 deletions

View file

@ -50,8 +50,8 @@ static int encoder_state_config_frame_init(encoder_state_t * const state) {
state->frame->cur_gop_bits_coded = 0; state->frame->cur_gop_bits_coded = 0;
state->frame->prepared = 0; state->frame->prepared = 0;
state->frame->done = 1; state->frame->done = 1;
state->frame->rc_alpha = 3.2003; state->frame->rc_alpha = 6.7542000000000000;
state->frame->rc_beta = -1.367; state->frame->rc_beta = 1.7860000000000000;
const encoder_control_t * const encoder = state->encoder_control; const encoder_control_t * const encoder = state->encoder_control;
const int num_lcus = encoder->in.width_in_lcu * encoder->in.height_in_lcu; const int num_lcus = encoder->in.width_in_lcu * encoder->in.height_in_lcu;

View file

@ -29,6 +29,7 @@
static const int SMOOTHING_WINDOW = 40; static const int SMOOTHING_WINDOW = 40;
static const double MIN_LAMBDA = 0.1; static const double MIN_LAMBDA = 0.1;
static const double MAX_LAMBDA = 10000; static const double MAX_LAMBDA = 10000;
#define BETA1 1.2517
/** /**
* \brief Clip lambda value to a valid range. * \brief Clip lambda value to a valid range.
@ -406,7 +407,7 @@ void kvz_estimate_pic_lambda(encoder_state_t * const state) {
int32_t num_pixels = state->encoder_control->cfg.width * state->encoder_control->cfg.height; int32_t num_pixels = state->encoder_control->cfg.width * state->encoder_control->cfg.height;
double bpp = bits / num_pixels; double bpp = bits / num_pixels;
if (state->frame->is_irap) { if (state->frame->is_irap) {
double temp = pow(state->frame->icost / num_pixels, 1.2517); double temp = pow(state->frame->icost / num_pixels, BETA1);
est_lambda = alpha / 256 * pow(temp/bpp, beta); est_lambda = alpha / 256 * pow(temp/bpp, beta);
} }
else { else {
@ -548,11 +549,12 @@ void kvz_set_ctu_qp_lambda(encoder_state_t * const state, vector2d_t pos) {
const int layer = encoder->cfg.gop[state->frame->gop_offset].layer - (state->frame->is_irap ? 1 : 0); const int layer = encoder->cfg.gop[state->frame->gop_offset].layer - (state->frame->is_irap ? 1 : 0);
int index = pos.x + pos.y * state->encoder_control->in.width_in_lcu; int index = pos.x + pos.y * state->encoder_control->in.width_in_lcu;
double bpp = bits / state->frame->lcu_stats[index].pixels; lcu_stats_t* ctu = &state->frame->lcu_stats[index];
double bpp = bits / ctu->pixels;
double alpha; double alpha;
double beta; double beta;
if (state->frame->poc == 0) { if (state->frame->is_irap) {
alpha = state->frame->rc_alpha; alpha = state->frame->rc_alpha;
beta = state->frame->rc_beta; beta = state->frame->rc_beta;
} }
@ -562,62 +564,78 @@ void kvz_set_ctu_qp_lambda(encoder_state_t * const state, vector2d_t pos) {
beta = state->frame->new_ratecontrol.k_para[layer][index] - 1; beta = state->frame->new_ratecontrol.k_para[layer][index] - 1;
} }
double est_lambda = alpha * pow(bpp, beta); double est_lambda;
double clip_lambda = state->frame->lambda; int est_qp;
if (state->frame->is_irap) {
double cost_per_pixel = (double)ctu->i_cost / ctu->pixels;
cost_per_pixel = pow(cost_per_pixel, BETA1);
est_lambda = alpha / 256.0 * pow(cost_per_pixel / bpp, beta);
est_qp = state->frame->QP;
double max_lambda = exp(((double)est_qp + 2.49 - 13.7122) / 4.2005);
double min_lambda = exp(((double)est_qp - 2.49 - 13.7122) / 4.2005);
est_lambda = CLIP(min_lambda, max_lambda, est_lambda);
double clip_neighbor_lambda = -1; est_qp = lambda_to_qp(est_lambda);
for(int temp_index = index - 1; temp_index >= 0; --temp_index) {
if(state->frame->lcu_stats[index].lambda > 0) {
clip_neighbor_lambda = state->frame->lcu_stats[index].lambda;
break;
}
}
if (clip_neighbor_lambda > 0) {
est_lambda = CLIP(clip_neighbor_lambda * pow(2, -(1.0 + frame_allocation) / 3.0),
clip_neighbor_lambda * pow(2.0, (1.0 + frame_allocation) / 3.0),
est_lambda);
}
if (clip_lambda > 0) {
est_lambda = CLIP(clip_lambda * pow(2, -(2.0 + frame_allocation) / 3.0),
clip_lambda * pow(2.0, (1.0 + frame_allocation) / 3.0),
est_lambda);
} }
else { else {
est_lambda = CLIP(10.0, 1000.0, est_lambda);
} est_lambda = alpha * pow(bpp, beta);
const double clip_lambda = state->frame->lambda;
if (est_lambda < 0.1) { double clip_neighbor_lambda = -1;
est_lambda = 0.1; for(int temp_index = index - 1; temp_index >= 0; --temp_index) {
} if(state->frame->lcu_stats[temp_index].lambda > 0) {
clip_neighbor_lambda = state->frame->lcu_stats[temp_index].lambda;
int est_qp = lambda_to_qp(est_lambda); break;
}
int clip_qp = -1;
for (int temp_index = index - 1; temp_index >= 0; --temp_index) {
if (state->frame->lcu_stats[index].qp > -1) {
clip_qp = state->frame->lcu_stats[index].qp;
break;
} }
}
if( clip_qp > -1) { if (clip_neighbor_lambda > 0) {
est_qp = CLIP(clip_qp - 1 - frame_allocation, est_lambda = CLIP(clip_neighbor_lambda * pow(2, -(1.0 + frame_allocation) / 3.0),
clip_qp + 1 + frame_allocation, clip_neighbor_lambda * pow(2.0, (1.0 + frame_allocation) / 3.0),
clip_qp); est_lambda);
} }
est_qp = CLIP(state->frame->QP - 2 - frame_allocation, if (clip_lambda > 0) {
state->frame->QP + 2 + frame_allocation, est_lambda = CLIP(clip_lambda * pow(2, -(2.0 + frame_allocation) / 3.0),
est_qp); clip_lambda * pow(2.0, (1.0 + frame_allocation) / 3.0),
est_lambda);
}
else {
est_lambda = CLIP(10.0, 1000.0, est_lambda);
}
if (est_lambda < 0.1) {
est_lambda = 0.1;
}
est_qp = lambda_to_qp(est_lambda);
int clip_qp = -1;
for (int temp_index = index - 1; temp_index >= 0; --temp_index) {
if (state->frame->lcu_stats[temp_index].qp > -1) {
clip_qp = state->frame->lcu_stats[temp_index].qp;
break;
}
}
if( clip_qp > -1) {
est_qp = CLIP(clip_qp - 1 - frame_allocation,
clip_qp + 1 + frame_allocation,
clip_qp);
}
est_qp = CLIP(state->frame->QP - 2 - frame_allocation,
state->frame->QP + 2 + frame_allocation,
est_qp);
}
state->lambda = est_lambda; state->lambda = est_lambda;
state->lambda_sqrt = sqrt(est_lambda); state->lambda_sqrt = sqrt(est_lambda);
state->qp = est_qp; state->qp = est_qp;
state->frame->lcu_stats[index].qp = est_qp; ctu->qp = est_qp;
state->frame->lcu_stats[index].lambda = est_lambda; ctu->lambda = est_lambda;
state->frame->lcu_stats[index].i_cost = 0; ctu->i_cost = 0;
} }
@ -697,10 +715,22 @@ static void update_ck(encoder_state_t * const state, int ctu_index, int layer)
void kvz_update_after_picture(encoder_state_t * const state) { void kvz_update_after_picture(encoder_state_t * const state) {
double total_distortion = 0; double total_distortion = 0;
double lambda = 0; double lambda = 0;
double pic_bpp = (double)state->frame->cur_frame_bits_coded / (state->encoder_control->in.width * state->encoder_control->in.height); int32_t pixels = (state->encoder_control->in.width * state->encoder_control->in.height);
double pic_bpp = (double)state->frame->cur_frame_bits_coded / pixels;
const encoder_control_t * const encoder = state->encoder_control; const encoder_control_t * const encoder = state->encoder_control;
const int layer = encoder->cfg.gop[state->frame->gop_offset].layer - (state->frame->is_irap ? 1 : 0); const int layer = encoder->cfg.gop[state->frame->gop_offset].layer - (state->frame->is_irap ? 1 : 0);
if (state->frame->is_irap) {
double lnbpp = log(pow(state->frame->icost / pixels, BETA1));
double diff_lambda = state->frame->rc_beta * log(state->frame->cur_frame_bits_coded) - log(state->frame->cur_pic_target_bits);
diff_lambda = CLIP(-0.125, 0.125, 0.25*diff_lambda);
state->frame->rc_alpha *= exp(diff_lambda);
state->frame->rc_beta += diff_lambda / lnbpp;
}
for(int y_ctu = 0; y_ctu < state->encoder_control->in.height_in_lcu; y_ctu++) { for(int y_ctu = 0; y_ctu < state->encoder_control->in.height_in_lcu; y_ctu++) {
for (int x_ctu = 0; x_ctu < state->encoder_control->in.width_in_lcu; x_ctu++) { for (int x_ctu = 0; x_ctu < state->encoder_control->in.width_in_lcu; x_ctu++) {
int ctu_distortion = 0; int ctu_distortion = 0;