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:
Arttu Ylä-Outinen 2015-05-06 14:08:18 +03:00
parent 93d2a95ddc
commit b54d5aa91f
3 changed files with 52 additions and 26 deletions

View file

@ -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;

View file

@ -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 */

View file

@ -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);
}