codecs: h264dec: Modify the DPB need bump check.

Accord to spec, we should not add the current picture into the DPB
when we check whether it needs to bump, so the checks of the IDR and
the "memory_management_control_operation equal to 5" are no needed.

And the spec also says that the DPB only needs to bump when there is
no empty frame buffer left(We handle the IDR cases in other places).
We need to follow that and the max_num_reorder_frames is useless.

We also minus 1 in has_empty_frame_buffer because the current frame
has not been added yet.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2373>
This commit is contained in:
He Junyan 2021-07-12 00:06:49 +08:00 committed by GStreamer Marge Bot
parent 4411a4e00f
commit f1df120797
3 changed files with 45 additions and 63 deletions

View file

@ -785,8 +785,7 @@ gst_h264_decoder_handle_frame_num_gap (GstH264Decoder * self, gint frame_num)
} else { } else {
gst_h264_dpb_add (priv->dpb, picture); gst_h264_dpb_add (priv->dpb, picture);
} }
while (gst_h264_dpb_needs_bump (priv->dpb, priv->max_num_reorder_frames, while (gst_h264_dpb_needs_bump (priv->dpb, picture, FALSE)) {
FALSE)) {
GstH264Picture *to_output; GstH264Picture *to_output;
to_output = gst_h264_dpb_bump (priv->dpb, FALSE); to_output = gst_h264_dpb_bump (priv->dpb, FALSE);
@ -1865,8 +1864,7 @@ gst_h264_decoder_finish_picture (GstH264Decoder * self,
picture, picture->frame_num, picture->pic_order_cnt, picture, picture->frame_num, picture->pic_order_cnt,
gst_h264_dpb_get_size (priv->dpb)); gst_h264_dpb_get_size (priv->dpb));
while (gst_h264_dpb_needs_bump (priv->dpb, priv->max_num_reorder_frames, while (gst_h264_dpb_needs_bump (priv->dpb, picture, priv->is_live)) {
priv->is_live)) {
GstH264Picture *to_output; GstH264Picture *to_output;
to_output = gst_h264_dpb_bump (priv->dpb, FALSE); to_output = gst_h264_dpb_bump (priv->dpb, FALSE);

View file

@ -277,6 +277,10 @@ gst_h264_dpb_add (GstH264Dpb * dpb, GstH264Picture * picture)
} }
g_array_append_val (dpb->pic_list, picture); g_array_append_val (dpb->pic_list, picture);
if (dpb->pic_list->len > dpb->max_num_frames * (dpb->interlaced + 1))
GST_ERROR ("DPB size is %d, exceed the max size %d",
dpb->pic_list->len, dpb->max_num_frames);
} }
/** /**
@ -599,7 +603,7 @@ gboolean
gst_h264_dpb_has_empty_frame_buffer (GstH264Dpb * dpb) gst_h264_dpb_has_empty_frame_buffer (GstH264Dpb * dpb)
{ {
if (!dpb->interlaced) { if (!dpb->interlaced) {
if (dpb->pic_list->len <= dpb->max_num_frames) if (dpb->pic_list->len < dpb->max_num_frames)
return TRUE; return TRUE;
} else { } else {
gint i; gint i;
@ -616,7 +620,7 @@ gst_h264_dpb_has_empty_frame_buffer (GstH264Dpb * dpb)
count++; count++;
} }
if (count <= dpb->max_num_frames) if (count < dpb->max_num_frames)
return TRUE; return TRUE;
} }
@ -665,7 +669,7 @@ gst_h264_dpb_get_lowest_output_needed_picture (GstH264Dpb * dpb,
/** /**
* gst_h264_dpb_needs_bump: * gst_h264_dpb_needs_bump:
* @dpb: a #GstH264Dpb * @dpb: a #GstH264Dpb
* @max_num_reorder_frames: allowed max_num_reorder_frames as specified by sps * @to_insert: the current #GstH264Picture to insert to dpb.
* @low_latency: %TRUE if low-latency bumping is required * @low_latency: %TRUE if low-latency bumping is required
* *
* Returns: %TRUE if bumping is required * Returns: %TRUE if bumping is required
@ -673,76 +677,56 @@ gst_h264_dpb_get_lowest_output_needed_picture (GstH264Dpb * dpb,
* Since: 1.20 * Since: 1.20
*/ */
gboolean gboolean
gst_h264_dpb_needs_bump (GstH264Dpb * dpb, guint32 max_num_reorder_frames, gst_h264_dpb_needs_bump (GstH264Dpb * dpb, GstH264Picture * to_insert,
gboolean low_latency) gboolean low_latency)
{ {
GstH264Picture *current_picture; GstH264Picture *picture = NULL;
gint32 lowest_poc;
g_return_val_if_fail (dpb != NULL, FALSE); g_return_val_if_fail (dpb != NULL, FALSE);
g_assert (dpb->num_output_needed >= 0); g_assert (dpb->num_output_needed >= 0);
/* Empty so nothing to bump */
if (dpb->pic_list->len == 0 || dpb->num_output_needed == 0)
return FALSE;
/* FIXME: Need to revisit for intelaced decoding */ /* FIXME: Need to revisit for intelaced decoding */
/* Case 1) if (low_latency) {
* C.4.2 Decoding of gaps in frame_num and storage of "non-existing" pictures /* TODO: */
* C.4.5.1 Storage and marking of a reference decoded picture into the DPB }
* C.4.5.2 Storage and marking of a non-reference decoded picture into the DPB
* /* C.4.5.3: The "bumping" process is invoked in the following cases.
* In summary, if DPB is full and there is no empty space to store current - There is no empty frame buffer and a empty frame buffer is needed
* picture, need bumping. for storage of an inferred "non-existing" frame.
* NOTE: current picture was added already by our decoding flow, So we need to - There is no empty frame buffer and an empty frame buffer is needed
* do bumping until dpb->pic_list->len == dpb->max_num_pic for storage of a decoded (non-IDR) reference picture.
*/ - There is no empty frame buffer and the current picture is a non-
if (!gst_h264_dpb_has_empty_frame_buffer (dpb)) { reference picture that is not the second field of a complementary
GST_TRACE ("No empty frame buffer, need bumping"); non-reference field pair and there are pictures in the DPB that are
marked as "needed for output" that precede the current non-reference
picture in output order. */
if (gst_h264_dpb_has_empty_frame_buffer (dpb)) {
GST_TRACE ("DPB has empty frame buffer, no need bumping.");
return FALSE;
}
if (to_insert->ref != GST_H264_PICTURE_REF_NONE) {
GST_TRACE ("No empty frame buffer for ref frame, need bumping.");
return TRUE; return TRUE;
} }
if (dpb->num_output_needed > max_num_reorder_frames) { lowest_poc = G_MAXINT32;
GST_TRACE
("not outputted frames (%d) > max_num_reorder_frames (%d), need bumping",
dpb->num_output_needed, max_num_reorder_frames);
return TRUE;
}
current_picture =
g_array_index (dpb->pic_list, GstH264Picture *, dpb->pic_list->len - 1);
if (current_picture->needed_for_output && current_picture->idr &&
!current_picture->dec_ref_pic_marking.no_output_of_prior_pics_flag) {
GST_TRACE ("IDR with no_output_of_prior_pics_flag == 0, need bumping");
return TRUE;
}
if (current_picture->needed_for_output && current_picture->mem_mgmt_5) {
GST_TRACE ("Memory management type 5, need bumping");
return TRUE;
}
/* HACK: Not all streams have PicOrderCnt increment by 2, but in practice this
* condition can be used */
if (low_latency && dpb->last_output_poc != G_MININT32) {
GstH264Picture *picture = NULL;
gint32 lowest_poc = G_MININT32;
gst_h264_dpb_get_lowest_output_needed_picture (dpb, &picture); gst_h264_dpb_get_lowest_output_needed_picture (dpb, &picture);
if (picture) { if (picture) {
lowest_poc = picture->pic_order_cnt; lowest_poc = picture->pic_order_cnt;
gst_h264_picture_unref (picture); gst_h264_picture_unref (picture);
} }
if (lowest_poc != G_MININT32 && lowest_poc > dpb->last_output_poc if (to_insert->pic_order_cnt > lowest_poc) {
&& abs (lowest_poc - dpb->last_output_poc) <= 2) { GST_TRACE ("No empty frame buffer, lowest poc %d < current poc %d,"
GST_TRACE ("bumping for low-latency, lowest-poc: %d, last-output-poc: %d", " need bumping.", lowest_poc, to_insert->pic_order_cnt);
lowest_poc, dpb->last_output_poc);
return TRUE; return TRUE;
} }
}
GST_TRACE ("No empty frame buffer, but lowest poc %d > current poc %d,"
" no need bumping.", lowest_poc, to_insert->pic_order_cnt);
return FALSE; return FALSE;
} }

View file

@ -283,7 +283,7 @@ gboolean gst_h264_dpb_has_empty_frame_buffer (GstH264Dpb * dpb);
GST_CODECS_API GST_CODECS_API
gboolean gst_h264_dpb_needs_bump (GstH264Dpb * dpb, gboolean gst_h264_dpb_needs_bump (GstH264Dpb * dpb,
guint32 max_num_reorder_frames, GstH264Picture * to_insert,
gboolean low_latency); gboolean low_latency);
GST_CODECS_API GST_CODECS_API