d3d11h264dec: Add support for interlaced stream
authorSeungha Yang <seungha@centricular.com>
Thu, 5 Nov 2020 17:45:21 +0000 (02:45 +0900)
committerGStreamer Merge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Fri, 13 Nov 2020 15:25:43 +0000 (15:25 +0000)
Add support for interlaced stream.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1534>

sys/d3d11/gstd3d11decoder.c
sys/d3d11/gstd3d11decoder.h
sys/d3d11/gstd3d11h264dec.c
sys/d3d11/gstd3d11h265dec.c
sys/d3d11/gstd3d11vp8dec.c
sys/d3d11/gstd3d11vp9dec.c

index 28c3e6a..fe453b1 100644 (file)
@@ -1403,8 +1403,8 @@ do_process:
 gboolean
 gst_d3d11_decoder_negotiate (GstVideoDecoder * decoder,
     GstVideoCodecState * input_state, GstVideoFormat format,
-    guint width, guint height, GstVideoCodecState ** output_state,
-    gboolean * downstream_supports_d3d11)
+    guint width, guint height, GstVideoInterlaceMode interlace_mode,
+    GstVideoCodecState ** output_state, gboolean * downstream_supports_d3d11)
 {
   GstCaps *peer_caps;
   GstVideoCodecState *state;
@@ -1419,6 +1419,8 @@ gst_d3d11_decoder_negotiate (GstVideoDecoder * decoder,
 
   state = gst_video_decoder_set_output_state (decoder,
       format, width, height, input_state);
+  if (interlace_mode != GST_VIDEO_INTERLACE_MODE_PROGRESSIVE)
+    state->info.interlace_mode = interlace_mode;
   state->caps = gst_video_info_to_caps (&state->info);
 
   if (*output_state)
index 1786c9e..b5ff7be 100644 (file)
@@ -119,6 +119,7 @@ gboolean          gst_d3d11_decoder_negotiate           (GstVideoDecoder * decod
                                                          GstVideoFormat format,
                                                          guint width,
                                                          guint height,
+                                                         GstVideoInterlaceMode interlace_mode,
                                                          GstVideoCodecState ** output_state,
                                                          gboolean * downstream_supports_d3d11);
 
index ded00ef..fe10352 100644 (file)
@@ -98,6 +98,7 @@ typedef struct _GstD3D11H264Dec
   guint bitdepth;
   guint chroma_format_idc;
   GstVideoFormat out_format;
+  gboolean interlaced;
 
   /* Array of DXVA_Slice_H264_Short */
   GArray *slice_list;
@@ -152,6 +153,8 @@ static gboolean gst_d3d11_h264_dec_new_sequence (GstH264Decoder * decoder,
     const GstH264SPS * sps, gint max_dpb_size);
 static gboolean gst_d3d11_h264_dec_new_picture (GstH264Decoder * decoder,
     GstVideoCodecFrame * frame, GstH264Picture * picture);
+static gboolean gst_d3d11_h264_dec_new_field_picture (GstH264Decoder *
+    decoder, const GstH264Picture * first_field, GstH264Picture * second_field);
 static GstFlowReturn gst_d3d11_h264_dec_output_picture (GstH264Decoder *
     decoder, GstVideoCodecFrame * frame, GstH264Picture * picture);
 static gboolean gst_d3d11_h264_dec_start_picture (GstH264Decoder * decoder,
@@ -227,6 +230,8 @@ gst_d3d11_h264_dec_class_init (GstD3D11H264DecClass * klass, gpointer data)
       GST_DEBUG_FUNCPTR (gst_d3d11_h264_dec_new_sequence);
   h264decoder_class->new_picture =
       GST_DEBUG_FUNCPTR (gst_d3d11_h264_dec_new_picture);
+  h264decoder_class->new_field_picture =
+      GST_DEBUG_FUNCPTR (gst_d3d11_h264_dec_new_field_picture);
   h264decoder_class->output_picture =
       GST_DEBUG_FUNCPTR (gst_d3d11_h264_dec_output_picture);
   h264decoder_class->start_picture =
@@ -335,8 +340,10 @@ gst_d3d11_h264_dec_negotiate (GstVideoDecoder * decoder)
   GstH264Decoder *h264dec = GST_H264_DECODER (decoder);
 
   if (!gst_d3d11_decoder_negotiate (decoder, h264dec->input_state,
-          self->out_format, self->width, self->height, &self->output_state,
-          &self->use_d3d11_output))
+          self->out_format, self->width, self->height,
+          self->interlaced ? GST_VIDEO_INTERLACE_MODE_MIXED :
+          GST_VIDEO_INTERLACE_MODE_PROGRESSIVE,
+          &self->output_state, &self->use_d3d11_output))
     return FALSE;
 
   return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder);
@@ -381,6 +388,7 @@ gst_d3d11_h264_dec_new_sequence (GstH264Decoder * decoder,
 {
   GstD3D11H264Dec *self = GST_D3D11_H264_DEC (decoder);
   gint crop_width, crop_height;
+  gboolean interlaced;
   gboolean modified = FALSE;
   static const GUID *supported_profiles[] = {
     &GST_GUID_D3D11_DECODER_PROFILE_H264_IDCT_FGT,
@@ -421,6 +429,13 @@ gst_d3d11_h264_dec_new_sequence (GstH264Decoder * decoder,
     modified = TRUE;
   }
 
+  interlaced = !sps->frame_mbs_only_flag;
+  if (self->interlaced != interlaced) {
+    GST_INFO_OBJECT (self, "interlaced sequence changed");
+    self->interlaced = interlaced;
+    modified = TRUE;
+  }
+
   if (modified || !self->d3d11_decoder->opened) {
     GstVideoInfo info;
 
@@ -559,8 +574,7 @@ gst_d3d11_h264_dec_start_picture (GstH264Decoder * decoder,
 
   dpb_array = gst_h264_dpb_get_pictures_all (dpb);
 
-  for (i = 0; i < dpb_array->len; i++) {
-    guint ref = 3;
+  for (i = dpb_array->len - 1, j = 0; i >= 0 && j < 16; i--) {
     GstH264Picture *other = g_array_index (dpb_array, GstH264Picture *, i);
     ID3D11VideoDecoderOutputView *other_view;
     gint id = 0xff;
@@ -568,20 +582,61 @@ gst_d3d11_h264_dec_start_picture (GstH264Decoder * decoder,
     if (!GST_H264_PICTURE_IS_REF (other))
       continue;
 
+    /* The second field picture will be handled differently */
+    if (other->second_field)
+      continue;
+
     other_view = gst_d3d11_h264_dec_get_output_view_from_picture (self, other);
 
     if (other_view)
       id = gst_d3d11_decoder_get_output_view_index (other_view);
 
-    self->ref_frame_list[i].Index7Bits = id;
-    self->ref_frame_list[i].AssociatedFlag =
-        GST_H264_PICTURE_IS_LONG_TERM_REF (other);
-    self->field_order_cnt_list[i][0] = other->top_field_order_cnt;
-    self->field_order_cnt_list[i][1] = other->bottom_field_order_cnt;
-    self->frame_num_list[i] = self->ref_frame_list[i].AssociatedFlag
-        ? other->long_term_frame_idx : other->frame_num;
-    self->used_for_reference_flags |= ref << (2 * i);
-    self->non_existing_frame_flags |= (other->nonexisting) << i;
+    self->ref_frame_list[j].Index7Bits = id;
+
+    if (GST_H264_PICTURE_IS_LONG_TERM_REF (other)) {
+      self->ref_frame_list[j].AssociatedFlag = 1;
+      self->frame_num_list[j] = other->long_term_frame_idx;
+    } else {
+      self->ref_frame_list[j].AssociatedFlag = 0;
+      self->frame_num_list[j] = other->frame_num;
+    }
+
+    switch (other->field) {
+      case GST_H264_PICTURE_FIELD_TOP_FIELD:
+        self->field_order_cnt_list[j][0] = other->top_field_order_cnt;
+        self->used_for_reference_flags |= 0x1 << (2 * j);
+        break;
+      case GST_H264_PICTURE_FIELD_BOTTOM_FIELD:
+        self->field_order_cnt_list[j][1] = other->bottom_field_order_cnt;
+        self->used_for_reference_flags |= 0x1 << (2 * j + 1);
+        break;
+      default:
+        self->field_order_cnt_list[j][0] = other->top_field_order_cnt;
+        self->field_order_cnt_list[j][1] = other->bottom_field_order_cnt;
+        self->used_for_reference_flags |= 0x3 << (2 * j);
+        break;
+    }
+
+    if (other->other_field) {
+      GstH264Picture *other_field = other->other_field;
+
+      switch (other_field->field) {
+        case GST_H264_PICTURE_FIELD_TOP_FIELD:
+          self->field_order_cnt_list[j][0] = other_field->top_field_order_cnt;
+          self->used_for_reference_flags |= 0x1 << (2 * j);
+          break;
+        case GST_H264_PICTURE_FIELD_BOTTOM_FIELD:
+          self->field_order_cnt_list[j][1] =
+              other_field->bottom_field_order_cnt;
+          self->used_for_reference_flags |= 0x1 << (2 * j + 1);
+          break;
+        default:
+          break;
+      }
+    }
+
+    self->non_existing_frame_flags |= (other->nonexisting) << j;
+    j++;
   }
 
   gst_d3d11_h264_dec_fill_picture_params (self, &slice->header, &pic_params);
@@ -591,12 +646,12 @@ gst_d3d11_h264_dec_start_picture (GstH264Decoder * decoder,
   pic_params.RefPicFlag = GST_H264_PICTURE_IS_REF (picture);
   pic_params.frame_num = picture->frame_num;
 
-  if (pic_params.field_pic_flag && pic_params.CurrPic.AssociatedFlag) {
-    pic_params.CurrFieldOrderCnt[1] = picture->bottom_field_order_cnt;
-    pic_params.CurrFieldOrderCnt[0] = 0;
-  } else if (pic_params.field_pic_flag && !pic_params.CurrPic.AssociatedFlag) {
+  if (picture->field == GST_H264_PICTURE_FIELD_TOP_FIELD) {
     pic_params.CurrFieldOrderCnt[0] = picture->top_field_order_cnt;
     pic_params.CurrFieldOrderCnt[1] = 0;
+  } else if (picture->field == GST_H264_PICTURE_FIELD_BOTTOM_FIELD) {
+    pic_params.CurrFieldOrderCnt[0] = 0;
+    pic_params.CurrFieldOrderCnt[1] = picture->bottom_field_order_cnt;
   } else {
     pic_params.CurrFieldOrderCnt[0] = picture->top_field_order_cnt;
     pic_params.CurrFieldOrderCnt[1] = picture->bottom_field_order_cnt;
@@ -707,6 +762,32 @@ gst_d3d11_h264_dec_new_picture (GstH264Decoder * decoder,
   return TRUE;
 }
 
+static gboolean
+gst_d3d11_h264_dec_new_field_picture (GstH264Decoder * decoder,
+    const GstH264Picture * first_field, GstH264Picture * second_field)
+{
+  GstD3D11H264Dec *self = GST_D3D11_H264_DEC (decoder);
+  GstBuffer *view_buffer;
+  GstD3D11Memory *mem;
+
+  view_buffer = gst_h264_picture_get_user_data ((GstH264Picture *) first_field);
+
+  if (!view_buffer) {
+    GST_WARNING_OBJECT (self, "First picture does not have output view buffer");
+    return TRUE;
+  }
+
+  mem = (GstD3D11Memory *) gst_buffer_peek_memory (view_buffer, 0);
+
+  GST_LOG_OBJECT (self, "New field picture with buffer %" GST_PTR_FORMAT
+      " (index %d)", view_buffer, mem->subresource_index);
+
+  gst_h264_picture_set_user_data (second_field,
+      gst_buffer_ref (view_buffer), (GDestroyNotify) gst_buffer_unref);
+
+  return TRUE;
+}
+
 static GstFlowReturn
 gst_d3d11_h264_dec_output_picture (GstH264Decoder * decoder,
     GstVideoCodecFrame * frame, GstH264Picture * picture)
@@ -758,6 +839,17 @@ gst_d3d11_h264_dec_output_picture (GstH264Decoder * decoder,
     goto error;
   }
 
+  if (picture->buffer_flags != 0) {
+    gboolean interlaced =
+        (picture->buffer_flags & GST_VIDEO_BUFFER_FLAG_INTERLACED) != 0;
+    gboolean tff = (picture->buffer_flags & GST_VIDEO_BUFFER_FLAG_TFF) != 0;
+
+    GST_TRACE_OBJECT (self,
+        "apply buffer flags 0x%x (interlaced %d, top-field-first %d)",
+        picture->buffer_flags, interlaced, tff);
+    GST_BUFFER_FLAG_SET (frame->output_buffer, picture->buffer_flags);
+  }
+
   gst_h264_picture_unref (picture);
 
   return gst_video_decoder_finish_frame (vdec, frame);
@@ -903,7 +995,9 @@ gst_d3d11_h264_dec_picture_params_from_sps (GstD3D11H264Dec * self,
   (params)->f = (sps)->f
 
   params->wFrameWidthInMbsMinus1 = sps->pic_width_in_mbs_minus1;
-  params->wFrameHeightInMbsMinus1 = sps->pic_height_in_map_units_minus1;
+  params->wFrameHeightInMbsMinus1 =
+      ((sps->pic_height_in_map_units_minus1 + 1) << !sps->frame_mbs_only_flag)
+      - 1;
   params->residual_colour_transform_flag = sps->separate_colour_plane_flag;
   params->MbaffFrameFlag = (sps->mb_adaptive_frame_field_flag && !field_pic);
   params->field_pic_flag = field_pic;
index f25314a..62468db 100644 (file)
@@ -310,8 +310,9 @@ gst_d3d11_h265_dec_negotiate (GstVideoDecoder * decoder)
   GstH265Decoder *h265dec = GST_H265_DECODER (decoder);
 
   if (!gst_d3d11_decoder_negotiate (decoder, h265dec->input_state,
-          self->out_format, self->width, self->height, &self->output_state,
-          &self->use_d3d11_output))
+          self->out_format, self->width, self->height,
+          GST_VIDEO_INTERLACE_MODE_PROGRESSIVE,
+          &self->output_state, &self->use_d3d11_output))
     return FALSE;
 
   return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder);
index bed32a3..4f46f1b 100644 (file)
@@ -260,8 +260,9 @@ gst_d3d11_vp8_dec_negotiate (GstVideoDecoder * decoder)
   GstVp8Decoder *vp8dec = GST_VP8_DECODER (decoder);
 
   if (!gst_d3d11_decoder_negotiate (decoder, vp8dec->input_state,
-          self->out_format, self->width, self->height, &self->output_state,
-          &self->use_d3d11_output))
+          self->out_format, self->width, self->height,
+          GST_VIDEO_INTERLACE_MODE_PROGRESSIVE,
+          &self->output_state, &self->use_d3d11_output))
     return FALSE;
 
   return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder);
index ced92cc..db34bda 100644 (file)
@@ -300,8 +300,9 @@ gst_d3d11_vp9_dec_negotiate (GstVideoDecoder * decoder)
   GstVp9Decoder *vp9dec = GST_VP9_DECODER (decoder);
 
   if (!gst_d3d11_decoder_negotiate (decoder, vp9dec->input_state,
-          self->out_format, self->width, self->height, &self->output_state,
-          &self->use_d3d11_output))
+          self->out_format, self->width, self->height,
+          GST_VIDEO_INTERLACE_MODE_PROGRESSIVE,
+          &self->output_state, &self->use_d3d11_output))
     return FALSE;
 
   return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder);