Fix picture and slice types

Changes handling of intra pictures for --gop=8 so that every picture
with POC divisible by the intra period is intra. The first picture is
IDR and the rest of the intra pictures are CRA. POC is not reset at CRA
pictures. The leading pictures that follow the CRA picture are changed
to RASL so they are allowed to refer to pictures before the CRA picture.

Changes inter slice types to P when the L1 reference list is empty and
to B otherwise.

In all-intra, all pictures are now IDR pictures with POC zero.
This commit is contained in:
Arttu Ylä-Outinen 2017-10-19 13:25:57 +03:00
parent 957b6850c3
commit 841597e123
2 changed files with 54 additions and 62 deletions

View file

@ -731,7 +731,7 @@ static void kvz_encoder_state_write_bitstream_slice_header_independent(
WRITE_UE(stream, encoder->cfg.gop_len?delta_poc - last_poc - 1:0, "delta_poc_s0_minus1"); WRITE_UE(stream, encoder->cfg.gop_len?delta_poc - last_poc - 1:0, "delta_poc_s0_minus1");
last_poc = delta_poc; last_poc = delta_poc;
WRITE_U(stream,1,1, "used_by_curr_pic_s0_flag"); WRITE_U(stream, !state->frame->is_irap, 1, "used_by_curr_pic_s0_flag");
} }
last_poc = 0; last_poc = 0;
poc_shift = 0; poc_shift = 0;
@ -758,12 +758,12 @@ static void kvz_encoder_state_write_bitstream_slice_header_independent(
WRITE_UE(stream, encoder->cfg.gop_len ? delta_poc - last_poc - 1 : 0, "delta_poc_s1_minus1"); WRITE_UE(stream, encoder->cfg.gop_len ? delta_poc - last_poc - 1 : 0, "delta_poc_s1_minus1");
last_poc = delta_poc; last_poc = delta_poc;
WRITE_U(stream, 1, 1, "used_by_curr_pic_s1_flag"); WRITE_U(stream, !state->frame->is_irap, 1, "used_by_curr_pic_s1_flag");
} }
//WRITE_UE(stream, 0, "short_term_ref_pic_set_idx"); //WRITE_UE(stream, 0, "short_term_ref_pic_set_idx");
if (state->encoder_control->cfg.tmvp_enable) { if (state->encoder_control->cfg.tmvp_enable) {
WRITE_U(stream, ref_negative?1:0, 1, "slice_temporal_mvp_enabled_flag"); WRITE_U(stream, ref_negative ? 1 : 0, 1, "slice_temporal_mvp_enabled_flag");
} }
} }

View file

@ -996,7 +996,7 @@ void kvz_encoder_create_ref_lists(const encoder_state_t *const state)
*/ */
static void encoder_state_remove_refs(encoder_state_t *state) { static void encoder_state_remove_refs(encoder_state_t *state) {
const encoder_control_t * const encoder = state->encoder_control; const encoder_control_t * const encoder = state->encoder_control;
int neg_refs = encoder->cfg.gop[state->frame->gop_offset].ref_neg_count; int neg_refs = encoder->cfg.gop[state->frame->gop_offset].ref_neg_count;
int pos_refs = encoder->cfg.gop[state->frame->gop_offset].ref_pos_count; int pos_refs = encoder->cfg.gop[state->frame->gop_offset].ref_pos_count;
@ -1006,7 +1006,10 @@ static void encoder_state_remove_refs(encoder_state_t *state) {
} else { } else {
target_ref_num = encoder->cfg.ref_frames; target_ref_num = encoder->cfg.ref_frames;
} }
if (state->frame->slicetype == KVZ_SLICE_I) {
if (state->frame->pictype == KVZ_NAL_IDR_W_RADL ||
state->frame->pictype == KVZ_NAL_IDR_N_LP)
{
target_ref_num = 0; target_ref_num = 0;
} }
@ -1018,7 +1021,7 @@ static void encoder_state_remove_refs(encoder_state_t *state) {
bool is_referenced = false; bool is_referenced = false;
int ref_poc = state->frame->ref->pocs[ref]; int ref_poc = state->frame->ref->pocs[ref];
for (int i = 0; i < neg_refs; i++) { for (int i = 0; i < neg_refs; i++) {
int ref_relative_poc = -encoder->cfg.gop[state->frame->gop_offset].ref_neg[i]; int ref_relative_poc = -encoder->cfg.gop[state->frame->gop_offset].ref_neg[i];
if (ref_poc == state->frame->poc + ref_relative_poc) { if (ref_poc == state->frame->poc + ref_relative_poc) {
@ -1027,7 +1030,6 @@ static void encoder_state_remove_refs(encoder_state_t *state) {
} }
} }
for (int i = 0; i < pos_refs; i++) { for (int i = 0; i < pos_refs; i++) {
int ref_relative_poc = encoder->cfg.gop[state->frame->gop_offset].ref_pos[i]; int ref_relative_poc = encoder->cfg.gop[state->frame->gop_offset].ref_pos[i];
if (ref_poc == state->frame->poc + ref_relative_poc) { if (ref_poc == state->frame->poc + ref_relative_poc) {
@ -1043,6 +1045,13 @@ static void encoder_state_remove_refs(encoder_state_t *state) {
is_referenced = false; is_referenced = false;
} }
if (encoder->cfg.intra_period > 0 &&
ref_poc < state->frame->irap_poc - encoder->cfg.intra_period)
{
// No frame can refer past the two preceding IRAP frames.
is_referenced = false;
}
if (!is_referenced) { if (!is_referenced) {
// This reference is not referred to by this frame, it must be removed. // This reference is not referred to by this frame, it must be removed.
kvz_image_list_rem(state->frame->ref, ref); kvz_image_list_rem(state->frame->ref, ref);
@ -1059,16 +1068,6 @@ static void encoder_state_remove_refs(encoder_state_t *state) {
assert(state->frame->ref->used_size <= target_ref_num); assert(state->frame->ref->used_size <= target_ref_num);
} }
static void encoder_state_reset_poc(encoder_state_t *state) {
state->frame->poc = 0;
kvz_videoframe_set_poc(state->tile->frame, 0);
for (int i = 0; state->children[i].encoder_control; ++i) {
encoder_state_t *sub_state = &(state->children[i]);
encoder_state_reset_poc(sub_state);
}
}
static void encoder_set_source_picture(encoder_state_t * const state, kvz_picture* frame) static void encoder_set_source_picture(encoder_state_t * const state, kvz_picture* frame)
{ {
assert(!state->tile->frame->source); assert(!state->tile->frame->source);
@ -1134,63 +1133,46 @@ static void encoder_state_init_new_frame(encoder_state_t * const state, kvz_pict
state->tile->frame->height state->tile->frame->height
); );
// Set POC.
if (state->frame->num == 0) {
state->frame->poc = 0;
} else if (cfg->gop_len && !cfg->gop_lowdelay) {
// Calculate POC according to the global frame counter and GOP structure
int32_t poc = state->frame->num - 1;
int32_t poc_offset = cfg->gop[state->frame->gop_offset].poc_offset;
state->frame->poc = poc - poc % cfg->gop_len + poc_offset;
kvz_videoframe_set_poc(state->tile->frame, state->frame->poc);
} else if (cfg->intra_period > 0) {
state->frame->poc = state->frame->num % cfg->intra_period;
} else {
state->frame->poc = state->frame->num;
}
// Check whether the frame is a keyframe or not. // Check whether the frame is a keyframe or not.
if (state->frame->num == 0) { if (state->frame->num == 0) {
state->frame->is_irap = true; state->frame->is_irap = true;
} else if (cfg->intra_period == 1) {
state->frame->is_irap = state->frame->num % 2 == 0;
} else if (cfg->intra_period > 1) {
if (cfg->gop_len > 0 && !cfg->gop_lowdelay) {
state->frame->is_irap = (state->frame->num - 1) % cfg->intra_period == 0;
} else {
state->frame->is_irap = state->frame->num % cfg->intra_period == 0;
}
} else { } else {
state->frame->is_irap = false; state->frame->is_irap =
cfg->intra_period > 0 &&
(state->frame->poc % cfg->intra_period) == 0;
} }
if (state->frame->is_irap) {
// Set slicetype. state->frame->irap_poc = state->frame->poc;
if (state->frame->is_irap || cfg->intra_period == 1) {
state->frame->slicetype = KVZ_SLICE_I;
} else if (cfg->gop_len > 0 && !cfg->gop_lowdelay) {
state->frame->slicetype = KVZ_SLICE_B;
} else {
state->frame->slicetype = KVZ_SLICE_P;
}
// Set POC.
if (cfg->intra_period != 1 &&
cfg->gop_len > 0 &&
!cfg->gop_lowdelay &&
state->frame->num > 0)
{
// Calculate POC according to the global frame counter and GOP
// structure.
if (cfg->intra_period > 0) {
int32_t poc = (state->frame->num - 1) % cfg->intra_period;
int poc_offset = cfg->gop[state->frame->gop_offset].poc_offset - 1;
state->frame->poc = poc - poc % cfg->gop_len + poc_offset;
} else {
int32_t poc = state->frame->num;
int poc_offset = cfg->gop[state->frame->gop_offset].poc_offset - 1;
state->frame->poc = poc - (poc - 1) % cfg->gop_len + poc_offset;
}
kvz_videoframe_set_poc(state->tile->frame, state->frame->poc);
} else if (state->frame->is_irap) {
encoder_state_reset_poc(state);
} }
// Set pictype. // Set pictype.
if (state->frame->is_irap) { if (state->frame->is_irap) {
if (cfg->gop_len > 0 && !cfg->gop_lowdelay && state->frame->num > 0) { if (state->frame->num == 0 ||
state->frame->pictype = KVZ_NAL_BLA_W_RADL; cfg->intra_period == 1 ||
} else { cfg->gop_len == 0 ||
cfg->gop_lowdelay)
{
state->frame->pictype = KVZ_NAL_IDR_W_RADL; state->frame->pictype = KVZ_NAL_IDR_W_RADL;
} else {
state->frame->pictype = KVZ_NAL_CRA_NUT;
} }
state->frame->irap_poc = state->frame->poc;
} else if (state->frame->poc < state->frame->irap_poc) { } else if (state->frame->poc < state->frame->irap_poc) {
state->frame->pictype = KVZ_NAL_RADL_R; state->frame->pictype = KVZ_NAL_RASL_R;
} else { } else {
state->frame->pictype = KVZ_NAL_TRAIL_R; state->frame->pictype = KVZ_NAL_TRAIL_R;
} }
@ -1198,6 +1180,15 @@ static void encoder_state_init_new_frame(encoder_state_t * const state, kvz_pict
encoder_state_remove_refs(state); encoder_state_remove_refs(state);
kvz_encoder_create_ref_lists(state); kvz_encoder_create_ref_lists(state);
// Set slicetype.
if (state->frame->is_irap) {
state->frame->slicetype = KVZ_SLICE_I;
} else if (state->frame->ref_LX_size[1] > 0) {
state->frame->slicetype = KVZ_SLICE_B;
} else {
state->frame->slicetype = KVZ_SLICE_P;
}
if (cfg->target_bitrate > 0 && state->frame->num > cfg->owf) { if (cfg->target_bitrate > 0 && state->frame->num > cfg->owf) {
normalize_lcu_weights(state); normalize_lcu_weights(state);
} }
@ -1278,6 +1269,7 @@ void kvz_encoder_prepare(encoder_state_t *state)
state->tile->frame->cu_array = kvz_cu_array_alloc(width, height); state->tile->frame->cu_array = kvz_cu_array_alloc(width, height);
kvz_image_list_copy_contents(state->frame->ref, prev_state->frame->ref); kvz_image_list_copy_contents(state->frame->ref, prev_state->frame->ref);
kvz_encoder_create_ref_lists(state);
} }
if (!encoder->cfg.gop_len || if (!encoder->cfg.gop_len ||