videoconvert: Support for alternate-field interlacing
authorVivia Nikolaidou <vivia@ahiru.eu>
Tue, 2 Feb 2021 18:33:27 +0000 (20:33 +0200)
committerVivia Nikolaidou <vivia@ahiru.eu>
Thu, 4 Feb 2021 16:22:07 +0000 (18:22 +0200)
Treat the data just like normal data with half the height. Also treat it
as progressive when converting from/to I420 because it requires
different handling for chroma subsampling.

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

gst-libs/gst/video/video-converter.c
gst/videoconvert/gstvideoconvert.c

index a259113..5de75b8 100644 (file)
@@ -1611,10 +1611,12 @@ chain_vscale (GstVideoConverter * convert, GstLineCache * prev, gint idx)
   method = GET_OPT_RESAMPLER_METHOD (convert);
   taps = GET_OPT_RESAMPLER_TAPS (convert);
 
-  if (GST_VIDEO_INFO_IS_INTERLACED (&convert->in_info)) {
+  if (GST_VIDEO_INFO_IS_INTERLACED (&convert->in_info)
+      && (GST_VIDEO_INFO_INTERLACE_MODE (&convert->in_info) !=
+          GST_VIDEO_INTERLACE_MODE_ALTERNATE)) {
     convert->v_scaler_i[idx] =
-        gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_INTERLACED,
-        taps, convert->in_height, convert->out_height, convert->config);
+        gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_INTERLACED, taps,
+        convert->in_height, convert->out_height, convert->config);
 
     gst_video_scaler_get_coeff (convert->v_scaler_i[idx], 0, NULL, &taps_i);
     backlog = taps_i;
@@ -2281,9 +2283,9 @@ gst_video_converter_new_with_pool (const GstVideoInfo * in_info,
     gst_video_converter_set_config (convert, config);
 
   convert->in_maxwidth = GST_VIDEO_INFO_WIDTH (in_info);
-  convert->in_maxheight = GST_VIDEO_INFO_HEIGHT (in_info);
+  convert->in_maxheight = GST_VIDEO_INFO_FIELD_HEIGHT (in_info);
   convert->out_maxwidth = GST_VIDEO_INFO_WIDTH (out_info);
-  convert->out_maxheight = GST_VIDEO_INFO_HEIGHT (out_info);
+  convert->out_maxheight = GST_VIDEO_INFO_FIELD_HEIGHT (out_info);
 
   convert->in_x = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_SRC_X, 0);
   convert->in_y = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_SRC_Y, 0);
@@ -2694,7 +2696,7 @@ gst_video_converter_frame (GstVideoConverter * convert,
           GST_VIDEO_FRAME_FORMAT (src)
           || GST_VIDEO_INFO_WIDTH (&convert->in_info) >
           GST_VIDEO_FRAME_WIDTH (src)
-          || GST_VIDEO_INFO_HEIGHT (&convert->in_info) >
+          || GST_VIDEO_INFO_FIELD_HEIGHT (&convert->in_info) >
           GST_VIDEO_FRAME_HEIGHT (src))) {
     g_critical ("Input video frame does not match configuration");
     return;
@@ -2703,7 +2705,7 @@ gst_video_converter_frame (GstVideoConverter * convert,
           GST_VIDEO_FRAME_FORMAT (dest)
           || GST_VIDEO_INFO_WIDTH (&convert->out_info) >
           GST_VIDEO_FRAME_WIDTH (dest)
-          || GST_VIDEO_INFO_HEIGHT (&convert->out_info) >
+          || GST_VIDEO_INFO_FIELD_HEIGHT (&convert->out_info) >
           GST_VIDEO_FRAME_HEIGHT (dest))) {
     g_critical ("Output video frame does not match configuration");
     return;
@@ -2753,7 +2755,9 @@ video_converter_compute_resample (GstVideoConverter * convert, gint idx)
       in_info->chroma_site != out_info->chroma_site ||
       in_info->width != out_info->width ||
       in_info->height != out_info->height) {
-    if (GST_VIDEO_INFO_IS_INTERLACED (in_info)) {
+    if (GST_VIDEO_INFO_IS_INTERLACED (in_info)
+        && GST_VIDEO_INFO_INTERLACE_MODE (in_info) !=
+        GST_VIDEO_INTERLACE_MODE_ALTERNATE) {
       if (!CHECK_CHROMA_DOWNSAMPLE (convert))
         convert->upsample_i[idx] = gst_video_chroma_resample_new (0,
             in_info->chroma_site, GST_VIDEO_CHROMA_FLAG_INTERLACED,
@@ -3309,7 +3313,9 @@ convert_I420_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
   int i;
   gint width = convert->in_width;
   gint height = convert->in_height;
-  gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
+  gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src)
+      && (GST_VIDEO_INFO_INTERLACE_MODE (&src->info) !=
+      GST_VIDEO_INTERLACE_MODE_ALTERNATE);
   gint h2;
   FConvertTask *tasks;
   FConvertTask **tasks_p;
@@ -3382,7 +3388,9 @@ convert_I420_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
   int i;
   gint width = convert->in_width;
   gint height = convert->in_height;
-  gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
+  gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src)
+      && (GST_VIDEO_INFO_INTERLACE_MODE (&src->info) !=
+      GST_VIDEO_INTERLACE_MODE_ALTERNATE);
   gint h2;
   FConvertTask *tasks;
   FConvertTask **tasks_p;
@@ -3455,7 +3463,9 @@ convert_I420_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
   int i;
   gint width = convert->in_width;
   gint height = convert->in_height;
-  gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
+  gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src)
+      && (GST_VIDEO_INFO_INTERLACE_MODE (&src->info) !=
+      GST_VIDEO_INTERLACE_MODE_ALTERNATE);
   guint8 alpha = MIN (convert->alpha_value, 255);
   gint h2;
   FConvertTask *tasks;
@@ -3533,7 +3543,9 @@ convert_YUY2_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
   int i;
   gint width = convert->in_width;
   gint height = convert->in_height;
-  gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
+  gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src)
+      && (GST_VIDEO_INFO_INTERLACE_MODE (&src->info) !=
+      GST_VIDEO_INTERLACE_MODE_ALTERNATE);
   gint h2;
   FConvertTask *tasks;
   FConvertTask **tasks_p;
@@ -3692,7 +3704,9 @@ convert_v210_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
   int i;
   gint width = convert->in_width;
   gint height = convert->in_height;
-  gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
+  gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src)
+      && (GST_VIDEO_INFO_INTERLACE_MODE (&src->info) !=
+      GST_VIDEO_INTERLACE_MODE_ALTERNATE);
   gint h2;
   FConvertTask *tasks;
   FConvertTask **tasks_p;
@@ -4075,7 +4089,9 @@ convert_UYVY_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
   int i;
   gint width = convert->in_width;
   gint height = convert->in_height;
-  gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
+  gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src)
+      && (GST_VIDEO_INFO_INTERLACE_MODE (&src->info) !=
+      GST_VIDEO_INTERLACE_MODE_ALTERNATE);
   gint h2;
   FConvertTask *tasks;
   FConvertTask **tasks_p;
@@ -6519,7 +6535,9 @@ setup_scale (GstVideoConverter * convert)
 
   n_planes = GST_VIDEO_INFO_N_PLANES (out_info);
 
-  interlaced = GST_VIDEO_INFO_IS_INTERLACED (&convert->in_info);
+  interlaced = GST_VIDEO_INFO_IS_INTERLACED (&convert->in_info)
+      && GST_VIDEO_INFO_INTERLACE_MODE (&convert->in_info) !=
+      GST_VIDEO_INTERLACE_MODE_ALTERNATE;
 
   method = GET_OPT_RESAMPLER_METHOD (convert);
   if (method == GST_VIDEO_RESAMPLER_METHOD_NEAREST)
@@ -7247,7 +7265,7 @@ video_converter_lookup_fastpath (GstVideoConverter * convert)
   guint in_bpp, out_bpp;
 
   width = GST_VIDEO_INFO_WIDTH (&convert->in_info);
-  height = GST_VIDEO_INFO_HEIGHT (&convert->in_info);
+  height = GST_VIDEO_INFO_FIELD_HEIGHT (&convert->in_info);
 
   if (GET_OPT_DITHER_QUANTIZATION (convert) != 1)
     return FALSE;
index 00f77fa..2d5b6ee 100644 (file)
@@ -111,6 +111,9 @@ static gboolean gst_video_convert_set_info (GstVideoFilter * filter,
 static GstFlowReturn gst_video_convert_transform_frame (GstVideoFilter * filter,
     GstVideoFrame * in_frame, GstVideoFrame * out_frame);
 
+static GstCapsFeatures *features_format_interlaced,
+    *features_format_interlaced_sysmem;
+
 /* copies the given caps */
 static GstCaps *
 gst_video_convert_caps_remove_format_info (GstCaps * caps)
@@ -135,10 +138,14 @@ gst_video_convert_caps_remove_format_info (GstCaps * caps)
     st = gst_structure_copy (st);
     /* Only remove format info for the cases when we can actually convert */
     if (!gst_caps_features_is_any (f)
-        && gst_caps_features_is_equal (f,
-            GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY))
+        && (gst_caps_features_is_equal (f,
+                GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY)
+            || gst_caps_features_is_equal (f, features_format_interlaced)
+            || gst_caps_features_is_equal (f,
+                features_format_interlaced_sysmem))) {
       gst_structure_remove_fields (st, "format", "colorimetry", "chroma-site",
           NULL);
+    }
 
     gst_caps_append_structure_full (res, st, gst_caps_features_copy (f));
   }
@@ -743,6 +750,13 @@ plugin_init (GstPlugin * plugin)
 
   _colorspace_quark = g_quark_from_static_string ("colorspace");
 
+  features_format_interlaced =
+      gst_caps_features_new (GST_CAPS_FEATURE_FORMAT_INTERLACED, NULL);
+  features_format_interlaced_sysmem =
+      gst_caps_features_copy (features_format_interlaced);
+  gst_caps_features_add (features_format_interlaced_sysmem,
+      GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY);
+
   return gst_element_register (plugin, "videoconvert",
       GST_RANK_NONE, GST_TYPE_VIDEO_CONVERT);
 }