The object is equivalent to GstVideoConverter but for D3D11.
Application can use this object directly for various conversions,
such as color space conversion, rescale, crop and flip/rotation.
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2767>
#include <gst/d3d11/gstd3d11_fwd.h>
#include <gst/d3d11/gstd3d11bufferpool.h>
#include <gst/d3d11/gstd3d11compile.h>
+#include <gst/d3d11/gstd3d11converter.h>
#include <gst/d3d11/gstd3d11device.h>
#include <gst/d3d11/gstd3d11format.h>
#include <gst/d3d11/gstd3d11memory.h>
typedef struct _GstD3D11Format GstD3D11Format;
+typedef struct _GstD3D11Converter GstD3D11Converter;
+typedef struct _GstD3D11ConverterClass GstD3D11ConverterClass;
+typedef struct _GstD3D11ConverterPrivate GstD3D11ConverterPrivate;
+
G_END_DECLS
#define GST_D3D11_N_FORMATS G_N_ELEMENTS(_gst_d3d11_default_format_map)
+typedef struct _GstD3D11ColorMatrix
+{
+ gdouble matrix[3][3];
+ gdouble offset[3];
+ gdouble min[3];
+ gdouble max[3];
+} GstD3D11ColorMatrix;
+
+GST_D3D11_API
+gchar * gst_d3d11_dump_color_matrix (GstD3D11ColorMatrix * matrix);
+
+GST_D3D11_API
+gboolean gst_d3d11_color_range_adjust_matrix_unorm (const GstVideoInfo * in_info,
+ const GstVideoInfo * out_info,
+ GstD3D11ColorMatrix * matrix);
+
+GST_D3D11_API
+gboolean gst_d3d11_yuv_to_rgb_matrix_unorm (const GstVideoInfo * in_yuv_info,
+ const GstVideoInfo * out_rgb_info,
+ GstD3D11ColorMatrix * matrix);
+
+GST_D3D11_API
+gboolean gst_d3d11_rgb_to_yuv_matrix_unorm (const GstVideoInfo * in_rgb_info,
+ const GstVideoInfo * out_yuv_info,
+ GstD3D11ColorMatrix * matrix);
+
+GST_D3D11_API
+gboolean gst_d3d11_color_primaries_matrix_unorm (const GstVideoColorPrimariesInfo * in_info,
+ const GstVideoColorPrimariesInfo * out_info,
+ GstD3D11ColorMatrix * matrix);
+
G_END_DECLS
#ifdef __cplusplus
/* GStreamer
* Copyright (C) <2019> Seungha Yang <seungha.yang@navercorp.com>
* Copyright (C) <2019> Jeongki Kim <jeongki.kim@jeongki.kim>
+ * Copyright (C) <2022> Seungha Yang <seungha@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
# include <config.h>
#endif
+#include "gstd3d11_private.h"
#include "gstd3d11converter.h"
-#include "gstd3d11pluginutils.h"
+#include "gstd3d11device.h"
+#include "gstd3d11utils.h"
+#include "gstd3d11memory.h"
+#include "gstd3d11compile.h"
+#include "gstd3d11bufferpool.h"
#include <wrl.h>
#include <string.h>
#include <math.h>
return TRUE;
}
+/**
+ * gst_d3d11_converter_new:
+ * @device: a #GstD3D11Device
+ * @in_info: a #GstVideoInfo
+ * @out_info: a #GstVideoInfo
+ * @method: (inout) (optional) (nullable): a #GstD3D11ConverterMethod
+
+ * Create a new converter object to convert between @in_info and @out_info
+ * with @method. When @method is not specified, converter will configure
+ * conversion path for all available method. Otherwise, converter will configure
+ * conversion path only for specified method(s) and set @method will be updated
+ * with supported method.
+ *
+ * Returns: a #GstD3D11Converter or %NULL if conversion is not possible
+ *
+ * Since: 1.22
+ */
GstD3D11Converter *
gst_d3d11_converter_new (GstD3D11Device * device, const GstVideoInfo * in_info,
const GstVideoInfo * out_info, GstStructure * config)
return ret;
}
+/**
+ * gst_d3d11_converter_convert_buffer:
+ * @converter: a #GstD3D11Converter
+ * @in_buf: a #GstBuffer
+ * @out_buf: a #GstBuffer
+ *
+ * Converts @in_buf into @out_buf
+ *
+ * Returns: %TRUE if conversion is successful
+ *
+ * Since: 1.22
+ */
gboolean
gst_d3d11_converter_convert_buffer (GstD3D11Converter * converter,
GstBuffer * in_buf, GstBuffer * out_buf)
in_buf, out_buf);
}
+/**
+ * gst_d3d11_converter_convert_buffer_unlocked:
+ * @converter: a #GstD3D11Converter
+ * @in_buf: a #GstBuffer
+ * @out_buf: a #GstBuffer
+ *
+ * Converts @in_buf into @out_buf. Caller should take d3d11 device lock
+ * in case that multiple threads can perform GPU processing using the
+ * same #GstD3D11Device
+ *
+ * Returns: %TRUE if conversion is successful
+ *
+ * Since: 1.22
+ */
+
gboolean
gst_d3d11_converter_convert_buffer_unlocked (GstD3D11Converter * converter,
GstBuffer * in_buf, GstBuffer * out_buf)
/* GStreamer
* Copyright (C) <2019> Seungha Yang <seungha.yang@navercorp.com>
+ * Copyright (C) <2022> Seungha Yang <seungha@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* Boston, MA 02110-1301, USA.
*/
-#ifndef __GST_D3D11_COLOR_CONVERTER_H__
-#define __GST_D3D11_COLOR_CONVERTER_H__
+#pragma once
#include <gst/gst.h>
#include <gst/video/video.h>
-#include <gst/d3d11/gstd3d11.h>
+#include <gst/d3d11/gstd3d11_fwd.h>
G_BEGIN_DECLS
#define GST_IS_D3D11_CONVERTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_D3D11_CONVERTER))
#define GST_D3D11_CONVERTER_CAST(obj) ((GstD3D11Converter*)(obj))
-typedef struct _GstD3D11Converter GstD3D11Converter;
-typedef struct _GstD3D11ConverterClass GstD3D11ConverterClass;
-typedef struct _GstD3D11ConverterPrivate GstD3D11ConverterPrivate;
-
+/**
+ * GstD3D11ConverterMethod:
+ * @GST_D3D11_CONVERTER_METHOD_SHADER: Performs conversion using pixel shader
+ * @GST_D3D11_CONVERTER_METHOD_VIDEO_PROCESSOR: Performs conversion using video processor
+ *
+ * Since: 1.22
+ */
typedef enum
{
GST_D3D11_CONVERTER_BACKEND_SHADER = (1 << 0),
GST_D3D11_CONVERTER_BACKEND_VIDEO_PROCESSOR = (1 << 1),
} GstD3D11ConverterBackend;
+
+GST_D3D11_API
+GType gst_d3d11_converter_backend_get_type (void);
#define GST_TYPE_D3D11_CONVERTER_BACKEND (gst_d3d11_converter_backend_get_type())
+/**
+ * GST_D3D11_CONVERTER_OPT_BACKEND:
+ *
+ * #GstD3D11ConverterBackend, the conversion backend
+ * (e.g., pixel shader and/or video processor) to use
+ *
+ * Since: 1.22
+ */
#define GST_D3D11_CONVERTER_OPT_BACKEND "GstD3D11Converter.backend"
struct _GstD3D11Converter
gpointer _gst_reserved[GST_PADDING];
};
-GType gst_d3d11_converter_backend_get_type (void);
-
+GST_D3D11_API
GType gst_d3d11_converter_get_type (void);
+GST_D3D11_API
GstD3D11Converter * gst_d3d11_converter_new (GstD3D11Device * device,
const GstVideoInfo * in_info,
const GstVideoInfo * out_info,
GstStructure * config);
+GST_D3D11_API
gboolean gst_d3d11_converter_convert_buffer (GstD3D11Converter * converter,
GstBuffer * in_buf,
GstBuffer * out_buf);
+GST_D3D11_API
gboolean gst_d3d11_converter_convert_buffer_unlocked (GstD3D11Converter * converter,
GstBuffer * in_buf,
GstBuffer * out_buf);
G_END_DECLS
-
-#endif /* __GST_D3D11_COLOR_CONVERTER_H__ */
return TRUE;
}
+
+gchar *
+gst_d3d11_dump_color_matrix (GstD3D11ColorMatrix * matrix)
+{
+ /* *INDENT-OFF* */
+ static const gchar format[] =
+ "[MATRIX]\n"
+ "|% .6f, % .6f, % .6f|\n"
+ "|% .6f, % .6f, % .6f|\n"
+ "|% .6f, % .6f, % .6f|\n"
+ "[OFFSET]\n"
+ "|% .6f, % .6f, % .6f|\n"
+ "[MIN]\n"
+ "|% .6f, % .6f, % .6f|\n"
+ "[MAX]\n"
+ "|% .6f, % .6f, % .6f|";
+ /* *INDENT-ON* */
+
+ g_return_val_if_fail (matrix != nullptr, nullptr);
+
+ return g_strdup_printf (format,
+ matrix->matrix[0][0], matrix->matrix[0][1], matrix->matrix[0][2],
+ matrix->matrix[1][0], matrix->matrix[1][1], matrix->matrix[1][2],
+ matrix->matrix[2][0], matrix->matrix[2][1], matrix->matrix[2][2],
+ matrix->offset[0], matrix->offset[1], matrix->offset[2],
+ matrix->min[0], matrix->min[1], matrix->min[2],
+ matrix->max[0], matrix->max[1], matrix->max[2]);
+}
+
+static void
+color_matrix_copy (GstD3D11ColorMatrix * dst, const GstD3D11ColorMatrix * src)
+{
+ for (guint i = 0; i < 3; i++) {
+ for (guint j = 0; j < 3; j++) {
+ dst->matrix[i][j] = src->matrix[i][j];
+ }
+ }
+}
+
+static void
+color_matrix_multiply (GstD3D11ColorMatrix * dst, GstD3D11ColorMatrix * a,
+ GstD3D11ColorMatrix * b)
+{
+ GstD3D11ColorMatrix tmp;
+
+ for (guint i = 0; i < 3; i++) {
+ for (guint j = 0; j < 3; j++) {
+ gdouble val = 0;
+ for (guint k = 0; k < 3; k++) {
+ val += a->matrix[i][k] * b->matrix[k][j];
+ }
+
+ tmp.matrix[i][j] = val;
+ }
+ }
+
+ color_matrix_copy (dst, &tmp);
+}
+
+static void
+color_matrix_identity (GstD3D11ColorMatrix * m)
+{
+ for (guint i = 0; i < 3; i++) {
+ for (guint j = 0; j < 3; j++) {
+ if (i == j)
+ m->matrix[i][j] = 1.0;
+ else
+ m->matrix[i][j] = 0;
+ }
+ }
+}
+
+static gboolean
+color_matrix_invert (GstD3D11ColorMatrix * dst, GstD3D11ColorMatrix * src)
+{
+ GstD3D11ColorMatrix tmp;
+ gdouble det;
+
+ color_matrix_identity (&tmp);
+ for (guint j = 0; j < 3; j++) {
+ for (guint i = 0; i < 3; i++) {
+ tmp.matrix[j][i] =
+ src->matrix[(i + 1) % 3][(j + 1) % 3] *
+ src->matrix[(i + 2) % 3][(j + 2) % 3] -
+ src->matrix[(i + 1) % 3][(j + 2) % 3] *
+ src->matrix[(i + 2) % 3][(j + 1) % 3];
+ }
+ }
+
+ det = tmp.matrix[0][0] * src->matrix[0][0] +
+ tmp.matrix[0][1] * src->matrix[1][0] +
+ tmp.matrix[0][2] * src->matrix[2][0];
+ if (det == 0)
+ return FALSE;
+
+ for (guint j = 0; j < 3; j++) {
+ for (guint i = 0; i < 3; i++) {
+ tmp.matrix[i][j] /= det;
+ }
+ }
+
+ color_matrix_copy (dst, &tmp);
+
+ return TRUE;
+}
+
+/**
+ * gst_d3d11_color_range_adjust_matrix_unorm:
+ * @in_info: a #GstVideoInfo
+ * @out_info: a #GstVideoInfo
+ * @matrix: a #GstD3D11ColorMatrix
+ *
+ * Calculates matrix for color range adjustment. Both input and output
+ * signals are in normalized [0.0..1.0] space.
+ *
+ * Resulting values can be calculated by
+ * | Yout | | Yin | | matrix.offset[0] |
+ * | Uout | = clamp ( matrix.matrix * | Uin | + | matrix.offset[1] |, matrix.min, matrix.max )
+ * | Vout | | Vin | | matrix.offset[2] |
+ *
+ * Returns: %TRUE if successful
+ */
+gboolean
+gst_d3d11_color_range_adjust_matrix_unorm (const GstVideoInfo * in_info,
+ const GstVideoInfo * out_info, GstD3D11ColorMatrix * matrix)
+{
+ gboolean in_rgb, out_rgb;
+ gint in_offset[GST_VIDEO_MAX_COMPONENTS];
+ gint in_scale[GST_VIDEO_MAX_COMPONENTS];
+ gint out_offset[GST_VIDEO_MAX_COMPONENTS];
+ gint out_scale[GST_VIDEO_MAX_COMPONENTS];
+ GstVideoColorRange in_range;
+ GstVideoColorRange out_range;
+ gdouble src_fullscale, dst_fullscale;
+
+ g_return_val_if_fail (in_info != nullptr, FALSE);
+ g_return_val_if_fail (out_info != nullptr, FALSE);
+ g_return_val_if_fail (matrix != nullptr, FALSE);
+
+ memset (matrix, 0, sizeof (GstD3D11ColorMatrix));
+ for (guint i = 0; i < 3; i++) {
+ matrix->matrix[i][i] = 1.0;
+ matrix->matrix[i][i] = 1.0;
+ matrix->matrix[i][i] = 1.0;
+ matrix->max[i] = 1.0;
+ }
+
+ in_rgb = GST_VIDEO_INFO_IS_RGB (in_info);
+ out_rgb = GST_VIDEO_INFO_IS_RGB (out_info);
+
+ if (in_rgb != out_rgb) {
+ GST_WARNING ("Invalid format conversion");
+ return FALSE;
+ }
+
+ in_range = in_info->colorimetry.range;
+ out_range = out_info->colorimetry.range;
+
+ if (in_range == GST_VIDEO_COLOR_RANGE_UNKNOWN) {
+ GST_WARNING ("Unknown input color range");
+ if (in_rgb || GST_VIDEO_INFO_IS_GRAY (in_info))
+ in_range = GST_VIDEO_COLOR_RANGE_0_255;
+ else
+ in_range = GST_VIDEO_COLOR_RANGE_16_235;
+ }
+
+ if (out_range == GST_VIDEO_COLOR_RANGE_UNKNOWN) {
+ GST_WARNING ("Unknown output color range");
+ if (out_rgb || GST_VIDEO_INFO_IS_GRAY (out_info))
+ out_range = GST_VIDEO_COLOR_RANGE_0_255;
+ else
+ out_range = GST_VIDEO_COLOR_RANGE_16_235;
+ }
+
+ src_fullscale = (gdouble) ((1 << in_info->finfo->depth[0]) - 1);
+ dst_fullscale = (gdouble) ((1 << out_info->finfo->depth[0]) - 1);
+
+ gst_video_color_range_offsets (in_range, in_info->finfo, in_offset, in_scale);
+ gst_video_color_range_offsets (out_range,
+ out_info->finfo, out_offset, out_scale);
+
+ matrix->min[0] = matrix->min[1] = matrix->min[2] =
+ (gdouble) out_offset[0] / dst_fullscale;
+
+ matrix->max[0] = (out_scale[0] + out_offset[0]) / dst_fullscale;
+ matrix->max[1] = matrix->max[2] =
+ (out_scale[1] + out_offset[0]) / dst_fullscale;
+
+ if (in_info->colorimetry.range == out_info->colorimetry.range) {
+ GST_DEBUG ("Same color range");
+ return TRUE;
+ }
+
+ /* Formula
+ *
+ * 1) Scales and offset compensates input to [0..1] range
+ * SRC_NORM[i] = (src[i] * src_fullscale - in_offset[i]) / in_scale[i]
+ * = (src[i] * src_fullscale / in_scale[i]) - in_offset[i] / in_scale[i]
+ *
+ * 2) Reverse to output UNIT scale
+ * DST_UINT[i] = SRC_NORM[i] * out_scale[i] + out_offset[i]
+ * = src[i] * src_fullscale * out_scale[i] / in_scale[i]
+ * - in_offset[i] * out_scale[i] / in_scale[i]
+ * + out_offset[i]
+ *
+ * 3) Back to [0..1] scale
+ * dst[i] = DST_UINT[i] / dst_fullscale
+ * = COEFF[i] * src[i] + OFF[i]
+ * where
+ * src_fullscale * out_scale[i]
+ * COEFF[i] = ------------------------------
+ * dst_fullscale * in_scale[i]
+ *
+ * out_offset[i] in_offset[i] * out_scale[i]
+ * OFF[i] = -------------- - ------------------------------
+ * dst_fullscale dst_fullscale * in_scale[i]
+ */
+ for (guint i = 0; i < 3; i++) {
+ matrix->matrix[i][i] = (src_fullscale * out_scale[i]) /
+ (dst_fullscale * in_scale[i]);
+ matrix->offset[i] = (out_offset[i] / dst_fullscale) -
+ ((gdouble) in_offset[i] * out_scale[i] / (dst_fullscale * in_scale[i]));
+ }
+
+ return TRUE;
+}
+
+/**
+ * gst_d3d11_yuv_to_rgb_matrix_unorm:
+ * @in_yuv_info: a #GstVideoInfo of input YUV signal
+ * @out_rgb_info: a #GstVideoInfo of output RGB signal
+ * @matrix: a #GstD3D11ColorMatrix
+ *
+ * Calculates transform matrix from YUV to RGB conversion. Both input and output
+ * signals are in normalized [0.0..1.0] space and additional gamma decoding
+ * or primary/transfer function transform is not performed by this matrix.
+ *
+ * Resulting non-linear RGB values can be calculated by
+ * | R' | | Y' | | matrix.offset[0] |
+ * | G' | = clamp ( matrix.matrix * | Cb | + | matrix.offset[1] | matrix.min, matrix.max )
+ * | B' | | Cr | | matrix.offset[2] |
+ *
+ * Returns: %TRUE if successful
+ */
+gboolean
+gst_d3d11_yuv_to_rgb_matrix_unorm (const GstVideoInfo * in_yuv_info,
+ const GstVideoInfo * out_rgb_info, GstD3D11ColorMatrix * matrix)
+{
+ gint offset[4], scale[4];
+ gdouble Kr, Kb, Kg;
+
+ g_return_val_if_fail (in_yuv_info != nullptr, FALSE);
+ g_return_val_if_fail (out_rgb_info != nullptr, FALSE);
+ g_return_val_if_fail (matrix != nullptr, FALSE);
+
+ /*
+ * <Formula>
+ *
+ * Input: Unsigned normalized Y'CbCr(unorm), [0.0..1.0] range
+ * Output: Unsigned normalized non-linear R'G'B'(unorm), [0.0..1.0] range
+ *
+ * 1) Y'CbCr(unorm) to scaled Y'CbCr
+ * | Y' | | Y'(unorm) |
+ * | Cb | = S | Cb(unorm) |
+ * | Cb | | Cr(unorm) |
+ * where S = (2 ^ bitdepth) - 1
+ *
+ * 2) Y'CbCr to YPbPr
+ * Y = (Y' - offsetY ) / scaleY
+ * Pb = [(Cb - offsetCbCr) / scaleCbCr]
+ * Pr = [(Cr - offsetCrCr) / scaleCrCr]
+ * =>
+ * Y = Y'(unorm) * Sy + Oy
+ * Pb = Cb(unorm) * Suv + Ouv
+ * Pb = Cr(unorm) * Suv + Ouv
+ * where
+ * Sy = S / scaleY
+ * Suv = S / scaleCbCr
+ * Oy = -(offsetY / scaleY)
+ * Ouv = -(offsetCbCr / scaleCbCr)
+ *
+ * 3) YPbPr to R'G'B'
+ * | R' | | Y |
+ * | G' | = M *| Pb |
+ * | B' | | Pr |
+ * where
+ * | vecR |
+ * M = | vecG |
+ * | vecB |
+ * vecR = | 1, 0 , 2(1 - Kr) |
+ * vecG = | 1, -(Kb/Kg) * 2(1 - Kb), -(Kr/Kg) * 2(1 - Kr) |
+ * vecB = | 1, 2(1 - Kb) , 0 |
+ * =>
+ * R' = dot(vecR, (Syuv * Y'CbCr(unorm))) + dot(vecR, Offset)
+ * G' = dot(vecG, (Svuy * Y'CbCr(unorm))) + dot(vecG, Offset)
+ * B' = dot(vecB, (Syuv * Y'CbCr(unorm)) + dot(vecB, Offset)
+ * where
+ * | Sy, 0, 0 |
+ * Syuv = | 0, Suv, 0 |
+ * | 0 0, Suv |
+ *
+ * | Oy |
+ * Offset = | Ouv |
+ * | Ouv |
+ *
+ * 4) YUV -> RGB matrix
+ * | R' | | Y'(unorm) | | offsetA |
+ * | G' | = Matrix * | Cb(unorm) | + | offsetB |
+ * | B' | | Cr(unorm) | | offsetC |
+ *
+ * where
+ * | vecR |
+ * Matrix = | vecG | * Syuv
+ * | vecB |
+ *
+ * offsetA = dot(vecR, Offset)
+ * offsetB = dot(vecG, Offset)
+ * offsetC = dot(vecB, Offset)
+ *
+ * 4) Consider 16-235 scale RGB
+ * RGBfull(0..255) -> RGBfull(16..235) matrix is represented by
+ * | Rs | | Rf | | Or |
+ * | Gs | = Ms | Gf | + | Og |
+ * | Bs | | Bf | | Ob |
+ *
+ * Combining all matrix into
+ * | Rs | | Y'(unorm) | | offsetA | | Or |
+ * | Gs | = Ms * ( Matrix * | Cb(unorm) | + | offsetB | ) + | Og |
+ * | Bs | | Cr(unorm) | | offsetC | | Ob |
+ *
+ * | Y'(unorm) | | offsetA | | Or |
+ * = Ms * Matrix * | Cb(unorm) | + Ms | offsetB | + | Og |
+ * | Cr(unorm) | | offsetC | | Ob |
+ */
+
+ memset (matrix, 0, sizeof (GstD3D11ColorMatrix));
+ for (guint i = 0; i < 3; i++)
+ matrix->max[i] = 1.0;
+
+ gst_video_color_range_offsets (in_yuv_info->colorimetry.range,
+ in_yuv_info->finfo, offset, scale);
+
+ if (gst_video_color_matrix_get_Kr_Kb (in_yuv_info->colorimetry.matrix,
+ &Kr, &Kb)) {
+ guint S;
+ gdouble Sy, Suv;
+ gdouble Oy, Ouv;
+ gdouble vecR[3], vecG[3], vecB[3];
+
+ Kg = 1.0 - Kr - Kb;
+
+ vecR[0] = 1.0;
+ vecR[1] = 0;
+ vecR[2] = 2 * (1 - Kr);
+
+ vecG[0] = 1.0;
+ vecG[1] = -(Kb / Kg) * 2 * (1 - Kb);
+ vecG[2] = -(Kr / Kg) * 2 * (1 - Kr);
+
+ vecB[0] = 1.0;
+ vecB[1] = 2 * (1 - Kb);
+ vecB[2] = 0;
+
+ /* Assume all components has the same bitdepth */
+ S = (1 << in_yuv_info->finfo->depth[0]) - 1;
+ Sy = (gdouble) S / scale[0];
+ Suv = (gdouble) S / scale[1];
+ Oy = -((gdouble) offset[0] / scale[0]);
+ Ouv = -((gdouble) offset[1] / scale[1]);
+
+ matrix->matrix[0][0] = Sy * vecR[0];
+ matrix->matrix[1][0] = Sy * vecG[0];
+ matrix->matrix[2][0] = Sy * vecB[0];
+
+ matrix->matrix[0][1] = Suv * vecR[1];
+ matrix->matrix[1][1] = Suv * vecG[1];
+ matrix->matrix[2][1] = Suv * vecB[1];
+
+ matrix->matrix[0][2] = Suv * vecR[2];
+ matrix->matrix[1][2] = Suv * vecG[2];
+ matrix->matrix[2][2] = Suv * vecB[2];
+
+ matrix->offset[0] = vecR[0] * Oy + vecR[1] * Ouv + vecR[2] * Ouv;
+ matrix->offset[1] = vecG[0] * Oy + vecG[1] * Ouv + vecG[2] * Ouv;
+ matrix->offset[2] = vecB[0] * Oy + vecB[1] * Ouv + vecB[2] * Ouv;
+
+ /* Apply RGB range scale matrix */
+ if (out_rgb_info->colorimetry.range == GST_VIDEO_COLOR_RANGE_16_235) {
+ GstD3D11ColorMatrix scale_matrix, rst;
+ GstVideoInfo full_rgb = *out_rgb_info;
+
+ full_rgb.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
+
+ if (gst_d3d11_color_range_adjust_matrix_unorm (&full_rgb,
+ out_rgb_info, &scale_matrix)) {
+ /* Ms * Matrix */
+ color_matrix_multiply (&rst, &scale_matrix, matrix);
+
+ /* Ms * transform offsets */
+ for (guint i = 0; i < 3; i++) {
+ gdouble val = 0;
+ for (guint j = 0; j < 3; j++) {
+ val += scale_matrix.matrix[i][j] * matrix->offset[j];
+ }
+ rst.offset[i] = val + scale_matrix.offset[i];
+ }
+
+ /* copy back to output matrix */
+ for (guint i = 0; i < 3; i++) {
+ for (guint j = 0; j < 3; j++) {
+ matrix->matrix[i][j] = rst.matrix[i][j];
+ }
+ matrix->offset[i] = rst.offset[i];
+ matrix->min[i] = scale_matrix.min[i];
+ matrix->max[i] = scale_matrix.max[i];
+ }
+ }
+ }
+ } else {
+ /* Unknown matrix */
+ matrix->matrix[0][0] = 1.0;
+ matrix->matrix[1][1] = 1.0;
+ matrix->matrix[2][2] = 1.0;
+ }
+
+ return TRUE;
+}
+
+/**
+ * gst_d3d11_rgb_to_yuv_matrix_unorm:
+ * @in_rgb_info: a #GstVideoInfo of input RGB signal
+ * @out_yuv_info: a #GstVideoInfo of output YUV signal
+ * @matrix: a #GstD3D11ColorMatrix
+ *
+ * Calculates transform matrix from RGB to YUV conversion. Both input and output
+ * signals are in normalized [0.0..1.0] space and additional gamma decoding
+ * or primary/transfer function transform is not performed by this matrix.
+ *
+ * Resulting RGB values can be calculated by
+ * | Y' | | R' | | matrix.offset[0] |
+ * | Cb | = clamp ( matrix.matrix * | G' | + | matrix.offset[1] |, matrix.min, matrix.max )
+ * | Cr | | B' | | matrix.offset[2] |
+ *
+ * Returns: %TRUE if successful
+ */
+gboolean
+gst_d3d11_rgb_to_yuv_matrix_unorm (const GstVideoInfo * in_rgb_info,
+ const GstVideoInfo * out_yuv_info, GstD3D11ColorMatrix * matrix)
+{
+ gint offset[4], scale[4];
+ gdouble Kr, Kb, Kg;
+
+ g_return_val_if_fail (in_rgb_info != nullptr, FALSE);
+ g_return_val_if_fail (out_yuv_info != nullptr, FALSE);
+ g_return_val_if_fail (matrix != nullptr, FALSE);
+
+ /*
+ * <Formula>
+ *
+ * Input: Unsigned normalized non-linear R'G'B'(unorm), [0.0..1.0] range
+ * Output: Unsigned normalized Y'CbCr(unorm), [0.0..1.0] range
+ *
+ * 1) R'G'B' to YPbPr
+ * | Y | | R' |
+ * | Pb | = M *| G' |
+ * | Pr | | B' |
+ * where
+ * | vecY |
+ * M = | vecU |
+ * | vecV |
+ * vecY = | Kr , Kg , Kb |
+ * vecU = | -0.5*Kr/(1-Kb), -0.5*Kg/(1-Kb), 0.5 |
+ * vecV = | 0.5 , -0.5*Kg/(1-Kr), -0.5*Kb(1-Kr) |
+ *
+ * 2) YPbPr to Y'CbCr(unorm)
+ * Y'(unorm) = (Y * scaleY + offsetY) / S
+ * Cb(unorm) = (Pb * scaleCbCr + offsetCbCr) / S
+ * Cr(unorm) = (Pr * scaleCbCr + offsetCbCr) / S
+ * =>
+ * Y'(unorm) = (Y * scaleY / S) + (offsetY / S)
+ * Cb(unorm) = (Pb * scaleCbCr / S) + (offsetCbCr / S)
+ * Cr(unorm) = (Pb * scaleCbCr / S) + (offsetCbCr / S)
+ * where S = (2 ^ bitdepth) - 1
+ *
+ * 3) RGB -> YUV matrix
+ * | Y'(unorm) | | R' | | offsetA |
+ * | Cb(unorm) | = Matrix * | G' | + | offsetB |
+ * | Cr(unorm) | | B' | | offsetC |
+ *
+ * where
+ * | (scaleY/S) * vecY |
+ * Matrix = | (scaleCbCr/S) * vecU |
+ * | (scaleCbCr/S) * vecV |
+ *
+ * offsetA = offsetY / S
+ * offsetB = offsetCbCr / S
+ * offsetC = offsetCbCr / S
+ *
+ * 4) Consider 16-235 scale RGB
+ * RGBstudio(16..235) -> RGBfull(0..255) matrix is represented by
+ * | Rf | | Rs | | Or |
+ * | Gf | = Ms | Gs | + | Og |
+ * | Bf | | Bs | | Ob |
+ *
+ * Combining all matrix into
+ * | Y'(unorm) | | Rs | | Or | | offsetA |
+ * | Cb(unorm) | = Matrix * ( Ms | Gs | + | Og | ) + | offsetB |
+ * | Cr(unorm) | | Bs | | Ob | | offsetC |
+ *
+ * | Rs | | Or | | offsetA |
+ * = Matrix * Ms | Gs | + Matrix | Og | + | offsetB |
+ * | Bs | | Ob | | offsetB |
+ */
+
+ memset (matrix, 0, sizeof (GstD3D11ColorMatrix));
+ for (guint i = 0; i < 3; i++)
+ matrix->max[i] = 1.0;
+
+ gst_video_color_range_offsets (out_yuv_info->colorimetry.range,
+ out_yuv_info->finfo, offset, scale);
+
+ if (gst_video_color_matrix_get_Kr_Kb (out_yuv_info->colorimetry.matrix,
+ &Kr, &Kb)) {
+ guint S;
+ gdouble Sy, Suv;
+ gdouble Oy, Ouv;
+ gdouble vecY[3], vecU[3], vecV[3];
+
+ Kg = 1.0 - Kr - Kb;
+
+ vecY[0] = Kr;
+ vecY[1] = Kg;
+ vecY[2] = Kb;
+
+ vecU[0] = -0.5 * Kr / (1 - Kb);
+ vecU[1] = -0.5 * Kg / (1 - Kb);
+ vecU[2] = 0.5;
+
+ vecV[0] = 0.5;
+ vecV[1] = -0.5 * Kg / (1 - Kr);
+ vecV[2] = -0.5 * Kb / (1 - Kr);
+
+ /* Assume all components has the same bitdepth */
+ S = (1 << out_yuv_info->finfo->depth[0]) - 1;
+ Sy = (gdouble) scale[0] / S;
+ Suv = (gdouble) scale[1] / S;
+ Oy = (gdouble) offset[0] / S;
+ Ouv = (gdouble) offset[1] / S;
+
+ for (guint i = 0; i < 3; i++) {
+ matrix->matrix[0][i] = Sy * vecY[i];
+ matrix->matrix[1][i] = Suv * vecU[i];
+ matrix->matrix[2][i] = Suv * vecV[i];
+ }
+
+ matrix->offset[0] = Oy;
+ matrix->offset[1] = Ouv;
+ matrix->offset[2] = Ouv;
+
+ matrix->min[0] = Oy;
+ matrix->min[1] = Oy;
+ matrix->min[2] = Oy;
+
+ matrix->max[0] = ((gdouble) scale[0] + offset[0]) / S;
+ matrix->max[1] = ((gdouble) scale[1] + offset[0]) / S;
+ matrix->max[2] = ((gdouble) scale[1] + offset[0]) / S;
+
+ /* Apply RGB range scale matrix */
+ if (in_rgb_info->colorimetry.range == GST_VIDEO_COLOR_RANGE_16_235) {
+ GstD3D11ColorMatrix scale_matrix, rst;
+ GstVideoInfo full_rgb = *in_rgb_info;
+
+ full_rgb.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
+
+ if (gst_d3d11_color_range_adjust_matrix_unorm (in_rgb_info,
+ &full_rgb, &scale_matrix)) {
+ /* Matrix * Ms */
+ color_matrix_multiply (&rst, matrix, &scale_matrix);
+
+ /* Matrix * scale offsets */
+ for (guint i = 0; i < 3; i++) {
+ gdouble val = 0;
+ for (guint j = 0; j < 3; j++) {
+ val += matrix->matrix[i][j] * scale_matrix.offset[j];
+ }
+ rst.offset[i] = val + matrix->offset[i];
+ }
+
+ /* copy back to output matrix */
+ for (guint i = 0; i < 3; i++) {
+ for (guint j = 0; j < 3; j++) {
+ matrix->matrix[i][j] = rst.matrix[i][j];
+ }
+ matrix->offset[i] = rst.offset[i];
+ }
+ }
+ }
+ } else {
+ /* Unknown matrix */
+ matrix->matrix[0][0] = 1.0;
+ matrix->matrix[1][1] = 1.0;
+ matrix->matrix[2][2] = 1.0;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+rgb_to_xyz_matrix (const GstVideoColorPrimariesInfo * info,
+ GstD3D11ColorMatrix * matrix)
+{
+ GstD3D11ColorMatrix m, im;
+ gdouble Sr, Sg, Sb;
+ gdouble Xw, Yw, Zw;
+
+ if (info->Rx == 0 || info->Gx == 0 || info->By == 0 || info->Wy == 0)
+ return FALSE;
+
+ color_matrix_identity (&m);
+
+ m.matrix[0][0] = info->Rx / info->Ry;
+ m.matrix[1][0] = 1.0;
+ m.matrix[2][0] = (1.0 - info->Rx - info->Ry) / info->Ry;
+
+ m.matrix[0][1] = info->Gx / info->Gy;
+ m.matrix[1][1] = 1.0;
+ m.matrix[2][1] = (1.0 - info->Gx - info->Gy) / info->Gy;
+
+ m.matrix[0][2] = info->Bx / info->By;
+ m.matrix[1][2] = 1.0;
+ m.matrix[2][2] = (1.0 - info->Bx - info->By) / info->By;
+
+ if (!color_matrix_invert (&im, &m))
+ return FALSE;
+
+ Xw = info->Wx / info->Wy;
+ Yw = 1.0;
+ Zw = (1.0 - info->Wx - info->Wy) / info->Wy;
+
+ Sr = im.matrix[0][0] * Xw + im.matrix[0][1] * Yw + im.matrix[0][2] * Zw;
+ Sg = im.matrix[1][0] * Xw + im.matrix[1][1] * Yw + im.matrix[1][2] * Zw;
+ Sb = im.matrix[2][0] * Xw + im.matrix[2][1] * Yw + im.matrix[2][2] * Zw;
+
+ for (guint i = 0; i < 3; i++) {
+ m.matrix[i][0] *= Sr;
+ m.matrix[i][1] *= Sg;
+ m.matrix[i][2] *= Sb;
+ }
+
+ color_matrix_copy (matrix, &m);
+
+ return TRUE;
+}
+
+/**
+ * gst_d3d11_color_primaries_matrix_unorm:
+ * @in_info: a #GstVideoColorPrimariesInfo of input signal
+ * @out_info: a #GstVideoColorPrimariesInfo of output signal
+ * @matrix: a #GstD3D11ColorMatrix
+ *
+ * Calculates color primaries conversion matrix
+ *
+ * Resulting RGB values can be calculated by
+ * | Rout | | Rin |
+ * | Gout | = saturate ( matrix.matrix * | Gin | )
+ * | Bout | | Bin |
+ *
+ * Returns: %TRUE if successful
+ */
+gboolean
+gst_d3d11_color_primaries_matrix_unorm (const GstVideoColorPrimariesInfo *
+ in_info, const GstVideoColorPrimariesInfo * out_info,
+ GstD3D11ColorMatrix * matrix)
+{
+ GstD3D11ColorMatrix Ms, invMd, ret;
+
+ g_return_val_if_fail (in_info != nullptr, FALSE);
+ g_return_val_if_fail (out_info != nullptr, FALSE);
+ g_return_val_if_fail (matrix != nullptr, FALSE);
+
+ /*
+ * <Formula>
+ *
+ * 1) RGB -> XYZ conversion
+ * | X | | R |
+ * | Y | = M | G |
+ * | Z | | B |
+ * where
+ * | SrXr, SgXg, SbXb |
+ * M = | SrYr, SgYg, SbYb |
+ * | SrZr, SgZg, SbZb |
+ *
+ * Xr = xr / yr
+ * Yr = 1
+ * Zr = (1 - xr - yr) / yr
+ * xr and yr are xy coordinates of red primary in the CIE 1931 color space.
+ * And its applied to G and B components
+ *
+ * | Sr | | Xr, Xg, Xb | | Xw |
+ * | Sg | = inv( | Yr, Yg, Yb | ) * | Yw |
+ * | Sb | | Zr, Zg, Zb | | Zw |
+ *
+ * 2) XYZsrc -> XYZdst conversion
+ * Apply chromatic adaptation
+ * | Xdst | | Xsrc |
+ * | Ydst | = Mc | Ysrc |
+ * | Zdst | | Zsrc |
+ * where
+ * | Xwdst / Xwsrc, 0 , 0 |
+ * Mc = | 0 , Ywdst / Ywsrc, 0 |
+ * | 0 , 0 , Zwdst / Zwsrc |
+ *
+ * where
+ *
+ * 3) Final matrix
+ * | Rd | | Rs |
+ * | Gd | = inv (Md) * Mc * Ms | Gs |
+ * | Bd | | Bs |
+ */
+
+ memset (matrix, 0, sizeof (GstD3D11ColorMatrix));
+ for (guint i = 0; i < 3; i++)
+ matrix->max[i] = 1.0;
+
+ if (!rgb_to_xyz_matrix (in_info, &Ms)) {
+ GST_WARNING ("Failed to get src XYZ matrix");
+ return FALSE;
+ }
+
+ if (!rgb_to_xyz_matrix (out_info, &invMd) ||
+ !color_matrix_invert (&invMd, &invMd)) {
+ GST_WARNING ("Failed to get dst XYZ matrix");
+ return FALSE;
+ }
+
+ if (in_info->Wx != out_info->Wx || in_info->Wy != out_info->Wy) {
+ GstD3D11ColorMatrix Mc;
+
+ color_matrix_identity (&Mc);
+ Mc.matrix[0][0] = (out_info->Wx / out_info->Wy) /
+ (in_info->Wx / in_info->Wy);
+ /* Yw == 1.0 */
+ Mc.matrix[2][2] = ((1.0 - out_info->Wx - out_info->Wy) / out_info->Wy) /
+ ((1.0 - in_info->Wx - in_info->Wy) / in_info->Wy);
+
+ color_matrix_multiply (&ret, &Mc, &Ms);
+ } else {
+ color_matrix_copy (&ret, &Ms);
+ }
+
+ color_matrix_multiply (&ret, &invMd, &ret);
+ color_matrix_copy (matrix, &ret);
+
+ return TRUE;
+}
d3d11_sources = [
'gstd3d11bufferpool.cpp',
'gstd3d11compile.cpp',
+ 'gstd3d11converter.cpp',
'gstd3d11device.cpp',
'gstd3d11format.cpp',
'gstd3d11memory.cpp',
'gstd3d11_fwd.h',
'gstd3d11.h',
'gstd3d11bufferpool.h',
+ 'gstd3d11converter.h',
'gstd3d11device.h',
'gstd3d11format.h',
'gstd3d11memory.h',
d3d11_enum_types_headers = [
'gstd3d11_fwd.h',
'gstd3d11bufferpool.h',
+ 'gstd3d11converter.h',
'gstd3d11device.h',
'gstd3d11format.h',
'gstd3d11memory.h',
#endif
#include "gstd3d11compositor.h"
-#include "gstd3d11converter.h"
#include "gstd3d11pluginutils.h"
#include <string.h>
#include <wrl.h>
#endif
#include "gstd3d11convert.h"
-#include "gstd3d11converter.h"
#include "gstd3d11pluginutils.h"
GST_DEBUG_CATEGORY_STATIC (gst_d3d11_convert_debug);
#endif
#include "gstd3d11decoder.h"
-#include "gstd3d11converter.h"
#include "gstd3d11pluginutils.h"
#include <string.h>
#include <string>
return pool;
}
-
-gchar *
-gst_d3d11_dump_color_matrix (GstD3D11ColorMatrix * matrix)
-{
- /* *INDENT-OFF* */
- static const gchar format[] =
- "[MATRIX]\n"
- "|% .6f, % .6f, % .6f|\n"
- "|% .6f, % .6f, % .6f|\n"
- "|% .6f, % .6f, % .6f|\n"
- "[OFFSET]\n"
- "|% .6f, % .6f, % .6f|\n"
- "[MIN]\n"
- "|% .6f, % .6f, % .6f|\n"
- "[MAX]\n"
- "|% .6f, % .6f, % .6f|";
- /* *INDENT-ON* */
-
- g_return_val_if_fail (matrix != nullptr, nullptr);
-
- return g_strdup_printf (format,
- matrix->matrix[0][0], matrix->matrix[0][1], matrix->matrix[0][2],
- matrix->matrix[1][0], matrix->matrix[1][1], matrix->matrix[1][2],
- matrix->matrix[2][0], matrix->matrix[2][1], matrix->matrix[2][2],
- matrix->offset[0], matrix->offset[1], matrix->offset[2],
- matrix->min[0], matrix->min[1], matrix->min[2],
- matrix->max[0], matrix->max[1], matrix->max[2]);
-}
-
-static void
-color_matrix_copy (GstD3D11ColorMatrix * dst, const GstD3D11ColorMatrix * src)
-{
- for (guint i = 0; i < 3; i++) {
- for (guint j = 0; j < 3; j++) {
- dst->matrix[i][j] = src->matrix[i][j];
- }
- }
-}
-
-static void
-color_matrix_multiply (GstD3D11ColorMatrix * dst, GstD3D11ColorMatrix * a,
- GstD3D11ColorMatrix * b)
-{
- GstD3D11ColorMatrix tmp;
-
- for (guint i = 0; i < 3; i++) {
- for (guint j = 0; j < 3; j++) {
- gdouble val = 0;
- for (guint k = 0; k < 3; k++) {
- val += a->matrix[i][k] * b->matrix[k][j];
- }
-
- tmp.matrix[i][j] = val;
- }
- }
-
- color_matrix_copy (dst, &tmp);
-}
-
-static void
-color_matrix_identity (GstD3D11ColorMatrix * m)
-{
- for (guint i = 0; i < 3; i++) {
- for (guint j = 0; j < 3; j++) {
- if (i == j)
- m->matrix[i][j] = 1.0;
- else
- m->matrix[i][j] = 0;
- }
- }
-}
-
-static gboolean
-color_matrix_invert (GstD3D11ColorMatrix * dst, GstD3D11ColorMatrix * src)
-{
- GstD3D11ColorMatrix tmp;
- gdouble det;
-
- color_matrix_identity (&tmp);
- for (guint j = 0; j < 3; j++) {
- for (guint i = 0; i < 3; i++) {
- tmp.matrix[j][i] =
- src->matrix[(i + 1) % 3][(j + 1) % 3] *
- src->matrix[(i + 2) % 3][(j + 2) % 3] -
- src->matrix[(i + 1) % 3][(j + 2) % 3] *
- src->matrix[(i + 2) % 3][(j + 1) % 3];
- }
- }
-
- det = tmp.matrix[0][0] * src->matrix[0][0] +
- tmp.matrix[0][1] * src->matrix[1][0] +
- tmp.matrix[0][2] * src->matrix[2][0];
- if (det == 0)
- return FALSE;
-
- for (guint j = 0; j < 3; j++) {
- for (guint i = 0; i < 3; i++) {
- tmp.matrix[i][j] /= det;
- }
- }
-
- color_matrix_copy (dst, &tmp);
-
- return TRUE;
-}
-
-/**
- * gst_d3d11_color_range_adjust_matrix_unorm:
- * @in_info: a #GstVideoInfo
- * @out_info: a #GstVideoInfo
- * @matrix: a #GstD3D11ColorMatrix
- *
- * Calculates matrix for color range adjustment. Both input and output
- * signals are in normalized [0.0..1.0] space.
- *
- * Resulting values can be calculated by
- * | Yout | | Yin | | matrix.offset[0] |
- * | Uout | = clamp ( matrix.matrix * | Uin | + | matrix.offset[1] |, matrix.min, matrix.max )
- * | Vout | | Vin | | matrix.offset[2] |
- *
- * Returns: %TRUE if successful
- */
-gboolean
-gst_d3d11_color_range_adjust_matrix_unorm (const GstVideoInfo * in_info,
- const GstVideoInfo * out_info, GstD3D11ColorMatrix * matrix)
-{
- gboolean in_rgb, out_rgb;
- gint in_offset[GST_VIDEO_MAX_COMPONENTS];
- gint in_scale[GST_VIDEO_MAX_COMPONENTS];
- gint out_offset[GST_VIDEO_MAX_COMPONENTS];
- gint out_scale[GST_VIDEO_MAX_COMPONENTS];
- GstVideoColorRange in_range;
- GstVideoColorRange out_range;
- gdouble src_fullscale, dst_fullscale;
-
- g_return_val_if_fail (in_info != nullptr, FALSE);
- g_return_val_if_fail (out_info != nullptr, FALSE);
- g_return_val_if_fail (matrix != nullptr, FALSE);
-
- memset (matrix, 0, sizeof (GstD3D11ColorMatrix));
- for (guint i = 0; i < 3; i++) {
- matrix->matrix[i][i] = 1.0;
- matrix->matrix[i][i] = 1.0;
- matrix->matrix[i][i] = 1.0;
- matrix->max[i] = 1.0;
- }
-
- in_rgb = GST_VIDEO_INFO_IS_RGB (in_info);
- out_rgb = GST_VIDEO_INFO_IS_RGB (out_info);
-
- if (in_rgb != out_rgb) {
- GST_WARNING ("Invalid format conversion");
- return FALSE;
- }
-
- in_range = in_info->colorimetry.range;
- out_range = out_info->colorimetry.range;
-
- if (in_range == GST_VIDEO_COLOR_RANGE_UNKNOWN) {
- GST_WARNING ("Unknown input color range");
- if (in_rgb || GST_VIDEO_INFO_IS_GRAY (in_info))
- in_range = GST_VIDEO_COLOR_RANGE_0_255;
- else
- in_range = GST_VIDEO_COLOR_RANGE_16_235;
- }
-
- if (out_range == GST_VIDEO_COLOR_RANGE_UNKNOWN) {
- GST_WARNING ("Unknown output color range");
- if (out_rgb || GST_VIDEO_INFO_IS_GRAY (out_info))
- out_range = GST_VIDEO_COLOR_RANGE_0_255;
- else
- out_range = GST_VIDEO_COLOR_RANGE_16_235;
- }
-
- src_fullscale = (gdouble) ((1 << in_info->finfo->depth[0]) - 1);
- dst_fullscale = (gdouble) ((1 << out_info->finfo->depth[0]) - 1);
-
- gst_video_color_range_offsets (in_range, in_info->finfo, in_offset, in_scale);
- gst_video_color_range_offsets (out_range,
- out_info->finfo, out_offset, out_scale);
-
- matrix->min[0] = matrix->min[1] = matrix->min[2] =
- (gdouble) out_offset[0] / dst_fullscale;
-
- matrix->max[0] = (out_scale[0] + out_offset[0]) / dst_fullscale;
- matrix->max[1] = matrix->max[2] =
- (out_scale[1] + out_offset[0]) / dst_fullscale;
-
- if (in_info->colorimetry.range == out_info->colorimetry.range) {
- GST_DEBUG ("Same color range");
- return TRUE;
- }
-
- /* Formula
- *
- * 1) Scales and offset compensates input to [0..1] range
- * SRC_NORM[i] = (src[i] * src_fullscale - in_offset[i]) / in_scale[i]
- * = (src[i] * src_fullscale / in_scale[i]) - in_offset[i] / in_scale[i]
- *
- * 2) Reverse to output UNIT scale
- * DST_UINT[i] = SRC_NORM[i] * out_scale[i] + out_offset[i]
- * = src[i] * src_fullscale * out_scale[i] / in_scale[i]
- * - in_offset[i] * out_scale[i] / in_scale[i]
- * + out_offset[i]
- *
- * 3) Back to [0..1] scale
- * dst[i] = DST_UINT[i] / dst_fullscale
- * = COEFF[i] * src[i] + OFF[i]
- * where
- * src_fullscale * out_scale[i]
- * COEFF[i] = ------------------------------
- * dst_fullscale * in_scale[i]
- *
- * out_offset[i] in_offset[i] * out_scale[i]
- * OFF[i] = -------------- - ------------------------------
- * dst_fullscale dst_fullscale * in_scale[i]
- */
- for (guint i = 0; i < 3; i++) {
- matrix->matrix[i][i] = (src_fullscale * out_scale[i]) /
- (dst_fullscale * in_scale[i]);
- matrix->offset[i] = (out_offset[i] / dst_fullscale) -
- ((gdouble) in_offset[i] * out_scale[i] / (dst_fullscale * in_scale[i]));
- }
-
- return TRUE;
-}
-
-/**
- * gst_d3d11_yuv_to_rgb_matrix_unorm:
- * @in_yuv_info: a #GstVideoInfo of input YUV signal
- * @out_rgb_info: a #GstVideoInfo of output RGB signal
- * @matrix: a #GstD3D11ColorMatrix
- *
- * Calculates transform matrix from YUV to RGB conversion. Both input and output
- * signals are in normalized [0.0..1.0] space and additional gamma decoding
- * or primary/transfer function transform is not performed by this matrix.
- *
- * Resulting non-linear RGB values can be calculated by
- * | R' | | Y' | | matrix.offset[0] |
- * | G' | = clamp ( matrix.matrix * | Cb | + | matrix.offset[1] | matrix.min, matrix.max )
- * | B' | | Cr | | matrix.offset[2] |
- *
- * Returns: %TRUE if successful
- */
-gboolean
-gst_d3d11_yuv_to_rgb_matrix_unorm (const GstVideoInfo * in_yuv_info,
- const GstVideoInfo * out_rgb_info, GstD3D11ColorMatrix * matrix)
-{
- gint offset[4], scale[4];
- gdouble Kr, Kb, Kg;
-
- g_return_val_if_fail (in_yuv_info != nullptr, FALSE);
- g_return_val_if_fail (out_rgb_info != nullptr, FALSE);
- g_return_val_if_fail (matrix != nullptr, FALSE);
-
- /*
- * <Formula>
- *
- * Input: Unsigned normalized Y'CbCr(unorm), [0.0..1.0] range
- * Output: Unsigned normalized non-linear R'G'B'(unorm), [0.0..1.0] range
- *
- * 1) Y'CbCr(unorm) to scaled Y'CbCr
- * | Y' | | Y'(unorm) |
- * | Cb | = S | Cb(unorm) |
- * | Cb | | Cr(unorm) |
- * where S = (2 ^ bitdepth) - 1
- *
- * 2) Y'CbCr to YPbPr
- * Y = (Y' - offsetY ) / scaleY
- * Pb = [(Cb - offsetCbCr) / scaleCbCr]
- * Pr = [(Cr - offsetCrCr) / scaleCrCr]
- * =>
- * Y = Y'(unorm) * Sy + Oy
- * Pb = Cb(unorm) * Suv + Ouv
- * Pb = Cr(unorm) * Suv + Ouv
- * where
- * Sy = S / scaleY
- * Suv = S / scaleCbCr
- * Oy = -(offsetY / scaleY)
- * Ouv = -(offsetCbCr / scaleCbCr)
- *
- * 3) YPbPr to R'G'B'
- * | R' | | Y |
- * | G' | = M *| Pb |
- * | B' | | Pr |
- * where
- * | vecR |
- * M = | vecG |
- * | vecB |
- * vecR = | 1, 0 , 2(1 - Kr) |
- * vecG = | 1, -(Kb/Kg) * 2(1 - Kb), -(Kr/Kg) * 2(1 - Kr) |
- * vecB = | 1, 2(1 - Kb) , 0 |
- * =>
- * R' = dot(vecR, (Syuv * Y'CbCr(unorm))) + dot(vecR, Offset)
- * G' = dot(vecG, (Svuy * Y'CbCr(unorm))) + dot(vecG, Offset)
- * B' = dot(vecB, (Syuv * Y'CbCr(unorm)) + dot(vecB, Offset)
- * where
- * | Sy, 0, 0 |
- * Syuv = | 0, Suv, 0 |
- * | 0 0, Suv |
- *
- * | Oy |
- * Offset = | Ouv |
- * | Ouv |
- *
- * 4) YUV -> RGB matrix
- * | R' | | Y'(unorm) | | offsetA |
- * | G' | = Matrix * | Cb(unorm) | + | offsetB |
- * | B' | | Cr(unorm) | | offsetC |
- *
- * where
- * | vecR |
- * Matrix = | vecG | * Syuv
- * | vecB |
- *
- * offsetA = dot(vecR, Offset)
- * offsetB = dot(vecG, Offset)
- * offsetC = dot(vecB, Offset)
- *
- * 4) Consider 16-235 scale RGB
- * RGBfull(0..255) -> RGBfull(16..235) matrix is represented by
- * | Rs | | Rf | | Or |
- * | Gs | = Ms | Gf | + | Og |
- * | Bs | | Bf | | Ob |
- *
- * Combining all matrix into
- * | Rs | | Y'(unorm) | | offsetA | | Or |
- * | Gs | = Ms * ( Matrix * | Cb(unorm) | + | offsetB | ) + | Og |
- * | Bs | | Cr(unorm) | | offsetC | | Ob |
- *
- * | Y'(unorm) | | offsetA | | Or |
- * = Ms * Matrix * | Cb(unorm) | + Ms | offsetB | + | Og |
- * | Cr(unorm) | | offsetC | | Ob |
- */
-
- memset (matrix, 0, sizeof (GstD3D11ColorMatrix));
- for (guint i = 0; i < 3; i++)
- matrix->max[i] = 1.0;
-
- gst_video_color_range_offsets (in_yuv_info->colorimetry.range,
- in_yuv_info->finfo, offset, scale);
-
- if (gst_video_color_matrix_get_Kr_Kb (in_yuv_info->colorimetry.matrix,
- &Kr, &Kb)) {
- guint S;
- gdouble Sy, Suv;
- gdouble Oy, Ouv;
- gdouble vecR[3], vecG[3], vecB[3];
-
- Kg = 1.0 - Kr - Kb;
-
- vecR[0] = 1.0;
- vecR[1] = 0;
- vecR[2] = 2 * (1 - Kr);
-
- vecG[0] = 1.0;
- vecG[1] = -(Kb / Kg) * 2 * (1 - Kb);
- vecG[2] = -(Kr / Kg) * 2 * (1 - Kr);
-
- vecB[0] = 1.0;
- vecB[1] = 2 * (1 - Kb);
- vecB[2] = 0;
-
- /* Assume all components has the same bitdepth */
- S = (1 << in_yuv_info->finfo->depth[0]) - 1;
- Sy = (gdouble) S / scale[0];
- Suv = (gdouble) S / scale[1];
- Oy = -((gdouble) offset[0] / scale[0]);
- Ouv = -((gdouble) offset[1] / scale[1]);
-
- matrix->matrix[0][0] = Sy * vecR[0];
- matrix->matrix[1][0] = Sy * vecG[0];
- matrix->matrix[2][0] = Sy * vecB[0];
-
- matrix->matrix[0][1] = Suv * vecR[1];
- matrix->matrix[1][1] = Suv * vecG[1];
- matrix->matrix[2][1] = Suv * vecB[1];
-
- matrix->matrix[0][2] = Suv * vecR[2];
- matrix->matrix[1][2] = Suv * vecG[2];
- matrix->matrix[2][2] = Suv * vecB[2];
-
- matrix->offset[0] = vecR[0] * Oy + vecR[1] * Ouv + vecR[2] * Ouv;
- matrix->offset[1] = vecG[0] * Oy + vecG[1] * Ouv + vecG[2] * Ouv;
- matrix->offset[2] = vecB[0] * Oy + vecB[1] * Ouv + vecB[2] * Ouv;
-
- /* Apply RGB range scale matrix */
- if (out_rgb_info->colorimetry.range == GST_VIDEO_COLOR_RANGE_16_235) {
- GstD3D11ColorMatrix scale_matrix, rst;
- GstVideoInfo full_rgb = *out_rgb_info;
-
- full_rgb.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
-
- if (gst_d3d11_color_range_adjust_matrix_unorm (&full_rgb,
- out_rgb_info, &scale_matrix)) {
- /* Ms * Matrix */
- color_matrix_multiply (&rst, &scale_matrix, matrix);
-
- /* Ms * transform offsets */
- for (guint i = 0; i < 3; i++) {
- gdouble val = 0;
- for (guint j = 0; j < 3; j++) {
- val += scale_matrix.matrix[i][j] * matrix->offset[j];
- }
- rst.offset[i] = val + scale_matrix.offset[i];
- }
-
- /* copy back to output matrix */
- for (guint i = 0; i < 3; i++) {
- for (guint j = 0; j < 3; j++) {
- matrix->matrix[i][j] = rst.matrix[i][j];
- }
- matrix->offset[i] = rst.offset[i];
- matrix->min[i] = scale_matrix.min[i];
- matrix->max[i] = scale_matrix.max[i];
- }
- }
- }
- } else {
- /* Unknown matrix */
- matrix->matrix[0][0] = 1.0;
- matrix->matrix[1][1] = 1.0;
- matrix->matrix[2][2] = 1.0;
- }
-
- return TRUE;
-}
-
-/**
- * gst_d3d11_rgb_to_yuv_matrix_unorm:
- * @in_rgb_info: a #GstVideoInfo of input RGB signal
- * @out_yuv_info: a #GstVideoInfo of output YUV signal
- * @matrix: a #GstD3D11ColorMatrix
- *
- * Calculates transform matrix from RGB to YUV conversion. Both input and output
- * signals are in normalized [0.0..1.0] space and additional gamma decoding
- * or primary/transfer function transform is not performed by this matrix.
- *
- * Resulting RGB values can be calculated by
- * | Y' | | R' | | matrix.offset[0] |
- * | Cb | = clamp ( matrix.matrix * | G' | + | matrix.offset[1] |, matrix.min, matrix.max )
- * | Cr | | B' | | matrix.offset[2] |
- *
- * Returns: %TRUE if successful
- */
-gboolean
-gst_d3d11_rgb_to_yuv_matrix_unorm (const GstVideoInfo * in_rgb_info,
- const GstVideoInfo * out_yuv_info, GstD3D11ColorMatrix * matrix)
-{
- gint offset[4], scale[4];
- gdouble Kr, Kb, Kg;
-
- g_return_val_if_fail (in_rgb_info != nullptr, FALSE);
- g_return_val_if_fail (out_yuv_info != nullptr, FALSE);
- g_return_val_if_fail (matrix != nullptr, FALSE);
-
- /*
- * <Formula>
- *
- * Input: Unsigned normalized non-linear R'G'B'(unorm), [0.0..1.0] range
- * Output: Unsigned normalized Y'CbCr(unorm), [0.0..1.0] range
- *
- * 1) R'G'B' to YPbPr
- * | Y | | R' |
- * | Pb | = M *| G' |
- * | Pr | | B' |
- * where
- * | vecY |
- * M = | vecU |
- * | vecV |
- * vecY = | Kr , Kg , Kb |
- * vecU = | -0.5*Kr/(1-Kb), -0.5*Kg/(1-Kb), 0.5 |
- * vecV = | 0.5 , -0.5*Kg/(1-Kr), -0.5*Kb(1-Kr) |
- *
- * 2) YPbPr to Y'CbCr(unorm)
- * Y'(unorm) = (Y * scaleY + offsetY) / S
- * Cb(unorm) = (Pb * scaleCbCr + offsetCbCr) / S
- * Cr(unorm) = (Pr * scaleCbCr + offsetCbCr) / S
- * =>
- * Y'(unorm) = (Y * scaleY / S) + (offsetY / S)
- * Cb(unorm) = (Pb * scaleCbCr / S) + (offsetCbCr / S)
- * Cr(unorm) = (Pb * scaleCbCr / S) + (offsetCbCr / S)
- * where S = (2 ^ bitdepth) - 1
- *
- * 3) RGB -> YUV matrix
- * | Y'(unorm) | | R' | | offsetA |
- * | Cb(unorm) | = Matrix * | G' | + | offsetB |
- * | Cr(unorm) | | B' | | offsetC |
- *
- * where
- * | (scaleY/S) * vecY |
- * Matrix = | (scaleCbCr/S) * vecU |
- * | (scaleCbCr/S) * vecV |
- *
- * offsetA = offsetY / S
- * offsetB = offsetCbCr / S
- * offsetC = offsetCbCr / S
- *
- * 4) Consider 16-235 scale RGB
- * RGBstudio(16..235) -> RGBfull(0..255) matrix is represented by
- * | Rf | | Rs | | Or |
- * | Gf | = Ms | Gs | + | Og |
- * | Bf | | Bs | | Ob |
- *
- * Combining all matrix into
- * | Y'(unorm) | | Rs | | Or | | offsetA |
- * | Cb(unorm) | = Matrix * ( Ms | Gs | + | Og | ) + | offsetB |
- * | Cr(unorm) | | Bs | | Ob | | offsetC |
- *
- * | Rs | | Or | | offsetA |
- * = Matrix * Ms | Gs | + Matrix | Og | + | offsetB |
- * | Bs | | Ob | | offsetB |
- */
-
- memset (matrix, 0, sizeof (GstD3D11ColorMatrix));
- for (guint i = 0; i < 3; i++)
- matrix->max[i] = 1.0;
-
- gst_video_color_range_offsets (out_yuv_info->colorimetry.range,
- out_yuv_info->finfo, offset, scale);
-
- if (gst_video_color_matrix_get_Kr_Kb (out_yuv_info->colorimetry.matrix,
- &Kr, &Kb)) {
- guint S;
- gdouble Sy, Suv;
- gdouble Oy, Ouv;
- gdouble vecY[3], vecU[3], vecV[3];
-
- Kg = 1.0 - Kr - Kb;
-
- vecY[0] = Kr;
- vecY[1] = Kg;
- vecY[2] = Kb;
-
- vecU[0] = -0.5 * Kr / (1 - Kb);
- vecU[1] = -0.5 * Kg / (1 - Kb);
- vecU[2] = 0.5;
-
- vecV[0] = 0.5;
- vecV[1] = -0.5 * Kg / (1 - Kr);
- vecV[2] = -0.5 * Kb / (1 - Kr);
-
- /* Assume all components has the same bitdepth */
- S = (1 << out_yuv_info->finfo->depth[0]) - 1;
- Sy = (gdouble) scale[0] / S;
- Suv = (gdouble) scale[1] / S;
- Oy = (gdouble) offset[0] / S;
- Ouv = (gdouble) offset[1] / S;
-
- for (guint i = 0; i < 3; i++) {
- matrix->matrix[0][i] = Sy * vecY[i];
- matrix->matrix[1][i] = Suv * vecU[i];
- matrix->matrix[2][i] = Suv * vecV[i];
- }
-
- matrix->offset[0] = Oy;
- matrix->offset[1] = Ouv;
- matrix->offset[2] = Ouv;
-
- matrix->min[0] = Oy;
- matrix->min[1] = Oy;
- matrix->min[2] = Oy;
-
- matrix->max[0] = ((gdouble) scale[0] + offset[0]) / S;
- matrix->max[1] = ((gdouble) scale[1] + offset[0]) / S;
- matrix->max[2] = ((gdouble) scale[1] + offset[0]) / S;
-
- /* Apply RGB range scale matrix */
- if (in_rgb_info->colorimetry.range == GST_VIDEO_COLOR_RANGE_16_235) {
- GstD3D11ColorMatrix scale_matrix, rst;
- GstVideoInfo full_rgb = *in_rgb_info;
-
- full_rgb.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
-
- if (gst_d3d11_color_range_adjust_matrix_unorm (in_rgb_info,
- &full_rgb, &scale_matrix)) {
- /* Matrix * Ms */
- color_matrix_multiply (&rst, matrix, &scale_matrix);
-
- /* Matrix * scale offsets */
- for (guint i = 0; i < 3; i++) {
- gdouble val = 0;
- for (guint j = 0; j < 3; j++) {
- val += matrix->matrix[i][j] * scale_matrix.offset[j];
- }
- rst.offset[i] = val + matrix->offset[i];
- }
-
- /* copy back to output matrix */
- for (guint i = 0; i < 3; i++) {
- for (guint j = 0; j < 3; j++) {
- matrix->matrix[i][j] = rst.matrix[i][j];
- }
- matrix->offset[i] = rst.offset[i];
- }
- }
- }
- } else {
- /* Unknown matrix */
- matrix->matrix[0][0] = 1.0;
- matrix->matrix[1][1] = 1.0;
- matrix->matrix[2][2] = 1.0;
- }
-
- return TRUE;
-}
-
-static gboolean
-rgb_to_xyz_matrix (const GstVideoColorPrimariesInfo * info,
- GstD3D11ColorMatrix * matrix)
-{
- GstD3D11ColorMatrix m, im;
- gdouble Sr, Sg, Sb;
- gdouble Xw, Yw, Zw;
-
- if (info->Rx == 0 || info->Gx == 0 || info->By == 0 || info->Wy == 0)
- return FALSE;
-
- color_matrix_identity (&m);
-
- m.matrix[0][0] = info->Rx / info->Ry;
- m.matrix[1][0] = 1.0;
- m.matrix[2][0] = (1.0 - info->Rx - info->Ry) / info->Ry;
-
- m.matrix[0][1] = info->Gx / info->Gy;
- m.matrix[1][1] = 1.0;
- m.matrix[2][1] = (1.0 - info->Gx - info->Gy) / info->Gy;
-
- m.matrix[0][2] = info->Bx / info->By;
- m.matrix[1][2] = 1.0;
- m.matrix[2][2] = (1.0 - info->Bx - info->By) / info->By;
-
- if (!color_matrix_invert (&im, &m))
- return FALSE;
-
- Xw = info->Wx / info->Wy;
- Yw = 1.0;
- Zw = (1.0 - info->Wx - info->Wy) / info->Wy;
-
- Sr = im.matrix[0][0] * Xw + im.matrix[0][1] * Yw + im.matrix[0][2] * Zw;
- Sg = im.matrix[1][0] * Xw + im.matrix[1][1] * Yw + im.matrix[1][2] * Zw;
- Sb = im.matrix[2][0] * Xw + im.matrix[2][1] * Yw + im.matrix[2][2] * Zw;
-
- for (guint i = 0; i < 3; i++) {
- m.matrix[i][0] *= Sr;
- m.matrix[i][1] *= Sg;
- m.matrix[i][2] *= Sb;
- }
-
- color_matrix_copy (matrix, &m);
-
- return TRUE;
-}
-
-/**
- * gst_d3d11_color_primaries_matrix_unorm:
- * @in_info: a #GstVideoColorPrimariesInfo of input signal
- * @out_info: a #GstVideoColorPrimariesInfo of output signal
- * @matrix: a #GstD3D11ColorMatrix
- *
- * Calculates color primaries conversion matrix
- *
- * Resulting RGB values can be calculated by
- * | Rout | | Rin |
- * | Gout | = saturate ( matrix.matrix * | Gin | )
- * | Bout | | Bin |
- *
- * Returns: %TRUE if successful
- */
-gboolean
-gst_d3d11_color_primaries_matrix_unorm (const GstVideoColorPrimariesInfo *
- in_info, const GstVideoColorPrimariesInfo * out_info,
- GstD3D11ColorMatrix * matrix)
-{
- GstD3D11ColorMatrix Ms, invMd, ret;
-
- g_return_val_if_fail (in_info != nullptr, FALSE);
- g_return_val_if_fail (out_info != nullptr, FALSE);
- g_return_val_if_fail (matrix != nullptr, FALSE);
-
- /*
- * <Formula>
- *
- * 1) RGB -> XYZ conversion
- * | X | | R |
- * | Y | = M | G |
- * | Z | | B |
- * where
- * | SrXr, SgXg, SbXb |
- * M = | SrYr, SgYg, SbYb |
- * | SrZr, SgZg, SbZb |
- *
- * Xr = xr / yr
- * Yr = 1
- * Zr = (1 - xr - yr) / yr
- * xr and yr are xy coordinates of red primary in the CIE 1931 color space.
- * And its applied to G and B components
- *
- * | Sr | | Xr, Xg, Xb | | Xw |
- * | Sg | = inv( | Yr, Yg, Yb | ) * | Yw |
- * | Sb | | Zr, Zg, Zb | | Zw |
- *
- * 2) XYZsrc -> XYZdst conversion
- * Apply chromatic adaptation
- * | Xdst | | Xsrc |
- * | Ydst | = Mc | Ysrc |
- * | Zdst | | Zsrc |
- * where
- * | Xwdst / Xwsrc, 0 , 0 |
- * Mc = | 0 , Ywdst / Ywsrc, 0 |
- * | 0 , 0 , Zwdst / Zwsrc |
- *
- * where
- *
- * 3) Final matrix
- * | Rd | | Rs |
- * | Gd | = inv (Md) * Mc * Ms | Gs |
- * | Bd | | Bs |
- */
-
- memset (matrix, 0, sizeof (GstD3D11ColorMatrix));
- for (guint i = 0; i < 3; i++)
- matrix->max[i] = 1.0;
-
- if (!rgb_to_xyz_matrix (in_info, &Ms)) {
- GST_WARNING ("Failed to get src XYZ matrix");
- return FALSE;
- }
-
- if (!rgb_to_xyz_matrix (out_info, &invMd) ||
- !color_matrix_invert (&invMd, &invMd)) {
- GST_WARNING ("Failed to get dst XYZ matrix");
- return FALSE;
- }
-
- if (in_info->Wx != out_info->Wx || in_info->Wy != out_info->Wy) {
- GstD3D11ColorMatrix Mc;
-
- color_matrix_identity (&Mc);
- Mc.matrix[0][0] = (out_info->Wx / out_info->Wy) /
- (in_info->Wx / in_info->Wy);
- /* Yw == 1.0 */
- Mc.matrix[2][2] = ((1.0 - out_info->Wx - out_info->Wy) / out_info->Wy) /
- ((1.0 - in_info->Wx - in_info->Wy) / in_info->Wy);
-
- color_matrix_multiply (&ret, &Mc, &Ms);
- } else {
- color_matrix_copy (&ret, &Ms);
- }
-
- color_matrix_multiply (&ret, &invMd, &ret);
- color_matrix_copy (matrix, &ret);
-
- return TRUE;
-}
GST_D3D11_DEVICE_VENDOR_XBOX,
} GstD3D11DeviceVendor;
-typedef struct _GstD3D11ColorMatrix
-{
- gdouble matrix[3][3];
- gdouble offset[3];
- gdouble min[3];
- gdouble max[3];
-} GstD3D11ColorMatrix;
-
void gst_d3d11_plugin_utils_init (D3D_FEATURE_LEVEL feature_level);
GstCaps * gst_d3d11_get_updated_template_caps (GstStaticCaps * template_caps);
guint min_buffers,
guint max_buffers);
-gchar * gst_d3d11_dump_color_matrix (GstD3D11ColorMatrix * matrix);
-
-gboolean gst_d3d11_color_range_adjust_matrix_unorm (const GstVideoInfo * in_info,
- const GstVideoInfo * out_info,
- GstD3D11ColorMatrix * matrix);
-
-gboolean gst_d3d11_yuv_to_rgb_matrix_unorm (const GstVideoInfo * in_yuv_info,
- const GstVideoInfo * out_rgb_info,
- GstD3D11ColorMatrix * matrix);
-
-gboolean gst_d3d11_rgb_to_yuv_matrix_unorm (const GstVideoInfo * in_rgb_info,
- const GstVideoInfo * out_yuv_info,
- GstD3D11ColorMatrix * matrix);
-
-gboolean gst_d3d11_color_primaries_matrix_unorm (const GstVideoColorPrimariesInfo * in_info,
- const GstVideoColorPrimariesInfo * out_info,
- GstD3D11ColorMatrix * matrix);
-
G_END_DECLS
#endif /* __GST_D3D11_PLUGIN_UTILS_H__ */
#include "gstd3d11testsrc.h"
#include "gstd3d11pluginutils.h"
-#include "gstd3d11converter.h"
#include <wrl.h>
#include <string.h>
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/d3d11/gstd3d11.h>
-#include "gstd3d11converter.h"
#include "gstd3d11overlaycompositor.h"
#include "gstd3d11pluginutils.h"
'gstd3d11basefilter.cpp',
'gstd3d11compositor.cpp',
'gstd3d11convert.cpp',
- 'gstd3d11converter.cpp',
'gstd3d11decoder.cpp',
'gstd3d11deinterlace.cpp',
'gstd3d11download.cpp',