codecs: h264decoder: Add more option arguments for reference picture getter

In case that "pic_order_cnt_type" is equal to zero, ref picture
list for B slice should not include non-existing picture
as per spec 8.2.4.2.3. And, the second field is not needed
for the process of frame picture reference list construction
since it needs to be frame unit, not field picture in that case.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1812>
This commit is contained in:
Seungha Yang 2020-11-17 18:39:56 +09:00
parent e1adc572a7
commit 88ebe8031a
4 changed files with 55 additions and 19 deletions

View file

@ -177,7 +177,8 @@ static gboolean gst_h264_decoder_drain_internal (GstH264Decoder * self);
static gboolean gst_h264_decoder_finish_current_picture (GstH264Decoder * self);
static gboolean gst_h264_decoder_finish_picture (GstH264Decoder * self,
GstH264Picture * picture);
static void gst_h264_decoder_prepare_ref_pic_lists (GstH264Decoder * self);
static void gst_h264_decoder_prepare_ref_pic_lists (GstH264Decoder * self,
GstH264Picture * current_picture);
static void gst_h264_decoder_clear_ref_pic_lists (GstH264Decoder * self);
static gboolean gst_h264_decoder_modify_ref_pic_lists (GstH264Decoder * self);
static gboolean
@ -816,7 +817,7 @@ gst_h264_decoder_start_current_picture (GstH264Decoder * self)
gst_h264_decoder_update_pic_nums (self, current_picture, frame_num);
if (priv->process_ref_pic_lists)
gst_h264_decoder_prepare_ref_pic_lists (self);
gst_h264_decoder_prepare_ref_pic_lists (self, current_picture);
klass = GST_H264_DECODER_GET_CLASS (self);
if (klass->start_picture)
@ -2111,7 +2112,8 @@ long_term_pic_num_asc_compare (const GstH264Picture ** a,
}
static void
construct_ref_pic_lists_p (GstH264Decoder * self)
construct_ref_pic_lists_p (GstH264Decoder * self,
GstH264Picture * current_picture)
{
GstH264DecoderPrivate *priv = self->priv;
gint pos;
@ -2122,11 +2124,13 @@ construct_ref_pic_lists_p (GstH264Decoder * self)
*/
g_array_set_size (priv->ref_pic_list_p0, 0);
gst_h264_dpb_get_pictures_short_term_ref (priv->dpb, priv->ref_pic_list_p0);
gst_h264_dpb_get_pictures_short_term_ref (priv->dpb,
TRUE, FALSE, priv->ref_pic_list_p0);
g_array_sort (priv->ref_pic_list_p0, (GCompareFunc) pic_num_desc_compare);
pos = priv->ref_pic_list_p0->len;
gst_h264_dpb_get_pictures_long_term_ref (priv->dpb, priv->ref_pic_list_p0);
gst_h264_dpb_get_pictures_long_term_ref (priv->dpb,
FALSE, priv->ref_pic_list_p0);
g_qsort_with_data (&g_array_index (priv->ref_pic_list_p0, gpointer, pos),
priv->ref_pic_list_p0->len - pos, sizeof (gpointer),
(GCompareDataFunc) long_term_pic_num_asc_compare, NULL);
@ -2206,7 +2210,8 @@ print_ref_pic_list_b (GstH264Decoder * self, GArray * ref_list_b, gint index)
}
static void
construct_ref_pic_lists_b (GstH264Decoder * self)
construct_ref_pic_lists_b (GstH264Decoder * self,
GstH264Picture * current_picture)
{
GstH264DecoderPrivate *priv = self->priv;
gint pos;
@ -2218,7 +2223,14 @@ construct_ref_pic_lists_b (GstH264Decoder * self)
*/
g_array_set_size (priv->ref_pic_list_b0, 0);
g_array_set_size (priv->ref_pic_list_b1, 0);
gst_h264_dpb_get_pictures_short_term_ref (priv->dpb, priv->ref_pic_list_b0);
/* 8.2.4.2.3
* When pic_order_cnt_type is equal to 0, reference pictures that are marked
* as "non-existing" as specified in clause 8.2.5.2 are not included in either
* RefPicList0 or RefPicList1
*/
gst_h264_dpb_get_pictures_short_term_ref (priv->dpb,
current_picture->pic_order_cnt_type != 0, FALSE, priv->ref_pic_list_b0);
/* First sort ascending, this will put [1] in right place and finish
* [2]. */
@ -2239,7 +2251,8 @@ construct_ref_pic_lists_b (GstH264Decoder * self)
/* Now add [3] and sort by ascending long_term_pic_num. */
pos = priv->ref_pic_list_b0->len;
gst_h264_dpb_get_pictures_long_term_ref (priv->dpb, priv->ref_pic_list_b0);
gst_h264_dpb_get_pictures_long_term_ref (priv->dpb,
FALSE, priv->ref_pic_list_b0);
g_qsort_with_data (&g_array_index (priv->ref_pic_list_b0, gpointer, pos),
priv->ref_pic_list_b0->len - pos, sizeof (gpointer),
(GCompareDataFunc) long_term_pic_num_asc_compare, NULL);
@ -2249,7 +2262,8 @@ construct_ref_pic_lists_b (GstH264Decoder * self)
* [2] shortterm ref pics with POC < curr_pic's POC by descending POC,
* [3] longterm ref pics by ascending long_term_pic_num.
*/
gst_h264_dpb_get_pictures_short_term_ref (priv->dpb, priv->ref_pic_list_b1);
gst_h264_dpb_get_pictures_short_term_ref (priv->dpb,
current_picture->pic_order_cnt_type != 0, FALSE, priv->ref_pic_list_b1);
/* First sort by descending POC. */
g_array_sort (priv->ref_pic_list_b1, (GCompareFunc) poc_desc_compare);
@ -2265,7 +2279,8 @@ construct_ref_pic_lists_b (GstH264Decoder * self)
/* Now add [3] and sort by ascending long_term_pic_num */
pos = priv->ref_pic_list_b1->len;
gst_h264_dpb_get_pictures_long_term_ref (priv->dpb, priv->ref_pic_list_b1);
gst_h264_dpb_get_pictures_long_term_ref (priv->dpb,
FALSE, priv->ref_pic_list_b1);
g_qsort_with_data (&g_array_index (priv->ref_pic_list_b1, gpointer, pos),
priv->ref_pic_list_b1->len - pos, sizeof (gpointer),
(GCompareDataFunc) long_term_pic_num_asc_compare, NULL);
@ -2286,7 +2301,8 @@ construct_ref_pic_lists_b (GstH264Decoder * self)
}
static void
gst_h264_decoder_prepare_ref_pic_lists (GstH264Decoder * self)
gst_h264_decoder_prepare_ref_pic_lists (GstH264Decoder * self,
GstH264Picture * current_picture)
{
GstH264DecoderPrivate *priv = self->priv;
gboolean construct_list = FALSE;
@ -2313,8 +2329,8 @@ gst_h264_decoder_prepare_ref_pic_lists (GstH264Decoder * self)
return;
}
construct_ref_pic_lists_p (self);
construct_ref_pic_lists_b (self);
construct_ref_pic_lists_p (self, current_picture);
construct_ref_pic_lists_b (self, current_picture);
}
static void

View file

@ -457,14 +457,19 @@ gst_h264_dpb_get_lowest_frame_num_short_ref (GstH264Dpb * dpb)
/**
* gst_h264_dpb_get_pictures_short_term_ref:
* @dpb: a #GstH264Dpb
* @include_non_existing: %TRUE if non-existing pictures need to be included
* @include_second_field: %TRUE if the second field pictures need to be included
* @out: (out) (element-type GstH264Picture) (transfer full): an array
* of #GstH264Picture pointers
*
* Retrieve all short-term reference pictures from @dpb. The picture will be
* appended to the array.
*
* Since: 1.20
*/
void
gst_h264_dpb_get_pictures_short_term_ref (GstH264Dpb * dpb, GArray * out)
gst_h264_dpb_get_pictures_short_term_ref (GstH264Dpb * dpb,
gboolean include_non_existing, gboolean include_second_field, GArray * out)
{
gint i;
@ -475,7 +480,12 @@ gst_h264_dpb_get_pictures_short_term_ref (GstH264Dpb * dpb, GArray * out)
GstH264Picture *picture =
g_array_index (dpb->pic_list, GstH264Picture *, i);
if (GST_H264_PICTURE_IS_SHORT_TERM_REF (picture)) {
if (!include_second_field && picture->second_field)
continue;
if (GST_H264_PICTURE_IS_SHORT_TERM_REF (picture) &&
(include_non_existing || (!include_non_existing &&
!picture->nonexisting))) {
gst_h264_picture_ref (picture);
g_array_append_val (out, picture);
}
@ -485,14 +495,18 @@ gst_h264_dpb_get_pictures_short_term_ref (GstH264Dpb * dpb, GArray * out)
/**
* gst_h264_dpb_get_pictures_long_term_ref:
* @dpb: a #GstH264Dpb
* @out: (out) (element-type GstH264Picture) (transfer full): an arrat
* @include_second_field: %TRUE if the second field pictures need to be included
* @out: (out) (element-type GstH264Picture) (transfer full): an array
* of #GstH264Picture pointer
*
* Retrieve all long-term reference pictures from @dpb. The picture will be
* appended to the array.
*
* Since: 1.20
*/
void
gst_h264_dpb_get_pictures_long_term_ref (GstH264Dpb * dpb, GArray * out)
gst_h264_dpb_get_pictures_long_term_ref (GstH264Dpb * dpb,
gboolean include_second_field, GArray * out)
{
gint i;
@ -503,6 +517,9 @@ gst_h264_dpb_get_pictures_long_term_ref (GstH264Dpb * dpb, GArray * out)
GstH264Picture *picture =
g_array_index (dpb->pic_list, GstH264Picture *, i);
if (!include_second_field && picture->second_field)
continue;
if (GST_H264_PICTURE_IS_LONG_TERM_REF (picture)) {
gst_h264_picture_ref (picture);
g_array_append_val (out, picture);

View file

@ -259,10 +259,13 @@ GstH264Picture * gst_h264_dpb_get_lowest_frame_num_short_ref (GstH264Dpb * dpb);
GST_CODECS_API
void gst_h264_dpb_get_pictures_short_term_ref (GstH264Dpb * dpb,
gboolean include_non_existing,
gboolean include_second_field,
GArray * out);
GST_CODECS_API
void gst_h264_dpb_get_pictures_long_term_ref (GstH264Dpb * dpb,
gboolean include_second_field,
GArray * out);
GST_CODECS_API

View file

@ -417,14 +417,14 @@ gst_va_h264_dec_start_picture (GstH264Decoder * decoder,
guint ref_frame_idx = 0;
g_array_set_size (ref_list, 0);
gst_h264_dpb_get_pictures_short_term_ref (dpb, ref_list);
gst_h264_dpb_get_pictures_short_term_ref (dpb, FALSE, FALSE, ref_list);
for (i = 0; ref_frame_idx < 16 && i < ref_list->len; i++) {
GstH264Picture *pic = g_array_index (ref_list, GstH264Picture *, i);
_fill_vaapi_pic (&pic_param.ReferenceFrames[ref_frame_idx++], pic);
}
g_array_set_size (ref_list, 0);
gst_h264_dpb_get_pictures_long_term_ref (dpb, ref_list);
gst_h264_dpb_get_pictures_long_term_ref (dpb, FALSE, ref_list);
for (i = 0; ref_frame_idx < 16 && i < ref_list->len; i++) {
GstH264Picture *pic = g_array_index (ref_list, GstH264Picture *, i);
_fill_vaapi_pic (&pic_param.ReferenceFrames[ref_frame_idx++], pic);