h264decoder: Add ability to lookup by system_frame_number

This is to avoid having to create a reference chain in decoders from
GstVideoCodecFrame to GstH264PIcture to implementation wrapper.

So this change introduces:

 - gst_h264_dpb_remove_outputed (dpb)
 - gst_h264_dpb_get_picture(dpb, system_frame_num)
 - gst_h264_decoder_get_picture (dec, system_frame_num)

In order to ensure that frames can be looked up during the draining
process, we now first remove all (including reference) frames that
have been outputed but are still in the DPB. Then for each remaining
buffers, we remove it from the DPB to reach reference 1 and output it.

Previously we could take all not outputed outside of the DPB which would
prevent lookup by the base class.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1449>
This commit is contained in:
Nicolas Dufresne 2020-07-20 16:48:32 -04:00 committed by Seungha Yang
parent 82fb55bdff
commit 6523c5bcb6
4 changed files with 78 additions and 1 deletions

View file

@ -1320,15 +1320,20 @@ gst_h264_decoder_drain_internal (GstH264Decoder * self)
GstH264DecoderPrivate *priv = self->priv;
GArray *to_output = priv->to_output;
/* We are around to drain, so we can get rist of everything that has been
* outputed already */
gst_h264_dpb_delete_outputed (priv->dpb);
gst_h264_dpb_get_pictures_not_outputted (priv->dpb, to_output);
g_array_sort (to_output, (GCompareFunc) poc_asc_compare);
gst_h264_dpb_clear (priv->dpb);
while (to_output->len) {
GstH264Picture *picture = g_array_index (to_output, GstH264Picture *, 0);
/* We want the last reference when outputing so take a ref and then remove
* from both arrays. */
gst_h264_picture_ref (picture);
g_array_remove_index (to_output, 0);
gst_h264_dpb_delete_by_poc (priv->dpb, picture->pic_order_cnt);
GST_LOG_OBJECT (self, "Output picture %p (frame num %d, poc %d)", picture,
picture->frame_num, picture->pic_order_cnt);
@ -1336,6 +1341,8 @@ gst_h264_decoder_drain_internal (GstH264Decoder * self)
}
g_array_set_size (to_output, 0);
gst_h264_dpb_clear (priv->dpb);
priv->last_output_poc = 0;
return TRUE;
}
@ -2456,3 +2463,10 @@ gst_h264_decoder_set_process_ref_pic_lists (GstH264Decoder * self,
{
self->priv->process_ref_pic_lists = process;
}
GstH264Picture *
gst_h264_decoder_get_picture (GstH264Decoder * self,
guint32 system_frame_number)
{
return gst_h264_dpb_get_picture (self->priv->dpb, system_frame_number);
}

View file

@ -139,6 +139,10 @@ GST_CODECS_API
void gst_h264_decoder_set_process_ref_pic_lists (GstH264Decoder * self,
gboolean process);
GST_CODECS_API
GstH264Picture * gst_h264_decoder_get_picture (GstH264Decoder * self,
guint32 system_frame_number);
G_END_DECLS
#endif /* __GST_H264_DECODER_H__ */

View file

@ -233,6 +233,32 @@ gst_h264_dpb_delete_unused (GstH264Dpb * dpb)
}
}
/**
* gst_h264_dpb_delete_outputed:
* @dpb: a #GstH264Dpb
*
* Delete already outputted picture, even if they are referenced.
*/
void
gst_h264_dpb_delete_outputed (GstH264Dpb * dpb)
{
gint i;
g_return_if_fail (dpb != NULL);
for (i = 0; i < dpb->pic_list->len; i++) {
GstH264Picture *picture =
g_array_index (dpb->pic_list, GstH264Picture *, i);
if (picture->outputted) {
GST_TRACE ("remove picture %p (frame num %d) from dpb",
picture, picture->frame_num);
g_array_remove_index_fast (dpb->pic_list, i);
i--;
}
}
}
/**
* gst_h264_dpb_delete_by_poc:
* @dpb: a #GstH264Dpb
@ -523,3 +549,29 @@ gst_h264_dpb_is_full (GstH264Dpb * dpb)
return dpb->pic_list->len >= dpb->max_num_pics;
}
/**
* gst_h264_dpb_get_picture:
* @system_frame_number The system frame number
*
* Returns: the picture identitifed with the specified @system_frame_number.
*/
GstH264Picture *
gst_h264_dpb_get_picture (GstH264Dpb * dpb, guint32 system_frame_number)
{
gint i;
g_return_val_if_fail (dpb != NULL, NULL);
for (i = 0; i < dpb->pic_list->len; i++) {
GstH264Picture *picture =
g_array_index (dpb->pic_list, GstH264Picture *, i);
if (picture->system_frame_number == system_frame_number) {
gst_h264_picture_ref (picture);
return picture;
}
}
return NULL;
}

View file

@ -169,6 +169,9 @@ void gst_h264_dpb_add (GstH264Dpb * dpb,
GST_CODECS_API
void gst_h264_dpb_delete_unused (GstH264Dpb * dpb);
GST_CODECS_API
void gst_h264_dpb_delete_outputed (GstH264Dpb * dpb);
GST_CODECS_API
void gst_h264_dpb_delete_by_poc (GstH264Dpb * dpb,
gint poc);
@ -205,6 +208,10 @@ void gst_h264_dpb_get_pictures_long_term_ref (GstH264Dpb * dpb,
GST_CODECS_API
GArray * gst_h264_dpb_get_pictures_all (GstH264Dpb * dpb);
GST_CODECS_API
GstH264Picture * gst_h264_dpb_get_picture (GstH264Dpb * dpb,
guint32 system_frame_number);
GST_CODECS_API
gint gst_h264_dpb_get_size (GstH264Dpb * dpb);