mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-19 13:55:41 +00:00
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:
parent
4411a4e00f
commit
f1df120797
3 changed files with 45 additions and 63 deletions
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue