2015-03-13 12:23:54 +00:00
|
|
|
/*****************************************************************************
|
|
|
|
* This file is part of Kvazaar HEVC encoder.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2013-2015 Tampere University of Technology and others (see
|
|
|
|
* COPYING file).
|
|
|
|
*
|
|
|
|
* Kvazaar is free software: you can redistribute it and/or modify it under
|
|
|
|
* the terms of the GNU Lesser General Public License as published by the
|
|
|
|
* Free Software Foundation; either version 2.1 of the License, or (at your
|
|
|
|
* option) any later version.
|
|
|
|
*
|
|
|
|
* Kvazaar is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
|
|
|
|
* more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with Kvazaar. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include "rate_control.h"
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
|
2016-04-01 14:14:23 +00:00
|
|
|
#include "encoder.h"
|
|
|
|
#include "kvazaar.h"
|
|
|
|
|
|
|
|
|
2015-03-13 12:23:54 +00:00
|
|
|
static const int SMOOTHING_WINDOW = 40;
|
2016-09-14 03:52:56 +00:00
|
|
|
static const double MIN_LAMBDA = 0.1;
|
|
|
|
static const double MAX_LAMBDA = 10000;
|
2015-03-13 12:23:54 +00:00
|
|
|
|
2016-08-24 02:38:10 +00:00
|
|
|
/**
|
|
|
|
* \brief Clip lambda value to a valid range.
|
|
|
|
*/
|
|
|
|
static double clip_lambda(double lambda) {
|
|
|
|
if (isnan(lambda)) return MAX_LAMBDA;
|
|
|
|
return CLIP(MIN_LAMBDA, MAX_LAMBDA, lambda);
|
|
|
|
}
|
|
|
|
|
2015-05-06 11:08:18 +00:00
|
|
|
/**
|
|
|
|
* \brief Update alpha and beta parameters.
|
|
|
|
*
|
2016-08-24 03:51:54 +00:00
|
|
|
* \param bits number of bits spent for coding the area
|
|
|
|
* \param pixels size of the area in pixels
|
|
|
|
* \param lambda_real lambda used for coding the area
|
|
|
|
* \param[in,out] alpha alpha parameter to update
|
|
|
|
* \param[in,out] beta beta parameter to update
|
2015-05-06 11:08:18 +00:00
|
|
|
*/
|
2016-08-24 03:51:54 +00:00
|
|
|
static void update_parameters(uint32_t bits,
|
|
|
|
uint32_t pixels,
|
|
|
|
double lambda_real,
|
|
|
|
double *alpha,
|
|
|
|
double *beta)
|
2015-05-06 11:08:18 +00:00
|
|
|
{
|
2016-08-24 03:51:54 +00:00
|
|
|
const double bpp = bits / (double)pixels;
|
|
|
|
const double lambda_comp = clip_lambda(*alpha * pow(bpp, *beta));
|
2015-05-06 11:08:18 +00:00
|
|
|
const double lambda_log_ratio = log(lambda_real) - log(lambda_comp);
|
|
|
|
|
2016-08-24 03:51:54 +00:00
|
|
|
*alpha += 0.10 * lambda_log_ratio * (*alpha);
|
|
|
|
*alpha = CLIP(0.05, 20, *alpha);
|
2015-05-06 11:08:18 +00:00
|
|
|
|
2016-08-24 03:51:54 +00:00
|
|
|
*beta += 0.05 * lambda_log_ratio * CLIP(-5.0, -1.0, log(bpp));
|
|
|
|
*beta = CLIP(-3, -0.1, *beta);
|
2015-05-06 11:08:18 +00:00
|
|
|
}
|
|
|
|
|
2015-03-13 12:23:54 +00:00
|
|
|
/**
|
2015-05-04 09:20:41 +00:00
|
|
|
* \brief Allocate bits for the current GOP.
|
2016-09-14 03:52:56 +00:00
|
|
|
* \param state the main encoder state
|
|
|
|
* \return target number of bits
|
2015-03-13 12:23:54 +00:00
|
|
|
*/
|
2016-09-14 03:52:56 +00:00
|
|
|
static double gop_allocate_bits(encoder_state_t * const state)
|
2015-03-13 12:23:54 +00:00
|
|
|
{
|
|
|
|
const encoder_control_t * const encoder = state->encoder_control;
|
|
|
|
|
|
|
|
// At this point, total_bits_coded of the current state contains the
|
|
|
|
// number of bits written encoder->owf frames before the current frame.
|
2016-08-10 00:46:23 +00:00
|
|
|
uint64_t bits_coded = state->frame->total_bits_coded;
|
2017-02-06 11:00:25 +00:00
|
|
|
int pictures_coded = MAX(0, state->frame->num - encoder->cfg.owf);
|
2015-03-13 12:23:54 +00:00
|
|
|
|
2017-02-06 11:00:25 +00:00
|
|
|
int gop_offset = (state->frame->gop_offset - encoder->cfg.owf) % MAX(1, encoder->cfg.gop_len);
|
2018-11-07 14:03:38 +00:00
|
|
|
|
|
|
|
if (encoder->cfg.gop_len > 0 && gop_offset != encoder->cfg.gop_len - 1 && encoder->cfg.gop_lp_definition.d == 0) {
|
2015-05-04 09:20:41 +00:00
|
|
|
// Subtract number of bits in the partially coded GOP.
|
2016-08-10 00:46:23 +00:00
|
|
|
bits_coded -= state->frame->cur_gop_bits_coded;
|
2015-05-04 09:20:41 +00:00
|
|
|
// Subtract number of pictures in the partially coded GOP.
|
|
|
|
pictures_coded -= gop_offset + 1;
|
|
|
|
}
|
2015-03-13 12:23:54 +00:00
|
|
|
|
2016-09-14 03:52:56 +00:00
|
|
|
// Equation 12 from https://doi.org/10.1109/TIP.2014.2336550
|
2015-05-04 09:20:41 +00:00
|
|
|
double gop_target_bits =
|
2015-05-27 12:41:45 +00:00
|
|
|
(encoder->target_avg_bppic * (pictures_coded + SMOOTHING_WINDOW) - bits_coded)
|
2017-02-05 09:59:21 +00:00
|
|
|
* MAX(1, encoder->cfg.gop_len) / SMOOTHING_WINDOW;
|
2016-09-14 03:52:56 +00:00
|
|
|
// Allocate at least 200 bits for each GOP like HM does.
|
|
|
|
return MAX(200, gop_target_bits);
|
2015-05-04 09:20:41 +00:00
|
|
|
}
|
|
|
|
|
2016-10-06 12:27:01 +00:00
|
|
|
/**
|
|
|
|
* Estimate number of bits used for headers of the current picture.
|
|
|
|
* \param state the main encoder state
|
|
|
|
* \return number of header bits
|
|
|
|
*/
|
|
|
|
static uint64_t pic_header_bits(encoder_state_t * const state)
|
|
|
|
{
|
2017-02-05 09:59:21 +00:00
|
|
|
const kvz_config* cfg = &state->encoder_control->cfg;
|
2016-10-06 12:27:01 +00:00
|
|
|
|
|
|
|
// nal type and slice header
|
|
|
|
uint64_t bits = 48 + 24;
|
|
|
|
|
|
|
|
// entry points
|
|
|
|
bits += 12 * state->encoder_control->in.height_in_lcu;
|
|
|
|
|
|
|
|
switch (cfg->hash) {
|
|
|
|
case KVZ_HASH_CHECKSUM:
|
|
|
|
bits += 168;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KVZ_HASH_MD5:
|
|
|
|
bits += 456;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KVZ_HASH_NONE:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (encoder_state_must_write_vps(state)) {
|
|
|
|
bits += 613;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state->frame->num == 0 && cfg->add_encoder_info) {
|
|
|
|
bits += 1392;
|
|
|
|
}
|
|
|
|
|
|
|
|
return bits;
|
|
|
|
}
|
|
|
|
|
2015-05-06 11:08:18 +00:00
|
|
|
/**
|
|
|
|
* Allocate bits for the current picture.
|
2016-09-14 03:52:56 +00:00
|
|
|
* \param state the main encoder state
|
2016-10-06 12:27:01 +00:00
|
|
|
* \return target number of bits, excluding headers
|
2015-05-06 11:08:18 +00:00
|
|
|
*/
|
2016-09-14 03:52:56 +00:00
|
|
|
static double pic_allocate_bits(encoder_state_t * const state)
|
2015-05-06 11:08:18 +00:00
|
|
|
{
|
2015-05-06 11:08:18 +00:00
|
|
|
const encoder_control_t * const encoder = state->encoder_control;
|
|
|
|
|
2017-02-05 09:59:21 +00:00
|
|
|
if (encoder->cfg.gop_len == 0 ||
|
2016-09-14 03:52:56 +00:00
|
|
|
state->frame->gop_offset == 0 ||
|
|
|
|
state->frame->num == 0)
|
|
|
|
{
|
|
|
|
// A new GOP starts at this frame.
|
|
|
|
state->frame->cur_gop_target_bits = gop_allocate_bits(state);
|
|
|
|
state->frame->cur_gop_bits_coded = 0;
|
|
|
|
} else {
|
|
|
|
state->frame->cur_gop_target_bits =
|
|
|
|
state->previous_encoder_state->frame->cur_gop_target_bits;
|
|
|
|
}
|
|
|
|
|
2017-02-05 09:59:21 +00:00
|
|
|
if (encoder->cfg.gop_len <= 0) {
|
2016-08-10 00:46:23 +00:00
|
|
|
return state->frame->cur_gop_target_bits;
|
2015-05-06 11:08:18 +00:00
|
|
|
}
|
|
|
|
|
2015-05-27 12:41:45 +00:00
|
|
|
const double pic_weight = encoder->gop_layer_weights[
|
2017-02-05 09:59:21 +00:00
|
|
|
encoder->cfg.gop[state->frame->gop_offset].layer - 1];
|
2016-10-06 12:27:01 +00:00
|
|
|
const double pic_target_bits =
|
|
|
|
state->frame->cur_gop_target_bits * pic_weight - pic_header_bits(state);
|
2016-09-14 03:52:56 +00:00
|
|
|
// Allocate at least 100 bits for each picture like HM does.
|
2015-05-06 11:08:18 +00:00
|
|
|
return MAX(100, pic_target_bits);
|
2015-05-06 11:08:18 +00:00
|
|
|
}
|
|
|
|
|
2017-01-11 06:47:53 +00:00
|
|
|
static int8_t lambda_to_qp(const double lambda)
|
2015-05-04 09:20:41 +00:00
|
|
|
{
|
2015-05-29 11:00:51 +00:00
|
|
|
const int8_t qp = 4.2005 * log(lambda) + 13.7223 + 0.5;
|
2017-05-17 09:41:51 +00:00
|
|
|
return CLIP_TO_QP(qp);
|
2015-03-13 12:23:54 +00:00
|
|
|
}
|
2015-05-29 11:00:51 +00:00
|
|
|
|
2020-02-15 20:32:52 +00:00
|
|
|
static double qp_to_lambda(encoder_state_t * const state, int qp)
|
2017-01-16 06:47:21 +00:00
|
|
|
{
|
2020-02-15 20:51:25 +00:00
|
|
|
const int shift_qp = 12;
|
|
|
|
double lambda = 0.57 * pow(2.0, (qp - shift_qp) / 3.0);
|
|
|
|
|
|
|
|
// NOTE: HM adjusts lambda for inter according to Hadamard usage in ME.
|
|
|
|
// SATD is currently always enabled for ME, so this has no effect.
|
|
|
|
// bool hadamard_me = true;
|
|
|
|
// if (!hadamard_me && state->frame->slicetype != KVZ_SLICE_I) {
|
|
|
|
// lambda *= 0.95;
|
|
|
|
// }
|
2017-01-16 06:47:21 +00:00
|
|
|
|
|
|
|
return lambda;
|
|
|
|
}
|
|
|
|
|
2015-05-29 11:00:51 +00:00
|
|
|
/**
|
2016-08-21 05:03:57 +00:00
|
|
|
* \brief Allocate bits and set lambda and QP for the current picture.
|
2015-05-29 11:00:51 +00:00
|
|
|
* \param state the main encoder state
|
|
|
|
*/
|
2016-08-21 05:03:57 +00:00
|
|
|
void kvz_set_picture_lambda_and_qp(encoder_state_t * const state)
|
2015-05-29 11:00:51 +00:00
|
|
|
{
|
2016-08-21 05:03:57 +00:00
|
|
|
const encoder_control_t * const ctrl = state->encoder_control;
|
|
|
|
|
2017-02-05 09:59:21 +00:00
|
|
|
if (ctrl->cfg.target_bitrate > 0) {
|
2016-08-21 05:03:57 +00:00
|
|
|
// Rate control enabled
|
|
|
|
|
2017-02-06 11:00:25 +00:00
|
|
|
if (state->frame->num > ctrl->cfg.owf) {
|
2016-08-21 05:03:57 +00:00
|
|
|
// At least one frame has been written.
|
2016-08-24 03:51:54 +00:00
|
|
|
update_parameters(state->stats_bitstream_length * 8,
|
|
|
|
ctrl->in.pixels_per_pic,
|
|
|
|
state->frame->lambda,
|
|
|
|
&state->frame->rc_alpha,
|
|
|
|
&state->frame->rc_beta);
|
2015-11-02 12:10:10 +00:00
|
|
|
}
|
2016-08-21 05:03:57 +00:00
|
|
|
|
|
|
|
const double pic_target_bits = pic_allocate_bits(state);
|
|
|
|
const double target_bpp = pic_target_bits / ctrl->in.pixels_per_pic;
|
2016-08-24 02:38:10 +00:00
|
|
|
double lambda = state->frame->rc_alpha * pow(target_bpp, state->frame->rc_beta);
|
|
|
|
lambda = clip_lambda(lambda);
|
|
|
|
|
|
|
|
state->frame->lambda = lambda;
|
|
|
|
state->frame->QP = lambda_to_qp(lambda);
|
|
|
|
state->frame->cur_pic_target_bits = pic_target_bits;
|
2016-08-21 05:03:57 +00:00
|
|
|
|
2015-05-29 11:00:51 +00:00
|
|
|
} else {
|
2016-08-21 05:03:57 +00:00
|
|
|
// Rate control disabled
|
2017-02-05 09:59:21 +00:00
|
|
|
kvz_gop_config const * const gop = &ctrl->cfg.gop[state->frame->gop_offset];
|
|
|
|
const int gop_len = ctrl->cfg.gop_len;
|
2016-08-21 05:03:57 +00:00
|
|
|
|
|
|
|
if (gop_len > 0 && state->frame->slicetype != KVZ_SLICE_I) {
|
2018-02-14 13:57:38 +00:00
|
|
|
double qp = ctrl->cfg.qp;
|
|
|
|
qp += gop->qp_offset;
|
|
|
|
qp += CLIP(0.0, 3.0, qp * gop->qp_model_scale + gop->qp_model_offset);
|
|
|
|
state->frame->QP = CLIP_TO_QP((int)(qp + 0.5));
|
|
|
|
|
2017-05-17 09:41:51 +00:00
|
|
|
} else {
|
2018-02-14 13:57:38 +00:00
|
|
|
state->frame->QP = CLIP_TO_QP(ctrl->cfg.qp + ctrl->cfg.intra_qp_offset);
|
2016-08-21 05:03:57 +00:00
|
|
|
}
|
|
|
|
|
2020-02-15 20:32:52 +00:00
|
|
|
state->frame->lambda = qp_to_lambda(state, state->frame->QP);
|
2015-11-02 12:10:10 +00:00
|
|
|
}
|
2016-08-21 05:03:57 +00:00
|
|
|
}
|
|
|
|
|
2016-08-24 02:38:10 +00:00
|
|
|
/**
|
|
|
|
* \brief Allocate bits for a LCU.
|
|
|
|
* \param state the main encoder state
|
|
|
|
* \param pos location of the LCU as number of LCUs from top left
|
|
|
|
* \return number of bits allocated for the LCU
|
|
|
|
*/
|
|
|
|
static double lcu_allocate_bits(encoder_state_t * const state,
|
|
|
|
vector2d_t pos)
|
|
|
|
{
|
|
|
|
double lcu_weight;
|
2017-02-06 11:00:25 +00:00
|
|
|
if (state->frame->num > state->encoder_control->cfg.owf) {
|
2016-08-24 02:38:10 +00:00
|
|
|
lcu_weight = kvz_get_lcu_stats(state, pos.x, pos.y)->weight;
|
|
|
|
} else {
|
|
|
|
const uint32_t num_lcus = state->encoder_control->in.width_in_lcu *
|
|
|
|
state->encoder_control->in.height_in_lcu;
|
|
|
|
lcu_weight = 1.0 / num_lcus;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Target number of bits for the current LCU.
|
|
|
|
const double lcu_target_bits = state->frame->cur_pic_target_bits * lcu_weight;
|
|
|
|
|
|
|
|
// Allocate at least one bit for each LCU.
|
|
|
|
return MAX(1, lcu_target_bits);
|
|
|
|
}
|
|
|
|
|
2016-08-24 01:16:48 +00:00
|
|
|
void kvz_set_lcu_lambda_and_qp(encoder_state_t * const state,
|
|
|
|
vector2d_t pos)
|
2016-08-21 05:03:57 +00:00
|
|
|
{
|
2016-08-24 02:38:10 +00:00
|
|
|
const encoder_control_t * const ctrl = state->encoder_control;
|
|
|
|
|
2017-02-05 09:59:21 +00:00
|
|
|
if (ctrl->cfg.roi.dqps != NULL) {
|
2017-01-16 06:47:21 +00:00
|
|
|
vector2d_t lcu = {
|
|
|
|
pos.x + state->tile->lcu_offset_x,
|
|
|
|
pos.y + state->tile->lcu_offset_y
|
|
|
|
};
|
|
|
|
vector2d_t roi = {
|
2017-02-05 09:59:21 +00:00
|
|
|
lcu.x * ctrl->cfg.roi.width / ctrl->in.width_in_lcu,
|
|
|
|
lcu.y * ctrl->cfg.roi.height / ctrl->in.height_in_lcu
|
2017-01-16 06:47:21 +00:00
|
|
|
};
|
2017-02-05 09:59:21 +00:00
|
|
|
int roi_index = roi.x + roi.y * ctrl->cfg.roi.width;
|
|
|
|
int dqp = ctrl->cfg.roi.dqps[roi_index];
|
2017-05-17 09:41:51 +00:00
|
|
|
state->qp = CLIP_TO_QP(state->frame->QP + dqp);
|
2020-02-15 20:32:52 +00:00
|
|
|
state->lambda = qp_to_lambda(state, state->qp);
|
2019-05-29 12:40:27 +00:00
|
|
|
state->lambda_sqrt = sqrt(state->lambda);
|
2017-01-16 06:47:21 +00:00
|
|
|
|
2017-02-05 09:59:21 +00:00
|
|
|
} else if (ctrl->cfg.target_bitrate > 0) {
|
2016-08-24 03:51:54 +00:00
|
|
|
lcu_stats_t *lcu = kvz_get_lcu_stats(state, pos.x, pos.y);
|
|
|
|
const uint32_t pixels = MIN(LCU_WIDTH, state->tile->frame->width - LCU_WIDTH * pos.x) *
|
2016-08-24 02:38:10 +00:00
|
|
|
MIN(LCU_WIDTH, state->tile->frame->height - LCU_WIDTH * pos.y);
|
2016-08-24 03:51:54 +00:00
|
|
|
|
2017-02-06 11:00:25 +00:00
|
|
|
if (state->frame->num > ctrl->cfg.owf) {
|
2016-08-24 03:51:54 +00:00
|
|
|
update_parameters(lcu->bits,
|
|
|
|
pixels,
|
|
|
|
lcu->lambda,
|
|
|
|
&lcu->rc_alpha,
|
|
|
|
&lcu->rc_beta);
|
|
|
|
} else {
|
|
|
|
lcu->rc_alpha = state->frame->rc_alpha;
|
|
|
|
lcu->rc_beta = state->frame->rc_beta;
|
|
|
|
}
|
|
|
|
|
2016-08-24 02:38:10 +00:00
|
|
|
const double target_bits = lcu_allocate_bits(state, pos);
|
|
|
|
const double target_bpp = target_bits / pixels;
|
|
|
|
|
2016-08-24 03:51:54 +00:00
|
|
|
double lambda = clip_lambda(lcu->rc_alpha * pow(target_bpp, lcu->rc_beta));
|
2016-08-24 03:57:31 +00:00
|
|
|
// Clip lambda according to the equations 24 and 26 in
|
|
|
|
// https://doi.org/10.1109/TIP.2014.2336550
|
2017-02-06 11:00:25 +00:00
|
|
|
if (state->frame->num > ctrl->cfg.owf) {
|
2016-08-24 03:57:31 +00:00
|
|
|
const double bpp = lcu->bits / (double)pixels;
|
|
|
|
const double lambda_comp = clip_lambda(lcu->rc_alpha * pow(bpp, lcu->rc_beta));
|
|
|
|
lambda = CLIP(lambda_comp * 0.7937005259840998,
|
|
|
|
lambda_comp * 1.2599210498948732,
|
|
|
|
lambda);
|
|
|
|
}
|
|
|
|
lambda = CLIP(state->frame->lambda * 0.6299605249474366,
|
|
|
|
state->frame->lambda * 1.5874010519681994,
|
|
|
|
lambda);
|
|
|
|
lambda = clip_lambda(lambda);
|
2016-08-24 02:38:10 +00:00
|
|
|
|
2016-08-24 03:51:54 +00:00
|
|
|
lcu->lambda = lambda;
|
2016-08-24 02:38:10 +00:00
|
|
|
state->lambda = lambda;
|
|
|
|
state->lambda_sqrt = sqrt(lambda);
|
2016-08-24 03:51:54 +00:00
|
|
|
state->qp = lambda_to_qp(lambda);
|
2016-08-24 02:38:10 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
state->qp = state->frame->QP;
|
|
|
|
state->lambda = state->frame->lambda;
|
|
|
|
state->lambda_sqrt = sqrt(state->frame->lambda);
|
|
|
|
}
|
2020-02-07 14:04:23 +00:00
|
|
|
|
|
|
|
// Apply variance adaptive quantization
|
|
|
|
if (ctrl->cfg.vaq) {
|
|
|
|
vector2d_t lcu = {
|
|
|
|
pos.x + state->tile->lcu_offset_x,
|
|
|
|
pos.y + state->tile->lcu_offset_y
|
|
|
|
};
|
|
|
|
int id = lcu.x + lcu.y * state->tile->frame->width_in_lcu;
|
|
|
|
int aq_offset = (int)state->frame->aq_offsets[id]; // TODO: Number stored in aq_offsets may need rounding
|
|
|
|
state->qp = CLIP_TO_QP(state->frame->QP + aq_offset);
|
|
|
|
state->lambda = qp_to_lamba(state, state->qp);
|
|
|
|
state->lambda_sqrt = sqrt(state->lambda);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2015-05-29 11:00:51 +00:00
|
|
|
}
|