codecs: h264decoder: Add more option arguments for reference picture getter
authorSeungha Yang <seungha@centricular.com>
Tue, 17 Nov 2020 09:39:56 +0000 (18:39 +0900)
committerSeungha Yang <seungha@centricular.com>
Tue, 17 Nov 2020 10:44:04 +0000 (19:44 +0900)
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>

gst-libs/gst/codecs/gsth264decoder.c
gst-libs/gst/codecs/gsth264picture.c
gst-libs/gst/codecs/gsth264picture.h
sys/va/gstvah264dec.c

index 7e26c71..b336c19 100644 (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
index 1dc73fb..be5013d 100644 (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);
index 1199cf5..bdf99b5 100644 (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
index f23b60c..c2d5388 100644 (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);