mirror of
https://github.com/ultravideo/uvg266.git
synced 2024-11-27 19:24:06 +00:00
Select GOP picture weights according to bitrate.
Pictures in same layer have equal weights. At low bitrates, the difference between low and high layers is greater than at high bitrates.
This commit is contained in:
parent
93d2a95ddc
commit
b54d5aa91f
24
src/config.c
24
src/config.c
|
@ -537,45 +537,37 @@ 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].qp_offset = 1; cfg->gop[0].layer = 1; cfg->gop[0].qp_factor = 0.442; cfg->gop[0].is_ref = 1;
|
||||
cfg->gop[0].poc_offset = 8; cfg->gop[0].layer = 1; 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[0].weight = 6;
|
||||
|
||||
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].poc_offset = 4; cfg->gop[1].layer = 2; 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[1].weight = 6;
|
||||
|
||||
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].poc_offset = 2; cfg->gop[2].layer = 3; 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[2].weight = 3;
|
||||
|
||||
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].poc_offset = 1; cfg->gop[3].layer = 4; 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[3].weight = 2;
|
||||
|
||||
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].poc_offset = 3; cfg->gop[4].layer = 4; 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[4].weight = 2;
|
||||
|
||||
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].poc_offset = 6; cfg->gop[5].layer = 3; 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[5].weight = 3;
|
||||
|
||||
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].poc_offset = 5; cfg->gop[6].layer = 4; 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[6].weight = 2;
|
||||
|
||||
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].poc_offset = 7; cfg->gop[7].layer = 4; 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;
|
||||
cfg->gop[7].weight = 2;
|
||||
} else if(atoi(value)) {
|
||||
fprintf(stderr, "Input error: goplen must be 8\n");
|
||||
return 0;
|
||||
|
|
|
@ -29,9 +29,6 @@
|
|||
|
||||
|
||||
typedef struct {
|
||||
double qp_factor;
|
||||
int8_t qp_offset; /*!< \brief QP offset */
|
||||
int8_t weight;
|
||||
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 */
|
||||
|
|
|
@ -59,6 +59,47 @@ static void gop_allocate_bits(encoder_state_t * const state)
|
|||
state->global->cur_gop_target_bits = MAX(200, gop_target_bits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate bits for the current picture.
|
||||
* \param state the main encoder state
|
||||
* \return target number of bits
|
||||
*/
|
||||
double pic_allocate_bits(const encoder_state_t * const state) {
|
||||
const encoder_control_t * const encoder = state->encoder_control;
|
||||
|
||||
if (encoder->cfg->gop_len <= 0) {
|
||||
return state->global->cur_gop_target_bits;
|
||||
}
|
||||
|
||||
const double avg_bits_per_picture =
|
||||
encoder->cfg->target_bitrate / encoder->cfg->framerate;
|
||||
const int pixels_per_picture = encoder->in.width * encoder->in.height;
|
||||
const double avg_bits_per_pixel = avg_bits_per_picture / pixels_per_picture;
|
||||
|
||||
int layer_weights[4];
|
||||
#define SET_ARRAY(array, x0, x1, x2, x3) \
|
||||
do { array[0] = x0; array[1] = x1; array[2] = x2; array[3] = x3; } while(0)
|
||||
|
||||
if (avg_bits_per_pixel <= 0.05) {
|
||||
SET_ARRAY(layer_weights, 30, 8, 4, 1);
|
||||
} else if (avg_bits_per_pixel <= 0.1) {
|
||||
SET_ARRAY(layer_weights, 25, 7, 4, 1);
|
||||
} else if (avg_bits_per_pixel <= 0.2) {
|
||||
SET_ARRAY(layer_weights, 20, 6, 4, 1);
|
||||
} else {
|
||||
SET_ARRAY(layer_weights, 15, 5, 4, 1);
|
||||
}
|
||||
#undef SET_ARRAY
|
||||
|
||||
const int pic_weight = layer_weights[encoder->cfg->gop[state->global->gop_offset].layer - 1];
|
||||
int sum_weights = 0;
|
||||
for (int i = 0; i < encoder->cfg->gop_len; ++i) {
|
||||
sum_weights += layer_weights[encoder->cfg->gop[i].layer - 1];
|
||||
}
|
||||
|
||||
return state->global->cur_gop_target_bits * pic_weight / sum_weights;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Select a lambda value for encoding the next picture
|
||||
* \param state the main encoder state
|
||||
|
@ -81,15 +122,11 @@ double select_picture_lambda(encoder_state_t * const state)
|
|||
state->previous_encoder_state->global->cur_gop_target_bits;
|
||||
}
|
||||
|
||||
const double target_bits_current_picture = (encoder->cfg->gop_len > 0)
|
||||
? (state->global->cur_gop_target_bits * encoder->cfg->gop[state->global->gop_offset].weight / 22.0)
|
||||
: state->global->cur_gop_target_bits
|
||||
;
|
||||
|
||||
// TODO: take the picture headers into account
|
||||
const int pixels_per_picture = encoder->in.width * encoder->in.height;
|
||||
const double target_bits_per_pixel = target_bits_current_picture / pixels_per_picture;
|
||||
|
||||
const double target_bits_current_picture = pic_allocate_bits(state);
|
||||
const double target_bits_per_pixel =
|
||||
target_bits_current_picture / pixels_per_picture;
|
||||
const double lambda = 3.2003 * pow(target_bits_per_pixel, -1.367);
|
||||
return CLIP(0.1, 10000, lambda);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue