diff --git a/gst-libs/gst/video/video-color.c b/gst-libs/gst/video/video-color.c index 1ed47f1930..c37dd5f00a 100644 --- a/gst-libs/gst/video/video-color.c +++ b/gst-libs/gst/video/video-color.c @@ -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; +} diff --git a/gst-libs/gst/video/video-color.h b/gst-libs/gst/video/video-color.h index d0830dff5e..b304d4ae3f 100644 --- a/gst-libs/gst/video/video-color.h +++ b/gst-libs/gst/video/video-color.h @@ -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__ */ diff --git a/gst-libs/gst/video/video-converter.c b/gst-libs/gst/video/video-converter.c index c89932a184..21b212a56e 100644 --- a/gst-libs/gst/video/video-converter.c +++ b/gst-libs/gst/video/video-converter.c @@ -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; diff --git a/gst/videoconvert/gstvideoconvert.c b/gst/videoconvert/gstvideoconvert.c index 66783c5240..b190c34228 100644 --- a/gst/videoconvert/gstvideoconvert.c +++ b/gst/videoconvert/gstvideoconvert.c @@ -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",