3 * Copyright (C) 2004, 2008 Wim Taymans <wim@fluendo.com>
4 * Copyright (C) 2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
5 * Copyright (C) 2014 Mathieu Duponchelle <mathieu.duponchelle@opencreed.com>
6 * Copyright (C) 2014 Thibault Saunier <tsaunier@gnome.org>
7 * Copyright (C) 2020 Seungha Yang <seungha@centricular.com>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
26 * SECTION:element-d3d11compositor
27 * @title: d3d11compositor
29 * A Direct3D11 based video compositing element.
31 * ## Example launch line
33 * gst-launch-1.0 d3d11compositor name=c ! d3d11videosink \
34 * videotestsrc ! video/x-raw,width=320,height=240 ! c. \
35 * videotestsrc pattern=ball ! video/x-raw,width=100,height=100 ! c.
45 #include "gstd3d11compositor.h"
46 #include "gstd3d11pluginutils.h"
50 GST_DEBUG_CATEGORY_STATIC (gst_d3d11_compositor_debug);
51 #define GST_CAT_DEFAULT gst_d3d11_compositor_debug
54 using namespace Microsoft::WRL;
59 GST_D3D11_COMPOSITOR_BACKGROUND_CHECKER,
60 GST_D3D11_COMPOSITOR_BACKGROUND_BLACK,
61 GST_D3D11_COMPOSITOR_BACKGROUND_WHITE,
62 GST_D3D11_COMPOSITOR_BACKGROUND_TRANSPARENT,
63 } GstD3D11CompositorBackground;
65 #define GST_TYPE_D3D11_COMPOSITOR_BACKGROUND (gst_d3d11_compositor_background_get_type())
67 gst_d3d11_compositor_background_get_type (void)
69 static GType compositor_background_type = 0;
71 static const GEnumValue compositor_background[] = {
72 {GST_D3D11_COMPOSITOR_BACKGROUND_CHECKER, "Checker pattern", "checker"},
73 {GST_D3D11_COMPOSITOR_BACKGROUND_BLACK, "Black", "black"},
74 {GST_D3D11_COMPOSITOR_BACKGROUND_WHITE, "White", "white"},
75 {GST_D3D11_COMPOSITOR_BACKGROUND_TRANSPARENT,
76 "Transparent Background to enable further compositing", "transparent"},
77 {0, nullptr, nullptr},
80 if (!compositor_background_type) {
81 compositor_background_type =
82 g_enum_register_static ("GstD3D11CompositorBackground",
83 compositor_background);
85 return compositor_background_type;
90 GST_D3D11_COMPOSITOR_OPERATOR_SOURCE,
91 GST_D3D11_COMPOSITOR_OPERATOR_OVER,
92 } GstD3D11CompositorOperator;
94 #define GST_TYPE_D3D11_COMPOSITOR_OPERATOR (gst_d3d11_compositor_operator_get_type())
96 gst_d3d11_compositor_operator_get_type (void)
98 static GType compositor_operator_type = 0;
100 static const GEnumValue compositor_operator[] = {
101 {GST_D3D11_COMPOSITOR_OPERATOR_SOURCE, "Source", "source"},
102 {GST_D3D11_COMPOSITOR_OPERATOR_OVER, "Over", "over"},
103 {0, nullptr, nullptr},
106 if (!compositor_operator_type) {
107 compositor_operator_type =
108 g_enum_register_static ("GstD3D11CompositorOperator",
109 compositor_operator);
111 return compositor_operator_type;
116 GST_D3D11_COMPOSITOR_SIZING_POLICY_NONE,
117 GST_D3D11_COMPOSITOR_SIZING_POLICY_KEEP_ASPECT_RATIO,
118 } GstD3D11CompositorSizingPolicy;
120 #define GST_TYPE_D3D11_COMPOSITOR_SIZING_POLICY (gst_d3d11_compositor_sizing_policy_get_type())
122 gst_d3d11_compositor_sizing_policy_get_type (void)
124 static GType sizing_policy_type = 0;
126 static const GEnumValue sizing_polices[] = {
127 {GST_D3D11_COMPOSITOR_SIZING_POLICY_NONE,
128 "None: Image is scaled to fill configured destination rectangle without "
129 "padding or keeping the aspect ratio", "none"},
130 {GST_D3D11_COMPOSITOR_SIZING_POLICY_KEEP_ASPECT_RATIO,
131 "Keep Aspect Ratio: Image is scaled to fit destination rectangle "
132 "specified by GstCompositorPad:{xpos, ypos, width, height} "
133 "with preserved aspect ratio. Resulting image will be centered in "
134 "the destination rectangle with padding if necessary",
135 "keep-aspect-ratio"},
136 {0, nullptr, nullptr},
139 if (!sizing_policy_type) {
141 g_enum_register_static ("GstD3D11CompositorSizingPolicy",
144 return sizing_policy_type;
148 static const gchar checker_vs_src[] =
151 " float4 Position : POSITION;\n"
156 " float4 Position: SV_POSITION;\n"
159 "VS_OUTPUT main(VS_INPUT input)\n"
164 static const gchar checker_ps_src_rgb[] =
165 "static const float blocksize = 8.0;\n"
166 "static const float4 high = float4(0.667, 0.667, 0.667, 1.0);\n"
167 "static const float4 low = float4(0.333, 0.333, 0.333, 1.0);\n"
170 " float4 Position: SV_POSITION;\n"
174 " float4 Plane: SV_TARGET;\n"
176 "PS_OUTPUT main(PS_INPUT input)\n"
178 " PS_OUTPUT output;\n"
179 " if ((input.Position.x % (blocksize * 2.0)) >= blocksize) {\n"
180 " if ((input.Position.y % (blocksize * 2.0)) >= blocksize)\n"
181 " output.Plane = low;\n"
183 " output.Plane = high;\n"
185 " if ((input.Position.y % (blocksize * 2.0)) < blocksize)\n"
186 " output.Plane = low;\n"
188 " output.Plane = high;\n"
193 static const gchar checker_ps_src_vuya[] =
194 "static const float blocksize = 8.0;\n"
195 "static const float4 high = float4(0.5, 0.5, 0.667, 1.0);\n"
196 "static const float4 low = float4(0.5, 0.5, 0.333, 1.0);\n"
199 " float4 Position: SV_POSITION;\n"
203 " float4 Plane: SV_TARGET;\n"
205 "PS_OUTPUT main(PS_INPUT input)\n"
207 " PS_OUTPUT output;\n"
208 " if ((input.Position.x % (blocksize * 2.0)) >= blocksize) {\n"
209 " if ((input.Position.y % (blocksize * 2.0)) >= blocksize)\n"
210 " output.Plane = low;\n"
212 " output.Plane = high;\n"
214 " if ((input.Position.y % (blocksize * 2.0)) < blocksize)\n"
215 " output.Plane = low;\n"
217 " output.Plane = high;\n"
222 static const gchar checker_ps_src_luma[] =
223 "static const float blocksize = 8.0;\n"
224 "static const float4 high = float4(0.667, 0.0, 0.0, 1.0);\n"
225 "static const float4 low = float4(0.333, 0.0, 0.0, 1.0);\n"
228 " float4 Position: SV_POSITION;\n"
232 " float4 Plane: SV_TARGET;\n"
234 "PS_OUTPUT main(PS_INPUT input)\n"
236 " PS_OUTPUT output;\n"
237 " if ((input.Position.x % (blocksize * 2.0)) >= blocksize) {\n"
238 " if ((input.Position.y % (blocksize * 2.0)) >= blocksize)\n"
239 " output.Plane = low;\n"
241 " output.Plane = high;\n"
243 " if ((input.Position.y % (blocksize * 2.0)) < blocksize)\n"
244 " output.Plane = low;\n"
246 " output.Plane = high;\n"
251 static D3D11_RENDER_TARGET_BLEND_DESC blend_templ[] = {
255 D3D11_BLEND_ONE, D3D11_BLEND_ZERO, D3D11_BLEND_OP_ADD,
256 D3D11_BLEND_ONE, D3D11_BLEND_ZERO, D3D11_BLEND_OP_ADD,
257 D3D11_COLOR_WRITE_ENABLE_ALL
262 D3D11_BLEND_SRC_ALPHA, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD,
263 D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD,
264 D3D11_COLOR_WRITE_ENABLE_ALL,
269 struct _GstD3D11CompositorPad
271 GstVideoAggregatorConvertPad parent;
273 GstD3D11Converter *convert;
275 gboolean position_updated;
276 gboolean alpha_updated;
277 gboolean blend_desc_updated;
278 gboolean config_updated;
279 ID3D11BlendState *blend;
281 D3D11_RENDER_TARGET_BLEND_DESC desc;
289 GstD3D11CompositorOperator op;
290 GstD3D11CompositorSizingPolicy sizing_policy;
291 GstVideoGammaMode gamma_mode;
292 GstVideoPrimariesMode primaries_mode;
297 ID3D11PixelShader *ps;
298 ID3D11VertexShader *vs;
299 ID3D11InputLayout *layout;
300 ID3D11Buffer *vertex_buffer;
301 ID3D11Buffer *index_buffer;
302 D3D11_VIEWPORT viewport;
303 } GstD3D11CompositorQuad;
309 } GstD3D11CompositorClearColor;
311 struct _GstD3D11Compositor
313 GstVideoAggregator parent;
315 GstD3D11Device *device;
317 GstBuffer *fallback_buf;
319 GstD3D11CompositorQuad *checker_background;
320 /* black/white/transparent */
321 GstD3D11CompositorClearColor clear_color[3];
323 gboolean downstream_supports_d3d11;
327 GstD3D11CompositorBackground background;
339 PROP_PAD_SIZING_POLICY,
341 PROP_PAD_PRIMARIES_MODE,
344 #define DEFAULT_PAD_XPOS 0
345 #define DEFAULT_PAD_YPOS 0
346 #define DEFAULT_PAD_WIDTH 0
347 #define DEFAULT_PAD_HEIGHT 0
348 #define DEFAULT_PAD_ALPHA 1.0
349 #define DEFAULT_PAD_OPERATOR GST_D3D11_COMPOSITOR_OPERATOR_OVER
350 #define DEFAULT_PAD_SIZING_POLICY GST_D3D11_COMPOSITOR_SIZING_POLICY_NONE
351 #define DEFAULT_PAD_GAMMA_MODE GST_VIDEO_GAMMA_MODE_NONE
352 #define DEFAULT_PAD_PRIMARIES_MODE GST_VIDEO_PRIMARIES_MODE_NONE
354 static void gst_d3d11_compositor_pad_set_property (GObject * object,
355 guint prop_id, const GValue * value, GParamSpec * pspec);
356 static void gst_d3d11_compositor_pad_get_property (GObject * object,
357 guint prop_id, GValue * value, GParamSpec * pspec);
359 gst_d3d11_compositor_pad_prepare_frame (GstVideoAggregatorPad * pad,
360 GstVideoAggregator * vagg, GstBuffer * buffer,
361 GstVideoFrame * prepared_frame);
362 static void gst_d3d11_compositor_pad_clean_frame (GstVideoAggregatorPad * vpad,
363 GstVideoAggregator * vagg, GstVideoFrame * prepared_frame);
365 #define gst_d3d11_compositor_pad_parent_class parent_pad_class
366 G_DEFINE_TYPE (GstD3D11CompositorPad, gst_d3d11_compositor_pad,
367 GST_TYPE_VIDEO_AGGREGATOR_PAD);
370 gst_d3d11_compositor_pad_class_init (GstD3D11CompositorPadClass * klass)
372 GObjectClass *object_class = G_OBJECT_CLASS (klass);
373 GstVideoAggregatorPadClass *vagg_pad_class =
374 GST_VIDEO_AGGREGATOR_PAD_CLASS (klass);
375 GParamFlags param_flags = (GParamFlags)
376 (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS);
378 object_class->set_property = gst_d3d11_compositor_pad_set_property;
379 object_class->get_property = gst_d3d11_compositor_pad_get_property;
381 g_object_class_install_property (object_class, PROP_PAD_XPOS,
382 g_param_spec_int ("xpos", "X Position", "X position of the picture",
383 G_MININT, G_MAXINT, DEFAULT_PAD_XPOS, param_flags));
384 g_object_class_install_property (object_class, PROP_PAD_YPOS,
385 g_param_spec_int ("ypos", "Y Position", "Y position of the picture",
386 G_MININT, G_MAXINT, DEFAULT_PAD_YPOS, param_flags));
387 g_object_class_install_property (object_class, PROP_PAD_WIDTH,
388 g_param_spec_int ("width", "Width", "Width of the picture",
389 G_MININT, G_MAXINT, DEFAULT_PAD_WIDTH, param_flags));
390 g_object_class_install_property (object_class, PROP_PAD_HEIGHT,
391 g_param_spec_int ("height", "Height", "Height of the picture",
392 G_MININT, G_MAXINT, DEFAULT_PAD_HEIGHT, param_flags));
393 g_object_class_install_property (object_class, PROP_PAD_ALPHA,
394 g_param_spec_double ("alpha", "Alpha", "Alpha of the picture", 0.0, 1.0,
395 DEFAULT_PAD_ALPHA, param_flags));
396 g_object_class_install_property (object_class, PROP_PAD_OPERATOR,
397 g_param_spec_enum ("operator", "Operator",
398 "Blending operator to use for blending this pad over the previous ones",
399 GST_TYPE_D3D11_COMPOSITOR_OPERATOR, DEFAULT_PAD_OPERATOR,
401 g_object_class_install_property (object_class, PROP_PAD_SIZING_POLICY,
402 g_param_spec_enum ("sizing-policy", "Sizing policy",
403 "Sizing policy to use for image scaling",
404 GST_TYPE_D3D11_COMPOSITOR_SIZING_POLICY, DEFAULT_PAD_SIZING_POLICY,
408 * GstD3D11CompositorPad:gamma-mode:
410 * Gamma conversion mode
414 g_object_class_install_property (object_class, PROP_PAD_GAMMA_MODE,
415 g_param_spec_enum ("gamma-mode", "Gamma mode",
416 "Gamma conversion mode", GST_TYPE_VIDEO_GAMMA_MODE,
417 DEFAULT_PAD_GAMMA_MODE, param_flags));
420 * GstD3D11CompositorPad:primaries-mode:
422 * Primaries conversion mode
426 g_object_class_install_property (object_class, PROP_PAD_PRIMARIES_MODE,
427 g_param_spec_enum ("primaries-mode", "Primaries Mode",
428 "Primaries conversion mode", GST_TYPE_VIDEO_PRIMARIES_MODE,
429 DEFAULT_PAD_PRIMARIES_MODE, param_flags));
431 vagg_pad_class->prepare_frame =
432 GST_DEBUG_FUNCPTR (gst_d3d11_compositor_pad_prepare_frame);
433 vagg_pad_class->clean_frame =
434 GST_DEBUG_FUNCPTR (gst_d3d11_compositor_pad_clean_frame);
436 gst_type_mark_as_plugin_api (GST_TYPE_D3D11_COMPOSITOR_OPERATOR,
437 (GstPluginAPIFlags) 0);
438 gst_type_mark_as_plugin_api (GST_TYPE_D3D11_COMPOSITOR_SIZING_POLICY,
439 (GstPluginAPIFlags) 0);
443 gst_d3d11_compositor_pad_init (GstD3D11CompositorPad * pad)
445 pad->xpos = DEFAULT_PAD_XPOS;
446 pad->ypos = DEFAULT_PAD_YPOS;
447 pad->width = DEFAULT_PAD_WIDTH;
448 pad->height = DEFAULT_PAD_HEIGHT;
449 pad->alpha = DEFAULT_PAD_ALPHA;
450 pad->op = DEFAULT_PAD_OPERATOR;
451 pad->sizing_policy = DEFAULT_PAD_SIZING_POLICY;
452 pad->desc = blend_templ[DEFAULT_PAD_OPERATOR];
453 pad->gamma_mode = DEFAULT_PAD_GAMMA_MODE;
454 pad->primaries_mode = DEFAULT_PAD_PRIMARIES_MODE;
458 gst_d3d11_compositor_pad_update_position (GstD3D11CompositorPad * self,
459 gint * old, const GValue * value)
461 gint tmp = g_value_get_int (value);
465 self->position_updated = TRUE;
470 gst_d3d11_compositor_pad_set_property (GObject * object, guint prop_id,
471 const GValue * value, GParamSpec * pspec)
473 GstD3D11CompositorPad *pad = GST_D3D11_COMPOSITOR_PAD (object);
477 gst_d3d11_compositor_pad_update_position (pad, &pad->xpos, value);
480 gst_d3d11_compositor_pad_update_position (pad, &pad->ypos, value);
483 gst_d3d11_compositor_pad_update_position (pad, &pad->width, value);
485 case PROP_PAD_HEIGHT:
486 gst_d3d11_compositor_pad_update_position (pad, &pad->height, value);
488 case PROP_PAD_ALPHA:{
489 gdouble alpha = g_value_get_double (value);
490 if (pad->alpha != alpha) {
491 pad->alpha_updated = TRUE;
496 case PROP_PAD_OPERATOR:{
497 GstD3D11CompositorOperator op =
498 (GstD3D11CompositorOperator) g_value_get_enum (value);
501 pad->desc = blend_templ[op];
502 pad->blend_desc_updated = TRUE;
506 case PROP_PAD_SIZING_POLICY:{
507 GstD3D11CompositorSizingPolicy policy =
508 (GstD3D11CompositorSizingPolicy) g_value_get_enum (value);
509 if (pad->sizing_policy != policy) {
510 pad->sizing_policy = policy;
511 pad->position_updated = TRUE;
515 case PROP_PAD_GAMMA_MODE:{
516 GstVideoGammaMode mode = (GstVideoGammaMode) g_value_get_enum (value);
517 if (pad->gamma_mode != mode) {
518 pad->gamma_mode = mode;
519 pad->config_updated = TRUE;
523 case PROP_PAD_PRIMARIES_MODE:{
524 GstVideoPrimariesMode mode =
525 (GstVideoPrimariesMode) g_value_get_enum (value);
526 if (pad->primaries_mode != mode) {
527 pad->primaries_mode = mode;
528 pad->config_updated = TRUE;
533 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
539 gst_d3d11_compositor_pad_get_property (GObject * object, guint prop_id,
540 GValue * value, GParamSpec * pspec)
542 GstD3D11CompositorPad *pad = GST_D3D11_COMPOSITOR_PAD (object);
546 g_value_set_int (value, pad->xpos);
549 g_value_set_int (value, pad->ypos);
552 g_value_set_int (value, pad->width);
554 case PROP_PAD_HEIGHT:
555 g_value_set_int (value, pad->height);
558 g_value_set_double (value, pad->alpha);
560 case PROP_PAD_OPERATOR:
561 g_value_set_enum (value, pad->op);
563 case PROP_PAD_SIZING_POLICY:
564 g_value_set_enum (value, pad->sizing_policy);
566 case PROP_PAD_GAMMA_MODE:
567 g_value_set_enum (value, pad->gamma_mode);
569 case PROP_PAD_PRIMARIES_MODE:
570 g_value_set_enum (value, pad->primaries_mode);
573 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
579 gst_d3d11_compositor_pad_get_output_size (GstD3D11CompositorPad * comp_pad,
580 gint out_par_n, gint out_par_d, gint * width, gint * height,
581 gint * x_offset, gint * y_offset)
583 GstVideoAggregatorPad *vagg_pad = GST_VIDEO_AGGREGATOR_PAD (comp_pad);
584 gint pad_width, pad_height;
592 /* FIXME: Anything better we can do here? */
593 if (!vagg_pad->info.finfo
594 || vagg_pad->info.finfo->format == GST_VIDEO_FORMAT_UNKNOWN) {
595 GST_DEBUG_OBJECT (comp_pad, "Have no caps yet");
601 0 ? GST_VIDEO_INFO_WIDTH (&vagg_pad->info) : comp_pad->width;
604 0 ? GST_VIDEO_INFO_HEIGHT (&vagg_pad->info) : comp_pad->height;
606 if (pad_width == 0 || pad_height == 0)
609 if (!gst_video_calculate_display_ratio (&dar_n, &dar_d, pad_width, pad_height,
610 GST_VIDEO_INFO_PAR_N (&vagg_pad->info),
611 GST_VIDEO_INFO_PAR_D (&vagg_pad->info), out_par_n, out_par_d)) {
612 GST_WARNING_OBJECT (comp_pad, "Cannot calculate display aspect ratio");
616 GST_TRACE_OBJECT (comp_pad, "scaling %ux%u by %u/%u (%u/%u / %u/%u)",
617 pad_width, pad_height, dar_n, dar_d,
618 GST_VIDEO_INFO_PAR_N (&vagg_pad->info),
619 GST_VIDEO_INFO_PAR_D (&vagg_pad->info), out_par_n, out_par_d);
621 switch (comp_pad->sizing_policy) {
622 case GST_D3D11_COMPOSITOR_SIZING_POLICY_NONE:
623 /* Pick either height or width, whichever is an integer multiple of the
624 * display aspect ratio. However, prefer preserving the height to account
625 * for interlaced video. */
626 if (pad_height % dar_n == 0) {
627 pad_width = gst_util_uint64_scale_int (pad_height, dar_n, dar_d);
628 } else if (pad_width % dar_d == 0) {
629 pad_height = gst_util_uint64_scale_int (pad_width, dar_d, dar_n);
631 pad_width = gst_util_uint64_scale_int (pad_height, dar_n, dar_d);
634 case GST_D3D11_COMPOSITOR_SIZING_POLICY_KEEP_ASPECT_RATIO:{
635 gint from_dar_n, from_dar_d, to_dar_n, to_dar_d, num, den;
637 /* Calculate DAR again with actual video size */
638 if (!gst_util_fraction_multiply (GST_VIDEO_INFO_WIDTH (&vagg_pad->info),
639 GST_VIDEO_INFO_HEIGHT (&vagg_pad->info),
640 GST_VIDEO_INFO_PAR_N (&vagg_pad->info),
641 GST_VIDEO_INFO_PAR_D (&vagg_pad->info), &from_dar_n,
643 from_dar_n = from_dar_d = -1;
646 if (!gst_util_fraction_multiply (pad_width, pad_height,
647 out_par_n, out_par_d, &to_dar_n, &to_dar_d)) {
648 to_dar_n = to_dar_d = -1;
651 if (from_dar_n != to_dar_n || from_dar_d != to_dar_d) {
652 /* Calculate new output resolution */
653 if (from_dar_n != -1 && from_dar_d != -1
654 && gst_util_fraction_multiply (from_dar_n, from_dar_d,
655 out_par_d, out_par_n, &num, &den)) {
656 GstVideoRectangle src_rect, dst_rect, rst_rect;
658 src_rect.h = gst_util_uint64_scale_int (pad_width, den, num);
659 if (src_rect.h == 0) {
665 src_rect.x = src_rect.y = 0;
666 src_rect.w = pad_width;
668 dst_rect.x = dst_rect.y = 0;
669 dst_rect.w = pad_width;
670 dst_rect.h = pad_height;
672 /* Scale rect to be centered in destination rect */
673 gst_video_center_rect (&src_rect, &dst_rect, &rst_rect, TRUE);
675 GST_LOG_OBJECT (comp_pad,
676 "Re-calculated size %dx%d -> %dx%d (x-offset %d, y-offset %d)",
677 pad_width, pad_height, rst_rect.w, rst_rect.h, rst_rect.x,
680 *x_offset = rst_rect.x;
681 *y_offset = rst_rect.y;
682 pad_width = rst_rect.w;
683 pad_height = rst_rect.h;
685 GST_WARNING_OBJECT (comp_pad, "Failed to calculate output size");
698 *height = pad_height;
701 static GstVideoRectangle
702 clamp_rectangle (gint x, gint y, gint w, gint h, gint outer_width,
707 GstVideoRectangle clamped;
709 /* Clamp the x/y coordinates of this frame to the output boundaries to cover
710 * the case where (say, with negative xpos/ypos or w/h greater than the output
711 * size) the non-obscured portion of the frame could be outside the bounds of
712 * the video itself and hence not visible at all */
713 clamped.x = CLAMP (x, 0, outer_width);
714 clamped.y = CLAMP (y, 0, outer_height);
715 clamped.w = CLAMP (x2, 0, outer_width) - clamped.x;
716 clamped.h = CLAMP (y2, 0, outer_height) - clamped.y;
722 gst_d3d11_compositor_pad_check_frame_obscured (GstVideoAggregatorPad * pad,
723 GstVideoAggregator * vagg)
725 GstD3D11CompositorPad *cpad = GST_D3D11_COMPOSITOR_PAD (pad);
727 GstVideoInfo *info = &vagg->info;
728 /* The rectangle representing this frame, clamped to the video's boundaries.
729 * Due to the clamping, this is different from the frame width/height above. */
730 GstVideoRectangle frame_rect;
731 gint x_offset, y_offset;
733 /* There's three types of width/height here:
734 * 1. GST_VIDEO_FRAME_WIDTH/HEIGHT:
735 * The frame width/height (same as pad->info.height/width;
736 * see gst_video_frame_map())
737 * 2. cpad->width/height:
738 * The optional pad property for scaling the frame (if zero, the video is
742 gst_d3d11_compositor_pad_get_output_size (cpad, GST_VIDEO_INFO_PAR_N (info),
743 GST_VIDEO_INFO_PAR_D (info), &width, &height, &x_offset, &y_offset);
745 frame_rect = clamp_rectangle (cpad->xpos + x_offset, cpad->ypos + y_offset,
746 width, height, GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info));
748 if (frame_rect.w == 0 || frame_rect.h == 0) {
749 GST_DEBUG_OBJECT (pad, "Resulting frame is zero-width or zero-height "
750 "(w: %i, h: %i), skipping", frame_rect.w, frame_rect.h);
758 gst_d3d11_compositor_pad_prepare_frame (GstVideoAggregatorPad * pad,
759 GstVideoAggregator * vagg, GstBuffer * buffer,
760 GstVideoFrame * prepared_frame)
762 /* Skip this frame */
763 if (gst_d3d11_compositor_pad_check_frame_obscured (pad, vagg))
766 /* don't map/upload now, it will happen in converter object.
767 * Just mark this frame is preparted instead */
768 prepared_frame->buffer = buffer;
774 gst_d3d11_compositor_pad_clean_frame (GstVideoAggregatorPad * vpad,
775 GstVideoAggregator * vagg, GstVideoFrame * prepared_frame)
777 memset (prepared_frame, 0, sizeof (GstVideoFrame));
781 gst_d3d11_compositor_pad_setup_converter (GstVideoAggregatorPad * pad,
782 GstVideoAggregator * vagg)
784 GstD3D11CompositorPad *cpad = GST_D3D11_COMPOSITOR_PAD (pad);
785 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (vagg);
787 GstVideoInfo *info = &vagg->info;
788 GstVideoRectangle frame_rect;
789 gboolean is_first = FALSE;
790 gboolean output_has_alpha_comp = FALSE;
791 gint x_offset, y_offset;
792 #ifndef GST_DISABLE_GST_DEBUG
795 static const D3D11_RENDER_TARGET_BLEND_DESC blend_over_no_alpha = {
797 D3D11_BLEND_BLEND_FACTOR, D3D11_BLEND_INV_BLEND_FACTOR, D3D11_BLEND_OP_ADD,
798 D3D11_BLEND_BLEND_FACTOR, D3D11_BLEND_INV_BLEND_FACTOR, D3D11_BLEND_OP_ADD,
799 D3D11_COLOR_WRITE_ENABLE_ALL,
802 if (GST_VIDEO_INFO_HAS_ALPHA (info) ||
803 GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_BGRx ||
804 GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_RGBx) {
805 output_has_alpha_comp = TRUE;
808 if (cpad->config_updated) {
809 gst_clear_object (&cpad->convert);
810 cpad->config_updated = FALSE;
813 if (!cpad->convert) {
814 GstStructure *config = gst_structure_new ("converter-config",
815 GST_D3D11_CONVERTER_OPT_GAMMA_MODE,
816 GST_TYPE_VIDEO_GAMMA_MODE, cpad->gamma_mode,
817 GST_D3D11_CONVERTER_OPT_PRIMARIES_MODE,
818 GST_TYPE_VIDEO_PRIMARIES_MODE, cpad->primaries_mode, nullptr);
820 cpad->convert = gst_d3d11_converter_new (self->device, &pad->info, info,
822 if (!cpad->convert) {
823 GST_ERROR_OBJECT (pad, "Couldn't create converter");
830 if (cpad->alpha_updated || is_first) {
831 if (output_has_alpha_comp) {
832 g_object_set (cpad->convert, "alpha", cpad->alpha, nullptr);
834 gfloat blend_factor = cpad->alpha;
836 g_object_set (cpad->convert,
837 "blend-factor-red", blend_factor,
838 "blend-factor-green", blend_factor,
839 "blend-factor-blue", blend_factor,
840 "blend-factor-alpha", blend_factor, nullptr);
843 cpad->alpha_updated = FALSE;
846 if (!cpad->blend || cpad->blend_desc_updated || is_first) {
848 D3D11_BLEND_DESC desc = { 0, };
849 ID3D11BlendState *blend = nullptr;
850 ID3D11Device *device_handle =
851 gst_d3d11_device_get_device_handle (self->device);
852 gfloat blend_factor = 1.0f;
854 GST_D3D11_CLEAR_COM (cpad->blend);
856 desc.AlphaToCoverageEnable = FALSE;
857 desc.IndependentBlendEnable = FALSE;
858 desc.RenderTarget[0] = cpad->desc;
859 if (!output_has_alpha_comp &&
860 cpad->op == GST_D3D11_COMPOSITOR_OPERATOR_OVER) {
861 desc.RenderTarget[0] = blend_over_no_alpha;
862 blend_factor = cpad->alpha;
865 hr = device_handle->CreateBlendState (&desc, &blend);
866 if (!gst_d3d11_result (hr, self->device)) {
867 GST_ERROR_OBJECT (pad, "Couldn't create blend staten, hr: 0x%x",
873 g_object_set (cpad->convert, "blend-state", blend,
874 "blend-factor-red", blend_factor,
875 "blend-factor-green", blend_factor,
876 "blend-factor-blue", blend_factor,
877 "blend-factor-alpha", blend_factor, nullptr);
879 cpad->blend_desc_updated = FALSE;
882 if (!is_first && !cpad->position_updated)
885 gst_d3d11_compositor_pad_get_output_size (cpad, GST_VIDEO_INFO_PAR_N (info),
886 GST_VIDEO_INFO_PAR_D (info), &width, &height, &x_offset, &y_offset);
888 frame_rect = clamp_rectangle (cpad->xpos + x_offset, cpad->ypos + y_offset,
889 width, height, GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info));
891 #ifndef GST_DISABLE_GST_DEBUG
892 g_object_get (pad, "zorder", &zorder, nullptr);
894 GST_LOG_OBJECT (pad, "Update position, pad-xpos %d, pad-ypos %d, "
895 "pad-zorder %d, pad-width %d, pad-height %d, in-resolution %dx%d, "
896 "out-resoution %dx%d, dst-{x,y,width,height} %d-%d-%d-%d",
897 cpad->xpos, cpad->ypos, zorder, cpad->width, cpad->height,
898 GST_VIDEO_INFO_WIDTH (&pad->info), GST_VIDEO_INFO_HEIGHT (&pad->info),
899 GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info),
900 frame_rect.x, frame_rect.y, frame_rect.w, frame_rect.h);
903 cpad->position_updated = FALSE;
905 g_object_set (cpad->convert, "dest-x", frame_rect.x,
906 "dest-y", frame_rect.y, "dest-width", frame_rect.w,
907 "dest-height", frame_rect.h, nullptr);
912 static GstStaticCaps sink_pad_template_caps =
913 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
914 (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, GST_D3D11_SINK_FORMATS) "; "
915 GST_VIDEO_CAPS_MAKE (GST_D3D11_SINK_FORMATS));
917 /* formats we can output without conversion.
918 * Excludes 10/12 bits planar YUV (needs bitshift) and
919 * AYUV/AYUV64 (d3d11 runtime does not understand the ayuv order) */
920 #define COMPOSITOR_SRC_FORMATS \
921 "{ RGBA64_LE, RGB10A2_LE, BGRA, RGBA, BGRx, RGBx, VUYA, NV12, NV21, " \
922 "P010_10LE, P012_LE, P016_LE, I420, YV12, Y42B, Y444, Y444_16LE, " \
925 static GstStaticCaps src_pad_template_caps =
926 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
927 (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, COMPOSITOR_SRC_FORMATS) "; "
928 GST_VIDEO_CAPS_MAKE (COMPOSITOR_SRC_FORMATS));
937 #define DEFAULT_ADAPTER -1
938 #define DEFAULT_BACKGROUND GST_D3D11_COMPOSITOR_BACKGROUND_CHECKER
940 static void gst_d3d11_compositor_child_proxy_init (gpointer g_iface,
941 gpointer iface_data);
942 static void gst_d3d11_compositor_dispose (GObject * object);
943 static void gst_d3d11_compositor_set_property (GObject * object,
944 guint prop_id, const GValue * value, GParamSpec * pspec);
945 static void gst_d3d11_compositor_get_property (GObject * object,
946 guint prop_id, GValue * value, GParamSpec * pspec);
948 static GstPad *gst_d3d11_compositor_request_new_pad (GstElement * element,
949 GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
950 static void gst_d3d11_compositor_release_pad (GstElement * element,
952 static void gst_d3d11_compositor_set_context (GstElement * element,
953 GstContext * context);
955 static gboolean gst_d3d11_compositor_start (GstAggregator * agg);
956 static gboolean gst_d3d11_compositor_stop (GstAggregator * agg);
957 static gboolean gst_d3d11_compositor_sink_query (GstAggregator * agg,
958 GstAggregatorPad * pad, GstQuery * query);
959 static gboolean gst_d3d11_compositor_src_query (GstAggregator * agg,
961 static GstCaps *gst_d3d11_compositor_fixate_src_caps (GstAggregator * agg,
963 static gboolean gst_d3d11_compositor_negotiated_src_caps (GstAggregator * agg,
966 gst_d3d11_compositor_propose_allocation (GstAggregator * agg,
967 GstAggregatorPad * pad, GstQuery * decide_query, GstQuery * query);
968 static gboolean gst_d3d11_compositor_decide_allocation (GstAggregator * agg,
971 gst_d3d11_compositor_aggregate_frames (GstVideoAggregator * vagg,
974 gst_d3d11_compositor_create_output_buffer (GstVideoAggregator * vagg,
975 GstBuffer ** outbuffer);
976 static void gst_d3d11_compositor_quad_free (GstD3D11CompositorQuad * quad);
978 #define gst_d3d11_compositor_parent_class parent_class
979 G_DEFINE_TYPE_WITH_CODE (GstD3D11Compositor, gst_d3d11_compositor,
980 GST_TYPE_VIDEO_AGGREGATOR, G_IMPLEMENT_INTERFACE (GST_TYPE_CHILD_PROXY,
981 gst_d3d11_compositor_child_proxy_init));
984 gst_d3d11_compositor_class_init (GstD3D11CompositorClass * klass)
986 GObjectClass *object_class = G_OBJECT_CLASS (klass);
987 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
988 GstAggregatorClass *agg_class = GST_AGGREGATOR_CLASS (klass);
989 GstVideoAggregatorClass *vagg_class = GST_VIDEO_AGGREGATOR_CLASS (klass);
992 object_class->dispose = gst_d3d11_compositor_dispose;
993 object_class->set_property = gst_d3d11_compositor_set_property;
994 object_class->get_property = gst_d3d11_compositor_get_property;
996 g_object_class_install_property (object_class, PROP_ADAPTER,
997 g_param_spec_int ("adapter", "Adapter",
998 "Adapter index for creating device (-1 for default)",
999 -1, G_MAXINT32, DEFAULT_ADAPTER,
1000 (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY |
1001 G_PARAM_STATIC_STRINGS)));
1003 g_object_class_install_property (object_class, PROP_BACKGROUND,
1004 g_param_spec_enum ("background", "Background", "Background type",
1005 GST_TYPE_D3D11_COMPOSITOR_BACKGROUND,
1007 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
1009 element_class->request_new_pad =
1010 GST_DEBUG_FUNCPTR (gst_d3d11_compositor_request_new_pad);
1011 element_class->release_pad =
1012 GST_DEBUG_FUNCPTR (gst_d3d11_compositor_release_pad);
1013 element_class->set_context =
1014 GST_DEBUG_FUNCPTR (gst_d3d11_compositor_set_context);
1016 agg_class->start = GST_DEBUG_FUNCPTR (gst_d3d11_compositor_start);
1017 agg_class->stop = GST_DEBUG_FUNCPTR (gst_d3d11_compositor_stop);
1018 agg_class->sink_query = GST_DEBUG_FUNCPTR (gst_d3d11_compositor_sink_query);
1019 agg_class->src_query = GST_DEBUG_FUNCPTR (gst_d3d11_compositor_src_query);
1020 agg_class->fixate_src_caps =
1021 GST_DEBUG_FUNCPTR (gst_d3d11_compositor_fixate_src_caps);
1022 agg_class->negotiated_src_caps =
1023 GST_DEBUG_FUNCPTR (gst_d3d11_compositor_negotiated_src_caps);
1024 agg_class->propose_allocation =
1025 GST_DEBUG_FUNCPTR (gst_d3d11_compositor_propose_allocation);
1026 agg_class->decide_allocation =
1027 GST_DEBUG_FUNCPTR (gst_d3d11_compositor_decide_allocation);
1029 vagg_class->aggregate_frames =
1030 GST_DEBUG_FUNCPTR (gst_d3d11_compositor_aggregate_frames);
1031 vagg_class->create_output_buffer =
1032 GST_DEBUG_FUNCPTR (gst_d3d11_compositor_create_output_buffer);
1034 caps = gst_d3d11_get_updated_template_caps (&sink_pad_template_caps);
1035 gst_element_class_add_pad_template (element_class,
1036 gst_pad_template_new_with_gtype ("sink_%u", GST_PAD_SINK, GST_PAD_REQUEST,
1037 caps, GST_TYPE_D3D11_COMPOSITOR_PAD));
1038 gst_caps_unref (caps);
1040 caps = gst_d3d11_get_updated_template_caps (&src_pad_template_caps);
1041 gst_element_class_add_pad_template (element_class,
1042 gst_pad_template_new_with_gtype ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
1043 caps, GST_TYPE_AGGREGATOR_PAD));
1044 gst_caps_unref (caps);
1046 gst_element_class_set_static_metadata (element_class, "Direct3D11 Compositor",
1047 "Filter/Editor/Video/Compositor", "A Direct3D11 compositor",
1048 "Seungha Yang <seungha@centricular.com>");
1050 gst_type_mark_as_plugin_api (GST_TYPE_D3D11_COMPOSITOR_BACKGROUND,
1051 (GstPluginAPIFlags) 0);
1052 gst_type_mark_as_plugin_api (GST_TYPE_D3D11_COMPOSITOR_PAD,
1053 (GstPluginAPIFlags) 0);
1055 GST_DEBUG_CATEGORY_INIT (gst_d3d11_compositor_debug,
1056 "d3d11compositor", 0, "d3d11compositor element");
1060 gst_d3d11_compositor_init (GstD3D11Compositor * self)
1062 self->adapter = DEFAULT_ADAPTER;
1063 self->background = DEFAULT_BACKGROUND;
1067 gst_d3d11_compositor_dispose (GObject * object)
1069 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (object);
1071 gst_clear_object (&self->device);
1072 gst_clear_buffer (&self->fallback_buf);
1073 g_clear_pointer (&self->checker_background, gst_d3d11_compositor_quad_free);
1075 G_OBJECT_CLASS (parent_class)->dispose (object);
1079 gst_d3d11_compositor_set_property (GObject * object,
1080 guint prop_id, const GValue * value, GParamSpec * pspec)
1082 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (object);
1086 self->adapter = g_value_get_int (value);
1088 case PROP_BACKGROUND:
1090 (GstD3D11CompositorBackground) g_value_get_enum (value);
1093 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1099 gst_d3d11_compositor_get_property (GObject * object,
1100 guint prop_id, GValue * value, GParamSpec * pspec)
1102 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (object);
1106 g_value_set_int (value, self->adapter);
1108 case PROP_BACKGROUND:
1109 g_value_set_enum (value, self->background);
1112 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1118 gst_d3d11_compositor_child_proxy_get_child_by_index (GstChildProxy * proxy,
1121 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (proxy);
1122 GObject *obj = nullptr;
1124 GST_OBJECT_LOCK (self);
1125 obj = (GObject *) g_list_nth_data (GST_ELEMENT_CAST (self)->sinkpads, index);
1127 gst_object_ref (obj);
1128 GST_OBJECT_UNLOCK (self);
1134 gst_d3d11_compositor_child_proxy_get_children_count (GstChildProxy * proxy)
1136 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (proxy);
1139 GST_OBJECT_LOCK (self);
1140 count = GST_ELEMENT_CAST (self)->numsinkpads;
1141 GST_OBJECT_UNLOCK (self);
1142 GST_INFO_OBJECT (self, "Children Count: %d", count);
1148 gst_d3d11_compositor_child_proxy_init (gpointer g_iface, gpointer iface_data)
1150 GstChildProxyInterface *iface = (GstChildProxyInterface *) g_iface;
1152 iface->get_child_by_index =
1153 gst_d3d11_compositor_child_proxy_get_child_by_index;
1154 iface->get_children_count =
1155 gst_d3d11_compositor_child_proxy_get_children_count;
1159 gst_d3d11_compositor_request_new_pad (GstElement * element,
1160 GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
1164 pad = GST_ELEMENT_CLASS (parent_class)->request_new_pad (element,
1168 GST_DEBUG_OBJECT (element, "could not create/add pad");
1172 gst_child_proxy_child_added (GST_CHILD_PROXY (element), G_OBJECT (pad),
1173 GST_OBJECT_NAME (pad));
1175 GST_DEBUG_OBJECT (element, "Created new pad %s:%s", GST_DEBUG_PAD_NAME (pad));
1181 gst_d3d11_compositor_pad_clear_resource (GstD3D11Compositor * self,
1182 GstD3D11CompositorPad * cpad, gpointer user_data)
1184 gst_clear_object (&cpad->convert);
1185 GST_D3D11_CLEAR_COM (cpad->blend);
1191 gst_d3d11_compositor_release_pad (GstElement * element, GstPad * pad)
1193 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (element);
1194 GstD3D11CompositorPad *cpad = GST_D3D11_COMPOSITOR_PAD (pad);
1196 GST_DEBUG_OBJECT (self, "Releasing pad %s:%s", GST_DEBUG_PAD_NAME (pad));
1198 gst_child_proxy_child_removed (GST_CHILD_PROXY (self), G_OBJECT (pad),
1199 GST_OBJECT_NAME (pad));
1201 gst_d3d11_compositor_pad_clear_resource (self, cpad, nullptr);
1203 GST_ELEMENT_CLASS (parent_class)->release_pad (element, pad);
1207 gst_d3d11_compositor_set_context (GstElement * element, GstContext * context)
1209 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (element);
1211 gst_d3d11_handle_set_context (element, context, self->adapter, &self->device);
1213 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
1217 gst_d3d11_compositor_start (GstAggregator * agg)
1219 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (agg);
1221 if (!gst_d3d11_ensure_element_data (GST_ELEMENT_CAST (self),
1222 self->adapter, &self->device)) {
1223 GST_ERROR_OBJECT (self, "Failed to get D3D11 device");
1227 return GST_AGGREGATOR_CLASS (parent_class)->start (agg);
1231 gst_d3d11_compositor_stop (GstAggregator * agg)
1233 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (agg);
1235 g_clear_pointer (&self->checker_background, gst_d3d11_compositor_quad_free);
1236 gst_clear_object (&self->device);
1238 return GST_AGGREGATOR_CLASS (parent_class)->stop (agg);
1242 gst_d3d11_compositor_sink_getcaps (GstPad * pad, GstCaps * filter)
1245 GstCaps *template_caps;
1246 GstCaps *filtered_caps;
1247 GstCaps *returned_caps;
1249 template_caps = gst_pad_get_pad_template_caps (pad);
1251 sinkcaps = gst_pad_get_current_caps (pad);
1252 if (sinkcaps == nullptr) {
1253 sinkcaps = gst_caps_ref (template_caps);
1255 sinkcaps = gst_caps_merge (sinkcaps, gst_caps_ref (template_caps));
1259 filtered_caps = gst_caps_intersect (sinkcaps, filter);
1260 gst_caps_unref (sinkcaps);
1262 filtered_caps = sinkcaps; /* pass ownership */
1265 returned_caps = gst_caps_intersect (filtered_caps, template_caps);
1267 gst_caps_unref (template_caps);
1268 gst_caps_unref (filtered_caps);
1270 GST_DEBUG_OBJECT (pad, "returning %" GST_PTR_FORMAT, returned_caps);
1272 return returned_caps;
1276 gst_d3d11_compositor_sink_acceptcaps (GstPad * pad, GstCaps * caps)
1279 GstCaps *template_caps;
1281 GST_DEBUG_OBJECT (pad, "try accept caps of %" GST_PTR_FORMAT, caps);
1283 template_caps = gst_pad_get_pad_template_caps (pad);
1284 template_caps = gst_caps_make_writable (template_caps);
1286 ret = gst_caps_can_intersect (caps, template_caps);
1287 GST_DEBUG_OBJECT (pad, "%saccepted caps %" GST_PTR_FORMAT,
1288 (ret ? "" : "not "), caps);
1289 gst_caps_unref (template_caps);
1295 gst_d3d11_compositor_sink_query (GstAggregator * agg,
1296 GstAggregatorPad * pad, GstQuery * query)
1298 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (agg);
1300 switch (GST_QUERY_TYPE (query)) {
1301 case GST_QUERY_CONTEXT:
1302 if (gst_d3d11_handle_context_query (GST_ELEMENT (agg), query,
1307 case GST_QUERY_CAPS:{
1308 GstCaps *filter, *caps;
1310 gst_query_parse_caps (query, &filter);
1311 caps = gst_d3d11_compositor_sink_getcaps (GST_PAD (pad), filter);
1312 gst_query_set_caps_result (query, caps);
1313 gst_caps_unref (caps);
1316 case GST_QUERY_ACCEPT_CAPS:{
1320 gst_query_parse_accept_caps (query, &caps);
1321 ret = gst_d3d11_compositor_sink_acceptcaps (GST_PAD (pad), caps);
1322 gst_query_set_accept_caps_result (query, ret);
1329 return GST_AGGREGATOR_CLASS (parent_class)->sink_query (agg, pad, query);
1333 gst_d3d11_compositor_src_query (GstAggregator * agg, GstQuery * query)
1335 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (agg);
1337 switch (GST_QUERY_TYPE (query)) {
1338 case GST_QUERY_CONTEXT:
1339 if (gst_d3d11_handle_context_query (GST_ELEMENT (agg), query,
1348 return GST_AGGREGATOR_CLASS (parent_class)->src_query (agg, query);
1352 gst_d3d11_compositor_fixate_src_caps (GstAggregator * agg, GstCaps * caps)
1354 GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (agg);
1356 gint best_width = -1, best_height = -1;
1357 gint best_fps_n = -1, best_fps_d = -1;
1359 gdouble best_fps = 0.;
1360 GstCaps *ret = nullptr;
1363 ret = gst_caps_make_writable (caps);
1365 /* we need this to calculate how large to make the output frame */
1366 s = gst_caps_get_structure (ret, 0);
1367 if (gst_structure_has_field (s, "pixel-aspect-ratio")) {
1368 gst_structure_fixate_field_nearest_fraction (s, "pixel-aspect-ratio", 1, 1);
1369 gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_n, &par_d);
1374 GST_OBJECT_LOCK (vagg);
1375 for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
1376 GstVideoAggregatorPad *vaggpad = GST_VIDEO_AGGREGATOR_PAD (l->data);
1377 GstD3D11CompositorPad *cpad = GST_D3D11_COMPOSITOR_PAD (vaggpad);
1378 gint this_width, this_height;
1385 fps_n = GST_VIDEO_INFO_FPS_N (&vaggpad->info);
1386 fps_d = GST_VIDEO_INFO_FPS_D (&vaggpad->info);
1387 gst_d3d11_compositor_pad_get_output_size (cpad,
1388 par_n, par_d, &width, &height, &x_offset, &y_offset);
1390 if (width == 0 || height == 0)
1393 /* {x,y}_offset represent padding size of each top and left area.
1394 * To calculate total resolution, count bottom and right padding area
1396 this_width = width + MAX (cpad->xpos + 2 * x_offset, 0);
1397 this_height = height + MAX (cpad->ypos + 2 * y_offset, 0);
1399 if (best_width < this_width)
1400 best_width = this_width;
1401 if (best_height < this_height)
1402 best_height = this_height;
1407 gst_util_fraction_to_double (fps_n, fps_d, &cur_fps);
1409 if (best_fps < cur_fps) {
1415 GST_OBJECT_UNLOCK (vagg);
1417 if (best_fps_n <= 0 || best_fps_d <= 0 || best_fps == 0.0) {
1423 gst_structure_fixate_field_nearest_int (s, "width", best_width);
1424 gst_structure_fixate_field_nearest_int (s, "height", best_height);
1425 gst_structure_fixate_field_nearest_fraction (s, "framerate", best_fps_n,
1427 ret = gst_caps_fixate (ret);
1429 GST_LOG_OBJECT (agg, "Fixated caps %" GST_PTR_FORMAT, ret);
1435 convert_info_gray_to_yuv (const GstVideoInfo * gray, GstVideoInfo * yuv)
1439 if (GST_VIDEO_INFO_IS_YUV (gray)) {
1444 if (gray->finfo->depth[0] == 8) {
1445 gst_video_info_set_format (&tmp,
1446 GST_VIDEO_FORMAT_Y444, gray->width, gray->height);
1448 gst_video_info_set_format (&tmp,
1449 GST_VIDEO_FORMAT_Y444_16LE, gray->width, gray->height);
1452 tmp.colorimetry.range = gray->colorimetry.range;
1453 if (tmp.colorimetry.range == GST_VIDEO_COLOR_RANGE_UNKNOWN)
1454 tmp.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
1456 tmp.colorimetry.primaries = gray->colorimetry.primaries;
1457 if (tmp.colorimetry.primaries == GST_VIDEO_COLOR_PRIMARIES_UNKNOWN)
1458 tmp.colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
1460 tmp.colorimetry.transfer = gray->colorimetry.transfer;
1461 if (tmp.colorimetry.transfer == GST_VIDEO_TRANSFER_UNKNOWN)
1462 tmp.colorimetry.transfer = GST_VIDEO_TRANSFER_BT709;
1464 tmp.colorimetry.matrix = gray->colorimetry.matrix;
1465 if (tmp.colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_UNKNOWN)
1466 tmp.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT709;
1472 gst_d3d11_compositor_calculate_background_color (GstD3D11Compositor * self,
1473 const GstVideoInfo * info)
1475 GstD3D11ColorMatrix clear_color_matrix;
1477 gdouble converted[3];
1478 GstVideoFormat format = GST_VIDEO_INFO_FORMAT (info);
1480 if (GST_VIDEO_INFO_IS_RGB (info)) {
1481 GstVideoInfo rgb_info = *info;
1482 rgb_info.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
1484 gst_d3d11_color_range_adjust_matrix_unorm (&rgb_info, info,
1485 &clear_color_matrix);
1487 GstVideoInfo rgb_info;
1488 GstVideoInfo yuv_info;
1490 gst_video_info_set_format (&rgb_info, GST_VIDEO_FORMAT_RGBA64_LE,
1491 info->width, info->height);
1492 convert_info_gray_to_yuv (info, &yuv_info);
1494 if (yuv_info.colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_UNKNOWN ||
1495 yuv_info.colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_RGB) {
1496 GST_WARNING_OBJECT (self, "Invalid matrix is detected");
1497 yuv_info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT709;
1500 gst_d3d11_rgb_to_yuv_matrix_unorm (&rgb_info,
1501 &yuv_info, &clear_color_matrix);
1504 /* Calculate black and white color values */
1505 for (guint i = 0; i < 2; i++) {
1506 GstD3D11CompositorClearColor *clear_color = &self->clear_color[i];
1507 rgb[0] = rgb[1] = rgb[2] = (gdouble) i;
1509 for (guint j = 0; j < 3; j++) {
1511 for (guint k = 0; k < 3; k++) {
1512 converted[j] += clear_color_matrix.matrix[j][k] * rgb[k];
1514 converted[j] += clear_color_matrix.offset[j];
1515 converted[j] = CLAMP (converted[j],
1516 clear_color_matrix.min[j], clear_color_matrix.max[j]);
1519 GST_DEBUG_OBJECT (self, "Calculated background color RGB: %f, %f, %f",
1520 converted[0], converted[1], converted[2]);
1522 if (GST_VIDEO_INFO_IS_RGB (info) || GST_VIDEO_INFO_IS_GRAY (info)) {
1523 for (guint j = 0; j < 3; j++)
1524 clear_color->color[0][j] = converted[j];
1525 clear_color->color[0][3] = 1.0;
1528 case GST_VIDEO_FORMAT_VUYA:
1529 clear_color->color[0][0] = converted[2];
1530 clear_color->color[0][1] = converted[1];
1531 clear_color->color[0][2] = converted[0];
1532 clear_color->color[0][3] = 1.0;
1534 case GST_VIDEO_FORMAT_NV12:
1535 case GST_VIDEO_FORMAT_NV21:
1536 case GST_VIDEO_FORMAT_P010_10LE:
1537 case GST_VIDEO_FORMAT_P012_LE:
1538 case GST_VIDEO_FORMAT_P016_LE:
1539 clear_color->color[0][0] = converted[0];
1540 clear_color->color[0][1] = 0;
1541 clear_color->color[0][2] = 0;
1542 clear_color->color[0][3] = 1.0;
1543 if (format == GST_VIDEO_FORMAT_NV21) {
1544 clear_color->color[1][0] = converted[2];
1545 clear_color->color[1][1] = converted[1];
1547 clear_color->color[1][0] = converted[1];
1548 clear_color->color[1][1] = converted[2];
1550 clear_color->color[1][2] = 0;
1551 clear_color->color[1][3] = 1.0;
1553 case GST_VIDEO_FORMAT_I420:
1554 case GST_VIDEO_FORMAT_YV12:
1555 case GST_VIDEO_FORMAT_I420_10LE:
1556 case GST_VIDEO_FORMAT_I420_12LE:
1557 case GST_VIDEO_FORMAT_Y42B:
1558 case GST_VIDEO_FORMAT_I422_10LE:
1559 case GST_VIDEO_FORMAT_I422_12LE:
1560 case GST_VIDEO_FORMAT_Y444:
1561 case GST_VIDEO_FORMAT_Y444_10LE:
1562 case GST_VIDEO_FORMAT_Y444_12LE:
1563 case GST_VIDEO_FORMAT_Y444_16LE:
1564 clear_color->color[0][0] = converted[0];
1565 clear_color->color[0][1] = 0;
1566 clear_color->color[0][2] = 0;
1567 clear_color->color[0][3] = 1.0;
1568 if (format == GST_VIDEO_FORMAT_YV12) {
1569 clear_color->color[1][0] = converted[2];
1570 clear_color->color[2][0] = converted[1];
1572 clear_color->color[1][0] = converted[1];
1573 clear_color->color[2][0] = converted[2];
1575 clear_color->color[1][1] = 0;
1576 clear_color->color[1][2] = 0;
1577 clear_color->color[1][3] = 1.0;
1578 clear_color->color[2][1] = 0;
1579 clear_color->color[2][2] = 0;
1580 clear_color->color[2][3] = 1.0;
1583 g_assert_not_reached ();
1591 gst_d3d11_compositor_negotiated_src_caps (GstAggregator * agg, GstCaps * caps)
1593 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (agg);
1594 GstCapsFeatures *features;
1597 if (!gst_video_info_from_caps (&info, caps)) {
1598 GST_ERROR_OBJECT (self, "Failed to convert caps to info");
1602 features = gst_caps_get_features (caps, 0);
1604 && gst_caps_features_contains (features,
1605 GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY)) {
1606 GST_DEBUG_OBJECT (self, "Negotiated with D3D11 memory caps");
1607 self->downstream_supports_d3d11 = TRUE;
1609 GST_DEBUG_OBJECT (self, "Negotiated with system memory caps");
1610 self->downstream_supports_d3d11 = FALSE;
1613 gst_element_foreach_sink_pad (GST_ELEMENT_CAST (self),
1614 (GstElementForeachPadFunc) gst_d3d11_compositor_pad_clear_resource,
1617 gst_clear_buffer (&self->fallback_buf);
1618 g_clear_pointer (&self->checker_background, gst_d3d11_compositor_quad_free);
1620 gst_d3d11_compositor_calculate_background_color (self, &info);
1622 if (!self->downstream_supports_d3d11) {
1623 GstD3D11AllocationParams *d3d11_params;
1624 GstBufferPool *pool;
1625 GstFlowReturn flow_ret;
1627 d3d11_params = gst_d3d11_allocation_params_new (self->device,
1628 &info, GST_D3D11_ALLOCATION_FLAG_DEFAULT,
1629 D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET, 0);
1631 pool = gst_d3d11_buffer_pool_new_with_options (self->device,
1632 caps, d3d11_params, 0, 0);
1633 gst_d3d11_allocation_params_free (d3d11_params);
1636 GST_ERROR_OBJECT (self, "Failed to create pool");
1640 if (!gst_buffer_pool_set_active (pool, TRUE)) {
1641 GST_ERROR_OBJECT (self, "Failed to set active");
1642 gst_object_unref (pool);
1646 flow_ret = gst_buffer_pool_acquire_buffer (pool, &self->fallback_buf,
1648 if (flow_ret != GST_FLOW_OK) {
1649 GST_ERROR_OBJECT (self, "Failed to acquire buffer");
1650 gst_object_unref (pool);
1654 gst_buffer_pool_set_active (pool, FALSE);
1655 gst_object_unref (pool);
1658 return GST_AGGREGATOR_CLASS (parent_class)->negotiated_src_caps (agg, caps);
1662 gst_d3d11_compositor_propose_allocation (GstAggregator * agg,
1663 GstAggregatorPad * pad, GstQuery * decide_query, GstQuery * query)
1665 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (agg);
1667 GstBufferPool *pool;
1671 gst_query_parse_allocation (query, &caps, nullptr);
1673 if (caps == nullptr)
1676 if (!gst_video_info_from_caps (&info, caps))
1679 if (gst_query_get_n_allocation_pools (query) == 0) {
1680 GstCapsFeatures *features;
1681 GstStructure *config;
1682 gboolean is_d3d11 = FALSE;
1684 features = gst_caps_get_features (caps, 0);
1686 && gst_caps_features_contains (features,
1687 GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY)) {
1688 GST_DEBUG_OBJECT (pad, "upstream support d3d11 memory");
1689 pool = gst_d3d11_buffer_pool_new (self->device);
1692 pool = gst_video_buffer_pool_new ();
1696 GST_ERROR_OBJECT (self, "Failed to create buffer pool");
1700 config = gst_buffer_pool_get_config (pool);
1701 gst_buffer_pool_config_add_option (config,
1702 GST_BUFFER_POOL_OPTION_VIDEO_META);
1704 size = GST_VIDEO_INFO_SIZE (&info);
1706 GstD3D11AllocationParams *d3d11_params;
1709 gst_d3d11_allocation_params_new (self->device,
1710 &info, GST_D3D11_ALLOCATION_FLAG_DEFAULT, D3D11_BIND_SHADER_RESOURCE,
1713 gst_buffer_pool_config_set_d3d11_allocation_params (config, d3d11_params);
1714 gst_d3d11_allocation_params_free (d3d11_params);
1716 gst_buffer_pool_config_add_option (config,
1717 GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
1720 gst_buffer_pool_config_set_params (config, caps, (guint) size, 0, 0);
1722 if (!gst_buffer_pool_set_config (pool, config)) {
1723 GST_ERROR_OBJECT (pool, "Couldn't set config");
1724 gst_object_unref (pool);
1729 /* d3d11 buffer pool will update buffer size based on allocated texture,
1730 * get size from config again */
1731 config = gst_buffer_pool_get_config (pool);
1732 gst_buffer_pool_config_get_params (config,
1733 nullptr, &size, nullptr, nullptr);
1734 gst_structure_free (config);
1736 gst_query_add_allocation_pool (query, pool, size, 0, 0);
1737 gst_object_unref (pool);
1740 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, nullptr);
1741 gst_query_add_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE, nullptr);
1747 gst_d3d11_compositor_decide_allocation (GstAggregator * agg, GstQuery * query)
1749 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (agg);
1751 GstBufferPool *pool = nullptr;
1752 guint n, size, min, max;
1754 GstStructure *config;
1755 gboolean use_d3d11_pool;
1757 gst_query_parse_allocation (query, &caps, nullptr);
1760 GST_DEBUG_OBJECT (self, "No output caps");
1764 if (!gst_video_info_from_caps (&info, caps)) {
1765 GST_ERROR_OBJECT (self, "Invalid caps");
1769 use_d3d11_pool = self->downstream_supports_d3d11;
1771 n = gst_query_get_n_allocation_pools (query);
1773 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
1775 /* create our own pool */
1776 if (pool && use_d3d11_pool) {
1777 if (!GST_IS_D3D11_BUFFER_POOL (pool)) {
1778 GST_DEBUG_OBJECT (self,
1779 "Downstream pool is not d3d11, will create new one");
1780 gst_clear_object (&pool);
1782 GstD3D11BufferPool *dpool = GST_D3D11_BUFFER_POOL (pool);
1783 if (dpool->device != self->device) {
1784 GST_DEBUG_OBJECT (self, "Different device, will create new one");
1785 gst_clear_object (&pool);
1790 size = (guint) info.size;
1794 pool = gst_d3d11_buffer_pool_new (self->device);
1796 pool = gst_video_buffer_pool_new ();
1802 config = gst_buffer_pool_get_config (pool);
1803 gst_buffer_pool_config_set_params (config, caps, size, min, max);
1804 gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
1806 if (use_d3d11_pool) {
1807 GstD3D11AllocationParams *d3d11_params;
1809 d3d11_params = gst_buffer_pool_config_get_d3d11_allocation_params (config);
1810 if (!d3d11_params) {
1811 d3d11_params = gst_d3d11_allocation_params_new (self->device,
1812 &info, GST_D3D11_ALLOCATION_FLAG_DEFAULT, D3D11_BIND_RENDER_TARGET,
1817 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&info); i++) {
1818 d3d11_params->desc[i].BindFlags |= D3D11_BIND_RENDER_TARGET;
1822 gst_buffer_pool_config_set_d3d11_allocation_params (config, d3d11_params);
1823 gst_d3d11_allocation_params_free (d3d11_params);
1826 gst_buffer_pool_set_config (pool, config);
1828 /* d3d11 buffer pool will update buffer size based on allocated texture,
1829 * get size from config again */
1830 config = gst_buffer_pool_get_config (pool);
1831 gst_buffer_pool_config_get_params (config, nullptr, &size, nullptr, nullptr);
1832 gst_structure_free (config);
1835 gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
1837 gst_query_add_allocation_pool (query, pool, size, min, max);
1838 gst_object_unref (pool);
1858 static GstD3D11CompositorQuad *
1859 gst_d3d11_compositor_create_checker_quad (GstD3D11Compositor * self,
1860 const GstVideoInfo * info)
1862 GstD3D11CompositorQuad *quad = nullptr;
1863 VertexData *vertex_data;
1865 ID3D11Device *device_handle;
1866 ID3D11DeviceContext *context_handle;
1867 D3D11_MAPPED_SUBRESOURCE map;
1868 D3D11_INPUT_ELEMENT_DESC input_desc;
1869 D3D11_BUFFER_DESC buffer_desc;
1870 ComPtr < ID3D11Buffer > vertex_buffer;
1871 ComPtr < ID3D11Buffer > index_buffer;
1872 ComPtr < ID3D11PixelShader > ps;
1873 ComPtr < ID3D11VertexShader > vs;
1874 ComPtr < ID3D11InputLayout > layout;
1876 const gchar *ps_src;
1878 device_handle = gst_d3d11_device_get_device_handle (self->device);
1879 context_handle = gst_d3d11_device_get_device_context_handle (self->device);
1881 if (GST_VIDEO_INFO_IS_RGB (info)) {
1882 ps_src = checker_ps_src_rgb;
1883 } else if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_VUYA) {
1884 ps_src = checker_ps_src_vuya;
1886 ps_src = checker_ps_src_luma;
1889 hr = gst_d3d11_create_pixel_shader_simple (self->device, ps_src, "main", &ps);
1890 if (!gst_d3d11_result (hr, self->device)) {
1891 GST_ERROR_OBJECT (self, "Couldn't setup pixel shader");
1895 memset (&input_desc, 0, sizeof (D3D11_INPUT_ELEMENT_DESC));
1896 input_desc.SemanticName = "POSITION";
1897 input_desc.SemanticIndex = 0;
1898 input_desc.Format = DXGI_FORMAT_R32G32B32_FLOAT;
1899 input_desc.InputSlot = 0;
1900 input_desc.AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
1901 input_desc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
1902 input_desc.InstanceDataStepRate = 0;
1904 hr = gst_d3d11_create_vertex_shader_simple (self->device, checker_vs_src,
1905 "main", &input_desc, 1, &vs, &layout);
1906 if (!gst_d3d11_result (hr, self->device)) {
1907 GST_ERROR_OBJECT (self, "Couldn't setup vertex shader");
1911 memset (&buffer_desc, 0, sizeof (D3D11_BUFFER_DESC));
1912 buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
1913 buffer_desc.ByteWidth = sizeof (VertexData) * 4;
1914 buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
1915 buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1917 hr = device_handle->CreateBuffer (&buffer_desc, nullptr, &vertex_buffer);
1918 if (!gst_d3d11_result (hr, self->device)) {
1919 GST_ERROR_OBJECT (self,
1920 "Couldn't create vertex buffer, hr: 0x%x", (guint) hr);
1924 hr = context_handle->Map (vertex_buffer.Get (),
1925 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
1927 if (!gst_d3d11_result (hr, self->device)) {
1928 GST_ERROR_OBJECT (self, "Couldn't map vertex buffer, hr: 0x%x", (guint) hr);
1932 vertex_data = (VertexData *) map.pData;
1934 vertex_data[0].position.x = -1.0f;
1935 vertex_data[0].position.y = -1.0f;
1936 vertex_data[0].position.z = 0.0f;
1937 vertex_data[0].texture.u = 0.0f;
1938 vertex_data[0].texture.v = 1.0f;
1941 vertex_data[1].position.x = -1.0f;
1942 vertex_data[1].position.y = 1.0f;
1943 vertex_data[1].position.z = 0.0f;
1944 vertex_data[1].texture.u = 0.0f;
1945 vertex_data[1].texture.v = 0.0f;
1948 vertex_data[2].position.x = 1.0f;
1949 vertex_data[2].position.y = 1.0f;
1950 vertex_data[2].position.z = 0.0f;
1951 vertex_data[2].texture.u = 1.0f;
1952 vertex_data[2].texture.v = 0.0f;
1955 vertex_data[3].position.x = 1.0f;
1956 vertex_data[3].position.y = -1.0f;
1957 vertex_data[3].position.z = 0.0f;
1958 vertex_data[3].texture.u = 1.0f;
1959 vertex_data[3].texture.v = 1.0f;
1961 context_handle->Unmap (vertex_buffer.Get (), 0);
1963 buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
1964 buffer_desc.ByteWidth = sizeof (WORD) * 6;
1965 buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
1966 buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1968 hr = device_handle->CreateBuffer (&buffer_desc, nullptr, &index_buffer);
1969 if (!gst_d3d11_result (hr, self->device)) {
1970 GST_ERROR_OBJECT (self,
1971 "Couldn't create index buffer, hr: 0x%x", (guint) hr);
1975 hr = context_handle->Map (index_buffer.Get (),
1976 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
1978 if (!gst_d3d11_result (hr, self->device)) {
1979 GST_ERROR_OBJECT (self, "Couldn't map index buffer, hr: 0x%x", (guint) hr);
1983 indices = (WORD *) map.pData;
1985 /* clockwise indexing */
1986 indices[0] = 0; /* bottom left */
1987 indices[1] = 1; /* top left */
1988 indices[2] = 2; /* top right */
1990 indices[3] = 3; /* bottom right */
1991 indices[4] = 0; /* bottom left */
1992 indices[5] = 2; /* top right */
1994 context_handle->Unmap (index_buffer.Get (), 0);
1995 quad = g_new0 (GstD3D11CompositorQuad, 1);
1996 quad->ps = ps.Detach ();
1997 quad->vs = vs.Detach ();
1998 quad->layout = layout.Detach ();
1999 quad->vertex_buffer = vertex_buffer.Detach ();
2000 quad->index_buffer = index_buffer.Detach ();
2002 quad->viewport.TopLeftX = 0;
2003 quad->viewport.TopLeftY = 0;
2004 quad->viewport.Width = GST_VIDEO_INFO_WIDTH (info);
2005 quad->viewport.Height = GST_VIDEO_INFO_HEIGHT (info);
2006 quad->viewport.MinDepth = 0.0f;
2007 quad->viewport.MaxDepth = 1.0f;
2013 gst_d3d11_compositor_quad_free (GstD3D11CompositorQuad * quad)
2018 GST_D3D11_CLEAR_COM (quad->ps);
2019 GST_D3D11_CLEAR_COM (quad->vs);
2020 GST_D3D11_CLEAR_COM (quad->layout);
2021 GST_D3D11_CLEAR_COM (quad->vertex_buffer);
2022 GST_D3D11_CLEAR_COM (quad->index_buffer);
2028 gst_d3d11_compositor_draw_background_checker (GstD3D11Compositor * self,
2029 ID3D11RenderTargetView * rtv)
2031 ID3D11DeviceContext *context =
2032 gst_d3d11_device_get_device_context_handle (self->device);
2034 UINT strides = sizeof (VertexData);
2035 GstD3D11CompositorQuad *quad;
2037 if (!self->checker_background) {
2038 GstVideoInfo *info = &GST_VIDEO_AGGREGATOR_CAST (self)->info;
2040 self->checker_background =
2041 gst_d3d11_compositor_create_checker_quad (self, info);
2042 if (!self->checker_background)
2046 quad = self->checker_background;
2047 context->IASetPrimitiveTopology (D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
2048 context->IASetInputLayout (quad->layout);
2049 context->IASetVertexBuffers (0, 1, &quad->vertex_buffer, &strides, &offsets);
2050 context->IASetIndexBuffer (quad->index_buffer, DXGI_FORMAT_R16_UINT, 0);
2051 context->VSSetShader (quad->vs, nullptr, 0);
2052 context->PSSetShader (quad->ps, nullptr, 0);
2053 context->RSSetViewports (1, &quad->viewport);
2054 context->OMSetRenderTargets (1, &rtv, nullptr);
2055 context->OMSetBlendState (nullptr, nullptr, 0xffffffff);
2056 context->DrawIndexed (6, 0, 0);
2057 context->OMSetRenderTargets (0, nullptr, nullptr);
2062 /* Must be called with d3d11 device lock */
2064 gst_d3d11_compositor_draw_background (GstD3D11Compositor * self,
2065 ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES], guint num_rtv)
2067 ID3D11DeviceContext *context =
2068 gst_d3d11_device_get_device_context_handle (self->device);
2069 GstD3D11CompositorClearColor *color = &self->clear_color[0];
2071 if (self->background == GST_D3D11_COMPOSITOR_BACKGROUND_CHECKER) {
2072 if (!gst_d3d11_compositor_draw_background_checker (self, rtv[0]))
2075 /* clear U and V components if needed */
2076 for (guint i = 1; i < num_rtv; i++)
2077 context->ClearRenderTargetView (rtv[i], color->color[i]);
2082 switch (self->background) {
2083 case GST_D3D11_COMPOSITOR_BACKGROUND_BLACK:
2084 color = &self->clear_color[0];
2086 case GST_D3D11_COMPOSITOR_BACKGROUND_WHITE:
2087 color = &self->clear_color[1];
2089 case GST_D3D11_COMPOSITOR_BACKGROUND_TRANSPARENT:
2090 color = &self->clear_color[2];
2093 g_assert_not_reached ();
2097 for (guint i = 0; i < num_rtv; i++)
2098 context->ClearRenderTargetView (rtv[i], color->color[i]);
2103 static GstFlowReturn
2104 gst_d3d11_compositor_aggregate_frames (GstVideoAggregator * vagg,
2107 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (vagg);
2109 GstBuffer *target_buf = outbuf;
2110 GstFlowReturn ret = GST_FLOW_OK;
2111 ID3D11RenderTargetView *rtv[GST_VIDEO_MAX_PLANES] = { nullptr, };
2112 GstVideoFrame target_frame;
2113 guint num_rtv = GST_VIDEO_INFO_N_PLANES (&vagg->info);
2114 GstD3D11DeviceLockGuard lk (self->device);
2116 if (!self->downstream_supports_d3d11)
2117 target_buf = self->fallback_buf;
2119 if (!gst_video_frame_map (&target_frame, &vagg->info, target_buf,
2120 (GstMapFlags) (GST_MAP_WRITE | GST_MAP_D3D11))) {
2121 GST_ERROR_OBJECT (self, "Failed to map render target frame");
2122 return GST_FLOW_ERROR;
2125 if (!gst_d3d11_buffer_get_render_target_view (target_buf, rtv)) {
2126 GST_ERROR_OBJECT (self, "RTV is unavailable");
2127 gst_video_frame_unmap (&target_frame);
2128 return GST_FLOW_ERROR;
2131 if (!gst_d3d11_compositor_draw_background (self, rtv, num_rtv)) {
2132 GST_ERROR_OBJECT (self, "Couldn't draw background");
2133 gst_video_frame_unmap (&target_frame);
2134 return GST_FLOW_ERROR;
2137 gst_video_frame_unmap (&target_frame);
2139 GST_OBJECT_LOCK (self);
2140 for (iter = GST_ELEMENT (vagg)->sinkpads; iter; iter = g_list_next (iter)) {
2141 GstVideoAggregatorPad *pad = GST_VIDEO_AGGREGATOR_PAD (iter->data);
2142 GstD3D11CompositorPad *cpad = GST_D3D11_COMPOSITOR_PAD (pad);
2143 GstVideoFrame *prepared_frame =
2144 gst_video_aggregator_pad_get_prepared_frame (pad);
2146 GstVideoCropMeta *crop_meta;
2148 if (!prepared_frame)
2151 if (!gst_d3d11_compositor_pad_setup_converter (pad, vagg)) {
2152 GST_ERROR_OBJECT (self, "Couldn't setup converter");
2153 ret = GST_FLOW_ERROR;
2157 crop_meta = gst_buffer_get_video_crop_meta (prepared_frame->buffer);
2161 w = crop_meta->width;
2162 h = crop_meta->height;
2165 w = pad->info.width;
2166 h = pad->info.height;
2169 g_object_set (cpad->convert, "src-x", x, "src-y", y, "src-width", w,
2170 "src-height", h, nullptr);
2172 if (!gst_d3d11_converter_convert_buffer_unlocked (cpad->convert,
2173 prepared_frame->buffer, target_buf)) {
2174 GST_ERROR_OBJECT (self, "Couldn't convert frame");
2175 ret = GST_FLOW_ERROR;
2179 GST_OBJECT_UNLOCK (self);
2181 if (ret != GST_FLOW_OK)
2184 if (!self->downstream_supports_d3d11) {
2185 if (!gst_d3d11_buffer_copy_into (outbuf, self->fallback_buf, &vagg->info)) {
2186 GST_ERROR_OBJECT (self, "Couldn't copy input buffer to fallback buffer");
2187 return GST_FLOW_ERROR;
2196 /* without holding ref */
2197 GstD3D11Device *other_device;
2198 gboolean have_same_device;
2202 gst_d3d11_compositor_check_device_update (GstElement * agg,
2203 GstVideoAggregatorPad * vpad, DeviceCheckData * data)
2205 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (agg);
2208 GstD3D11Memory *dmem;
2209 gboolean update_device = FALSE;
2211 buf = gst_video_aggregator_pad_get_current_buffer (vpad);
2215 /* Ignore gap buffer */
2216 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP) ||
2217 gst_buffer_get_size (buf) == 0) {
2221 mem = gst_buffer_peek_memory (buf, 0);
2222 if (!gst_is_d3d11_memory (mem))
2225 dmem = GST_D3D11_MEMORY_CAST (mem);
2227 /* We can use existing device */
2228 if (dmem->device == self->device) {
2229 data->have_same_device = TRUE;
2233 if (self->adapter < 0) {
2234 update_device = TRUE;
2238 g_object_get (dmem->device, "adapter", &adapter, nullptr);
2239 /* The same GPU as what user wanted, update */
2240 if (adapter == (guint) self->adapter)
2241 update_device = TRUE;
2247 data->other_device = dmem->device;
2249 /* Keep iterate since there might be one buffer which holds the same device
2254 static GstFlowReturn
2255 gst_d3d11_compositor_create_output_buffer (GstVideoAggregator * vagg,
2256 GstBuffer ** outbuffer)
2258 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (vagg);
2259 DeviceCheckData data;
2261 /* Check whether there is at least one sinkpad which holds d3d11 buffer
2262 * with compatible device, and if not, update our device */
2263 data.other_device = nullptr;
2264 data.have_same_device = FALSE;
2266 gst_element_foreach_sink_pad (GST_ELEMENT_CAST (vagg),
2267 (GstElementForeachPadFunc) gst_d3d11_compositor_check_device_update,
2270 if (data.have_same_device || !data.other_device) {
2272 GST_VIDEO_AGGREGATOR_CLASS (parent_class)->create_output_buffer (vagg,
2276 /* Clear all device dependent resources */
2277 gst_element_foreach_sink_pad (GST_ELEMENT_CAST (vagg),
2278 (GstElementForeachPadFunc) gst_d3d11_compositor_pad_clear_resource,
2281 gst_clear_buffer (&self->fallback_buf);
2282 g_clear_pointer (&self->checker_background, gst_d3d11_compositor_quad_free);
2284 GST_INFO_OBJECT (self, "Updating device %" GST_PTR_FORMAT " -> %"
2285 GST_PTR_FORMAT, self->device, data.other_device);
2286 gst_object_unref (self->device);
2287 self->device = (GstD3D11Device *) gst_object_ref (data.other_device);
2289 /* We cannot call gst_aggregator_negotiate() here, since GstVideoAggregator
2290 * is holding GST_VIDEO_AGGREGATOR_LOCK() already.
2291 * Mark reconfigure and do reconfigure later */
2292 gst_pad_mark_reconfigure (GST_AGGREGATOR_SRC_PAD (vagg));
2294 return GST_AGGREGATOR_FLOW_NEED_DATA;