video-converter: Make fast path work for equivalent transfer functions
authorVivia Nikolaidou <vivia@ahiru.eu>
Fri, 26 Jun 2020 09:22:08 +0000 (12:22 +0300)
committerVivia Nikolaidou <vivia@ahiru.eu>
Fri, 3 Jul 2020 08:57:49 +0000 (11:57 +0300)
For example, BT709, BT601, and BT2020_10 all have theoretically
different transfer functions, but the same function in practice. In
these cases, we should use the fast path for negotiating. Also,
BT2020_12 is essentially the same as the other three, just with one more
decimal point, so it gives the same result for fewer bits. This is now
also aliased to the former three.

Also make videoconvert do passthrough if the caps have equivalent
transfer functions but are otherwise matching.

As of the previous commit, we write the correct transfer function for
BT601, instead of the (functionally identical but different ISO code)
transfer function for BT709. Files created using GStreamer prior to that
commit write the wrong transfer function for BT601 and are, strictly
speaking, 2:4:5:4 instead. However, this commit takes care of
negotiation, so that conversions from/to the same transfer function are
done using the fast path.

Fixes #783

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

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

index 1ed47f19309e485d28a66e5a62d1b1f584e99860..c37dd5f00a9096b2f28cd56b91b1c2549e58d579 100644 (file)
@@ -897,3 +897,51 @@ gst_video_color_primaries_from_iso (guint value)
       return GST_VIDEO_COLOR_PRIMARIES_UNKNOWN;
   }
 }
+
+static GstVideoTransferFunction
+map_equivalent_transfer (GstVideoTransferFunction func, guint bpp)
+{
+  switch (func) {
+    case GST_VIDEO_TRANSFER_BT2020_12:
+      if (bpp >= 12)
+        break;
+      /* fallthrough */
+    case GST_VIDEO_TRANSFER_BT709:
+    case GST_VIDEO_TRANSFER_BT601:
+    case GST_VIDEO_TRANSFER_BT2020_10:
+      return GST_VIDEO_TRANSFER_BT709;
+    default:
+      break;
+  }
+
+  return func;
+}
+
+/**
+ * gst_video_color_transfer_is_equivalent:
+ * @from_func: #GstVideoTransferFunction to convert from
+ * @from_bpp: bits per pixel to convert from
+ * @to_func: #GstVideoTransferFunction to convert into
+ * @to_bpp: bits per pixel to convert into
+ *
+ * Returns whether @from_func and @to_func are equivalent. There are cases
+ * (e.g. BT601, BT709, and BT2020_10) where several functions are functionally
+ * identical. In these cases, when doing conversion, we should consider them
+ * as equivalent. Also, BT2020_12 is the same as the aforementioned three for
+ * less than 12 bits per pixel.
+ *
+ * Returns: TRUE if @from_func and @to_func can be considered equivalent.
+ *
+ * Since: 1.18
+ */
+gboolean
+gst_video_color_transfer_is_equivalent (GstVideoTransferFunction from_func,
+    guint from_bpp, GstVideoTransferFunction to_func, guint to_bpp)
+{
+  from_func = map_equivalent_transfer (from_func, from_bpp);
+  to_func = map_equivalent_transfer (to_func, to_bpp);
+  if (from_func == GST_VIDEO_TRANSFER_BT2020_12 && to_bpp < 12 &&
+      to_func == GST_VIDEO_TRANSFER_BT709)
+    return TRUE;
+  return from_func == to_func;
+}
index d0830dff5ef4152dc7487deb1d4736bb804a6992..b304d4ae3f288c6d1af241865eda0c44dc5b1c43 100644 (file)
@@ -287,6 +287,12 @@ GstVideoTransferFunction  gst_video_color_transfer_from_iso  (guint value);
 GST_VIDEO_API
 GstVideoColorPrimaries    gst_video_color_primaries_from_iso (guint value);
 
+GST_VIDEO_API
+gboolean                  gst_video_color_transfer_is_equivalent (GstVideoTransferFunction from_func,
+                                                               guint from_bpp,
+                                                               GstVideoTransferFunction to_func,
+                                                               guint to_bpp);
+
 G_END_DECLS
 
 #endif /* __GST_VIDEO_COLOR_H__ */
index c89932a184e2bdc1b46714a4615c286f6112099e..21b212a56e82bc7b85155e6247d34e84dc08a644 100644 (file)
@@ -6741,6 +6741,7 @@ video_converter_lookup_fastpath (GstVideoConverter * convert)
   gboolean interlaced, same_matrix, same_primaries, same_size, crop, border;
   gboolean need_copy, need_set, need_mult;
   gint width, height;
+  guint in_bpp, out_bpp;
 
   width = GST_VIDEO_INFO_WIDTH (&convert->in_info);
   height = GST_VIDEO_INFO_HEIGHT (&convert->in_info);
@@ -6748,6 +6749,9 @@ video_converter_lookup_fastpath (GstVideoConverter * convert)
   if (GET_OPT_DITHER_QUANTIZATION (convert) != 1)
     return FALSE;
 
+  in_bpp = convert->in_info.finfo->bits;
+  out_bpp = convert->out_info.finfo->bits;
+
   /* we don't do gamma conversion in fastpath */
   in_transf = convert->in_info.colorimetry.transfer;
   out_transf = convert->out_info.colorimetry.transfer;
@@ -6755,7 +6759,9 @@ video_converter_lookup_fastpath (GstVideoConverter * convert)
   same_size = (width == convert->out_width && height == convert->out_height);
 
   /* fastpaths don't do gamma */
-  if (CHECK_GAMMA_REMAP (convert) && (!same_size || in_transf != out_transf))
+  if (CHECK_GAMMA_REMAP (convert) && (!same_size
+          || !gst_video_color_transfer_is_equivalent (in_transf, in_bpp,
+              out_transf, out_bpp)))
     return FALSE;
 
   need_copy = (convert->alpha_mode & ALPHA_MODE_COPY) == ALPHA_MODE_COPY;
index 66783c5240dba88f6d03d24a327c1ba2de086287..b190c342289837cf26076cb1e0726d64bc8a6b62 100644 (file)
@@ -430,6 +430,9 @@ gst_video_convert_set_info (GstVideoFilter * filter,
     GstVideoInfo * out_info)
 {
   GstVideoConvert *space;
+  GstBaseTransformClass *gstbasetransform_class =
+      GST_BASE_TRANSFORM_GET_CLASS (filter);
+  GstVideoInfo tmp_info;
 
   space = GST_VIDEO_CONVERT_CAST (filter);
 
@@ -451,6 +454,21 @@ gst_video_convert_set_info (GstVideoFilter * filter,
   if (in_info->interlace_mode != out_info->interlace_mode)
     goto format_mismatch;
 
+  /* if the only thing different in the caps is the transfer function, and
+   * we're converting between equivalent transfer functions, do passthrough */
+  tmp_info = *in_info;
+  tmp_info.colorimetry.transfer = out_info->colorimetry.transfer;
+  if (gst_video_info_is_equal (&tmp_info, out_info)) {
+    if (gst_video_color_transfer_is_equivalent (in_info->colorimetry.transfer,
+            in_info->finfo->bits, out_info->colorimetry.transfer,
+            out_info->finfo->bits)) {
+      gstbasetransform_class->passthrough_on_same_caps = FALSE;
+      gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (filter), TRUE);
+      return TRUE;
+    }
+  }
+  gstbasetransform_class->passthrough_on_same_caps = TRUE;
+  gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (filter), FALSE);
 
   space->convert = gst_video_converter_new (in_info, out_info,
       gst_structure_new ("GstVideoConvertConfig",