mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-19 14:56:36 +00:00
d3d11: Move GstD3D11Converter to gst-libs
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>
This commit is contained in:
parent
32eeadb4a5
commit
1c3fac818d
15 changed files with 870 additions and 799 deletions
|
@ -29,6 +29,7 @@
|
|||
#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>
|
||||
|
|
|
@ -59,5 +59,9 @@ typedef struct _GstD3D11StagingBufferPoolPrivate GstD3D11StagingBufferPoolPrivat
|
|||
|
||||
typedef struct _GstD3D11Format GstD3D11Format;
|
||||
|
||||
typedef struct _GstD3D11Converter GstD3D11Converter;
|
||||
typedef struct _GstD3D11ConverterClass GstD3D11ConverterClass;
|
||||
typedef struct _GstD3D11ConverterPrivate GstD3D11ConverterPrivate;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
|
|
@ -111,6 +111,37 @@ static const GstD3D11Format _gst_d3d11_default_format_map[] = {
|
|||
|
||||
#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
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* 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
|
||||
|
@ -22,8 +23,13 @@
|
|||
# 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>
|
||||
|
@ -2860,6 +2866,23 @@ gst_d3d11_converter_setup_processor (GstD3D11Converter * self)
|
|||
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)
|
||||
|
@ -3815,6 +3838,18 @@ out:
|
|||
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)
|
||||
|
@ -3829,6 +3864,21 @@ gst_d3d11_converter_convert_buffer (GstD3D11Converter * converter,
|
|||
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)
|
|
@ -1,5 +1,6 @@
|
|||
/* 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
|
||||
|
@ -17,12 +18,11 @@
|
|||
* 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
|
||||
|
||||
|
@ -34,17 +34,31 @@ 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
|
||||
|
@ -66,23 +80,23 @@ struct _GstD3D11ConverterClass
|
|||
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__ */
|
|
@ -913,3 +913,758 @@ gst_video_info_apply_dxgi_color_space (DXGI_COLOR_SPACE_TYPE color_space,
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
d3d11_sources = [
|
||||
'gstd3d11bufferpool.cpp',
|
||||
'gstd3d11compile.cpp',
|
||||
'gstd3d11converter.cpp',
|
||||
'gstd3d11device.cpp',
|
||||
'gstd3d11format.cpp',
|
||||
'gstd3d11memory.cpp',
|
||||
|
@ -12,6 +13,7 @@ d3d11_headers = [
|
|||
'gstd3d11_fwd.h',
|
||||
'gstd3d11.h',
|
||||
'gstd3d11bufferpool.h',
|
||||
'gstd3d11converter.h',
|
||||
'gstd3d11device.h',
|
||||
'gstd3d11format.h',
|
||||
'gstd3d11memory.h',
|
||||
|
@ -21,6 +23,7 @@ d3d11_headers = [
|
|||
d3d11_enum_types_headers = [
|
||||
'gstd3d11_fwd.h',
|
||||
'gstd3d11bufferpool.h',
|
||||
'gstd3d11converter.h',
|
||||
'gstd3d11device.h',
|
||||
'gstd3d11format.h',
|
||||
'gstd3d11memory.h',
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
#endif
|
||||
|
||||
#include "gstd3d11compositor.h"
|
||||
#include "gstd3d11converter.h"
|
||||
#include "gstd3d11pluginutils.h"
|
||||
#include <string.h>
|
||||
#include <wrl.h>
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#endif
|
||||
|
||||
#include "gstd3d11convert.h"
|
||||
#include "gstd3d11converter.h"
|
||||
#include "gstd3d11pluginutils.h"
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_d3d11_convert_debug);
|
||||
|
|
|
@ -52,7 +52,6 @@
|
|||
#endif
|
||||
|
||||
#include "gstd3d11decoder.h"
|
||||
#include "gstd3d11converter.h"
|
||||
#include "gstd3d11pluginutils.h"
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
|
|
@ -655,758 +655,3 @@ gst_d3d11_buffer_pool_new_with_options (GstD3D11Device * device,
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -38,14 +38,6 @@ typedef enum
|
|||
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);
|
||||
|
@ -95,24 +87,6 @@ GstBufferPool * gst_d3d11_buffer_pool_new_with_options (GstD3D11Device * device
|
|||
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__ */
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
|
||||
#include "gstd3d11testsrc.h"
|
||||
#include "gstd3d11pluginutils.h"
|
||||
#include "gstd3d11converter.h"
|
||||
#include <wrl.h>
|
||||
#include <string.h>
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include <gst/gst.h>
|
||||
#include <gst/video/video.h>
|
||||
#include <gst/d3d11/gstd3d11.h>
|
||||
#include "gstd3d11converter.h"
|
||||
#include "gstd3d11overlaycompositor.h"
|
||||
#include "gstd3d11pluginutils.h"
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ d3d11_sources = [
|
|||
'gstd3d11basefilter.cpp',
|
||||
'gstd3d11compositor.cpp',
|
||||
'gstd3d11convert.cpp',
|
||||
'gstd3d11converter.cpp',
|
||||
'gstd3d11decoder.cpp',
|
||||
'gstd3d11deinterlace.cpp',
|
||||
'gstd3d11download.cpp',
|
||||
|
|
Loading…
Reference in a new issue