mirror of
https://github.com/ultravideo/uvg266.git
synced 2024-11-23 18:14:06 +00:00
Command line parameters for oba rc and implementation of the usage of the intra parameter
This commit is contained in:
parent
eb73548af5
commit
6cc3bcd87e
31
src/cfg.c
31
src/cfg.c
|
@ -141,6 +141,8 @@ int kvz_config_init(kvz_config *cfg)
|
|||
cfg->max_merge = 5;
|
||||
cfg->early_skip = true;
|
||||
|
||||
cfg->rc_algorithm = KVZ_NO_RC;
|
||||
cfg->intra_bit_allocation = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -386,6 +388,8 @@ int kvz_config_parse(kvz_config *cfg, const char *name, const char *value)
|
|||
|
||||
static const char * const scaling_list_names[] = { "off", "custom", "default", NULL };
|
||||
|
||||
static const char * const rc_algorithm_names[] = { "no-rc", "lambda", "oba", NULL };
|
||||
|
||||
static const char * const preset_values[11][25*2] = {
|
||||
{
|
||||
"ultrafast",
|
||||
|
@ -928,6 +932,8 @@ int kvz_config_parse(kvz_config *cfg, const char *name, const char *value)
|
|||
cfg->gop_len = gop.g;
|
||||
cfg->gop_lp_definition.d = gop.d;
|
||||
cfg->gop_lp_definition.t = gop.t;
|
||||
|
||||
cfg->intra_bit_allocation = false;
|
||||
} else if (atoi(value) == 8) {
|
||||
cfg->gop_lowdelay = 0;
|
||||
// GOP
|
||||
|
@ -979,8 +985,12 @@ int kvz_config_parse(kvz_config *cfg, const char *name, const char *value)
|
|||
}
|
||||
else if OPT("bipred")
|
||||
cfg->bipred = atobool(value);
|
||||
else if OPT("bitrate")
|
||||
else if OPT("bitrate") {
|
||||
cfg->target_bitrate = atoi(value);
|
||||
if (!cfg->rc_algorithm) {
|
||||
cfg->rc_algorithm = KVZ_LAMBDA;
|
||||
}
|
||||
}
|
||||
else if OPT("preset") {
|
||||
int preset_line = 0;
|
||||
|
||||
|
@ -1260,6 +1270,20 @@ int kvz_config_parse(kvz_config *cfg, const char *name, const char *value)
|
|||
else if OPT("early-skip") {
|
||||
cfg->early_skip = (bool)atobool(value);
|
||||
}
|
||||
else if OPT("rc-algorithm") {
|
||||
int8_t rc_algorithm = 0;
|
||||
if (!parse_enum(value, rc_algorithm_names, &rc_algorithm)) {
|
||||
fprintf(stderr, "Invalid rate control algorithm %s. Valid values include %s, %s, and %s\n", value,
|
||||
rc_algorithm_names[0],
|
||||
rc_algorithm_names[1],
|
||||
rc_algorithm_names[2]);
|
||||
return 0;
|
||||
}
|
||||
cfg->rc_algorithm = rc_algorithm;
|
||||
}
|
||||
else if OPT("intra-bits") {
|
||||
cfg->intra_bit_allocation = atobool(value);
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
|
@ -1572,6 +1596,11 @@ int kvz_config_validate(const kvz_config *const cfg)
|
|||
error = 1;
|
||||
}
|
||||
|
||||
if(cfg->target_bitrate > 0 && cfg->rc_algorithm == 0) {
|
||||
fprintf(stderr, "Bitrate set but rc-algorithm is turned off.\n");
|
||||
error = 1;
|
||||
}
|
||||
|
||||
return !error;
|
||||
}
|
||||
|
||||
|
|
|
@ -137,6 +137,9 @@ static const struct option long_options[] = {
|
|||
{ "max-merge", required_argument, NULL, 0 },
|
||||
{ "early-skip", no_argument, NULL, 0 },
|
||||
{ "no-early-skip", no_argument, NULL, 0 },
|
||||
{ "rc-algorithm", required_argument, NULL, 0 },
|
||||
{ "intra-bits", no_argument, NULL, 0 },
|
||||
{ "no-intra-bits", no_argument, NULL, 0 },
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
|
@ -410,6 +413,12 @@ void print_help(void)
|
|||
" --bitrate <integer> : Target bitrate [0]\n"
|
||||
" - 0: Disable rate control.\n"
|
||||
" - N: Target N bits per second.\n"
|
||||
" --rc-algorithm <string>: Select used rc-algorithm. [lambda]\n"
|
||||
" - lambda: rate control from:\n"
|
||||
" DOI: 10.1109/TIP.2014.2336550 \n"
|
||||
" - oba: DOI: 10.1109/TCSVT.2016.2589878\n"
|
||||
" --intra-bits : Use Hadamard cost based allocation for intra\n"
|
||||
" frames. Default on for gop 8 and off for lp-gop\n"
|
||||
" --(no-)lossless : Use lossless coding. [disabled]\n"
|
||||
" --mv-constraint <string> : Constrain movement vectors. [none]\n"
|
||||
" - none: No constraint\n"
|
||||
|
|
|
@ -51,8 +51,9 @@ static int encoder_state_config_frame_init(encoder_state_t * const state) {
|
|||
state->frame->cur_gop_bits_coded = 0;
|
||||
state->frame->prepared = 0;
|
||||
state->frame->done = 1;
|
||||
state->frame->rc_alpha = 6.7542000000000000;
|
||||
state->frame->rc_beta = 1.7860000000000000;
|
||||
|
||||
state->frame->rc_alpha = 3.2003;
|
||||
state->frame->rc_beta = -1.367;
|
||||
|
||||
const encoder_control_t * const encoder = state->encoder_control;
|
||||
const int num_lcus = encoder->in.width_in_lcu * encoder->in.height_in_lcu;
|
||||
|
|
|
@ -253,8 +253,10 @@ static int kvazaar_encode(kvz_encoder *enc,
|
|||
CHECKPOINT_MARK("read source frame: %d", state->frame->num + enc->control->cfg.seek);
|
||||
}
|
||||
|
||||
// TODO: only when the OBA rc is used
|
||||
kvz_picture* frame = kvz_encoder_feed_frame(&enc->input_buffer, state, pic_in, enc->frames_done);
|
||||
kvz_picture* frame = kvz_encoder_feed_frame(
|
||||
&enc->input_buffer, state, pic_in,
|
||||
enc->frames_done || state->encoder_control->cfg.rc_algorithm != KVZ_OBA
|
||||
);
|
||||
if (frame) {
|
||||
assert(state->frame->num == enc->frames_started);
|
||||
// Start encoding.
|
||||
|
@ -272,11 +274,10 @@ static int kvazaar_encode(kvz_encoder *enc,
|
|||
enc->cur_state_num = (enc->cur_state_num + 1) % (enc->num_encoder_states);
|
||||
}
|
||||
|
||||
// TODO: OBA check
|
||||
encoder_state_t *output_state = &enc->states[enc->out_state_num];
|
||||
if ((!output_state->frame->done &&
|
||||
(pic_in == NULL || enc->cur_state_num == enc->out_state_num))
|
||||
|| state->frame->num == 0) {
|
||||
(pic_in == NULL || enc->cur_state_num == enc->out_state_num)) ||
|
||||
(state->frame->num == 0 && state->encoder_control->cfg.rc_algorithm == KVZ_OBA)) {
|
||||
|
||||
kvz_threadqueue_waitfor(enc->control->threadqueue, output_state->tqj_bitstream_written);
|
||||
// The job pointer must be set to NULL here since it won't be usable after
|
||||
|
|
|
@ -218,6 +218,12 @@ enum kvz_scalinglist {
|
|||
KVZ_SCALING_LIST_DEFAULT = 2,
|
||||
};
|
||||
|
||||
enum kvz_rc_algorithm
|
||||
{
|
||||
KVZ_NO_RC = 0,
|
||||
KVZ_LAMBDA = 1,
|
||||
KVZ_OBA = 2,
|
||||
};
|
||||
// Map from input format to chroma format.
|
||||
#define KVZ_FORMAT2CSP(format) ((enum kvz_chroma_format)"\0\1\2\3"[format])
|
||||
|
||||
|
@ -394,7 +400,15 @@ typedef struct kvz_config
|
|||
|
||||
/** \brief Enable Early Skip Mode Decision */
|
||||
uint8_t early_skip;
|
||||
|
||||
/** \brief Currently unused parameter for OBA rc */
|
||||
int8_t frame_allocation;
|
||||
|
||||
/** \brief used rc scheme, 0 for QP */
|
||||
int8_t rc_algorithm;
|
||||
|
||||
/** \brief whether to use hadamard based bit allocation for intra frames or not */
|
||||
uint8_t intra_bit_allocation;
|
||||
} kvz_config;
|
||||
|
||||
/**
|
||||
|
|
|
@ -68,6 +68,8 @@ kvz_rc_data * kvz_get_rc_data(const encoder_control_t * const encoder) {
|
|||
data->intra_pic_bpp = 0.0;
|
||||
data->intra_pic_distortion = 0.0;
|
||||
|
||||
data->intra_alpha = 6.7542000000000000;
|
||||
data->intra_beta = 1.7860000000000000;
|
||||
return data;
|
||||
}
|
||||
|
||||
|
@ -292,10 +294,15 @@ static double pic_allocate_bits(encoder_state_t * const state)
|
|||
state->frame->cur_gop_target_bits =
|
||||
state->previous_encoder_state->frame->cur_gop_target_bits;
|
||||
}
|
||||
if(state->frame->is_irap) {
|
||||
|
||||
if (encoder->cfg.gop_len <= 0) {
|
||||
return state->frame->cur_gop_target_bits;
|
||||
}
|
||||
|
||||
if (state->frame->is_irap && encoder->cfg.intra_bit_allocation) {
|
||||
double bits = state->frame->cur_gop_target_bits / MAX(encoder->cfg.gop_len, 1);
|
||||
double alpha, beta = 0.5582;
|
||||
if (bits*40 < encoder->cfg.width * encoder->cfg.height) {
|
||||
if (bits * 40 < encoder->cfg.width * encoder->cfg.height) {
|
||||
alpha = 0.25;
|
||||
}
|
||||
else {
|
||||
|
@ -304,10 +311,6 @@ static double pic_allocate_bits(encoder_state_t * const state)
|
|||
return MAX(100, alpha*pow(state->frame->icost * 4 / bits, beta)*bits);
|
||||
}
|
||||
|
||||
if (encoder->cfg.gop_len <= 0) {
|
||||
return state->frame->cur_gop_target_bits;
|
||||
}
|
||||
|
||||
const double pic_weight = encoder->gop_layer_weights[
|
||||
encoder->cfg.gop[state->frame->gop_offset].layer - 1];
|
||||
const double pic_target_bits =
|
||||
|
@ -418,7 +421,8 @@ static INLINE double calculate_weights(encoder_state_t* const state, const int l
|
|||
|
||||
void kvz_estimate_pic_lambda(encoder_state_t * const state) {
|
||||
const encoder_control_t * const encoder = state->encoder_control;
|
||||
if(state->frame->is_irap) {
|
||||
|
||||
if(encoder->cfg.intra_bit_allocation && state->frame->is_irap) {
|
||||
int total_cost = 0;
|
||||
for (int y = 0; y < encoder->cfg.height; y += 8) {
|
||||
for (int x = 0; x < encoder->cfg.width; x += 8) {
|
||||
|
@ -436,7 +440,11 @@ void kvz_estimate_pic_lambda(encoder_state_t * const state) {
|
|||
|
||||
double alpha;
|
||||
double beta;
|
||||
if(state->frame->poc == 0) {
|
||||
if(state->frame->is_irap && encoder->cfg.intra_bit_allocation) {
|
||||
alpha = state->frame->new_ratecontrol->intra_alpha;
|
||||
beta = state->frame->new_ratecontrol->intra_beta;
|
||||
}
|
||||
else if(state->frame->poc == 0) {
|
||||
alpha = state->frame->rc_alpha;
|
||||
beta = state->frame->rc_beta;
|
||||
}
|
||||
|
@ -455,9 +463,15 @@ void kvz_estimate_pic_lambda(encoder_state_t * const state) {
|
|||
int32_t num_pixels = state->encoder_control->cfg.width * state->encoder_control->cfg.height;
|
||||
double bpp = bits / num_pixels;
|
||||
if (state->frame->is_irap) {
|
||||
state->frame->i_bits_left = bits;
|
||||
double temp = pow(state->frame->icost / num_pixels, BETA1);
|
||||
est_lambda = alpha / 256 * pow(temp/bpp, beta);
|
||||
if(encoder->cfg.intra_bit_allocation) {
|
||||
state->frame->i_bits_left = bits;
|
||||
double temp = pow(state->frame->icost / num_pixels, BETA1);
|
||||
est_lambda = alpha / 256 * pow(temp/bpp, beta);
|
||||
}
|
||||
else {
|
||||
// arbitrary reduction to the lambda for intra frames
|
||||
est_lambda = alpha * pow(bpp, beta) * 0.5;
|
||||
}
|
||||
}
|
||||
else {
|
||||
est_lambda = alpha * pow(bpp, beta);
|
||||
|
@ -503,6 +517,7 @@ void kvz_estimate_pic_lambda(encoder_state_t * const state) {
|
|||
}
|
||||
else {
|
||||
for (int i = 0; i < ctu_count; ++i) {
|
||||
// TODO: This might be incorrect
|
||||
state->frame->lcu_stats[i].weight = MAX(0.01,
|
||||
state->frame->lcu_stats[i].pixels * pow(est_lambda / state->frame->rc_alpha,
|
||||
1.0 / state->frame->rc_beta));
|
||||
|
@ -529,17 +544,23 @@ static double get_ctu_bits(encoder_state_t * const state, vector2d_t pos) {
|
|||
const int index = pos.x + pos.y * state->tile->frame->width_in_lcu;
|
||||
|
||||
if (state->frame->is_irap) {
|
||||
int cus_left = num_ctu - index + 1;
|
||||
int window = MIN(4, cus_left);
|
||||
double mad = kvz_get_lcu_stats(state, pos.x, pos.y)->i_cost;
|
||||
if(encoder->cfg.intra_bit_allocation) {
|
||||
int cus_left = num_ctu - index + 1;
|
||||
int window = MIN(4, cus_left);
|
||||
double mad = kvz_get_lcu_stats(state, pos.x, pos.y)->i_cost;
|
||||
|
||||
pthread_mutex_lock(&state->frame->rc_lock);
|
||||
double bits_left = state->frame->cur_pic_target_bits - state->frame->cur_frame_bits_coded;
|
||||
double weighted_bits_left = (bits_left * window + (bits_left - state->frame->i_bits_left)*cus_left) / window;
|
||||
avg_bits = mad * weighted_bits_left / state->frame->remaining_weight;
|
||||
state->frame->remaining_weight -= mad;
|
||||
state->frame->i_bits_left -= state->frame->cur_pic_target_bits * mad / state->frame->icost;
|
||||
pthread_mutex_unlock(&state->frame->rc_lock);
|
||||
pthread_mutex_lock(&state->frame->rc_lock);
|
||||
double bits_left = state->frame->cur_pic_target_bits - state->frame->cur_frame_bits_coded;
|
||||
double weighted_bits_left = (bits_left * window + (bits_left - state->frame->i_bits_left)*cus_left) / window;
|
||||
avg_bits = mad * weighted_bits_left / state->frame->remaining_weight;
|
||||
state->frame->remaining_weight -= mad;
|
||||
state->frame->i_bits_left -= state->frame->cur_pic_target_bits * mad / state->frame->icost;
|
||||
pthread_mutex_unlock(&state->frame->rc_lock);
|
||||
}
|
||||
else {
|
||||
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 total_weight = 0;
|
||||
|
@ -608,7 +629,11 @@ void kvz_set_ctu_qp_lambda(encoder_state_t * const state, vector2d_t pos) {
|
|||
|
||||
double alpha;
|
||||
double beta;
|
||||
if (state->frame->is_irap) {
|
||||
if (state->frame->is_irap && encoder->cfg.intra_bit_allocation) {
|
||||
alpha = state->frame->new_ratecontrol->intra_alpha;
|
||||
beta = state->frame->new_ratecontrol->intra_beta;
|
||||
}
|
||||
else if(state->frame->num == 0) {
|
||||
alpha = state->frame->rc_alpha;
|
||||
beta = state->frame->rc_beta;
|
||||
}
|
||||
|
@ -620,7 +645,7 @@ void kvz_set_ctu_qp_lambda(encoder_state_t * const state, vector2d_t pos) {
|
|||
|
||||
double est_lambda;
|
||||
int est_qp;
|
||||
if (state->frame->is_irap) {
|
||||
if (state->frame->is_irap && encoder->cfg.intra_bit_allocation) {
|
||||
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);
|
||||
|
@ -777,14 +802,14 @@ void kvz_update_after_picture(encoder_state_t * const state) {
|
|||
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);
|
||||
|
||||
if (state->frame->is_irap) {
|
||||
if (state->frame->is_irap && encoder->cfg.intra_bit_allocation) {
|
||||
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);
|
||||
double diff_lambda = state->frame->new_ratecontrol->intra_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;
|
||||
state->frame->new_ratecontrol->intra_alpha *= exp(diff_lambda);
|
||||
state->frame->new_ratecontrol->intra_beta += diff_lambda / lnbpp;
|
||||
}
|
||||
|
||||
for(int y_ctu = 0; y_ctu < state->encoder_control->in.height_in_lcu; y_ctu++) {
|
||||
|
@ -804,7 +829,7 @@ void kvz_update_after_picture(encoder_state_t * const state) {
|
|||
}
|
||||
}
|
||||
total_distortion /= (state->encoder_control->in.height_in_lcu * state->encoder_control->in.width_in_lcu);
|
||||
if (state->frame->is_irap) {
|
||||
if (state->frame->is_irap && encoder->cfg.intra_bit_allocation) {
|
||||
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, x_ctu, y_ctu);
|
||||
|
|
|
@ -43,6 +43,9 @@ typedef struct kvz_rc_data {
|
|||
double intra_pic_distortion;
|
||||
double intra_pic_bpp;
|
||||
|
||||
double intra_alpha;
|
||||
double intra_beta;
|
||||
|
||||
pthread_mutex_t ck_frame_lock;
|
||||
} kvz_rc_data;
|
||||
|
||||
|
|
Loading…
Reference in a new issue