History

Merge "Add recode loop logics for rate_ctrl experiment"

Angie Chiang committed 6 years ago

Commit 8a8e7802 parents bdbf872 566905e2 files · +205 −1Browse files

Unified · Split

2 files
  1. vp9/encoder/vp9_encoder.c +168 −1
  2. vp9/encoder/vp9_encoder.h +37 −0
vp9/encoder/vp9_encoder.c+168−1
@@ -4201,6 +4201,134 @@ static int get_qstep_adj(int rate_excess, int rate_limit) { · 4200 unmodified lines
4201 return VPXMIN(qstep, MAX_QSTEP_ADJ);4201 return VPXMIN(qstep, MAX_QSTEP_ADJ);
4202}4202}
4203 4203
4204#if CONFIG_RATE_CTRL
4205#define RATE_CTRL_MAX_RECODE_NUM 7
4206
4207typedef struct RATE_QINDEX_HISTORY {
4208 int recode_count;
4209 int q_index_history[RATE_CTRL_MAX_RECODE_NUM];
4210 int rate_history[RATE_CTRL_MAX_RECODE_NUM];
4211 int q_index_high;
4212 int q_index_low;
4213} RATE_QINDEX_HISTORY;
4214
4215static void init_rq_history(RATE_QINDEX_HISTORY *rq_history) {
4216 rq_history->recode_count = 0;
4217 rq_history->q_index_high = 255;
4218 rq_history->q_index_low = 0;
4219}
4220
4221static void update_rq_history(RATE_QINDEX_HISTORY *rq_history, int target_bits,
4222 int actual_bits, int q_index) {
4223 rq_history->q_index_history[rq_history->recode_count] = q_index;
4224 rq_history->rate_history[rq_history->recode_count] = actual_bits;
4225 if (actual_bits <= target_bits) {
4226 rq_history->q_index_high = q_index;
4227 }
4228 if (actual_bits >= target_bits) {
4229 rq_history->q_index_low = q_index;
4230 }
4231 rq_history->recode_count += 1;
4232}
4233
4234static int guess_q_index_from_model(const RATE_QSTEP_MODEL *rq_model,
4235 int target_bits) {
4236 // The model predicts bits as follows.
4237 // target_bits = bias - ratio * log2(q_step)
4238 // Given the target_bits, we compute the q_step as follows.
4239 const double q_step =
4240 pow(2.0, (rq_model->bias - target_bits) / rq_model->ratio);
4241 // TODO(angiebird): Make this function support highbitdepth.
4242 return vp9_convert_q_to_qindex(q_step, VPX_BITS_8);
4243}
4244
4245static int guess_q_index_linear(int prev_q_index, int target_bits,
4246 int actual_bits, int gap) {
4247 int q_index = prev_q_index;
4248 if (actual_bits < target_bits) {
4249 q_index -= gap;
4250 q_index = VPXMAX(q_index, 0);
4251 } else {
4252 q_index += gap;
4253 q_index = VPXMIN(q_index, 255);
4254 }
4255 return q_index;
4256}
4257
4258static double get_bits_percent_diff(int target_bits, int actual_bits) {
4259 double diff = abs(target_bits - actual_bits) * 1. / target_bits;
4260 diff *= 100;
4261 return diff;
4262}
4263
4264static int rq_model_predict_q_index(const RATE_QSTEP_MODEL *rq_model,
4265 const RATE_QINDEX_HISTORY *rq_history,
4266 int target_bits) {
4267 int q_index = -1;
4268 if (rq_history->recode_count > 0) {
4269 const int actual_bits =
4270 rq_history->rate_history[rq_history->recode_count - 1];
4271 const int prev_q_index =
4272 rq_history->q_index_history[rq_history->recode_count - 1];
4273 const double percent_diff = get_bits_percent_diff(target_bits, actual_bits);
4274 if (percent_diff > 50) {
4275 // Binary search.
4276 // When the actual_bits and target_bits are far apart, binary search
4277 // q_index is faster.
4278 q_index = (rq_history->q_index_low + rq_history->q_index_high) / 2;
4279 } else {
4280 if (rq_model->ready) {
4281 q_index = guess_q_index_from_model(rq_model, target_bits);
4282 } else {
4283 // TODO(angiebird): Find a better way to set the gap.
4284 q_index =
4285 guess_q_index_linear(prev_q_index, target_bits, actual_bits, 20);
4286 }
4287 }
4288 } else {
4289 if (rq_model->ready) {
4290 q_index = guess_q_index_from_model(rq_model, target_bits);
4291 }
4292 }
4293
4294 assert(rq_history->q_index_low <= rq_history->q_index_high);
4295 if (q_index <= rq_history->q_index_low) {
4296 q_index = rq_history->q_index_low + 1;
4297 }
4298 if (q_index >= rq_history->q_index_high) {
4299 q_index = rq_history->q_index_high - 1;
4300 }
4301 return q_index;
4302}
4303
4304static void rq_model_update(const RATE_QINDEX_HISTORY *rq_history,
4305 int target_bits, RATE_QSTEP_MODEL *rq_model) {
4306 const int recode_count = rq_history->recode_count;
4307 if (recode_count >= 2) {
4308 // Fit the ratio and bias of rq_model based on last two recode histories.
4309 const double s1 = vp9_convert_qindex_to_q(
4310 rq_history->q_index_history[recode_count - 2], VPX_BITS_8);
4311 const double s2 = vp9_convert_qindex_to_q(
4312 rq_history->q_index_history[recode_count - 1], VPX_BITS_8);
4313 const double r1 = rq_history->rate_history[recode_count - 2];
4314 const double r2 = rq_history->rate_history[recode_count - 1];
4315 rq_model->ratio = (r2 - r1) / (log2(s1) - log2(s2));
4316 rq_model->bias = r1 + (rq_model->ratio) * log2(s1);
4317 rq_model->ready = 1;
4318 } else if (recode_count == 1) {
4319 if (rq_model->ready) {
4320 // Update the ratio only when the initial model exists and we only have
4321 // one recode history.
4322 const int prev_q = rq_history->q_index_history[recode_count - 1];
4323 const double prev_q_step = vp9_convert_qindex_to_q(prev_q, VPX_BITS_8);
4324 const int actual_bits = rq_history->rate_history[recode_count - 1];
4325 rq_model->ratio =
4326 rq_model->ratio - (target_bits - actual_bits) / log2(prev_q_step);
4327 }
4328 }
4329}
4330#endif // CONFIG_RATE_CTRL
4331
4204static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size,4332static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size,
4205 uint8_t *dest) {4333 uint8_t *dest) {
4206 const VP9EncoderConfig *const oxcf = &cpi->oxcf;4334 const VP9EncoderConfig *const oxcf = &cpi->oxcf;
@@ -4220,6 +4348,15 @@ static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, · 13 unmodified lines
4220 int qrange_adj = 1;4348 int qrange_adj = 1;
4221#endif4349#endif
4222 4350
4351#if CONFIG_RATE_CTRL
4352 const FRAME_UPDATE_TYPE update_type =
4353 cpi->twopass.gf_group.update_type[cpi->twopass.gf_group.index];
4354 const ENCODE_FRAME_TYPE frame_type = get_encode_frame_type(update_type);
4355 RATE_QSTEP_MODEL *rq_model = &cpi->rq_model[frame_type];
4356 RATE_QINDEX_HISTORY rq_history;
4357 init_rq_history(&rq_history);
4358#endif // CONFIG_RATE_CTRL
4359
4223 if (cm->show_existing_frame) {4360 if (cm->show_existing_frame) {
4224 rc->this_frame_target = 0;4361 rc->this_frame_target = 0;
4225 if (is_psnr_calc_enabled(cpi)) set_raw_source_frame(cpi);4362 if (is_psnr_calc_enabled(cpi)) set_raw_source_frame(cpi);
@@ -4266,6 +4403,15 @@ static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, · 40 unmodified lines
4266 loop_at_this_size = 0;4403 loop_at_this_size = 0;
4267 }4404 }
4268 4405
4406#if CONFIG_RATE_CTRL
4407 {
4408 const int suggested_q_index = rq_model_predict_q_index(
4409 rq_model, &rq_history, rc->this_frame_target);
4410 if (suggested_q_index != -1) {
4411 q = suggested_q_index;
4412 }
4413 }
4414#endif // CONFIG_RATE_CTRL
4269 // Decide frame size bounds first time through.4415 // Decide frame size bounds first time through.
4270 if (loop_count == 0) {4416 if (loop_count == 0) {
4271 vp9_rc_compute_frame_size_bounds(cpi, rc->this_frame_target,4417 vp9_rc_compute_frame_size_bounds(cpi, rc->this_frame_target,
@@ -4359,7 +4505,28 @@ static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, · 87 unmodified lines
4359 if (cpi->encode_command.use_external_quantize_index) {4505 if (cpi->encode_command.use_external_quantize_index) {
4360 break;4506 break;
4361 }4507 }
4362#endif4508
4509 if (cpi->encode_command.use_external_target_frame_bits) {
4510 const double percent_diff = get_bits_percent_diff(
4511 rc->this_frame_target, rc->projected_frame_size);
4512 update_rq_history(&rq_history, rc->this_frame_target,
4513 rc->projected_frame_size, q);
4514 loop_count += 1;
4515
4516 rq_model_update(&rq_history, rc->this_frame_target, rq_model);
4517
4518 // Check if we hit the target bitrate.
4519 if (percent_diff <= 15 ||
4520 rq_history.recode_count >= RATE_CTRL_MAX_RECODE_NUM ||
4521 rq_history.q_index_low >= rq_history.q_index_high) {
4522 break;
4523 }
4524
4525 loop = 1;
4526 restore_coding_context(cpi);
4527 continue;
4528 }
4529#endif // CONFIG_RATE_CTRL
4363 4530
4364 if (oxcf->rc_mode == VPX_Q) {4531 if (oxcf->rc_mode == VPX_Q) {
4365 loop = 0;4532 loop = 0;
vp9/encoder/vp9_encoder.h+37−0
@@ -560,6 +560,41 @@ static INLINE int gop_command_coding_frame_count( · 559 unmodified lines
560 return gop_command->show_frame_count + gop_command->use_alt_ref;560 return gop_command->show_frame_count + gop_command->use_alt_ref;
561}561}
562 562
563// TODO(angiebird): See if we can merge this one with FrameType in
564// simple_encode.h
565typedef enum ENCODE_FRAME_TYPE {
566 ENCODE_FRAME_TYPE_KEY,
567 ENCODE_FRAME_TYPE_INTER,
568 ENCODE_FRAME_TYPE_ALTREF,
569 ENCODE_FRAME_TYPE_OVERLAY,
570 ENCODE_FRAME_TYPE_GOLDEN,
571 ENCODE_FRAME_TYPES,
572} ENCODE_FRAME_TYPE;
573
574// TODO(angiebird): Merge this function with get_frame_type_from_update_type()
575static INLINE ENCODE_FRAME_TYPE
576get_encode_frame_type(FRAME_UPDATE_TYPE update_type) {
577 switch (update_type) {
578 case KF_UPDATE: return ENCODE_FRAME_TYPE_KEY;
579 case ARF_UPDATE: return ENCODE_FRAME_TYPE_ALTREF;
580 case GF_UPDATE: return ENCODE_FRAME_TYPE_GOLDEN;
581 case OVERLAY_UPDATE: return ENCODE_FRAME_TYPE_OVERLAY;
582 case LF_UPDATE: return ENCODE_FRAME_TYPE_INTER;
583 default:
584 fprintf(stderr, "Unsupported update_type %d\n", update_type);
585 abort();
586 return ENCODE_FRAME_TYPE_INTER;
587 }
588}
589
590typedef struct RATE_QSTEP_MODEL {
591 // The rq model predict the bit usage as follows.
592 // rate = bias - ratio * log2(q_step)
593 int ready;
594 double bias;
595 double ratio;
596} RATE_QSTEP_MODEL;
597
563typedef struct ENCODE_COMMAND {598typedef struct ENCODE_COMMAND {
564 int use_external_quantize_index;599 int use_external_quantize_index;
565 int external_quantize_index;600 int external_quantize_index;
@@ -917,6 +952,8 @@ typedef struct VP9_COMP { · 351 unmodified lines
917 ENCODE_COMMAND encode_command;952 ENCODE_COMMAND encode_command;
918 PARTITION_INFO *partition_info;953 PARTITION_INFO *partition_info;
919 MOTION_VECTOR_INFO *motion_vector_info;954 MOTION_VECTOR_INFO *motion_vector_info;
955
956 RATE_QSTEP_MODEL rq_model[ENCODE_FRAME_TYPES];
920#endif957#endif
921} VP9_COMP;958} VP9_COMP;
922 959

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t