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
*/
2019-09-03 07:57:13 +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 )
2019-09-03 07:57:13 +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.
2019-09-03 07:57:13 +00:00
state - > frame - > cur_gop_target_bits = gop_allocate_bits ( state ) ;
2016-09-14 03:52:56 +00:00
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
}
2019-09-03 07:57:13 +00:00
const double pic_weight = encoder - > gop_layer_weights [
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
}
2019-09-25 09:12:21 +00:00
static int8_t lambda_to_qp ( const double lambda )
{
const int8_t qp = 4.2005 * log ( lambda ) + 13.7223 + 0.5 ;
return CLIP_TO_QP ( qp ) ;
}
2019-09-03 07:57:13 +00:00
static double solve_cubic_equation ( const encoder_state_config_frame_t * const state ,
int ctu_index ,
int last_ctu ,
int layer ,
double est_lambda ,
double target_bits )
{
double bestlambda = 0.0 ;
double paraA = 0.0 ;
double paraB = 0.0 ;
double paraC = 0.0 ;
double paraD = 0.0 ;
double delta = 0.0 ;
double paraAA = 0.0 ;
double paraBB = 0.0 ;
double paraCC = 0.0 ;
for ( int i = ctu_index ; i < last_ctu ; i + + )
{
double a = 0.0 ;
double b = 0.0 ;
double c = 0.0 ;
double d = 0.0 ;
2019-09-25 09:12:21 +00:00
assert ( ( state - > new_ratecontrol . c_para [ layer ] [ i ] < = 0 ) | | ( state - > new_ratecontrol . k_para [ layer ] [ i ] > = 0 ) ) ; //Check C and K during each solution
2019-09-03 07:57:13 +00:00
2019-09-25 09:12:21 +00:00
double CLCU = state - > new_ratecontrol . c_para [ layer ] [ i ] ;
double KLCU = state - > new_ratecontrol . k_para [ layer ] [ i ] ;
2019-09-03 07:57:13 +00:00
a = - CLCU * KLCU / pow ( state - > lcu_stats [ i ] . pixels , KLCU - 1.0 ) ;
b = - 1.0 / ( KLCU - 1.0 ) ;
d = est_lambda ;
c = pow ( a / d , b ) ;
paraA = paraA - c * pow ( b , 3.0 ) / 6.0 ;
paraB = paraB + ( pow ( b , 2.0 ) / 2.0 + pow ( b , 3.0 ) * log ( d ) / 2.0 ) * c ;
paraC = paraC - ( pow ( b , 3.0 ) / 2.0 * pow ( log ( d ) , 2.0 ) + pow ( b , 2.0 ) * log ( d ) + b ) * c ;
paraD = paraD + c * ( 1 + b * log ( d ) + pow ( b , 2.0 ) / 2 * pow ( log ( d ) , 2.0 ) + pow ( b , 3.0 ) / 6 * pow ( log ( d ) , 3.0 ) ) ;
}
paraD = paraD - target_bits ;
paraAA = paraB * paraB - 3 * paraA * paraC ;
paraBB = paraB * paraC - 9 * paraA * paraD ;
paraCC = paraC * paraC - 3 * paraB * paraD ;
delta = paraBB * paraBB - 4 * paraAA * paraCC ;
if ( delta > 0.0 ) //Check whether delta is right
{
double tempx = 0.0 ;
double part1 = 0.0 ;
double part2 = 0.0 ;
double flag1 = 0.0 ;
double flag2 = 0.0 ;
part1 = paraAA * paraB + 3 * paraA * ( - paraBB - pow ( delta , 0.5 ) ) / 2.0 ;
part2 = paraAA * paraB + 3 * paraA * ( - paraBB + pow ( delta , 0.5 ) ) / 2.0 ;
if ( part1 < 0.0 ) {
part1 = - part1 ;
flag1 = - 1.0 ;
}
else {
flag1 = 1.0 ;
}
if ( part2 < 0.0 ) {
part2 = - part2 ;
flag2 = - 1.0 ;
}
else {
flag2 = 1.0 ;
}
tempx = ( - paraB - flag1 * pow ( part1 , 1.0 / 3.0 ) - flag2 * pow ( part2 , 1.0 / 3.0 ) ) / 3 / paraA ;
bestlambda = exp ( tempx ) ;
}
else {
bestlambda = est_lambda ; //Use the original picture estimated lambda for the current CTU
}
bestlambda = CLIP ( 0.001 , 100000000.0 , bestlambda ) ;
return bestlambda ;
}
static INLINE double calculate_weights ( encoder_state_t * const state , const int layer , const int ctu_count , double estLambda ) {
double total_weight = 0 ;
for ( int i = 0 ; i < ctu_count ; i + + ) {
2019-09-25 09:12:21 +00:00
double CLCU = state - > frame - > new_ratecontrol . c_para [ layer ] [ i ] ;
double KLCU = state - > frame - > new_ratecontrol . k_para [ layer ] [ i ] ;
2019-09-03 07:57:13 +00:00
double a = - CLCU * KLCU / pow ( state - > frame - > lcu_stats [ i ] . pixels , KLCU - 1.0 ) ;
double b = - 1.0 / ( KLCU - 1.0 ) ;
state - > frame - > lcu_stats [ i ] . weight = pow ( a / estLambda , b ) ;
if ( state - > frame - > lcu_stats [ i ] . weight < 0.01 ) {
state - > frame - > lcu_stats [ i ] . weight = 0.01 ;
}
total_weight + = state - > frame - > lcu_stats [ i ] . weight ;
}
return total_weight ;
}
2019-09-25 09:12:21 +00:00
// TODO: Missing QP calculation
2019-09-03 07:57:13 +00:00
void estimatePicLambda ( encoder_state_t * const state ) {
double bits = pic_allocate_bits ( state ) ;
const int layer = state - > frame - > gop_offset - ( state - > frame - > is_irap ? 1 : 0 ) ;
const int ctu_count = state - > tile - > frame - > height_in_lcu * state - > tile - > frame - > width_in_lcu ;
double alpha ;
double beta ;
if ( state - > frame - > poc = = 0 ) {
alpha = state - > frame - > rc_alpha ;
beta = state - > frame - > rc_beta ;
}
else {
2019-09-25 09:12:21 +00:00
alpha = - state - > frame - > new_ratecontrol . pic_c_para [ state - > frame - > gop_offset ] *
state - > frame - > new_ratecontrol . pic_k_para [ state - > frame - > gop_offset ] ;
beta = state - > frame - > new_ratecontrol . pic_k_para [ state - > frame - > gop_offset ] - 1 ;
2019-09-03 07:57:13 +00:00
}
double estLambda ;
double bpp = bits / ( state - > encoder_control - > cfg . width * state - > encoder_control - > cfg . height ) ;
if ( state - > frame - > is_irap ) {
// TODO: Intra
estLambda = alpha * pow ( bpp , beta ) * 0.5 ;
}
else {
estLambda = alpha * pow ( bpp , beta ) ;
}
double temp_lambda ;
2019-09-25 09:12:21 +00:00
if ( ( temp_lambda = state - > frame - > new_ratecontrol . previous_lambdas [ layer ] ) > 0.0 ) {
2019-09-03 07:57:13 +00:00
estLambda = CLIP ( temp_lambda * pow ( 2.0 , - 1 ) , temp_lambda * 2 , estLambda ) ;
}
2019-09-26 13:02:57 +00:00
if ( ( temp_lambda = state - > frame - > new_ratecontrol . previous_frame_lambda ) > 0.0 ) {
2019-09-03 07:57:13 +00:00
estLambda = CLIP ( temp_lambda * pow ( 2.0 , - 10.0 / 3.0 ) , temp_lambda * pow ( 2.0 , 10.0 / 3.0 ) , estLambda ) ;
}
estLambda = MIN ( estLambda , 0.1 ) ;
double total_weight = 0 ;
if ( ! state - > frame - > is_irap ) {
if ( ! state - > encoder_control - > cfg . frame_allocation ) {
double best_lambda = 0.0 ;
temp_lambda = estLambda ;
double taylor_e3 ;
int iteration_number = 0 ;
do {
taylor_e3 = 0.0 ;
best_lambda = temp_lambda = solve_cubic_equation ( state - > frame , 0 , ctu_count , layer , temp_lambda , bits ) ;
for ( int i = 0 ; i < ctu_count ; + + i ) {
2019-09-25 09:12:21 +00:00
double CLCU = state - > frame - > new_ratecontrol . c_para [ layer ] [ i ] ;
double KLCU = state - > frame - > new_ratecontrol . k_para [ layer ] [ i ] ;
2019-09-03 07:57:13 +00:00
double a = - CLCU * KLCU / pow ( state - > frame - > lcu_stats [ i ] . pixels , KLCU - 1.0 ) ;
double b = - 1.0 / ( KLCU - 1.0 ) ;
taylor_e3 + = pow ( a / best_lambda , b ) ;
}
}
while ( fabs ( taylor_e3 - bits ) > 0.01 & & iteration_number < = 11 ) ;
}
total_weight = calculate_weights ( state , layer , ctu_count , estLambda ) ;
}
else {
for ( int i = 0 ; i < ctu_count ; + + i ) {
state - > frame - > lcu_stats [ i ] . weight = MAX ( 0.01 ,
state - > frame - > lcu_stats [ i ] . pixels * pow ( estLambda / state - > frame - > rc_alpha ,
1.0 / state - > frame - > rc_beta ) ) ;
total_weight + = state - > frame - > lcu_stats [ i ] . weight ;
}
}
for ( int i = 0 ; i < ctu_count ; + + i ) {
state - > frame - > lcu_stats [ i ] . weight = bits * state - > frame - > lcu_stats [ i ] . weight / total_weight ;
}
state - > frame - > lambda = estLambda ;
}
2019-09-25 09:12:21 +00:00
static double get_ctu_bits ( encoder_state_t * const state , vector2d_t pos ) {
int avg_bits ;
const int layer = state - > frame - > gop_offset - ( state - > frame - > is_irap ? 1 : 0 ) ;
const int num_ctu = state - > encoder_control - > in . width_in_lcu * state - > encoder_control - > in . height_in_lcu ;
const int index = pos . x + pos . y * state - > tile - > frame - > width_in_lcu ;
if ( state - > frame - > is_irap ) {
// TODO: intra
avg_bits = state - > frame - > cur_pic_target_bits / ( ( double ) state - > frame - > lcu_stats [ index ] . pixels /
( state - > encoder_control - > in . height * state - > encoder_control - > in . width ) ) ;
}
else {
double totalWeight = 0 ;
const int realInfluenceLCU = MIN ( 4 , num_ctu - index ) ; //g_RCLCUSmoothWindowSize, the same as the original RC scheme
int TargetbitsForSmoothWindow = 0 ;
double bestlambda = 0.0 ;
double Templambda = state - > frame - > lambda ;
double TaylorE3 = 0.0 ;
int IterationNum = 0 ;
double estLambda = Templambda ;
for ( int i = index ; i < num_ctu ; i + + ) {
totalWeight + = state - > frame - > lcu_stats [ i ] . weight ;
}
int last_ctu = index + realInfluenceLCU ;
for ( int i = index ; i < last_ctu ; i + + ) {
TargetbitsForSmoothWindow + = state - > frame - > lcu_stats [ i ] . weight ;
}
TargetbitsForSmoothWindow = MAX ( TargetbitsForSmoothWindow + state - > frame - > total_bits_coded - ( int ) totalWeight , 10 ) ; //obtain the total bit-rate for the realInfluenceLCU (=4) CTUs
//just similar with the process at frame level, details can refer to the function TEncRCPic::estimatePicLambda
do {
TaylorE3 = 0.0 ;
bestlambda = solve_cubic_equation ( state - > frame , index , last_ctu , layer , Templambda , TargetbitsForSmoothWindow ) ;
Templambda = bestlambda ;
for ( int i = index ; i < last_ctu ; i + + ) {
double CLCU = state - > frame - > new_ratecontrol . c_para [ layer ] [ i ] ;
double KLCU = state - > frame - > new_ratecontrol . k_para [ layer ] [ i ] ;
double a = - CLCU * KLCU / pow ( ( double ) state - > frame - > lcu_stats [ i ] . pixels , KLCU - 1.0 ) ;
double b = - 1.0 / ( KLCU - 1.0 ) ;
TaylorE3 + = pow ( a / bestlambda , b ) ;
}
IterationNum + + ;
} while ( fabs ( TaylorE3 - TargetbitsForSmoothWindow ) > 0.01 & & IterationNum < 5 ) ;
double CLCU = state - > frame - > new_ratecontrol . c_para [ layer ] [ index ] ;
double KLCU = state - > frame - > new_ratecontrol . k_para [ layer ] [ index ] ;
double a = - CLCU * KLCU / pow ( ( ( double ) state - > frame - > lcu_stats [ index ] . pixels ) , KLCU - 1.0 ) ;
double b = - 1.0 / ( KLCU - 1.0 ) ;
state - > frame - > lcu_stats [ index ] . weight = MAX ( pow ( a / bestlambda , b ) , 0.01 ) ;
avg_bits = ( int ) ( state - > frame - > lcu_stats [ index ] . weight + 0.5 ) ;
}
if ( avg_bits < 1 ) {
avg_bits = 1 ;
}
return avg_bits ;
2015-03-13 12:23:54 +00:00
}
2015-05-29 11:00:51 +00:00
2019-09-25 09:12:21 +00:00
void kvz_set_ctu_qp_lambda ( encoder_state_t * const state , vector2d_t pos ) {
double bits = get_ctu_bits ( state , pos ) ;
const int frame_allocation = state - > encoder_control - > cfg . frame_allocation ;
2019-09-26 13:02:57 +00:00
const int layer = state - > frame - > gop_offset - ( state - > frame - > is_irap ? 1 : 0 ) ;
2019-09-25 09:12:21 +00:00
int index = pos . x + pos . y * state - > encoder_control - > in . width_in_lcu ;
double bpp = bits / state - > frame - > lcu_stats [ index ] . pixels ;
double alpha ;
double beta ;
if ( state - > frame - > poc = = 0 ) {
alpha = state - > frame - > rc_alpha ;
beta = state - > frame - > rc_beta ;
}
else {
2019-09-26 13:02:57 +00:00
alpha = - state - > frame - > new_ratecontrol . c_para [ layer ] [ index ] *
state - > frame - > new_ratecontrol . k_para [ layer ] [ index ] ;
beta = state - > frame - > new_ratecontrol . k_para [ layer ] [ index ] - 1 ;
2019-09-25 09:12:21 +00:00
}
double est_lambda = alpha * pow ( bpp , beta ) ;
double clip_lambda = state - > frame - > lambda ;
double clip_neighbor_lambda = - 1 ;
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 {
est_lambda = CLIP ( 10.0 , 1000.0 , est_lambda ) ;
}
if ( est_lambda < 0.1 ) {
est_lambda = 0.1 ;
}
int 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 [ index ] . qp > - 1 ) {
clip_qp = state - > frame - > lcu_stats [ 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_sqrt = sqrt ( est_lambda ) ;
state - > qp = est_qp ;
state - > frame - > lcu_stats [ index ] . qp = est_qp ;
}
2019-09-26 13:02:57 +00:00
static void update_pic_ck ( encoder_state_t * const state , double bpp , double distortion , double lambda , int layer ) {
2019-09-26 10:09:28 +00:00
double new_k , new_c ;
if ( state - > frame - > num = = 1 ) {
2019-09-26 13:02:57 +00:00
new_k = log ( distortion / state - > frame - > new_ratecontrol . intra_pic_distortion ) /
log ( bpp / state - > frame - > new_ratecontrol . intra_pic_bpp ) ;
2019-09-26 10:09:28 +00:00
new_c = distortion / pow ( bpp , new_k ) ;
}
else {
new_k = - bpp * lambda / distortion ;
new_c = distortion / pow ( bpp , new_k ) ;
}
new_c = CLIP ( + .1 , 100.0 , new_c ) ;
new_k = CLIP ( - 3.0 , - 0.001 , new_k ) ;
if ( state - > frame - > is_irap | | state - > frame - > num < = ( 4 - state - > encoder_control - > cfg . frame_allocation ) ) {
for ( int i = 1 ; i < 5 ; i + + ) {
state - > frame - > new_ratecontrol . pic_c_para [ i ] = new_c ;
state - > frame - > new_ratecontrol . pic_k_para [ i ] = new_k ;
}
}
else {
2019-09-26 13:02:57 +00:00
state - > frame - > new_ratecontrol . pic_c_para [ layer ] = new_c ;
state - > frame - > new_ratecontrol . pic_k_para [ layer ] = new_k ;
2019-09-26 10:09:28 +00:00
}
}
2019-09-26 13:02:57 +00:00
static void update_ck ( encoder_state_t * const state , int ctu_index , int layer )
2019-09-26 10:09:28 +00:00
{
double bpp = ( double ) state - > frame - > lcu_stats [ ctu_index ] . bits / state - > frame - > lcu_stats [ ctu_index ] . pixels ;
double distortion = state - > frame - > lcu_stats [ ctu_index ] . distortion ;
double lambda = state - > frame - > lcu_stats [ ctu_index ] . lambda ;
double new_k , new_c ;
if ( ! state - > frame - > lcu_stats [ ctu_index ] . skipped ) {
if ( state - > frame - > num = = 1 ) {
2019-09-26 13:02:57 +00:00
new_k = log ( distortion / state - > frame - > new_ratecontrol . intra_pic_distortion ) /
log ( bpp / state - > frame - > new_ratecontrol . intra_pic_bpp ) ;
2019-09-26 10:09:28 +00:00
new_c = distortion / pow ( bpp , new_k ) ;
}
else {
2019-09-26 13:02:57 +00:00
bpp = CLIP ( 0.0001 , 10.0 , bpp ) ;
2019-09-26 10:09:28 +00:00
new_k = - bpp * lambda / distortion ;
new_c = distortion / pow ( bpp , new_k ) ;
}
new_c = CLIP ( + .1 , 100.0 , new_c ) ;
new_k = CLIP ( - 3.0 , - 0.001 , new_k ) ;
if ( state - > frame - > is_irap | | state - > frame - > num < = ( 4 - state - > encoder_control - > cfg . frame_allocation ) ) {
for ( int i = 1 ; i < 5 ; i + + ) {
2019-09-26 13:02:57 +00:00
state - > frame - > new_ratecontrol . c_para [ i ] [ ctu_index ] = new_c ;
state - > frame - > new_ratecontrol . k_para [ i ] [ ctu_index ] = new_k ;
2019-09-26 10:09:28 +00:00
}
}
else {
2019-09-26 13:02:57 +00:00
state - > frame - > new_ratecontrol . c_para [ layer ] [ ctu_index ] = new_c ;
state - > frame - > new_ratecontrol . k_para [ layer ] [ ctu_index ] = new_k ;
2019-09-26 10:09:28 +00:00
}
}
}
void kvz_update_after_picture ( encoder_state_t * const state ) {
double total_distortion = 0 ;
double lambda = 0 ;
2019-09-26 13:02:57 +00:00
double pic_bpp = ( double ) state - > frame - > cur_frame_bits_coded / ( state - > encoder_control - > in . width * state - > encoder_control - > in . height ) ;
const int layer = state - > frame - > gop_offset - ( state - > frame - > is_irap ? 1 : 0 ) ;
2019-09-26 10:09:28 +00:00
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 + + ) {
int ctu_distortion = 0 ;
lcu_stats_t * ctu = kvz_get_lcu_stats ( state , y_ctu , x_ctu ) ;
for ( int y = y_ctu * 64 ; y < MIN ( ( y_ctu + 1 ) * 64 , state - > tile - > frame - > height ) ; y + + ) {
for ( int x = x_ctu * 64 ; x < MIN ( ( x_ctu + 1 ) * 64 , state - > tile - > frame - > width ) ; x + + ) {
int temp = ( int ) state - > tile - > frame - > source - > y [ x + y * state - > encoder_control - > in . width ] -
state - > tile - > frame - > rec - > y [ x + y * state - > encoder_control - > in . width ] ;
ctu_distortion + = temp * temp ;
}
}
ctu - > distortion = ( double ) ctu_distortion / ctu - > pixels ;
total_distortion + = ( double ) ctu_distortion / ctu - > pixels ;
lambda + = ctu - > lambda / ctu - > pixels ;
}
}
2019-09-26 13:02:57 +00:00
if ( state - > frame - > is_irap ) {
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 + + ) {
lcu_stats_t * ctu = kvz_get_lcu_stats ( state , y_ctu , x_ctu ) ;
state - > frame - > new_ratecontrol . intra_dis [ x_ctu + y_ctu * state - > encoder_control - > in . width_in_lcu ] =
ctu - > distortion ;
state - > frame - > new_ratecontrol . intra_bpp [ x_ctu + y_ctu * state - > encoder_control - > in . width_in_lcu ] =
ctu - > bits / ctu - > pixels ;
}
}
state - > frame - > new_ratecontrol . intra_pic_distortion = total_distortion ;
state - > frame - > new_ratecontrol . intra_pic_bpp = pic_bpp ;
}
state - > frame - > new_ratecontrol . previous_frame_lambda = lambda ;
state - > frame - > new_ratecontrol . previous_lambdas [ layer ] = lambda ;
2019-09-26 10:09:28 +00:00
2019-09-26 13:02:57 +00:00
update_pic_ck ( state , pic_bpp , total_distortion , lambda , layer ) ;
for ( int i = 0 ; i < state - > encoder_control - > in . width_in_lcu * state - > encoder_control - > in . height_in_lcu ; i + + ) {
update_ck ( state , i , layer ) ;
}
2019-09-26 10:09:28 +00:00
}
2017-01-16 06:47:21 +00:00
static double qp_to_lamba ( encoder_state_t * const state , int qp )
{
const encoder_control_t * const ctrl = state - > encoder_control ;
2017-02-05 09:59:21 +00:00
const int gop_len = ctrl - > cfg . gop_len ;
const int period = gop_len > 0 ? gop_len : ctrl - > cfg . intra_period ;
2017-01-16 06:47:21 +00:00
2017-02-05 09:59:21 +00:00
kvz_gop_config const * const gop = & ctrl - > cfg . gop [ state - > frame - > gop_offset ] ;
2017-01-16 06:47:21 +00:00
double lambda = pow ( 2.0 , ( qp - 12 ) / 3.0 ) ;
if ( state - > frame - > slicetype = = KVZ_SLICE_I ) {
lambda * = 0.57 ;
// Reduce lambda for I-frames according to the number of references.
if ( period = = 0 ) {
lambda * = 0.5 ;
} else {
lambda * = 1.0 - CLIP ( 0.0 , 0.5 , 0.05 * ( period - 1 ) ) ;
}
} else if ( gop_len > 0 ) {
lambda * = gop - > qp_factor ;
} else {
lambda * = 0.4624 ;
}
// Increase lambda if not key-frame.
if ( period > 0 & & state - > frame - > poc % period ! = 0 ) {
lambda * = CLIP ( 2.0 , 4.0 , ( state - > frame - > QP - 12 ) / 6.0 ) ;
}
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 ) {
2017-05-17 09:41:51 +00:00
state - > frame - > QP = CLIP_TO_QP ( ctrl - > cfg . qp + gop - > qp_offset ) ;
} else {
state - > frame - > QP = ctrl - > cfg . qp ;
2016-08-21 05:03:57 +00:00
}
2017-01-16 06:47:21 +00:00
state - > frame - > lambda = qp_to_lamba ( 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 ) ;
2017-01-16 06:47:21 +00:00
state - > lambda = qp_to_lamba ( 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
2019-08-29 06:28:10 +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 ) ;
}
2015-05-29 11:00:51 +00:00
}