Set QP completely at CU level as the name '--set-qp-in-cu' implies

-Move slice delta QP to CU level when using --set-qp-in-cu
-Separate functionality from roi
This commit is contained in:
Ari Lemmetti 2019-05-22 17:26:10 +03:00
parent 87a9208db8
commit 9339845e8b
7 changed files with 15 additions and 31 deletions

View file

@ -138,7 +138,7 @@ Video structure:
QP values in raster order. The map can be of any QP values in raster order. The map can be of any
size and will be scaled to the video size. size and will be scaled to the video size.
--set-qp-in-cu : Set QP at CU level keeping pic_init_qp_minus26. --set-qp-in-cu : Set QP at CU level keeping pic_init_qp_minus26.
in PPS zero. in PPS and slice_qp_delta in slize header zero.
--(no-)erp-aqp : Use adaptive QP for 360 degree video with --(no-)erp-aqp : Use adaptive QP for 360 degree video with
equirectangular projection. [disabled] equirectangular projection. [disabled]
--level <number> : Use the given HEVC level in the output and give --level <number> : Use the given HEVC level in the output and give

View file

@ -1,4 +1,4 @@
.TH KVAZAAR "1" "October 2018" "kvazaar v1.2.0" "User Commands" .TH KVAZAAR "1" "May 2019" "kvazaar v1.2.0" "User Commands"
.SH NAME .SH NAME
kvazaar \- open source HEVC encoder kvazaar \- open source HEVC encoder
.SH SYNOPSIS .SH SYNOPSIS
@ -157,7 +157,7 @@ size and will be scaled to the video size.
.TP .TP
\fB\-\-set\-qp\-in\-cu \fB\-\-set\-qp\-in\-cu
Set QP at CU level keeping pic_init_qp_minus26. Set QP at CU level keeping pic_init_qp_minus26.
in PPS zero. in PPS and slice_qp_delta in slize header zero.
.TP .TP
\fB\-\-(no\-)erp\-aqp \fB\-\-(no\-)erp\-aqp
Use adaptive QP for 360 degree video with Use adaptive QP for 360 degree video with

View file

@ -420,7 +420,7 @@ void print_help(void)
" QP values in raster order. The map can be of any\n" " QP values in raster order. The map can be of any\n"
" size and will be scaled to the video size.\n" " size and will be scaled to the video size.\n"
" --set-qp-in-cu : Set QP at CU level keeping pic_init_qp_minus26.\n" " --set-qp-in-cu : Set QP at CU level keeping pic_init_qp_minus26.\n"
" in PPS zero.\n" " in PPS and slice_qp_delta in slize header zero.\n"
" --(no-)erp-aqp : Use adaptive QP for 360 degree video with\n" " --(no-)erp-aqp : Use adaptive QP for 360 degree video with\n"
" equirectangular projection. [disabled]\n" " equirectangular projection. [disabled]\n"
" --level <number> : Use the given HEVC level in the output and give\n" " --level <number> : Use the given HEVC level in the output and give\n"

View file

@ -352,32 +352,11 @@ encoder_control_t* kvz_encoder_control_init(const kvz_config *const cfg)
} }
// If QP will be set at CU level instead of PPS,
// encoder is given qp 26 making pic_init_qp_minus26
// zero. The difference is added to the delta QP map.
if (cfg->set_qp_in_cu) {
encoder->cfg.qp = 26;
// If delta QP map does not already exist, it has to be created.
if (encoder->cfg.roi.dqps == NULL) {
encoder->cfg.roi.width = 1;
encoder->cfg.roi.height = 1;
encoder->cfg.roi.dqps = calloc(1, sizeof(cfg->roi.dqps[0]));
}
const size_t roi_size = encoder->cfg.roi.width * encoder->cfg.roi.height;
for (int i = 0; i < roi_size; ++i) {
encoder->cfg.roi.dqps[i] += cfg->qp - 26;
encoder->cfg.roi.dqps[i] = CLIP(-51, 51, encoder->cfg.roi.dqps[i]);
}
}
// NOTE: When tr_depth_inter is equal to 0, the transform is still split // NOTE: When tr_depth_inter is equal to 0, the transform is still split
// for SMP and AMP partition units. // for SMP and AMP partition units.
encoder->tr_depth_inter = 0; encoder->tr_depth_inter = 0;
if (encoder->cfg.target_bitrate > 0 || encoder->cfg.roi.dqps) { if (encoder->cfg.target_bitrate > 0 || encoder->cfg.roi.dqps || encoder->cfg.set_qp_in_cu) {
encoder->max_qp_delta_depth = 0; encoder->max_qp_delta_depth = 0;
} else { } else {
encoder->max_qp_delta_depth = -1; encoder->max_qp_delta_depth = -1;

View file

@ -456,8 +456,9 @@ static void encoder_state_write_bitstream_pic_parameter_set(bitstream_t* stream,
WRITE_UE(stream, 0, "num_ref_idx_l1_default_active_minus1"); WRITE_UE(stream, 0, "num_ref_idx_l1_default_active_minus1");
// If tiles and slices = tiles is enabled, signal QP in the slice header. Keeping the PPS constant for OMAF etc // If tiles and slices = tiles is enabled, signal QP in the slice header. Keeping the PPS constant for OMAF etc
bool signal_qp_in_slice_header = (encoder->cfg.slices & KVZ_SLICES_TILES) && encoder->tiles_enable; // Keep QP constant here also if it will be only set at CU level.
WRITE_SE(stream, signal_qp_in_slice_header ?0:(((int8_t)encoder->cfg.qp) - 26), "pic_init_qp_minus26"); bool constant_qp_in_pps = ((encoder->cfg.slices & KVZ_SLICES_TILES) && encoder->tiles_enable) || encoder->cfg.set_qp_in_cu;
WRITE_SE(stream, constant_qp_in_pps ? 0 : (((int8_t)encoder->cfg.qp) - 26), "pic_init_qp_minus26");
WRITE_U(stream, 0, 1, "constrained_intra_pred_flag"); WRITE_U(stream, 0, 1, "constrained_intra_pred_flag");
WRITE_U(stream, encoder->cfg.trskip_enable, 1, "transform_skip_enabled_flag"); WRITE_U(stream, encoder->cfg.trskip_enable, 1, "transform_skip_enabled_flag");
@ -812,8 +813,10 @@ static void kvz_encoder_state_write_bitstream_slice_header_independent(
{ {
// If tiles are enabled, signal the full QP here (relative to the base value of 26) // If tiles are enabled, signal the full QP here (relative to the base value of 26)
// If QP is to be set only at CU level, force slice_qp_delta zero
bool signal_qp_in_slice_header = (encoder->cfg.slices & KVZ_SLICES_TILES) && encoder->tiles_enable; bool signal_qp_in_slice_header = (encoder->cfg.slices & KVZ_SLICES_TILES) && encoder->tiles_enable;
int slice_qp_delta = state->frame->QP - (signal_qp_in_slice_header ? 26 : encoder->cfg.qp); int slice_qp_delta = state->frame->QP - (signal_qp_in_slice_header ? 26 : encoder->cfg.qp);
if(encoder->cfg.set_qp_in_cu) slice_qp_delta = 0;
WRITE_SE(stream, slice_qp_delta, "slice_qp_delta"); WRITE_SE(stream, slice_qp_delta, "slice_qp_delta");
} }
} }

View file

@ -726,7 +726,8 @@ static void encoder_state_encode_leaf(encoder_state_t * const state)
const encoder_control_t *ctrl = state->encoder_control; const encoder_control_t *ctrl = state->encoder_control;
const kvz_config *cfg = &ctrl->cfg; const kvz_config *cfg = &ctrl->cfg;
state->last_qp = state->frame->QP; // Signaled slice QP may be different to frame QP with set-qp-in-cu enabled.
state->last_qp = ctrl->cfg.set_qp_in_cu ? 26 : state->frame->QP;
if (cfg->crypto_features) { if (cfg->crypto_features) {
state->crypto_hdl = kvz_crypto_create(cfg); state->crypto_hdl = kvz_crypto_create(cfg);
@ -1140,7 +1141,7 @@ static void encoder_state_init_children(encoder_state_t * const state) {
if (state->is_leaf) { if (state->is_leaf) {
//Leaf states have cabac and context //Leaf states have cabac and context
kvz_cabac_start(&state->cabac); kvz_cabac_start(&state->cabac);
kvz_init_contexts(state, state->frame->QP, state->frame->slicetype); kvz_init_contexts(state, state->encoder_control->cfg.set_qp_in_cu ? 26 : state->frame->QP, state->frame->slicetype);
} }
//Clear the jobs //Clear the jobs

View file

@ -272,7 +272,8 @@ static int8_t get_qp_y_pred(const encoder_state_t* state, int x, int y, edge_dir
} else if (dir == EDGE_VER && x > 0) { } else if (dir == EDGE_VER && x > 0) {
qp_p = kvz_cu_array_at_const(state->tile->frame->cu_array, x - 1, y)->qp; qp_p = kvz_cu_array_at_const(state->tile->frame->cu_array, x - 1, y)->qp;
} else { } else {
qp_p = state->frame->QP; // TODO: This seems to be dead code. Investigate.
qp_p = state->encoder_control->cfg.set_qp_in_cu ? 26 : state->frame->QP;
} }
const int32_t qp_q = const int32_t qp_q =