video-converter: Make fast path work for equivalent transfer functions

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>
This commit is contained in:
Vivia Nikolaidou 2020-06-26 12:22:08 +03:00
parent 1d0ccf8baa
commit ad55d3ce9d
4 changed files with 79 additions and 1 deletions

View 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;
}

View 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__ */

View 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;

View 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",