2 * Copyright (C) 2020 Seungha Yang <seungha@centricular.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
24 #include "gstd3d11format.h"
25 #include "gstd3d11utils.h"
26 #include "gstd3d11device.h"
27 #include "gstd3d11memory.h"
28 #include "gstd3d11-private.h"
33 * SECTION:gstd3d11format
34 * @title: GstD3D11Format
35 * @short_description: Bridge of Direct3D11 and GStreamer video format representation
40 #ifndef GST_DISABLE_GST_DEBUG
41 #define GST_CAT_DEFAULT ensure_debug_category()
42 static GstDebugCategory *
43 ensure_debug_category (void)
45 static GstDebugCategory *cat = nullptr;
47 GST_D3D11_CALL_ONCE_BEGIN {
48 cat = _gst_debug_category_new ("d3d11format", 0, "d3d11 specific formats");
49 } GST_D3D11_CALL_ONCE_END;
54 #define ensure_debug_category() /* NOOP */
55 #endif /* GST_DISABLE_GST_DEBUG */
58 gst_d3d11_format_support_get_type (void)
60 static GType support_type = 0;
61 static const GFlagsValue support_values[] = {
62 {D3D11_FORMAT_SUPPORT_BUFFER, "BUFFER", "buffer"},
63 {D3D11_FORMAT_SUPPORT_IA_VERTEX_BUFFER, "IA_VERTEX_BUFFER",
65 {D3D11_FORMAT_SUPPORT_IA_INDEX_BUFFER, "IA_INDEX_BUFFER",
67 {D3D11_FORMAT_SUPPORT_SO_BUFFER, "SO_BUFFER", "so-buffer"},
68 {D3D11_FORMAT_SUPPORT_TEXTURE1D, "TEXTURE1D", "texture1d"},
69 {D3D11_FORMAT_SUPPORT_TEXTURE2D, "TEXTURE2D", "texture2d"},
70 {D3D11_FORMAT_SUPPORT_TEXTURE3D, "TEXTURE3D", "texture3d"},
71 {D3D11_FORMAT_SUPPORT_TEXTURECUBE, "TEXTURECUBE", "texturecube"},
72 {D3D11_FORMAT_SUPPORT_SHADER_LOAD, "SHADER_LOAD", "shader-load"},
73 {D3D11_FORMAT_SUPPORT_SHADER_SAMPLE, "SHADER_SAMPLE", "shader-sample"},
74 {D3D11_FORMAT_SUPPORT_SHADER_SAMPLE_COMPARISON, "SHADER_COMPARISION",
75 "shader-comparision"},
76 {D3D11_FORMAT_SUPPORT_SHADER_SAMPLE_MONO_TEXT, "SHADER_SAMPLE_MONO_TEXT",
77 "shader-sample-mono-text"},
78 {D3D11_FORMAT_SUPPORT_MIP, "MIP", "mip"},
79 {D3D11_FORMAT_SUPPORT_MIP_AUTOGEN, "MIP_AUTOGEN", "mip-autogen"},
80 {D3D11_FORMAT_SUPPORT_RENDER_TARGET, "RENDER_TARGET", "render-target"},
81 {D3D11_FORMAT_SUPPORT_BLENDABLE, "BLANDABLE", "blandable"},
82 {D3D11_FORMAT_SUPPORT_DEPTH_STENCIL, "DEPTH_STENCIL", "depth-stencil"},
83 {D3D11_FORMAT_SUPPORT_CPU_LOCKABLE, "CPU_LOCKABLE", "cpu-lockable"},
84 {D3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE, "MULTISAMPLE_RESOLVE",
85 "multisample-resolve"},
86 {D3D11_FORMAT_SUPPORT_DISPLAY, "DISPLAY", "display"},
87 {D3D11_FORMAT_SUPPORT_CAST_WITHIN_BIT_LAYOUT, "CAST_WITHIN_BIT_LAYOUT",
88 "cast-within-bit-layout"},
89 {D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET, "MULTISAMPLE_RENDERTARGET",
90 "multisample-rendertarget"},
91 {D3D11_FORMAT_SUPPORT_MULTISAMPLE_LOAD, "MULTISAMPLE_LOAD",
93 {D3D11_FORMAT_SUPPORT_SHADER_GATHER, "SHADER_GATHER", "shader-gether"},
94 {D3D11_FORMAT_SUPPORT_BACK_BUFFER_CAST, "BACK_BUFFER_CAST",
96 {D3D11_FORMAT_SUPPORT_TYPED_UNORDERED_ACCESS_VIEW, "UNORDERED_ACCESS_VIEW",
97 "unordered-access-view"},
98 {D3D11_FORMAT_SUPPORT_SHADER_GATHER_COMPARISON, "SHADER_GATHER_COMPARISON",
99 "shader-gether-comparision"},
100 {D3D11_FORMAT_SUPPORT_DECODER_OUTPUT, "DECODER_OUTPUT", "decoder-output"},
101 {D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_OUTPUT, "VIDEO_PROCESSOR_OUTPUT",
102 "video-processor-output"},
103 {D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_INPUT, "VIDEO_PROCESSOR_INPUT",
104 "video-processor-input"},
105 {D3D11_FORMAT_SUPPORT_VIDEO_ENCODER, "VIDEO_ENCODER", "video-encoder"},
106 {0, nullptr, nullptr}
109 GST_D3D11_CALL_ONCE_BEGIN {
110 support_type = g_flags_register_static ("GstD3D11FormatSupport",
112 } GST_D3D11_CALL_ONCE_END;
118 * gst_d3d11_dxgi_format_get_size:
119 * @format: a DXGI_FORMAT
120 * @width: a texture width
121 * @height: a texture height
122 * @pitch: a pitch of texture
123 * @offset: offset for each plane
124 * @stride: stride for each plane
125 * @size: (out): required memory size for given format
127 * Calculate required memory size and per plane stride with
128 * based on information
130 * Returns: %TRUE if @size can be calculated with given information
135 gst_d3d11_dxgi_format_get_size (DXGI_FORMAT format, guint width, guint height,
136 guint pitch, gsize offset[GST_VIDEO_MAX_PLANES],
137 gint stride[GST_VIDEO_MAX_PLANES], gsize * size)
139 g_return_val_if_fail (format != DXGI_FORMAT_UNKNOWN, FALSE);
142 case DXGI_FORMAT_B8G8R8A8_UNORM:
143 case DXGI_FORMAT_R8G8B8A8_UNORM:
144 case DXGI_FORMAT_R10G10B10A2_UNORM:
145 case DXGI_FORMAT_AYUV:
146 case DXGI_FORMAT_YUY2:
147 case DXGI_FORMAT_R8_UNORM:
148 case DXGI_FORMAT_R8G8_UNORM:
149 case DXGI_FORMAT_R16_UNORM:
150 case DXGI_FORMAT_R16G16_UNORM:
151 case DXGI_FORMAT_G8R8_G8B8_UNORM:
152 case DXGI_FORMAT_R8G8_B8G8_UNORM:
153 case DXGI_FORMAT_Y210:
154 case DXGI_FORMAT_Y410:
155 case DXGI_FORMAT_R16G16B16A16_UNORM:
158 *size = pitch * height;
160 case DXGI_FORMAT_NV12:
161 case DXGI_FORMAT_P010:
162 case DXGI_FORMAT_P016:
165 offset[1] = offset[0] + stride[0] * height;
167 *size = offset[1] + stride[1] * GST_ROUND_UP_2 (height / 2);
173 GST_LOG ("Calculated buffer size: %" G_GSIZE_FORMAT
174 " (dxgi format:%d, %dx%d, Pitch %d)",
175 *size, format, width, height, pitch);
181 * gst_d3d11_dxgi_format_to_gst:
182 * @format: a DXGI_FORMAT
184 * Converts the @format to its #GstVideoFormat representation.
186 * Returns: a #GstVideoFormat equivalent to @format
191 gst_d3d11_dxgi_format_to_gst (DXGI_FORMAT format)
194 case DXGI_FORMAT_B8G8R8A8_UNORM:
195 return GST_VIDEO_FORMAT_BGRA;
196 case DXGI_FORMAT_R8G8B8A8_UNORM:
197 return GST_VIDEO_FORMAT_RGBA;
198 case DXGI_FORMAT_R10G10B10A2_UNORM:
199 return GST_VIDEO_FORMAT_RGB10A2_LE;
200 case DXGI_FORMAT_AYUV:
201 return GST_VIDEO_FORMAT_VUYA;
202 case DXGI_FORMAT_YUY2:
203 return GST_VIDEO_FORMAT_YUY2;
204 case DXGI_FORMAT_Y210:
205 return GST_VIDEO_FORMAT_Y210;
206 case DXGI_FORMAT_Y410:
207 return GST_VIDEO_FORMAT_Y410;
208 case DXGI_FORMAT_NV12:
209 return GST_VIDEO_FORMAT_NV12;
210 case DXGI_FORMAT_P010:
211 return GST_VIDEO_FORMAT_P010_10LE;
212 case DXGI_FORMAT_P016:
213 return GST_VIDEO_FORMAT_P016_LE;
218 return GST_VIDEO_FORMAT_UNKNOWN;
222 * gst_d3d11_format_init:
223 * @format: (out caller-allocates): a #GstD3D11Format
225 * Initialize @format with default values.
230 gst_d3d11_format_init (GstD3D11Format * format)
232 g_return_if_fail (format != nullptr);
234 memset (format, 0, sizeof (GstD3D11Format));
238 * gst_d3d11_dxgi_format_get_resource_format:
239 * @format: a DXGI_FORMAT
240 * @resource_format: (out caller-allocats): Resource formats for each plane
242 * Returns: the number of planes for @format
247 gst_d3d11_dxgi_format_get_resource_format (DXGI_FORMAT format,
248 DXGI_FORMAT resource_format[GST_VIDEO_MAX_PLANES])
250 for (guint i = 0; i < GST_VIDEO_MAX_PLANES; i++)
251 resource_format[i] = DXGI_FORMAT_UNKNOWN;
253 if (format == DXGI_FORMAT_UNKNOWN)
256 for (guint i = 0; i < GST_D3D11_N_FORMATS; i++) {
257 const GstD3D11Format *fmt = &_gst_d3d11_default_format_map[i];
259 if (fmt->dxgi_format == format) {
262 for (n_planes = 0; n_planes < GST_VIDEO_MAX_PLANES; n_planes++) {
263 if (fmt->resource_format[n_planes] == DXGI_FORMAT_UNKNOWN)
266 resource_format[n_planes] = fmt->resource_format[n_planes];
273 resource_format[0] = format;
278 * gst_d3d11_dxgi_format_get_alignment:
279 * @format: a DXGI_FORMAT
281 * Returns: Width and height Alignment requirement for given @format
286 gst_d3d11_dxgi_format_get_alignment (DXGI_FORMAT format)
289 case DXGI_FORMAT_NV12:
290 case DXGI_FORMAT_P010:
291 case DXGI_FORMAT_P016:
301 * gst_d3d11_dxgi_format_to_string:
302 * @format: a DXGI_FORMAT
304 * Converts @format enum value to its string representation
306 * Returns: a string representation of @format
311 gst_d3d11_dxgi_format_to_string (DXGI_FORMAT format)
314 case DXGI_FORMAT_ ##f: \
315 return G_STRINGIFY (f);
319 CASE (R32G32B32A32_TYPELESS);
320 CASE (R32G32B32A32_FLOAT);
321 CASE (R32G32B32A32_UINT);
322 CASE (R32G32B32A32_SINT);
323 CASE (R32G32B32_TYPELESS);
324 CASE (R32G32B32_FLOAT);
325 CASE (R32G32B32_UINT);
326 CASE (R32G32B32_SINT);
327 CASE (R16G16B16A16_TYPELESS);
328 CASE (R16G16B16A16_FLOAT);
329 CASE (R16G16B16A16_UNORM);
330 CASE (R16G16B16A16_UINT);
331 CASE (R16G16B16A16_SNORM);
332 CASE (R16G16B16A16_SINT);
333 CASE (R32G32_TYPELESS);
337 CASE (R32G8X24_TYPELESS);
338 CASE (D32_FLOAT_S8X24_UINT);
339 CASE (R32_FLOAT_X8X24_TYPELESS);
340 CASE (X32_TYPELESS_G8X24_UINT);
341 CASE (R10G10B10A2_TYPELESS);
342 CASE (R10G10B10A2_UNORM);
343 CASE (R10G10B10A2_UINT);
344 CASE (R11G11B10_FLOAT);
345 CASE (R8G8B8A8_TYPELESS);
346 CASE (R8G8B8A8_UNORM);
347 CASE (R8G8B8A8_UNORM_SRGB);
348 CASE (R8G8B8A8_UINT);
349 CASE (R8G8B8A8_SNORM);
350 CASE (R8G8B8A8_SINT);
351 CASE (R16G16_TYPELESS);
362 CASE (R24G8_TYPELESS);
363 CASE (D24_UNORM_S8_UINT);
364 CASE (R24_UNORM_X8_TYPELESS);
365 CASE (X24_TYPELESS_G8_UINT);
366 CASE (R8G8_TYPELESS);
385 CASE (R9G9B9E5_SHAREDEXP);
386 CASE (R8G8_B8G8_UNORM);
387 CASE (G8R8_G8B8_UNORM);
390 CASE (BC1_UNORM_SRGB);
393 CASE (BC2_UNORM_SRGB);
396 CASE (BC3_UNORM_SRGB);
404 CASE (B5G5R5A1_UNORM);
405 CASE (B8G8R8A8_UNORM);
406 CASE (B8G8R8X8_UNORM);
407 CASE (R10G10B10_XR_BIAS_A2_UNORM);
408 CASE (B8G8R8A8_TYPELESS);
409 CASE (B8G8R8A8_UNORM_SRGB);
410 CASE (B8G8R8X8_TYPELESS);
411 CASE (B8G8R8X8_UNORM_SRGB);
412 CASE (BC6H_TYPELESS);
417 CASE (BC7_UNORM_SRGB);
424 case DXGI_FORMAT_420_OPAQUE:
434 CASE (B4G4R4A4_UNORM);
446 /* Some values are not defined in old MinGW toolchain */
449 GST_DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 = 0,
450 GST_DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709 = 1,
451 GST_DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709 = 2,
452 GST_DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020 = 3,
453 GST_DXGI_COLOR_SPACE_RESERVED = 4,
454 GST_DXGI_COLOR_SPACE_YCBCR_FULL_G22_NONE_P709_X601 = 5,
455 GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601 = 6,
456 GST_DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P601 = 7,
457 GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709 = 8,
458 GST_DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P709 = 9,
459 GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P2020 = 10,
460 GST_DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020 = 11,
461 GST_DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 = 12,
462 GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_LEFT_P2020 = 13,
463 GST_DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020 = 14,
464 GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_TOPLEFT_P2020 = 15,
465 GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_TOPLEFT_P2020 = 16,
466 GST_DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020 = 17,
467 GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_GHLG_TOPLEFT_P2020 = 18,
468 GST_DXGI_COLOR_SPACE_YCBCR_FULL_GHLG_TOPLEFT_P2020 = 19,
469 GST_DXGI_COLOR_SPACE_RGB_STUDIO_G24_NONE_P709 = 20,
470 GST_DXGI_COLOR_SPACE_RGB_STUDIO_G24_NONE_P2020 = 21,
471 GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_LEFT_P709 = 22,
472 GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_LEFT_P2020 = 23,
473 GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_TOPLEFT_P2020 = 24,
474 } GST_DXGI_COLOR_SPACE_TYPE;
477 rgb_to_colorspace (const GstVideoColorimetry * cinfo,
478 DXGI_COLOR_SPACE_TYPE * color_space)
481 GST_DXGI_COLOR_SPACE_TYPE type = GST_DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
483 /* Defined DXGI RGB colorspace
484 * 1) DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 = 0 (sRGB)
485 * 2) DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709 = 1 (scRGB)
486 * 3) DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709 = 2 (BT601/BT709 studio range)
487 * 4) DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020 = 3 (BT2020 SDR studio range)
488 * 5) DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 = 12 (HDR10 full range)
489 * 6) DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020 = 13 (HDR10 studio range)
490 * 7) DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020 = 17 (BT2020 SDR fullrange)
491 * 8) DXGI_COLOR_SPACE_RGB_STUDIO_G24_NONE_P709 = 20 (unused)
492 * 9) DXGI_COLOR_SPACE_RGB_STUDIO_G24_NONE_P2020 = 21 (unused)
494 * Note that GStreamer does not define gamma2.4. So, 8) and 9) are excluded
496 if (cinfo->transfer == GST_VIDEO_TRANSFER_GAMMA10) {
497 type = GST_DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;
501 /* HLG RGB colorspace is not defined, approximated to HDR10 */
502 if (cinfo->transfer == GST_VIDEO_TRANSFER_SMPTE2084 ||
503 cinfo->transfer == GST_VIDEO_TRANSFER_ARIB_STD_B67) {
504 if (cinfo->range == GST_VIDEO_COLOR_RANGE_16_235) {
505 type = GST_DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020;
507 type = GST_DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
512 if (cinfo->primaries == GST_VIDEO_COLOR_PRIMARIES_BT2020) {
513 if (cinfo->range == GST_VIDEO_COLOR_RANGE_16_235) {
514 type = GST_DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020;
516 type = GST_DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020;
521 if (cinfo->range == GST_VIDEO_COLOR_RANGE_16_235)
522 type = GST_DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709;
525 *color_space = (DXGI_COLOR_SPACE_TYPE) type;
531 yuv_to_colorspace (const GstVideoColorimetry * cinfo,
532 GstVideoChromaSite chroma_site, DXGI_COLOR_SPACE_TYPE * color_space)
535 GST_DXGI_COLOR_SPACE_TYPE type =
536 GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709;
538 /* Defined DXGI RGB colorspace
539 * 1) DXGI_COLOR_SPACE_YCBCR_FULL_G22_NONE_P709_X601 = 5 (common JPG)
540 * 2) DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601 = 6 (BT601 studio range)
541 * 3) DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P601 = 7 (BT601 full range)
542 * 4) DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709 = 8 (BT709 studio range)
543 * 5) DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P709 = 9 (BT709 full range)
544 * 6) DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P2020 = 10 (BT2020 4:2:0 studio range)
545 * 7) DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020 = 11 (BT2020 full range)
546 * 8) DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_LEFT_P2020 = 13 (HDR10 4:2:0 studio range)
547 * 9) DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_TOPLEFT_P2020 = 15 (BT2020 4:2:2 or 4:4:4: studio range)
548 * 10) DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_TOPLEFT_P2020 = 16 (HDR10 4:2:2 or 4:4:4 studio range)
549 * 11) DXGI_COLOR_SPACE_YCBCR_STUDIO_GHLG_TOPLEFT_P2020 = 18 (HLG studio range)
550 * 12) DXGI_COLOR_SPACE_YCBCR_FULL_GHLG_TOPLEFT_P2020 = 19 (HLG full range)
551 * 13) DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_LEFT_P709 = 22 (unused)
552 * 14) DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_LEFT_P2020 = 23 (unused)
553 * 15) DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_TOPLEFT_P2020 = 24 (unused)
555 * Note that GStreamer does not define gamma2.4. So, 13) ~ 15) are excluded
559 if (cinfo->transfer == GST_VIDEO_TRANSFER_ARIB_STD_B67) {
560 if (cinfo->range == GST_VIDEO_COLOR_RANGE_0_255) {
561 type = GST_DXGI_COLOR_SPACE_YCBCR_FULL_GHLG_TOPLEFT_P2020;
563 type = GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_GHLG_TOPLEFT_P2020;
569 if (cinfo->transfer == GST_VIDEO_TRANSFER_SMPTE2084) {
570 if (chroma_site == GST_VIDEO_CHROMA_SITE_H_COSITED) {
571 type = GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_LEFT_P2020;
573 type = GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_TOPLEFT_P2020;
579 if (cinfo->primaries == GST_VIDEO_COLOR_PRIMARIES_BT2020) {
580 if (cinfo->range == GST_VIDEO_COLOR_RANGE_0_255) {
581 type = GST_DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020;
582 } else if (chroma_site == GST_VIDEO_CHROMA_SITE_H_COSITED) {
583 type = GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P2020;
585 type = GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_TOPLEFT_P2020;
590 /* BT601/BT709 primaries are similar. Depends on RGB matrix */
591 if (cinfo->matrix == GST_VIDEO_COLOR_MATRIX_BT601) {
592 if (cinfo->range == GST_VIDEO_COLOR_RANGE_0_255) {
593 if (cinfo->primaries == GST_VIDEO_COLOR_PRIMARIES_BT709) {
594 type = GST_DXGI_COLOR_SPACE_YCBCR_FULL_G22_NONE_P709_X601;
596 type = GST_DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P601;
599 type = GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601;
604 if (cinfo->range == GST_VIDEO_COLOR_RANGE_0_255)
605 type = GST_DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P709;
608 *color_space = (DXGI_COLOR_SPACE_TYPE) type;
614 * gst_video_info_to_dxgi_color_space:
615 * @info: a #GstVideoInfo
616 * @color_space: (out): DXGI color space
618 * Derives DXGI_COLOR_SPACE_TYPE from @info
620 * Returns: %TRUE if successful
625 gst_video_info_to_dxgi_color_space (const GstVideoInfo * info,
626 DXGI_COLOR_SPACE_TYPE * color_space)
628 const GstVideoColorimetry *cinfo;
629 GstVideoColorimetry c;
631 g_return_val_if_fail (info != nullptr, FALSE);
632 g_return_val_if_fail (color_space != nullptr, FALSE);
634 cinfo = &info->colorimetry;
636 if (GST_VIDEO_INFO_IS_RGB (info)) {
637 /* ensure RGB matrix if format is already RGB */
638 c.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
639 } else if (GST_VIDEO_INFO_IS_YUV (info) &&
640 cinfo->matrix == GST_VIDEO_COLOR_MATRIX_RGB) {
642 c.matrix = GST_VIDEO_COLOR_MATRIX_UNKNOWN;
644 c.matrix = cinfo->matrix;
647 switch (cinfo->range) {
648 case GST_VIDEO_COLOR_RANGE_0_255:
649 c.range = GST_VIDEO_COLOR_RANGE_0_255;
651 case GST_VIDEO_COLOR_RANGE_16_235:
652 c.range = GST_VIDEO_COLOR_RANGE_16_235;
655 if (c.matrix == GST_VIDEO_COLOR_MATRIX_RGB)
656 c.range = GST_VIDEO_COLOR_RANGE_0_255;
658 c.range = GST_VIDEO_COLOR_RANGE_16_235;
662 /* DXGI primaries: BT601, BT709, BT2020 */
663 switch (cinfo->primaries) {
664 case GST_VIDEO_COLOR_PRIMARIES_BT2020:
665 c.primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
667 case GST_VIDEO_COLOR_PRIMARIES_SMPTE170M:
668 case GST_VIDEO_COLOR_PRIMARIES_SMPTE240M:
669 c.primaries = GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
672 c.primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
676 /* DXGI gamma functions: linear (RGB only), gamma2.2, PQ, and HLG */
677 switch (cinfo->transfer) {
678 case GST_VIDEO_TRANSFER_SMPTE2084:
679 c.transfer = GST_VIDEO_TRANSFER_SMPTE2084;
681 case GST_VIDEO_TRANSFER_ARIB_STD_B67:
682 c.transfer = GST_VIDEO_TRANSFER_ARIB_STD_B67;
684 case GST_VIDEO_TRANSFER_GAMMA10:
685 /* Only DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709 supports linear gamma */
686 if (c.matrix == GST_VIDEO_COLOR_MATRIX_RGB) {
687 c.transfer = GST_VIDEO_TRANSFER_GAMMA10;
688 c.range = GST_VIDEO_COLOR_RANGE_0_255;
690 c.transfer = GST_VIDEO_TRANSFER_GAMMA22;
694 /* Simply map the rest of values to gamma 2.2. We don't have any other
696 c.transfer = GST_VIDEO_TRANSFER_GAMMA22;
700 /* DXGI transform matrix: BT601, BT709, and BT2020 */
702 case GST_VIDEO_COLOR_MATRIX_RGB:
703 c.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
705 case GST_VIDEO_COLOR_MATRIX_FCC:
706 case GST_VIDEO_COLOR_MATRIX_BT601:
707 c.matrix = GST_VIDEO_COLOR_MATRIX_BT601;
709 case GST_VIDEO_COLOR_MATRIX_BT2020:
710 c.matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
713 c.matrix = GST_VIDEO_COLOR_MATRIX_BT709;
717 if (c.matrix == GST_VIDEO_COLOR_MATRIX_RGB)
718 return rgb_to_colorspace (&c, color_space);
720 return yuv_to_colorspace (&c, info->chroma_site, color_space);
724 dxgi_color_space_is_rgb (GST_DXGI_COLOR_SPACE_TYPE color_space)
726 switch (color_space) {
727 case GST_DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709:
728 case GST_DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709:
729 case GST_DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709:
730 case GST_DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020:
731 case GST_DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020:
732 case GST_DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020:
733 case GST_DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020:
734 case GST_DXGI_COLOR_SPACE_RGB_STUDIO_G24_NONE_P709:
735 case GST_DXGI_COLOR_SPACE_RGB_STUDIO_G24_NONE_P2020:
745 * gst_video_info_apply_dxgi_color_space:
746 * @color_space: DXGI color space
747 * @info: (inout): a #GstVideoInfo
749 * Updates color information of @info using @color_space
751 * Returns: %TRUE if successful
756 gst_video_info_apply_dxgi_color_space (DXGI_COLOR_SPACE_TYPE color_space,
759 GST_DXGI_COLOR_SPACE_TYPE type;
760 GstVideoColorimetry c;
762 g_return_val_if_fail (info != nullptr, FALSE);
764 type = (GST_DXGI_COLOR_SPACE_TYPE) color_space;
766 if (GST_VIDEO_INFO_IS_RGB (info) && !dxgi_color_space_is_rgb (type)) {
767 GST_WARNING ("Invalid DXGI color space mapping");
772 case GST_DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709:
773 c.range = GST_VIDEO_COLOR_RANGE_0_255;
774 c.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
775 c.transfer = GST_VIDEO_TRANSFER_SRGB;
776 c.primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
778 case GST_DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709:
779 c.range = GST_VIDEO_COLOR_RANGE_0_255;
780 c.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
781 c.transfer = GST_VIDEO_TRANSFER_GAMMA10;
782 c.primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
784 case GST_DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709:
785 case GST_DXGI_COLOR_SPACE_RGB_STUDIO_G24_NONE_P709:
786 c.range = GST_VIDEO_COLOR_RANGE_16_235;
787 c.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
788 c.transfer = GST_VIDEO_TRANSFER_BT709;
789 c.primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
791 case GST_DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020:
792 case GST_DXGI_COLOR_SPACE_RGB_STUDIO_G24_NONE_P2020:
793 c.range = GST_VIDEO_COLOR_RANGE_16_235;
794 c.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
795 if (GST_VIDEO_INFO_COMP_DEPTH (info, 0) >= 12)
796 c.transfer = GST_VIDEO_TRANSFER_BT2020_12;
798 c.transfer = GST_VIDEO_TRANSFER_BT2020_10;
799 c.primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
801 case GST_DXGI_COLOR_SPACE_RESERVED:
802 GST_WARNING ("Reserved color space");
804 case GST_DXGI_COLOR_SPACE_YCBCR_FULL_G22_NONE_P709_X601:
805 c.range = GST_VIDEO_COLOR_RANGE_0_255;
806 c.matrix = GST_VIDEO_COLOR_MATRIX_BT601;
807 c.transfer = GST_VIDEO_TRANSFER_BT601;
808 c.primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
810 case GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601:
811 c.range = GST_VIDEO_COLOR_RANGE_16_235;
812 c.matrix = GST_VIDEO_COLOR_MATRIX_BT601;
813 c.transfer = GST_VIDEO_TRANSFER_BT601;
814 c.primaries = GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
816 case GST_DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P601:
817 c.range = GST_VIDEO_COLOR_RANGE_0_255;
818 c.matrix = GST_VIDEO_COLOR_MATRIX_BT601;
819 c.transfer = GST_VIDEO_TRANSFER_BT601;
820 c.primaries = GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
822 case GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709:
823 case GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_LEFT_P709:
824 c.range = GST_VIDEO_COLOR_RANGE_16_235;
825 c.matrix = GST_VIDEO_COLOR_MATRIX_BT709;
826 c.transfer = GST_VIDEO_TRANSFER_BT709;
827 c.primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
829 case GST_DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P709:
830 c.range = GST_VIDEO_COLOR_RANGE_0_255;
831 c.matrix = GST_VIDEO_COLOR_MATRIX_BT709;
832 c.transfer = GST_VIDEO_TRANSFER_BT709;
833 c.primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
835 case GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P2020:
836 case GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_LEFT_P2020:
837 c.range = GST_VIDEO_COLOR_RANGE_16_235;
838 c.matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
839 if (GST_VIDEO_INFO_COMP_DEPTH (info, 0) >= 12)
840 c.transfer = GST_VIDEO_TRANSFER_BT2020_12;
842 c.transfer = GST_VIDEO_TRANSFER_BT2020_10;
843 c.primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
845 case GST_DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020:
846 c.range = GST_VIDEO_COLOR_RANGE_0_255;
847 c.matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
848 if (GST_VIDEO_INFO_COMP_DEPTH (info, 0) >= 12)
849 c.transfer = GST_VIDEO_TRANSFER_BT2020_12;
851 c.transfer = GST_VIDEO_TRANSFER_BT2020_10;
852 c.primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
854 case GST_DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020:
855 c.range = GST_VIDEO_COLOR_RANGE_0_255;
856 c.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
857 c.transfer = GST_VIDEO_TRANSFER_SMPTE2084;
858 c.primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
860 case GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_LEFT_P2020:
861 c.range = GST_VIDEO_COLOR_RANGE_16_235;
862 c.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
863 c.transfer = GST_VIDEO_TRANSFER_SMPTE2084;
864 c.primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
866 case GST_DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020:
867 c.range = GST_VIDEO_COLOR_RANGE_16_235;
868 c.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
869 c.transfer = GST_VIDEO_TRANSFER_SMPTE2084;
870 c.primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
872 case GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_TOPLEFT_P2020:
873 case GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_TOPLEFT_P2020:
874 c.range = GST_VIDEO_COLOR_RANGE_16_235;
875 c.matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
876 if (GST_VIDEO_INFO_COMP_DEPTH (info, 0) >= 12)
877 c.transfer = GST_VIDEO_TRANSFER_BT2020_12;
879 c.transfer = GST_VIDEO_TRANSFER_BT2020_10;
880 c.primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
882 case GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_TOPLEFT_P2020:
883 c.range = GST_VIDEO_COLOR_RANGE_16_235;
884 c.matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
885 c.transfer = GST_VIDEO_TRANSFER_SMPTE2084;
886 c.primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
888 case GST_DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020:
889 c.range = GST_VIDEO_COLOR_RANGE_0_255;
890 c.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
891 if (GST_VIDEO_INFO_COMP_DEPTH (info, 0) >= 12)
892 c.transfer = GST_VIDEO_TRANSFER_BT2020_12;
894 c.transfer = GST_VIDEO_TRANSFER_BT2020_10;
895 c.primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
897 case GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_GHLG_TOPLEFT_P2020:
898 c.range = GST_VIDEO_COLOR_RANGE_16_235;
899 c.matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
900 c.transfer = GST_VIDEO_TRANSFER_ARIB_STD_B67;
901 c.primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
903 case GST_DXGI_COLOR_SPACE_YCBCR_FULL_GHLG_TOPLEFT_P2020:
904 c.range = GST_VIDEO_COLOR_RANGE_0_255;
905 c.matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
906 c.transfer = GST_VIDEO_TRANSFER_ARIB_STD_B67;
907 c.primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
910 GST_WARNING ("Unknown DXGI color space %d", type);
914 info->colorimetry = c;
920 gst_d3d11_dump_color_matrix (GstD3D11ColorMatrix * matrix)
923 static const gchar format[] =
925 "|% .6f, % .6f, % .6f|\n"
926 "|% .6f, % .6f, % .6f|\n"
927 "|% .6f, % .6f, % .6f|\n"
929 "|% .6f, % .6f, % .6f|\n"
931 "|% .6f, % .6f, % .6f|\n"
933 "|% .6f, % .6f, % .6f|";
936 g_return_val_if_fail (matrix != nullptr, nullptr);
938 return g_strdup_printf (format,
939 matrix->matrix[0][0], matrix->matrix[0][1], matrix->matrix[0][2],
940 matrix->matrix[1][0], matrix->matrix[1][1], matrix->matrix[1][2],
941 matrix->matrix[2][0], matrix->matrix[2][1], matrix->matrix[2][2],
942 matrix->offset[0], matrix->offset[1], matrix->offset[2],
943 matrix->min[0], matrix->min[1], matrix->min[2],
944 matrix->max[0], matrix->max[1], matrix->max[2]);
948 color_matrix_copy (GstD3D11ColorMatrix * dst, const GstD3D11ColorMatrix * src)
950 for (guint i = 0; i < 3; i++) {
951 for (guint j = 0; j < 3; j++) {
952 dst->matrix[i][j] = src->matrix[i][j];
958 color_matrix_multiply (GstD3D11ColorMatrix * dst, GstD3D11ColorMatrix * a,
959 GstD3D11ColorMatrix * b)
961 GstD3D11ColorMatrix tmp;
963 for (guint i = 0; i < 3; i++) {
964 for (guint j = 0; j < 3; j++) {
966 for (guint k = 0; k < 3; k++) {
967 val += a->matrix[i][k] * b->matrix[k][j];
970 tmp.matrix[i][j] = val;
974 color_matrix_copy (dst, &tmp);
978 color_matrix_identity (GstD3D11ColorMatrix * m)
980 for (guint i = 0; i < 3; i++) {
981 for (guint j = 0; j < 3; j++) {
983 m->matrix[i][j] = 1.0;
991 color_matrix_invert (GstD3D11ColorMatrix * dst, GstD3D11ColorMatrix * src)
993 GstD3D11ColorMatrix tmp;
996 color_matrix_identity (&tmp);
997 for (guint j = 0; j < 3; j++) {
998 for (guint i = 0; i < 3; i++) {
1000 src->matrix[(i + 1) % 3][(j + 1) % 3] *
1001 src->matrix[(i + 2) % 3][(j + 2) % 3] -
1002 src->matrix[(i + 1) % 3][(j + 2) % 3] *
1003 src->matrix[(i + 2) % 3][(j + 1) % 3];
1007 det = tmp.matrix[0][0] * src->matrix[0][0] +
1008 tmp.matrix[0][1] * src->matrix[1][0] +
1009 tmp.matrix[0][2] * src->matrix[2][0];
1013 for (guint j = 0; j < 3; j++) {
1014 for (guint i = 0; i < 3; i++) {
1015 tmp.matrix[i][j] /= det;
1019 color_matrix_copy (dst, &tmp);
1025 * gst_d3d11_color_range_adjust_matrix_unorm:
1026 * @in_info: a #GstVideoInfo
1027 * @out_info: a #GstVideoInfo
1028 * @matrix: a #GstD3D11ColorMatrix
1030 * Calculates matrix for color range adjustment. Both input and output
1031 * signals are in normalized [0.0..1.0] space.
1033 * Resulting values can be calculated by
1034 * | Yout | | Yin | | matrix.offset[0] |
1035 * | Uout | = clamp ( matrix.matrix * | Uin | + | matrix.offset[1] |, matrix.min, matrix.max )
1036 * | Vout | | Vin | | matrix.offset[2] |
1038 * Returns: %TRUE if successful
1041 gst_d3d11_color_range_adjust_matrix_unorm (const GstVideoInfo * in_info,
1042 const GstVideoInfo * out_info, GstD3D11ColorMatrix * matrix)
1044 gboolean in_rgb, out_rgb;
1045 gint in_offset[GST_VIDEO_MAX_COMPONENTS];
1046 gint in_scale[GST_VIDEO_MAX_COMPONENTS];
1047 gint out_offset[GST_VIDEO_MAX_COMPONENTS];
1048 gint out_scale[GST_VIDEO_MAX_COMPONENTS];
1049 GstVideoColorRange in_range;
1050 GstVideoColorRange out_range;
1051 gdouble src_fullscale, dst_fullscale;
1053 g_return_val_if_fail (in_info != nullptr, FALSE);
1054 g_return_val_if_fail (out_info != nullptr, FALSE);
1055 g_return_val_if_fail (matrix != nullptr, FALSE);
1057 memset (matrix, 0, sizeof (GstD3D11ColorMatrix));
1058 for (guint i = 0; i < 3; i++) {
1059 matrix->matrix[i][i] = 1.0;
1060 matrix->matrix[i][i] = 1.0;
1061 matrix->matrix[i][i] = 1.0;
1062 matrix->max[i] = 1.0;
1065 in_rgb = GST_VIDEO_INFO_IS_RGB (in_info);
1066 out_rgb = GST_VIDEO_INFO_IS_RGB (out_info);
1068 if (in_rgb != out_rgb) {
1069 GST_WARNING ("Invalid format conversion");
1073 in_range = in_info->colorimetry.range;
1074 out_range = out_info->colorimetry.range;
1076 if (in_range == GST_VIDEO_COLOR_RANGE_UNKNOWN) {
1077 GST_WARNING ("Unknown input color range");
1078 if (in_rgb || GST_VIDEO_INFO_IS_GRAY (in_info))
1079 in_range = GST_VIDEO_COLOR_RANGE_0_255;
1081 in_range = GST_VIDEO_COLOR_RANGE_16_235;
1084 if (out_range == GST_VIDEO_COLOR_RANGE_UNKNOWN) {
1085 GST_WARNING ("Unknown output color range");
1086 if (out_rgb || GST_VIDEO_INFO_IS_GRAY (out_info))
1087 out_range = GST_VIDEO_COLOR_RANGE_0_255;
1089 out_range = GST_VIDEO_COLOR_RANGE_16_235;
1092 src_fullscale = (gdouble) ((1 << in_info->finfo->depth[0]) - 1);
1093 dst_fullscale = (gdouble) ((1 << out_info->finfo->depth[0]) - 1);
1095 gst_video_color_range_offsets (in_range, in_info->finfo, in_offset, in_scale);
1096 gst_video_color_range_offsets (out_range,
1097 out_info->finfo, out_offset, out_scale);
1099 matrix->min[0] = matrix->min[1] = matrix->min[2] =
1100 (gdouble) out_offset[0] / dst_fullscale;
1102 matrix->max[0] = (out_scale[0] + out_offset[0]) / dst_fullscale;
1103 matrix->max[1] = matrix->max[2] =
1104 (out_scale[1] + out_offset[0]) / dst_fullscale;
1106 if (in_info->colorimetry.range == out_info->colorimetry.range) {
1107 GST_DEBUG ("Same color range");
1113 * 1) Scales and offset compensates input to [0..1] range
1114 * SRC_NORM[i] = (src[i] * src_fullscale - in_offset[i]) / in_scale[i]
1115 * = (src[i] * src_fullscale / in_scale[i]) - in_offset[i] / in_scale[i]
1117 * 2) Reverse to output UNIT scale
1118 * DST_UINT[i] = SRC_NORM[i] * out_scale[i] + out_offset[i]
1119 * = src[i] * src_fullscale * out_scale[i] / in_scale[i]
1120 * - in_offset[i] * out_scale[i] / in_scale[i]
1123 * 3) Back to [0..1] scale
1124 * dst[i] = DST_UINT[i] / dst_fullscale
1125 * = COEFF[i] * src[i] + OFF[i]
1127 * src_fullscale * out_scale[i]
1128 * COEFF[i] = ------------------------------
1129 * dst_fullscale * in_scale[i]
1131 * out_offset[i] in_offset[i] * out_scale[i]
1132 * OFF[i] = -------------- - ------------------------------
1133 * dst_fullscale dst_fullscale * in_scale[i]
1135 for (guint i = 0; i < 3; i++) {
1136 matrix->matrix[i][i] = (src_fullscale * out_scale[i]) /
1137 (dst_fullscale * in_scale[i]);
1138 matrix->offset[i] = (out_offset[i] / dst_fullscale) -
1139 ((gdouble) in_offset[i] * out_scale[i] / (dst_fullscale * in_scale[i]));
1146 * gst_d3d11_yuv_to_rgb_matrix_unorm:
1147 * @in_yuv_info: a #GstVideoInfo of input YUV signal
1148 * @out_rgb_info: a #GstVideoInfo of output RGB signal
1149 * @matrix: a #GstD3D11ColorMatrix
1151 * Calculates transform matrix from YUV to RGB conversion. Both input and output
1152 * signals are in normalized [0.0..1.0] space and additional gamma decoding
1153 * or primary/transfer function transform is not performed by this matrix.
1155 * Resulting non-linear RGB values can be calculated by
1156 * | R' | | Y' | | matrix.offset[0] |
1157 * | G' | = clamp ( matrix.matrix * | Cb | + | matrix.offset[1] | matrix.min, matrix.max )
1158 * | B' | | Cr | | matrix.offset[2] |
1160 * Returns: %TRUE if successful
1163 gst_d3d11_yuv_to_rgb_matrix_unorm (const GstVideoInfo * in_yuv_info,
1164 const GstVideoInfo * out_rgb_info, GstD3D11ColorMatrix * matrix)
1166 gint offset[4], scale[4];
1169 g_return_val_if_fail (in_yuv_info != nullptr, FALSE);
1170 g_return_val_if_fail (out_rgb_info != nullptr, FALSE);
1171 g_return_val_if_fail (matrix != nullptr, FALSE);
1176 * Input: Unsigned normalized Y'CbCr(unorm), [0.0..1.0] range
1177 * Output: Unsigned normalized non-linear R'G'B'(unorm), [0.0..1.0] range
1179 * 1) Y'CbCr(unorm) to scaled Y'CbCr
1180 * | Y' | | Y'(unorm) |
1181 * | Cb | = S | Cb(unorm) |
1182 * | Cb | | Cr(unorm) |
1183 * where S = (2 ^ bitdepth) - 1
1185 * 2) Y'CbCr to YPbPr
1186 * Y = (Y' - offsetY ) / scaleY
1187 * Pb = [(Cb - offsetCbCr) / scaleCbCr]
1188 * Pr = [(Cr - offsetCrCr) / scaleCrCr]
1190 * Y = Y'(unorm) * Sy + Oy
1191 * Pb = Cb(unorm) * Suv + Ouv
1192 * Pb = Cr(unorm) * Suv + Ouv
1195 * Suv = S / scaleCbCr
1196 * Oy = -(offsetY / scaleY)
1197 * Ouv = -(offsetCbCr / scaleCbCr)
1199 * 3) YPbPr to R'G'B'
1201 * | G' | = M *| Pb |
1207 * vecR = | 1, 0 , 2(1 - Kr) |
1208 * vecG = | 1, -(Kb/Kg) * 2(1 - Kb), -(Kr/Kg) * 2(1 - Kr) |
1209 * vecB = | 1, 2(1 - Kb) , 0 |
1211 * R' = dot(vecR, (Syuv * Y'CbCr(unorm))) + dot(vecR, Offset)
1212 * G' = dot(vecG, (Svuy * Y'CbCr(unorm))) + dot(vecG, Offset)
1213 * B' = dot(vecB, (Syuv * Y'CbCr(unorm)) + dot(vecB, Offset)
1216 * Syuv = | 0, Suv, 0 |
1223 * 4) YUV -> RGB matrix
1224 * | R' | | Y'(unorm) | | offsetA |
1225 * | G' | = Matrix * | Cb(unorm) | + | offsetB |
1226 * | B' | | Cr(unorm) | | offsetC |
1230 * Matrix = | vecG | * Syuv
1233 * offsetA = dot(vecR, Offset)
1234 * offsetB = dot(vecG, Offset)
1235 * offsetC = dot(vecB, Offset)
1237 * 4) Consider 16-235 scale RGB
1238 * RGBfull(0..255) -> RGBfull(16..235) matrix is represented by
1239 * | Rs | | Rf | | Or |
1240 * | Gs | = Ms | Gf | + | Og |
1241 * | Bs | | Bf | | Ob |
1243 * Combining all matrix into
1244 * | Rs | | Y'(unorm) | | offsetA | | Or |
1245 * | Gs | = Ms * ( Matrix * | Cb(unorm) | + | offsetB | ) + | Og |
1246 * | Bs | | Cr(unorm) | | offsetC | | Ob |
1248 * | Y'(unorm) | | offsetA | | Or |
1249 * = Ms * Matrix * | Cb(unorm) | + Ms | offsetB | + | Og |
1250 * | Cr(unorm) | | offsetC | | Ob |
1253 memset (matrix, 0, sizeof (GstD3D11ColorMatrix));
1254 for (guint i = 0; i < 3; i++)
1255 matrix->max[i] = 1.0;
1257 gst_video_color_range_offsets (in_yuv_info->colorimetry.range,
1258 in_yuv_info->finfo, offset, scale);
1260 if (gst_video_color_matrix_get_Kr_Kb (in_yuv_info->colorimetry.matrix,
1265 gdouble vecR[3], vecG[3], vecB[3];
1271 vecR[2] = 2 * (1 - Kr);
1274 vecG[1] = -(Kb / Kg) * 2 * (1 - Kb);
1275 vecG[2] = -(Kr / Kg) * 2 * (1 - Kr);
1278 vecB[1] = 2 * (1 - Kb);
1281 /* Assume all components has the same bitdepth */
1282 S = (1 << in_yuv_info->finfo->depth[0]) - 1;
1283 Sy = (gdouble) S / scale[0];
1284 Suv = (gdouble) S / scale[1];
1285 Oy = -((gdouble) offset[0] / scale[0]);
1286 Ouv = -((gdouble) offset[1] / scale[1]);
1288 matrix->matrix[0][0] = Sy * vecR[0];
1289 matrix->matrix[1][0] = Sy * vecG[0];
1290 matrix->matrix[2][0] = Sy * vecB[0];
1292 matrix->matrix[0][1] = Suv * vecR[1];
1293 matrix->matrix[1][1] = Suv * vecG[1];
1294 matrix->matrix[2][1] = Suv * vecB[1];
1296 matrix->matrix[0][2] = Suv * vecR[2];
1297 matrix->matrix[1][2] = Suv * vecG[2];
1298 matrix->matrix[2][2] = Suv * vecB[2];
1300 matrix->offset[0] = vecR[0] * Oy + vecR[1] * Ouv + vecR[2] * Ouv;
1301 matrix->offset[1] = vecG[0] * Oy + vecG[1] * Ouv + vecG[2] * Ouv;
1302 matrix->offset[2] = vecB[0] * Oy + vecB[1] * Ouv + vecB[2] * Ouv;
1304 /* Apply RGB range scale matrix */
1305 if (out_rgb_info->colorimetry.range == GST_VIDEO_COLOR_RANGE_16_235) {
1306 GstD3D11ColorMatrix scale_matrix, rst;
1307 GstVideoInfo full_rgb = *out_rgb_info;
1309 full_rgb.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
1311 if (gst_d3d11_color_range_adjust_matrix_unorm (&full_rgb,
1312 out_rgb_info, &scale_matrix)) {
1314 color_matrix_multiply (&rst, &scale_matrix, matrix);
1316 /* Ms * transform offsets */
1317 for (guint i = 0; i < 3; i++) {
1319 for (guint j = 0; j < 3; j++) {
1320 val += scale_matrix.matrix[i][j] * matrix->offset[j];
1322 rst.offset[i] = val + scale_matrix.offset[i];
1325 /* copy back to output matrix */
1326 for (guint i = 0; i < 3; i++) {
1327 for (guint j = 0; j < 3; j++) {
1328 matrix->matrix[i][j] = rst.matrix[i][j];
1330 matrix->offset[i] = rst.offset[i];
1331 matrix->min[i] = scale_matrix.min[i];
1332 matrix->max[i] = scale_matrix.max[i];
1337 /* Unknown matrix */
1338 matrix->matrix[0][0] = 1.0;
1339 matrix->matrix[1][1] = 1.0;
1340 matrix->matrix[2][2] = 1.0;
1347 * gst_d3d11_rgb_to_yuv_matrix_unorm:
1348 * @in_rgb_info: a #GstVideoInfo of input RGB signal
1349 * @out_yuv_info: a #GstVideoInfo of output YUV signal
1350 * @matrix: a #GstD3D11ColorMatrix
1352 * Calculates transform matrix from RGB to YUV conversion. Both input and output
1353 * signals are in normalized [0.0..1.0] space and additional gamma decoding
1354 * or primary/transfer function transform is not performed by this matrix.
1356 * Resulting RGB values can be calculated by
1357 * | Y' | | R' | | matrix.offset[0] |
1358 * | Cb | = clamp ( matrix.matrix * | G' | + | matrix.offset[1] |, matrix.min, matrix.max )
1359 * | Cr | | B' | | matrix.offset[2] |
1361 * Returns: %TRUE if successful
1364 gst_d3d11_rgb_to_yuv_matrix_unorm (const GstVideoInfo * in_rgb_info,
1365 const GstVideoInfo * out_yuv_info, GstD3D11ColorMatrix * matrix)
1367 gint offset[4], scale[4];
1370 g_return_val_if_fail (in_rgb_info != nullptr, FALSE);
1371 g_return_val_if_fail (out_yuv_info != nullptr, FALSE);
1372 g_return_val_if_fail (matrix != nullptr, FALSE);
1377 * Input: Unsigned normalized non-linear R'G'B'(unorm), [0.0..1.0] range
1378 * Output: Unsigned normalized Y'CbCr(unorm), [0.0..1.0] range
1380 * 1) R'G'B' to YPbPr
1382 * | Pb | = M *| G' |
1388 * vecY = | Kr , Kg , Kb |
1389 * vecU = | -0.5*Kr/(1-Kb), -0.5*Kg/(1-Kb), 0.5 |
1390 * vecV = | 0.5 , -0.5*Kg/(1-Kr), -0.5*Kb(1-Kr) |
1392 * 2) YPbPr to Y'CbCr(unorm)
1393 * Y'(unorm) = (Y * scaleY + offsetY) / S
1394 * Cb(unorm) = (Pb * scaleCbCr + offsetCbCr) / S
1395 * Cr(unorm) = (Pr * scaleCbCr + offsetCbCr) / S
1397 * Y'(unorm) = (Y * scaleY / S) + (offsetY / S)
1398 * Cb(unorm) = (Pb * scaleCbCr / S) + (offsetCbCr / S)
1399 * Cr(unorm) = (Pb * scaleCbCr / S) + (offsetCbCr / S)
1400 * where S = (2 ^ bitdepth) - 1
1402 * 3) RGB -> YUV matrix
1403 * | Y'(unorm) | | R' | | offsetA |
1404 * | Cb(unorm) | = Matrix * | G' | + | offsetB |
1405 * | Cr(unorm) | | B' | | offsetC |
1408 * | (scaleY/S) * vecY |
1409 * Matrix = | (scaleCbCr/S) * vecU |
1410 * | (scaleCbCr/S) * vecV |
1412 * offsetA = offsetY / S
1413 * offsetB = offsetCbCr / S
1414 * offsetC = offsetCbCr / S
1416 * 4) Consider 16-235 scale RGB
1417 * RGBstudio(16..235) -> RGBfull(0..255) matrix is represented by
1418 * | Rf | | Rs | | Or |
1419 * | Gf | = Ms | Gs | + | Og |
1420 * | Bf | | Bs | | Ob |
1422 * Combining all matrix into
1423 * | Y'(unorm) | | Rs | | Or | | offsetA |
1424 * | Cb(unorm) | = Matrix * ( Ms | Gs | + | Og | ) + | offsetB |
1425 * | Cr(unorm) | | Bs | | Ob | | offsetC |
1427 * | Rs | | Or | | offsetA |
1428 * = Matrix * Ms | Gs | + Matrix | Og | + | offsetB |
1429 * | Bs | | Ob | | offsetB |
1432 memset (matrix, 0, sizeof (GstD3D11ColorMatrix));
1433 for (guint i = 0; i < 3; i++)
1434 matrix->max[i] = 1.0;
1436 gst_video_color_range_offsets (out_yuv_info->colorimetry.range,
1437 out_yuv_info->finfo, offset, scale);
1439 if (gst_video_color_matrix_get_Kr_Kb (out_yuv_info->colorimetry.matrix,
1444 gdouble vecY[3], vecU[3], vecV[3];
1452 vecU[0] = -0.5 * Kr / (1 - Kb);
1453 vecU[1] = -0.5 * Kg / (1 - Kb);
1457 vecV[1] = -0.5 * Kg / (1 - Kr);
1458 vecV[2] = -0.5 * Kb / (1 - Kr);
1460 /* Assume all components has the same bitdepth */
1461 S = (1 << out_yuv_info->finfo->depth[0]) - 1;
1462 Sy = (gdouble) scale[0] / S;
1463 Suv = (gdouble) scale[1] / S;
1464 Oy = (gdouble) offset[0] / S;
1465 Ouv = (gdouble) offset[1] / S;
1467 for (guint i = 0; i < 3; i++) {
1468 matrix->matrix[0][i] = Sy * vecY[i];
1469 matrix->matrix[1][i] = Suv * vecU[i];
1470 matrix->matrix[2][i] = Suv * vecV[i];
1473 matrix->offset[0] = Oy;
1474 matrix->offset[1] = Ouv;
1475 matrix->offset[2] = Ouv;
1477 matrix->min[0] = Oy;
1478 matrix->min[1] = Oy;
1479 matrix->min[2] = Oy;
1481 matrix->max[0] = ((gdouble) scale[0] + offset[0]) / S;
1482 matrix->max[1] = ((gdouble) scale[1] + offset[0]) / S;
1483 matrix->max[2] = ((gdouble) scale[1] + offset[0]) / S;
1485 /* Apply RGB range scale matrix */
1486 if (in_rgb_info->colorimetry.range == GST_VIDEO_COLOR_RANGE_16_235) {
1487 GstD3D11ColorMatrix scale_matrix, rst;
1488 GstVideoInfo full_rgb = *in_rgb_info;
1490 full_rgb.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
1492 if (gst_d3d11_color_range_adjust_matrix_unorm (in_rgb_info,
1493 &full_rgb, &scale_matrix)) {
1495 color_matrix_multiply (&rst, matrix, &scale_matrix);
1497 /* Matrix * scale offsets */
1498 for (guint i = 0; i < 3; i++) {
1500 for (guint j = 0; j < 3; j++) {
1501 val += matrix->matrix[i][j] * scale_matrix.offset[j];
1503 rst.offset[i] = val + matrix->offset[i];
1506 /* copy back to output matrix */
1507 for (guint i = 0; i < 3; i++) {
1508 for (guint j = 0; j < 3; j++) {
1509 matrix->matrix[i][j] = rst.matrix[i][j];
1511 matrix->offset[i] = rst.offset[i];
1516 /* Unknown matrix */
1517 matrix->matrix[0][0] = 1.0;
1518 matrix->matrix[1][1] = 1.0;
1519 matrix->matrix[2][2] = 1.0;
1526 rgb_to_xyz_matrix (const GstVideoColorPrimariesInfo * info,
1527 GstD3D11ColorMatrix * matrix)
1529 GstD3D11ColorMatrix m, im;
1533 if (info->Rx == 0 || info->Gx == 0 || info->By == 0 || info->Wy == 0)
1536 color_matrix_identity (&m);
1538 m.matrix[0][0] = info->Rx / info->Ry;
1539 m.matrix[1][0] = 1.0;
1540 m.matrix[2][0] = (1.0 - info->Rx - info->Ry) / info->Ry;
1542 m.matrix[0][1] = info->Gx / info->Gy;
1543 m.matrix[1][1] = 1.0;
1544 m.matrix[2][1] = (1.0 - info->Gx - info->Gy) / info->Gy;
1546 m.matrix[0][2] = info->Bx / info->By;
1547 m.matrix[1][2] = 1.0;
1548 m.matrix[2][2] = (1.0 - info->Bx - info->By) / info->By;
1550 if (!color_matrix_invert (&im, &m))
1553 Xw = info->Wx / info->Wy;
1555 Zw = (1.0 - info->Wx - info->Wy) / info->Wy;
1557 Sr = im.matrix[0][0] * Xw + im.matrix[0][1] * Yw + im.matrix[0][2] * Zw;
1558 Sg = im.matrix[1][0] * Xw + im.matrix[1][1] * Yw + im.matrix[1][2] * Zw;
1559 Sb = im.matrix[2][0] * Xw + im.matrix[2][1] * Yw + im.matrix[2][2] * Zw;
1561 for (guint i = 0; i < 3; i++) {
1562 m.matrix[i][0] *= Sr;
1563 m.matrix[i][1] *= Sg;
1564 m.matrix[i][2] *= Sb;
1567 color_matrix_copy (matrix, &m);
1573 * gst_d3d11_color_primaries_matrix_unorm:
1574 * @in_info: a #GstVideoColorPrimariesInfo of input signal
1575 * @out_info: a #GstVideoColorPrimariesInfo of output signal
1576 * @matrix: a #GstD3D11ColorMatrix
1578 * Calculates color primaries conversion matrix
1580 * Resulting RGB values can be calculated by
1582 * | Gout | = saturate ( matrix.matrix * | Gin | )
1585 * Returns: %TRUE if successful
1588 gst_d3d11_color_primaries_matrix_unorm (const GstVideoColorPrimariesInfo *
1589 in_info, const GstVideoColorPrimariesInfo * out_info,
1590 GstD3D11ColorMatrix * matrix)
1592 GstD3D11ColorMatrix Ms, invMd, ret;
1594 g_return_val_if_fail (in_info != nullptr, FALSE);
1595 g_return_val_if_fail (out_info != nullptr, FALSE);
1596 g_return_val_if_fail (matrix != nullptr, FALSE);
1601 * 1) RGB -> XYZ conversion
1606 * | SrXr, SgXg, SbXb |
1607 * M = | SrYr, SgYg, SbYb |
1608 * | SrZr, SgZg, SbZb |
1612 * Zr = (1 - xr - yr) / yr
1613 * xr and yr are xy coordinates of red primary in the CIE 1931 color space.
1614 * And its applied to G and B components
1616 * | Sr | | Xr, Xg, Xb | | Xw |
1617 * | Sg | = inv( | Yr, Yg, Yb | ) * | Yw |
1618 * | Sb | | Zr, Zg, Zb | | Zw |
1620 * 2) XYZsrc -> XYZdst conversion
1621 * Apply chromatic adaptation
1623 * | Ydst | = Mc | Ysrc |
1626 * | Xwdst / Xwsrc, 0 , 0 |
1627 * Mc = | 0 , Ywdst / Ywsrc, 0 |
1628 * | 0 , 0 , Zwdst / Zwsrc |
1634 * | Gd | = inv (Md) * Mc * Ms | Gs |
1638 memset (matrix, 0, sizeof (GstD3D11ColorMatrix));
1639 for (guint i = 0; i < 3; i++)
1640 matrix->max[i] = 1.0;
1642 if (!rgb_to_xyz_matrix (in_info, &Ms)) {
1643 GST_WARNING ("Failed to get src XYZ matrix");
1647 if (!rgb_to_xyz_matrix (out_info, &invMd) ||
1648 !color_matrix_invert (&invMd, &invMd)) {
1649 GST_WARNING ("Failed to get dst XYZ matrix");
1653 if (in_info->Wx != out_info->Wx || in_info->Wy != out_info->Wy) {
1654 GstD3D11ColorMatrix Mc;
1656 color_matrix_identity (&Mc);
1657 Mc.matrix[0][0] = (out_info->Wx / out_info->Wy) /
1658 (in_info->Wx / in_info->Wy);
1660 Mc.matrix[2][2] = ((1.0 - out_info->Wx - out_info->Wy) / out_info->Wy) /
1661 ((1.0 - in_info->Wx - in_info->Wy) / in_info->Wy);
1663 color_matrix_multiply (&ret, &Mc, &Ms);
1665 color_matrix_copy (&ret, &Ms);
1668 color_matrix_multiply (&ret, &invMd, &ret);
1669 color_matrix_copy (matrix, &ret);