CWG-G094: Bugfix for Output Order when Frames are Output at a Restricted Switch Frame Output using av2_output_frame_buffers() in case of restricted_prediction_switch. **Background:** When we get a switch frame with restricted_prediction_switch == 1, all frames that are going to be set as restricted need to be output first (if eligible for output -- e.g. because implicit_output_frame == 1). **Issue:** Currently, these reference frames get output in the order they appear in ref_frame_map array -- ignoring their display_order_hint values. This makes it very easy for encoder to make a mistake -- if reference frames in the DPB are NOT in the display order hint order, they will get output in the wrong order. **Solution:** Instead of calling `assign_output_frame_buffer_p`, call `av2_output_frame_buffers` directly to output previous, current and future eligible frames in correct order. Fixes #1466
diff --git a/av2/decoder/decodeframe.c b/av2/decoder/decodeframe.c index f466cf6..13db610 100644 --- a/av2/decoder/decodeframe.c +++ b/av2/decoder/decodeframe.c
@@ -8075,21 +8075,18 @@ if (is_mlayer_transitively_dependent( &cm->seq_params, cm->ref_frame_map[i]->mlayer_id, cm->mlayer_id)) { + if (is_frame_eligible_for_output(cm->ref_frame_map[i])) { + const int doh_error = av2_output_frame_buffers(pbi, i); + if (doh_error) { + avm_internal_error( + &cm->error, AVM_CODEC_UNSUP_BITSTREAM, + "Display order hint of an output picture is not unique" + " in the same (xlayer_id %d) layer.", + cm->xlayer_id); + } + } cm->ref_frame_map[i]->is_restricted = true; cm->ref_frame_map[i]->display_order_hint = REF_RESTRICTED_DOH; - if (is_frame_eligible_for_output(cm->ref_frame_map[i])) { - assign_output_frame_buffer_p( - &pbi->output_frames[pbi->num_output_frames++], - cm->ref_frame_map[i]); -#if CONFIG_BITSTREAM_DEBUG - avm_bitstream_queue_set_frame_read( - derive_output_order_idx(cm, cm->ref_frame_map[i]) * 2 + 1); -#endif // CONFIG_BITSTREAM_DEBUG -#if CONFIG_MISMATCH_DEBUG - mismatch_move_frame_idx_r(0); -#endif // CONFIG_MISMATCH_DEBUG - } - cm->ref_frame_map[i]->frame_output_done = true; } } }
diff --git a/av2/decoder/decoder.c b/av2/decoder/decoder.c index 0f82106..634230f 100644 --- a/av2/decoder/decoder.c +++ b/av2/decoder/decoder.c
@@ -636,16 +636,7 @@ return 0; } -// This function outputs frames that are ready to be output. -// The output frames may be the output trigger frame along with -// past frames that have not yet been output, -// and/or future frames that are continuous with the output trigger frame. -// The output trigger frame is the current frame or -// the frame to be flushed out from the ref_frame_map slot. -// ref_idx == -1 indicates the output process is trigged by -// decoding the current frame. -// Returns 0 on success, 1 if a DOH conformance violation was detected. -int output_frame_buffers(AV2Decoder *pbi, int ref_idx) { +int av2_output_frame_buffers(AV2Decoder *pbi, int ref_idx) { AV2_COMMON *const cm = &pbi->common; RefCntBuffer *trigger_frame = NULL; RefCntBuffer *output_candidate = NULL; @@ -775,7 +766,7 @@ } } if (is_frame_eligible_for_output(cm->ref_frame_map[ref_index])) - doh_error |= output_frame_buffers(pbi, ref_index); + doh_error |= av2_output_frame_buffers(pbi, ref_index); decrease_ref_count(cm->ref_frame_map[ref_index], pool); if (av2_skip_reference_buffer_update(clear_multiple_insert_in_one, @@ -792,7 +783,7 @@ pbi->enable_subgop_stats); if (((cm->immediate_output_picture && !cm->cur_frame->frame_output_done) || cm->show_existing_frame)) { - doh_error |= output_frame_buffers(pbi, -1); + doh_error |= av2_output_frame_buffers(pbi, -1); decrease_ref_count(cm->cur_frame, pool); } else { decrease_ref_count(cm->cur_frame, pool);
diff --git a/av2/decoder/decoder.h b/av2/decoder/decoder.h index 242c1cf..f102a0c 100644 --- a/av2/decoder/decoder.h +++ b/av2/decoder/decoder.h
@@ -811,6 +811,17 @@ PARTITION_TYPE partition, BLOCK_SIZE bsize, PARTITION_TREE *parent, int index); +// This function outputs frames that are ready to be output. +// The output frames may be the output trigger frame along with +// past frames that have not yet been output, +// and/or future frames that are continuous with the output trigger frame. +// The output trigger frame is the current frame or +// the frame to be flushed out from the ref_frame_map slot. +// ref_idx == -1 indicates the output process is trigged by +// decoding the current frame. +// Returns 0 on success, 1 if a DOH conformance violation was detected. +int av2_output_frame_buffers(AV2Decoder *pbi, int ref_idx); + /*!\endcond */ #if CONFIG_COLLECT_COMPONENT_TIMING