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;
95 * GstD3D11CompositorOperator:
99 #define GST_TYPE_D3D11_COMPOSITOR_OPERATOR (gst_d3d11_compositor_operator_get_type())
101 gst_d3d11_compositor_operator_get_type (void)
103 static GType compositor_operator_type = 0;
105 static const GEnumValue compositor_operator[] = {
106 {GST_D3D11_COMPOSITOR_OPERATOR_SOURCE, "Source", "source"},
107 {GST_D3D11_COMPOSITOR_OPERATOR_OVER, "Over", "over"},
108 {0, nullptr, nullptr},
111 if (!compositor_operator_type) {
112 compositor_operator_type =
113 g_enum_register_static ("GstD3D11CompositorOperator",
114 compositor_operator);
116 return compositor_operator_type;
121 GST_D3D11_COMPOSITOR_SIZING_POLICY_NONE,
122 GST_D3D11_COMPOSITOR_SIZING_POLICY_KEEP_ASPECT_RATIO,
123 } GstD3D11CompositorSizingPolicy;
125 #define GST_TYPE_D3D11_COMPOSITOR_SIZING_POLICY (gst_d3d11_compositor_sizing_policy_get_type())
127 gst_d3d11_compositor_sizing_policy_get_type (void)
129 static GType sizing_policy_type = 0;
131 static const GEnumValue sizing_polices[] = {
132 {GST_D3D11_COMPOSITOR_SIZING_POLICY_NONE,
133 "None: Image is scaled to fill configured destination rectangle without "
134 "padding or keeping the aspect ratio", "none"},
135 {GST_D3D11_COMPOSITOR_SIZING_POLICY_KEEP_ASPECT_RATIO,
136 "Keep Aspect Ratio: Image is scaled to fit destination rectangle "
137 "specified by GstCompositorPad:{xpos, ypos, width, height} "
138 "with preserved aspect ratio. Resulting image will be centered in "
139 "the destination rectangle with padding if necessary",
140 "keep-aspect-ratio"},
141 {0, nullptr, nullptr},
144 if (!sizing_policy_type) {
146 g_enum_register_static ("GstD3D11CompositorSizingPolicy",
149 return sizing_policy_type;
153 static const gchar checker_vs_src[] =
156 " float4 Position : POSITION;\n"
161 " float4 Position: SV_POSITION;\n"
164 "VS_OUTPUT main(VS_INPUT input)\n"
169 static const gchar checker_ps_src_rgb[] =
170 "static const float blocksize = 8.0;\n"
171 "static const float4 high = float4(0.667, 0.667, 0.667, 1.0);\n"
172 "static const float4 low = float4(0.333, 0.333, 0.333, 1.0);\n"
175 " float4 Position: SV_POSITION;\n"
179 " float4 Plane: SV_TARGET;\n"
181 "PS_OUTPUT main(PS_INPUT input)\n"
183 " PS_OUTPUT output;\n"
184 " if ((input.Position.x % (blocksize * 2.0)) >= blocksize) {\n"
185 " if ((input.Position.y % (blocksize * 2.0)) >= blocksize)\n"
186 " output.Plane = low;\n"
188 " output.Plane = high;\n"
190 " if ((input.Position.y % (blocksize * 2.0)) < blocksize)\n"
191 " output.Plane = low;\n"
193 " output.Plane = high;\n"
198 static const gchar checker_ps_src_vuya[] =
199 "static const float blocksize = 8.0;\n"
200 "static const float4 high = float4(0.5, 0.5, 0.667, 1.0);\n"
201 "static const float4 low = float4(0.5, 0.5, 0.333, 1.0);\n"
204 " float4 Position: SV_POSITION;\n"
208 " float4 Plane: SV_TARGET;\n"
210 "PS_OUTPUT main(PS_INPUT input)\n"
212 " PS_OUTPUT output;\n"
213 " if ((input.Position.x % (blocksize * 2.0)) >= blocksize) {\n"
214 " if ((input.Position.y % (blocksize * 2.0)) >= blocksize)\n"
215 " output.Plane = low;\n"
217 " output.Plane = high;\n"
219 " if ((input.Position.y % (blocksize * 2.0)) < blocksize)\n"
220 " output.Plane = low;\n"
222 " output.Plane = high;\n"
227 static const gchar checker_ps_src_luma[] =
228 "static const float blocksize = 8.0;\n"
229 "static const float4 high = float4(0.667, 0.0, 0.0, 1.0);\n"
230 "static const float4 low = float4(0.333, 0.0, 0.0, 1.0);\n"
233 " float4 Position: SV_POSITION;\n"
237 " float4 Plane: SV_TARGET;\n"
239 "PS_OUTPUT main(PS_INPUT input)\n"
241 " PS_OUTPUT output;\n"
242 " if ((input.Position.x % (blocksize * 2.0)) >= blocksize) {\n"
243 " if ((input.Position.y % (blocksize * 2.0)) >= blocksize)\n"
244 " output.Plane = low;\n"
246 " output.Plane = high;\n"
248 " if ((input.Position.y % (blocksize * 2.0)) < blocksize)\n"
249 " output.Plane = low;\n"
251 " output.Plane = high;\n"
256 static D3D11_RENDER_TARGET_BLEND_DESC blend_templ[] = {
260 D3D11_BLEND_ONE, D3D11_BLEND_ZERO, D3D11_BLEND_OP_ADD,
261 D3D11_BLEND_ONE, D3D11_BLEND_ZERO, D3D11_BLEND_OP_ADD,
262 D3D11_COLOR_WRITE_ENABLE_ALL
267 D3D11_BLEND_SRC_ALPHA, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD,
268 D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD,
269 D3D11_COLOR_WRITE_ENABLE_ALL,
274 struct _GstD3D11CompositorPad
276 GstVideoAggregatorConvertPad parent;
278 GstD3D11Converter *convert;
280 gboolean position_updated;
281 gboolean alpha_updated;
282 gboolean blend_desc_updated;
283 gboolean config_updated;
284 ID3D11BlendState *blend;
286 D3D11_RENDER_TARGET_BLEND_DESC desc;
294 GstD3D11CompositorOperator op;
295 GstD3D11CompositorSizingPolicy sizing_policy;
296 GstVideoGammaMode gamma_mode;
297 GstVideoPrimariesMode primaries_mode;
302 ID3D11PixelShader *ps;
303 ID3D11VertexShader *vs;
304 ID3D11InputLayout *layout;
305 ID3D11Buffer *vertex_buffer;
306 ID3D11Buffer *index_buffer;
307 D3D11_VIEWPORT viewport;
308 } GstD3D11CompositorQuad;
314 } GstD3D11CompositorClearColor;
316 struct _GstD3D11Compositor
318 GstVideoAggregator parent;
320 GstD3D11Device *device;
322 GstBuffer *fallback_buf;
323 GstCaps *negotiated_caps;
325 GstD3D11CompositorQuad *checker_background;
326 /* black/white/transparent */
327 GstD3D11CompositorClearColor clear_color[3];
329 gboolean downstream_supports_d3d11;
333 GstD3D11CompositorBackground background;
345 PROP_PAD_SIZING_POLICY,
347 PROP_PAD_PRIMARIES_MODE,
350 #define DEFAULT_PAD_XPOS 0
351 #define DEFAULT_PAD_YPOS 0
352 #define DEFAULT_PAD_WIDTH 0
353 #define DEFAULT_PAD_HEIGHT 0
354 #define DEFAULT_PAD_ALPHA 1.0
355 #define DEFAULT_PAD_OPERATOR GST_D3D11_COMPOSITOR_OPERATOR_OVER
356 #define DEFAULT_PAD_SIZING_POLICY GST_D3D11_COMPOSITOR_SIZING_POLICY_NONE
357 #define DEFAULT_PAD_GAMMA_MODE GST_VIDEO_GAMMA_MODE_NONE
358 #define DEFAULT_PAD_PRIMARIES_MODE GST_VIDEO_PRIMARIES_MODE_NONE
360 static void gst_d3d11_compositor_pad_dispose (GObject * object);
361 static void gst_d3d11_compositor_pad_set_property (GObject * object,
362 guint prop_id, const GValue * value, GParamSpec * pspec);
363 static void gst_d3d11_compositor_pad_get_property (GObject * object,
364 guint prop_id, GValue * value, GParamSpec * pspec);
366 gst_d3d11_compositor_pad_prepare_frame (GstVideoAggregatorPad * pad,
367 GstVideoAggregator * vagg, GstBuffer * buffer,
368 GstVideoFrame * prepared_frame);
369 static void gst_d3d11_compositor_pad_clean_frame (GstVideoAggregatorPad * vpad,
370 GstVideoAggregator * vagg, GstVideoFrame * prepared_frame);
372 #define gst_d3d11_compositor_pad_parent_class parent_pad_class
373 G_DEFINE_TYPE (GstD3D11CompositorPad, gst_d3d11_compositor_pad,
374 GST_TYPE_VIDEO_AGGREGATOR_PAD);
377 gst_d3d11_compositor_pad_class_init (GstD3D11CompositorPadClass * klass)
379 GObjectClass *object_class = G_OBJECT_CLASS (klass);
380 GstVideoAggregatorPadClass *vagg_pad_class =
381 GST_VIDEO_AGGREGATOR_PAD_CLASS (klass);
382 GParamFlags param_flags = (GParamFlags)
383 (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS);
385 object_class->dispose = gst_d3d11_compositor_pad_dispose;
386 object_class->set_property = gst_d3d11_compositor_pad_set_property;
387 object_class->get_property = gst_d3d11_compositor_pad_get_property;
389 g_object_class_install_property (object_class, PROP_PAD_XPOS,
390 g_param_spec_int ("xpos", "X Position", "X position of the picture",
391 G_MININT, G_MAXINT, DEFAULT_PAD_XPOS, param_flags));
392 g_object_class_install_property (object_class, PROP_PAD_YPOS,
393 g_param_spec_int ("ypos", "Y Position", "Y position of the picture",
394 G_MININT, G_MAXINT, DEFAULT_PAD_YPOS, param_flags));
395 g_object_class_install_property (object_class, PROP_PAD_WIDTH,
396 g_param_spec_int ("width", "Width", "Width of the picture",
397 G_MININT, G_MAXINT, DEFAULT_PAD_WIDTH, param_flags));
398 g_object_class_install_property (object_class, PROP_PAD_HEIGHT,
399 g_param_spec_int ("height", "Height", "Height of the picture",
400 G_MININT, G_MAXINT, DEFAULT_PAD_HEIGHT, param_flags));
401 g_object_class_install_property (object_class, PROP_PAD_ALPHA,
402 g_param_spec_double ("alpha", "Alpha", "Alpha of the picture", 0.0, 1.0,
403 DEFAULT_PAD_ALPHA, param_flags));
406 * GstD3D11CompositorPad:operator:
408 * Blending operator to use for blending this pad over the previous ones
412 g_object_class_install_property (object_class, PROP_PAD_OPERATOR,
413 g_param_spec_enum ("operator", "Operator",
414 "Blending operator to use for blending this pad over the previous ones",
415 GST_TYPE_D3D11_COMPOSITOR_OPERATOR, DEFAULT_PAD_OPERATOR,
417 g_object_class_install_property (object_class, PROP_PAD_SIZING_POLICY,
418 g_param_spec_enum ("sizing-policy", "Sizing policy",
419 "Sizing policy to use for image scaling",
420 GST_TYPE_D3D11_COMPOSITOR_SIZING_POLICY, DEFAULT_PAD_SIZING_POLICY,
424 * GstD3D11CompositorPad:gamma-mode:
426 * Gamma conversion mode
430 g_object_class_install_property (object_class, PROP_PAD_GAMMA_MODE,
431 g_param_spec_enum ("gamma-mode", "Gamma mode",
432 "Gamma conversion mode", GST_TYPE_VIDEO_GAMMA_MODE,
433 DEFAULT_PAD_GAMMA_MODE, param_flags));
436 * GstD3D11CompositorPad:primaries-mode:
438 * Primaries conversion mode
442 g_object_class_install_property (object_class, PROP_PAD_PRIMARIES_MODE,
443 g_param_spec_enum ("primaries-mode", "Primaries Mode",
444 "Primaries conversion mode", GST_TYPE_VIDEO_PRIMARIES_MODE,
445 DEFAULT_PAD_PRIMARIES_MODE, param_flags));
447 vagg_pad_class->prepare_frame =
448 GST_DEBUG_FUNCPTR (gst_d3d11_compositor_pad_prepare_frame);
449 vagg_pad_class->clean_frame =
450 GST_DEBUG_FUNCPTR (gst_d3d11_compositor_pad_clean_frame);
452 gst_type_mark_as_plugin_api (GST_TYPE_D3D11_COMPOSITOR_OPERATOR,
453 (GstPluginAPIFlags) 0);
454 gst_type_mark_as_plugin_api (GST_TYPE_D3D11_COMPOSITOR_SIZING_POLICY,
455 (GstPluginAPIFlags) 0);
459 gst_d3d11_compositor_pad_init (GstD3D11CompositorPad * pad)
461 pad->xpos = DEFAULT_PAD_XPOS;
462 pad->ypos = DEFAULT_PAD_YPOS;
463 pad->width = DEFAULT_PAD_WIDTH;
464 pad->height = DEFAULT_PAD_HEIGHT;
465 pad->alpha = DEFAULT_PAD_ALPHA;
466 pad->op = DEFAULT_PAD_OPERATOR;
467 pad->sizing_policy = DEFAULT_PAD_SIZING_POLICY;
468 pad->desc = blend_templ[DEFAULT_PAD_OPERATOR];
469 pad->gamma_mode = DEFAULT_PAD_GAMMA_MODE;
470 pad->primaries_mode = DEFAULT_PAD_PRIMARIES_MODE;
474 gst_d3d11_compositor_pad_dispose (GObject * object)
476 GstD3D11CompositorPad *self = GST_D3D11_COMPOSITOR_PAD (object);
478 gst_clear_object (&self->convert);
479 GST_D3D11_CLEAR_COM (self->blend);
481 G_OBJECT_CLASS (parent_pad_class)->dispose (object);
485 gst_d3d11_compositor_pad_update_position (GstD3D11CompositorPad * self,
486 gint * old, const GValue * value)
488 gint tmp = g_value_get_int (value);
492 self->position_updated = TRUE;
497 gst_d3d11_compositor_pad_set_property (GObject * object, guint prop_id,
498 const GValue * value, GParamSpec * pspec)
500 GstD3D11CompositorPad *pad = GST_D3D11_COMPOSITOR_PAD (object);
504 gst_d3d11_compositor_pad_update_position (pad, &pad->xpos, value);
507 gst_d3d11_compositor_pad_update_position (pad, &pad->ypos, value);
510 gst_d3d11_compositor_pad_update_position (pad, &pad->width, value);
512 case PROP_PAD_HEIGHT:
513 gst_d3d11_compositor_pad_update_position (pad, &pad->height, value);
515 case PROP_PAD_ALPHA:{
516 gdouble alpha = g_value_get_double (value);
517 if (pad->alpha != alpha) {
518 pad->alpha_updated = TRUE;
523 case PROP_PAD_OPERATOR:{
524 GstD3D11CompositorOperator op =
525 (GstD3D11CompositorOperator) g_value_get_enum (value);
528 pad->desc = blend_templ[op];
529 pad->blend_desc_updated = TRUE;
533 case PROP_PAD_SIZING_POLICY:{
534 GstD3D11CompositorSizingPolicy policy =
535 (GstD3D11CompositorSizingPolicy) g_value_get_enum (value);
536 if (pad->sizing_policy != policy) {
537 pad->sizing_policy = policy;
538 pad->position_updated = TRUE;
542 case PROP_PAD_GAMMA_MODE:{
543 GstVideoGammaMode mode = (GstVideoGammaMode) g_value_get_enum (value);
544 if (pad->gamma_mode != mode) {
545 pad->gamma_mode = mode;
546 pad->config_updated = TRUE;
550 case PROP_PAD_PRIMARIES_MODE:{
551 GstVideoPrimariesMode mode =
552 (GstVideoPrimariesMode) g_value_get_enum (value);
553 if (pad->primaries_mode != mode) {
554 pad->primaries_mode = mode;
555 pad->config_updated = TRUE;
560 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
566 gst_d3d11_compositor_pad_get_property (GObject * object, guint prop_id,
567 GValue * value, GParamSpec * pspec)
569 GstD3D11CompositorPad *pad = GST_D3D11_COMPOSITOR_PAD (object);
573 g_value_set_int (value, pad->xpos);
576 g_value_set_int (value, pad->ypos);
579 g_value_set_int (value, pad->width);
581 case PROP_PAD_HEIGHT:
582 g_value_set_int (value, pad->height);
585 g_value_set_double (value, pad->alpha);
587 case PROP_PAD_OPERATOR:
588 g_value_set_enum (value, pad->op);
590 case PROP_PAD_SIZING_POLICY:
591 g_value_set_enum (value, pad->sizing_policy);
593 case PROP_PAD_GAMMA_MODE:
594 g_value_set_enum (value, pad->gamma_mode);
596 case PROP_PAD_PRIMARIES_MODE:
597 g_value_set_enum (value, pad->primaries_mode);
600 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
606 gst_d3d11_compositor_pad_get_output_size (GstD3D11CompositorPad * comp_pad,
607 gint out_par_n, gint out_par_d, gint * width, gint * height,
608 gint * x_offset, gint * y_offset)
610 GstVideoAggregatorPad *vagg_pad = GST_VIDEO_AGGREGATOR_PAD (comp_pad);
611 gint pad_width, pad_height;
619 /* FIXME: Anything better we can do here? */
620 if (!vagg_pad->info.finfo
621 || vagg_pad->info.finfo->format == GST_VIDEO_FORMAT_UNKNOWN) {
622 GST_DEBUG_OBJECT (comp_pad, "Have no caps yet");
628 0 ? GST_VIDEO_INFO_WIDTH (&vagg_pad->info) : comp_pad->width;
631 0 ? GST_VIDEO_INFO_HEIGHT (&vagg_pad->info) : comp_pad->height;
633 if (pad_width == 0 || pad_height == 0)
636 if (!gst_video_calculate_display_ratio (&dar_n, &dar_d, pad_width, pad_height,
637 GST_VIDEO_INFO_PAR_N (&vagg_pad->info),
638 GST_VIDEO_INFO_PAR_D (&vagg_pad->info), out_par_n, out_par_d)) {
639 GST_WARNING_OBJECT (comp_pad, "Cannot calculate display aspect ratio");
643 GST_TRACE_OBJECT (comp_pad, "scaling %ux%u by %u/%u (%u/%u / %u/%u)",
644 pad_width, pad_height, dar_n, dar_d,
645 GST_VIDEO_INFO_PAR_N (&vagg_pad->info),
646 GST_VIDEO_INFO_PAR_D (&vagg_pad->info), out_par_n, out_par_d);
648 switch (comp_pad->sizing_policy) {
649 case GST_D3D11_COMPOSITOR_SIZING_POLICY_NONE:
650 /* Pick either height or width, whichever is an integer multiple of the
651 * display aspect ratio. However, prefer preserving the height to account
652 * for interlaced video. */
653 if (pad_height % dar_n == 0) {
654 pad_width = gst_util_uint64_scale_int (pad_height, dar_n, dar_d);
655 } else if (pad_width % dar_d == 0) {
656 pad_height = gst_util_uint64_scale_int (pad_width, dar_d, dar_n);
658 pad_width = gst_util_uint64_scale_int (pad_height, dar_n, dar_d);
661 case GST_D3D11_COMPOSITOR_SIZING_POLICY_KEEP_ASPECT_RATIO:{
662 gint from_dar_n, from_dar_d, to_dar_n, to_dar_d, num, den;
664 /* Calculate DAR again with actual video size */
665 if (!gst_util_fraction_multiply (GST_VIDEO_INFO_WIDTH (&vagg_pad->info),
666 GST_VIDEO_INFO_HEIGHT (&vagg_pad->info),
667 GST_VIDEO_INFO_PAR_N (&vagg_pad->info),
668 GST_VIDEO_INFO_PAR_D (&vagg_pad->info), &from_dar_n,
670 from_dar_n = from_dar_d = -1;
673 if (!gst_util_fraction_multiply (pad_width, pad_height,
674 out_par_n, out_par_d, &to_dar_n, &to_dar_d)) {
675 to_dar_n = to_dar_d = -1;
678 if (from_dar_n != to_dar_n || from_dar_d != to_dar_d) {
679 /* Calculate new output resolution */
680 if (from_dar_n != -1 && from_dar_d != -1
681 && gst_util_fraction_multiply (from_dar_n, from_dar_d,
682 out_par_d, out_par_n, &num, &den)) {
683 GstVideoRectangle src_rect, dst_rect, rst_rect;
685 src_rect.h = gst_util_uint64_scale_int (pad_width, den, num);
686 if (src_rect.h == 0) {
692 src_rect.x = src_rect.y = 0;
693 src_rect.w = pad_width;
695 dst_rect.x = dst_rect.y = 0;
696 dst_rect.w = pad_width;
697 dst_rect.h = pad_height;
699 /* Scale rect to be centered in destination rect */
700 gst_video_center_rect (&src_rect, &dst_rect, &rst_rect, TRUE);
702 GST_LOG_OBJECT (comp_pad,
703 "Re-calculated size %dx%d -> %dx%d (x-offset %d, y-offset %d)",
704 pad_width, pad_height, rst_rect.w, rst_rect.h, rst_rect.x,
707 *x_offset = rst_rect.x;
708 *y_offset = rst_rect.y;
709 pad_width = rst_rect.w;
710 pad_height = rst_rect.h;
712 GST_WARNING_OBJECT (comp_pad, "Failed to calculate output size");
725 *height = pad_height;
728 static GstVideoRectangle
729 clamp_rectangle (gint x, gint y, gint w, gint h, gint outer_width,
734 GstVideoRectangle clamped;
736 /* Clamp the x/y coordinates of this frame to the output boundaries to cover
737 * the case where (say, with negative xpos/ypos or w/h greater than the output
738 * size) the non-obscured portion of the frame could be outside the bounds of
739 * the video itself and hence not visible at all */
740 clamped.x = CLAMP (x, 0, outer_width);
741 clamped.y = CLAMP (y, 0, outer_height);
742 clamped.w = CLAMP (x2, 0, outer_width) - clamped.x;
743 clamped.h = CLAMP (y2, 0, outer_height) - clamped.y;
749 gst_d3d11_compositor_pad_check_frame_obscured (GstVideoAggregatorPad * pad,
750 GstVideoAggregator * vagg)
752 GstD3D11CompositorPad *cpad = GST_D3D11_COMPOSITOR_PAD (pad);
754 GstVideoInfo *info = &vagg->info;
755 /* The rectangle representing this frame, clamped to the video's boundaries.
756 * Due to the clamping, this is different from the frame width/height above. */
757 GstVideoRectangle frame_rect;
758 gint x_offset, y_offset;
760 /* There's three types of width/height here:
761 * 1. GST_VIDEO_FRAME_WIDTH/HEIGHT:
762 * The frame width/height (same as pad->info.height/width;
763 * see gst_video_frame_map())
764 * 2. cpad->width/height:
765 * The optional pad property for scaling the frame (if zero, the video is
769 gst_d3d11_compositor_pad_get_output_size (cpad, GST_VIDEO_INFO_PAR_N (info),
770 GST_VIDEO_INFO_PAR_D (info), &width, &height, &x_offset, &y_offset);
772 frame_rect = clamp_rectangle (cpad->xpos + x_offset, cpad->ypos + y_offset,
773 width, height, GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info));
775 if (frame_rect.w == 0 || frame_rect.h == 0) {
776 GST_DEBUG_OBJECT (pad, "Resulting frame is zero-width or zero-height "
777 "(w: %i, h: %i), skipping", frame_rect.w, frame_rect.h);
785 gst_d3d11_compositor_pad_prepare_frame (GstVideoAggregatorPad * pad,
786 GstVideoAggregator * vagg, GstBuffer * buffer,
787 GstVideoFrame * prepared_frame)
789 /* Skip this frame */
790 if (gst_d3d11_compositor_pad_check_frame_obscured (pad, vagg))
793 /* don't map/upload now, it will happen in converter object.
794 * Just mark this frame is preparted instead */
795 prepared_frame->buffer = buffer;
801 gst_d3d11_compositor_pad_clean_frame (GstVideoAggregatorPad * vpad,
802 GstVideoAggregator * vagg, GstVideoFrame * prepared_frame)
804 memset (prepared_frame, 0, sizeof (GstVideoFrame));
808 gst_d3d11_compositor_pad_setup_converter (GstVideoAggregatorPad * pad,
809 GstVideoAggregator * vagg)
811 GstD3D11CompositorPad *cpad = GST_D3D11_COMPOSITOR_PAD (pad);
812 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (vagg);
814 GstVideoInfo *info = &vagg->info;
815 GstVideoRectangle frame_rect;
816 gboolean is_first = FALSE;
817 gboolean output_has_alpha_comp = FALSE;
818 gint x_offset, y_offset;
819 #ifndef GST_DISABLE_GST_DEBUG
822 static const D3D11_RENDER_TARGET_BLEND_DESC blend_over_no_alpha = {
824 D3D11_BLEND_BLEND_FACTOR, D3D11_BLEND_INV_BLEND_FACTOR, D3D11_BLEND_OP_ADD,
825 D3D11_BLEND_BLEND_FACTOR, D3D11_BLEND_INV_BLEND_FACTOR, D3D11_BLEND_OP_ADD,
826 D3D11_COLOR_WRITE_ENABLE_ALL,
829 if (GST_VIDEO_INFO_HAS_ALPHA (info) ||
830 GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_BGRx ||
831 GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_RGBx) {
832 output_has_alpha_comp = TRUE;
835 if (cpad->config_updated) {
836 gst_clear_object (&cpad->convert);
837 cpad->config_updated = FALSE;
840 if (!cpad->convert) {
841 GstStructure *config = gst_structure_new ("converter-config",
842 /* XXX: Always use shader, to workaround buggy blending behavior of
843 * vendor implemented converter. Need investigation */
844 GST_D3D11_CONVERTER_OPT_BACKEND, GST_TYPE_D3D11_CONVERTER_BACKEND,
845 GST_D3D11_CONVERTER_BACKEND_SHADER,
846 GST_D3D11_CONVERTER_OPT_GAMMA_MODE,
847 GST_TYPE_VIDEO_GAMMA_MODE, cpad->gamma_mode,
848 GST_D3D11_CONVERTER_OPT_PRIMARIES_MODE,
849 GST_TYPE_VIDEO_PRIMARIES_MODE, cpad->primaries_mode, nullptr);
851 cpad->convert = gst_d3d11_converter_new (self->device, &pad->info, info,
853 if (!cpad->convert) {
854 GST_ERROR_OBJECT (pad, "Couldn't create converter");
861 if (cpad->alpha_updated || is_first) {
862 if (output_has_alpha_comp) {
863 g_object_set (cpad->convert, "alpha", cpad->alpha, nullptr);
865 gfloat blend_factor = cpad->alpha;
867 g_object_set (cpad->convert,
868 "blend-factor-red", blend_factor,
869 "blend-factor-green", blend_factor,
870 "blend-factor-blue", blend_factor,
871 "blend-factor-alpha", blend_factor, nullptr);
874 cpad->alpha_updated = FALSE;
877 if (!cpad->blend || cpad->blend_desc_updated || is_first) {
879 D3D11_BLEND_DESC desc = { 0, };
880 ID3D11BlendState *blend = nullptr;
881 ID3D11Device *device_handle =
882 gst_d3d11_device_get_device_handle (self->device);
883 gfloat blend_factor = 1.0f;
885 GST_D3D11_CLEAR_COM (cpad->blend);
887 desc.AlphaToCoverageEnable = FALSE;
888 desc.IndependentBlendEnable = FALSE;
889 desc.RenderTarget[0] = cpad->desc;
890 if (!output_has_alpha_comp &&
891 cpad->op == GST_D3D11_COMPOSITOR_OPERATOR_OVER) {
892 desc.RenderTarget[0] = blend_over_no_alpha;
893 blend_factor = cpad->alpha;
896 hr = device_handle->CreateBlendState (&desc, &blend);
897 if (!gst_d3d11_result (hr, self->device)) {
898 GST_ERROR_OBJECT (pad, "Couldn't create blend staten, hr: 0x%x",
904 g_object_set (cpad->convert, "blend-state", blend,
905 "blend-factor-red", blend_factor,
906 "blend-factor-green", blend_factor,
907 "blend-factor-blue", blend_factor,
908 "blend-factor-alpha", blend_factor, nullptr);
910 cpad->blend_desc_updated = FALSE;
913 if (!is_first && !cpad->position_updated)
916 gst_d3d11_compositor_pad_get_output_size (cpad, GST_VIDEO_INFO_PAR_N (info),
917 GST_VIDEO_INFO_PAR_D (info), &width, &height, &x_offset, &y_offset);
919 frame_rect = clamp_rectangle (cpad->xpos + x_offset, cpad->ypos + y_offset,
920 width, height, GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info));
922 #ifndef GST_DISABLE_GST_DEBUG
923 g_object_get (pad, "zorder", &zorder, nullptr);
925 GST_LOG_OBJECT (pad, "Update position, pad-xpos %d, pad-ypos %d, "
926 "pad-zorder %d, pad-width %d, pad-height %d, in-resolution %dx%d, "
927 "out-resoution %dx%d, dst-{x,y,width,height} %d-%d-%d-%d",
928 cpad->xpos, cpad->ypos, zorder, cpad->width, cpad->height,
929 GST_VIDEO_INFO_WIDTH (&pad->info), GST_VIDEO_INFO_HEIGHT (&pad->info),
930 GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info),
931 frame_rect.x, frame_rect.y, frame_rect.w, frame_rect.h);
934 cpad->position_updated = FALSE;
936 g_object_set (cpad->convert, "dest-x", frame_rect.x,
937 "dest-y", frame_rect.y, "dest-width", frame_rect.w,
938 "dest-height", frame_rect.h, nullptr);
943 static GstStaticCaps sink_pad_template_caps =
944 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
945 (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, GST_D3D11_SINK_FORMATS) "; "
946 GST_VIDEO_CAPS_MAKE (GST_D3D11_SINK_FORMATS));
948 /* formats we can output without conversion.
949 * Excludes 10/12 bits planar YUV (needs bitshift) and
950 * AYUV/AYUV64 (d3d11 runtime does not understand the ayuv order) */
951 #define COMPOSITOR_SRC_FORMATS \
952 "{ RGBA64_LE, RGB10A2_LE, BGRA, RGBA, BGRx, RGBx, VUYA, NV12, NV21, " \
953 "P010_10LE, P012_LE, P016_LE, I420, YV12, Y42B, Y444, Y444_16LE, " \
956 static GstStaticCaps src_pad_template_caps =
957 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
958 (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, COMPOSITOR_SRC_FORMATS) "; "
959 GST_VIDEO_CAPS_MAKE (COMPOSITOR_SRC_FORMATS));
968 #define DEFAULT_ADAPTER -1
969 #define DEFAULT_BACKGROUND GST_D3D11_COMPOSITOR_BACKGROUND_CHECKER
971 static void gst_d3d11_compositor_child_proxy_init (gpointer g_iface,
972 gpointer iface_data);
973 static void gst_d3d11_compositor_dispose (GObject * object);
974 static void gst_d3d11_compositor_set_property (GObject * object,
975 guint prop_id, const GValue * value, GParamSpec * pspec);
976 static void gst_d3d11_compositor_get_property (GObject * object,
977 guint prop_id, GValue * value, GParamSpec * pspec);
979 static GstPad *gst_d3d11_compositor_request_new_pad (GstElement * element,
980 GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
981 static void gst_d3d11_compositor_release_pad (GstElement * element,
983 static void gst_d3d11_compositor_set_context (GstElement * element,
984 GstContext * context);
986 static gboolean gst_d3d11_compositor_start (GstAggregator * agg);
987 static gboolean gst_d3d11_compositor_stop (GstAggregator * agg);
988 static gboolean gst_d3d11_compositor_sink_query (GstAggregator * agg,
989 GstAggregatorPad * pad, GstQuery * query);
990 static gboolean gst_d3d11_compositor_src_query (GstAggregator * agg,
992 static GstCaps *gst_d3d11_compositor_fixate_src_caps (GstAggregator * agg,
994 static gboolean gst_d3d11_compositor_negotiated_src_caps (GstAggregator * agg,
997 gst_d3d11_compositor_propose_allocation (GstAggregator * agg,
998 GstAggregatorPad * pad, GstQuery * decide_query, GstQuery * query);
999 static gboolean gst_d3d11_compositor_decide_allocation (GstAggregator * agg,
1001 static GstFlowReturn
1002 gst_d3d11_compositor_aggregate_frames (GstVideoAggregator * vagg,
1003 GstBuffer * outbuf);
1004 static GstFlowReturn
1005 gst_d3d11_compositor_create_output_buffer (GstVideoAggregator * vagg,
1006 GstBuffer ** outbuffer);
1007 static void gst_d3d11_compositor_quad_free (GstD3D11CompositorQuad * quad);
1009 #define gst_d3d11_compositor_parent_class parent_class
1010 G_DEFINE_TYPE_WITH_CODE (GstD3D11Compositor, gst_d3d11_compositor,
1011 GST_TYPE_VIDEO_AGGREGATOR, G_IMPLEMENT_INTERFACE (GST_TYPE_CHILD_PROXY,
1012 gst_d3d11_compositor_child_proxy_init));
1015 gst_d3d11_compositor_class_init (GstD3D11CompositorClass * klass)
1017 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1018 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
1019 GstAggregatorClass *agg_class = GST_AGGREGATOR_CLASS (klass);
1020 GstVideoAggregatorClass *vagg_class = GST_VIDEO_AGGREGATOR_CLASS (klass);
1023 object_class->dispose = gst_d3d11_compositor_dispose;
1024 object_class->set_property = gst_d3d11_compositor_set_property;
1025 object_class->get_property = gst_d3d11_compositor_get_property;
1027 g_object_class_install_property (object_class, PROP_ADAPTER,
1028 g_param_spec_int ("adapter", "Adapter",
1029 "Adapter index for creating device (-1 for default)",
1030 -1, G_MAXINT32, DEFAULT_ADAPTER,
1031 (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY |
1032 G_PARAM_STATIC_STRINGS)));
1034 g_object_class_install_property (object_class, PROP_BACKGROUND,
1035 g_param_spec_enum ("background", "Background", "Background type",
1036 GST_TYPE_D3D11_COMPOSITOR_BACKGROUND,
1038 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
1040 element_class->request_new_pad =
1041 GST_DEBUG_FUNCPTR (gst_d3d11_compositor_request_new_pad);
1042 element_class->release_pad =
1043 GST_DEBUG_FUNCPTR (gst_d3d11_compositor_release_pad);
1044 element_class->set_context =
1045 GST_DEBUG_FUNCPTR (gst_d3d11_compositor_set_context);
1047 agg_class->start = GST_DEBUG_FUNCPTR (gst_d3d11_compositor_start);
1048 agg_class->stop = GST_DEBUG_FUNCPTR (gst_d3d11_compositor_stop);
1049 agg_class->sink_query = GST_DEBUG_FUNCPTR (gst_d3d11_compositor_sink_query);
1050 agg_class->src_query = GST_DEBUG_FUNCPTR (gst_d3d11_compositor_src_query);
1051 agg_class->fixate_src_caps =
1052 GST_DEBUG_FUNCPTR (gst_d3d11_compositor_fixate_src_caps);
1053 agg_class->negotiated_src_caps =
1054 GST_DEBUG_FUNCPTR (gst_d3d11_compositor_negotiated_src_caps);
1055 agg_class->propose_allocation =
1056 GST_DEBUG_FUNCPTR (gst_d3d11_compositor_propose_allocation);
1057 agg_class->decide_allocation =
1058 GST_DEBUG_FUNCPTR (gst_d3d11_compositor_decide_allocation);
1060 vagg_class->aggregate_frames =
1061 GST_DEBUG_FUNCPTR (gst_d3d11_compositor_aggregate_frames);
1062 vagg_class->create_output_buffer =
1063 GST_DEBUG_FUNCPTR (gst_d3d11_compositor_create_output_buffer);
1065 caps = gst_d3d11_get_updated_template_caps (&sink_pad_template_caps);
1066 gst_element_class_add_pad_template (element_class,
1067 gst_pad_template_new_with_gtype ("sink_%u", GST_PAD_SINK, GST_PAD_REQUEST,
1068 caps, GST_TYPE_D3D11_COMPOSITOR_PAD));
1069 gst_caps_unref (caps);
1071 caps = gst_d3d11_get_updated_template_caps (&src_pad_template_caps);
1072 gst_element_class_add_pad_template (element_class,
1073 gst_pad_template_new_with_gtype ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
1074 caps, GST_TYPE_AGGREGATOR_PAD));
1075 gst_caps_unref (caps);
1077 gst_element_class_set_static_metadata (element_class, "Direct3D11 Compositor",
1078 "Filter/Editor/Video/Compositor", "A Direct3D11 compositor",
1079 "Seungha Yang <seungha@centricular.com>");
1081 gst_type_mark_as_plugin_api (GST_TYPE_D3D11_COMPOSITOR_BACKGROUND,
1082 (GstPluginAPIFlags) 0);
1083 gst_type_mark_as_plugin_api (GST_TYPE_D3D11_COMPOSITOR_PAD,
1084 (GstPluginAPIFlags) 0);
1086 GST_DEBUG_CATEGORY_INIT (gst_d3d11_compositor_debug,
1087 "d3d11compositor", 0, "d3d11compositor element");
1091 gst_d3d11_compositor_init (GstD3D11Compositor * self)
1093 self->adapter = DEFAULT_ADAPTER;
1094 self->background = DEFAULT_BACKGROUND;
1098 gst_d3d11_compositor_dispose (GObject * object)
1100 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (object);
1102 gst_clear_object (&self->device);
1103 gst_clear_buffer (&self->fallback_buf);
1104 g_clear_pointer (&self->checker_background, gst_d3d11_compositor_quad_free);
1106 G_OBJECT_CLASS (parent_class)->dispose (object);
1110 gst_d3d11_compositor_set_property (GObject * object,
1111 guint prop_id, const GValue * value, GParamSpec * pspec)
1113 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (object);
1117 self->adapter = g_value_get_int (value);
1119 case PROP_BACKGROUND:
1121 (GstD3D11CompositorBackground) g_value_get_enum (value);
1124 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1130 gst_d3d11_compositor_get_property (GObject * object,
1131 guint prop_id, GValue * value, GParamSpec * pspec)
1133 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (object);
1137 g_value_set_int (value, self->adapter);
1139 case PROP_BACKGROUND:
1140 g_value_set_enum (value, self->background);
1143 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1149 gst_d3d11_compositor_child_proxy_get_child_by_index (GstChildProxy * proxy,
1152 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (proxy);
1153 GObject *obj = nullptr;
1155 GST_OBJECT_LOCK (self);
1156 obj = (GObject *) g_list_nth_data (GST_ELEMENT_CAST (self)->sinkpads, index);
1158 gst_object_ref (obj);
1159 GST_OBJECT_UNLOCK (self);
1165 gst_d3d11_compositor_child_proxy_get_children_count (GstChildProxy * proxy)
1167 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (proxy);
1170 GST_OBJECT_LOCK (self);
1171 count = GST_ELEMENT_CAST (self)->numsinkpads;
1172 GST_OBJECT_UNLOCK (self);
1173 GST_INFO_OBJECT (self, "Children Count: %d", count);
1179 gst_d3d11_compositor_child_proxy_init (gpointer g_iface, gpointer iface_data)
1181 GstChildProxyInterface *iface = (GstChildProxyInterface *) g_iface;
1183 iface->get_child_by_index =
1184 gst_d3d11_compositor_child_proxy_get_child_by_index;
1185 iface->get_children_count =
1186 gst_d3d11_compositor_child_proxy_get_children_count;
1190 gst_d3d11_compositor_request_new_pad (GstElement * element,
1191 GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
1195 pad = GST_ELEMENT_CLASS (parent_class)->request_new_pad (element,
1199 GST_DEBUG_OBJECT (element, "could not create/add pad");
1203 gst_child_proxy_child_added (GST_CHILD_PROXY (element), G_OBJECT (pad),
1204 GST_OBJECT_NAME (pad));
1206 GST_DEBUG_OBJECT (element, "Created new pad %s:%s", GST_DEBUG_PAD_NAME (pad));
1212 gst_d3d11_compositor_pad_clear_resource (GstD3D11Compositor * self,
1213 GstD3D11CompositorPad * cpad, gpointer user_data)
1215 gst_clear_object (&cpad->convert);
1216 GST_D3D11_CLEAR_COM (cpad->blend);
1222 gst_d3d11_compositor_release_pad (GstElement * element, GstPad * pad)
1224 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (element);
1226 GST_DEBUG_OBJECT (self, "Releasing pad %s:%s", GST_DEBUG_PAD_NAME (pad));
1228 gst_child_proxy_child_removed (GST_CHILD_PROXY (self), G_OBJECT (pad),
1229 GST_OBJECT_NAME (pad));
1231 GST_ELEMENT_CLASS (parent_class)->release_pad (element, pad);
1235 gst_d3d11_compositor_set_context (GstElement * element, GstContext * context)
1237 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (element);
1239 gst_d3d11_handle_set_context (element, context, self->adapter, &self->device);
1241 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
1245 gst_d3d11_compositor_start (GstAggregator * agg)
1247 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (agg);
1249 if (!gst_d3d11_ensure_element_data (GST_ELEMENT_CAST (self),
1250 self->adapter, &self->device)) {
1251 GST_ERROR_OBJECT (self, "Failed to get D3D11 device");
1255 return GST_AGGREGATOR_CLASS (parent_class)->start (agg);
1259 gst_d3d11_compositor_stop (GstAggregator * agg)
1261 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (agg);
1263 g_clear_pointer (&self->checker_background, gst_d3d11_compositor_quad_free);
1264 gst_clear_object (&self->device);
1265 gst_clear_caps (&self->negotiated_caps);
1267 return GST_AGGREGATOR_CLASS (parent_class)->stop (agg);
1271 gst_d3d11_compositor_sink_getcaps (GstPad * pad, GstCaps * filter)
1274 GstCaps *template_caps;
1275 GstCaps *filtered_caps;
1276 GstCaps *returned_caps;
1278 template_caps = gst_pad_get_pad_template_caps (pad);
1280 sinkcaps = gst_pad_get_current_caps (pad);
1281 if (sinkcaps == nullptr) {
1282 sinkcaps = gst_caps_ref (template_caps);
1284 sinkcaps = gst_caps_merge (sinkcaps, gst_caps_ref (template_caps));
1288 filtered_caps = gst_caps_intersect (sinkcaps, filter);
1289 gst_caps_unref (sinkcaps);
1291 filtered_caps = sinkcaps; /* pass ownership */
1294 returned_caps = gst_caps_intersect (filtered_caps, template_caps);
1296 gst_caps_unref (template_caps);
1297 gst_caps_unref (filtered_caps);
1299 GST_DEBUG_OBJECT (pad, "returning %" GST_PTR_FORMAT, returned_caps);
1301 return returned_caps;
1305 gst_d3d11_compositor_sink_acceptcaps (GstPad * pad, GstCaps * caps)
1308 GstCaps *template_caps;
1310 GST_DEBUG_OBJECT (pad, "try accept caps of %" GST_PTR_FORMAT, caps);
1312 template_caps = gst_pad_get_pad_template_caps (pad);
1313 template_caps = gst_caps_make_writable (template_caps);
1315 ret = gst_caps_can_intersect (caps, template_caps);
1316 GST_DEBUG_OBJECT (pad, "%saccepted caps %" GST_PTR_FORMAT,
1317 (ret ? "" : "not "), caps);
1318 gst_caps_unref (template_caps);
1324 gst_d3d11_compositor_sink_query (GstAggregator * agg,
1325 GstAggregatorPad * pad, GstQuery * query)
1327 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (agg);
1329 switch (GST_QUERY_TYPE (query)) {
1330 case GST_QUERY_CONTEXT:
1331 if (gst_d3d11_handle_context_query (GST_ELEMENT (agg), query,
1336 case GST_QUERY_CAPS:{
1337 GstCaps *filter, *caps;
1339 gst_query_parse_caps (query, &filter);
1340 caps = gst_d3d11_compositor_sink_getcaps (GST_PAD (pad), filter);
1341 gst_query_set_caps_result (query, caps);
1342 gst_caps_unref (caps);
1345 case GST_QUERY_ACCEPT_CAPS:{
1349 gst_query_parse_accept_caps (query, &caps);
1350 ret = gst_d3d11_compositor_sink_acceptcaps (GST_PAD (pad), caps);
1351 gst_query_set_accept_caps_result (query, ret);
1358 return GST_AGGREGATOR_CLASS (parent_class)->sink_query (agg, pad, query);
1362 gst_d3d11_compositor_src_query (GstAggregator * agg, GstQuery * query)
1364 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (agg);
1366 switch (GST_QUERY_TYPE (query)) {
1367 case GST_QUERY_CONTEXT:
1368 if (gst_d3d11_handle_context_query (GST_ELEMENT (agg), query,
1377 return GST_AGGREGATOR_CLASS (parent_class)->src_query (agg, query);
1381 gst_d3d11_compositor_fixate_src_caps (GstAggregator * agg, GstCaps * caps)
1383 GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (agg);
1385 gint best_width = -1, best_height = -1;
1386 gint best_fps_n = -1, best_fps_d = -1;
1388 gdouble best_fps = 0.;
1389 GstCaps *ret = nullptr;
1392 ret = gst_caps_make_writable (caps);
1394 /* we need this to calculate how large to make the output frame */
1395 s = gst_caps_get_structure (ret, 0);
1396 if (gst_structure_has_field (s, "pixel-aspect-ratio")) {
1397 gst_structure_fixate_field_nearest_fraction (s, "pixel-aspect-ratio", 1, 1);
1398 gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_n, &par_d);
1403 GST_OBJECT_LOCK (vagg);
1404 for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
1405 GstVideoAggregatorPad *vaggpad = GST_VIDEO_AGGREGATOR_PAD (l->data);
1406 GstD3D11CompositorPad *cpad = GST_D3D11_COMPOSITOR_PAD (vaggpad);
1407 gint this_width, this_height;
1414 fps_n = GST_VIDEO_INFO_FPS_N (&vaggpad->info);
1415 fps_d = GST_VIDEO_INFO_FPS_D (&vaggpad->info);
1416 gst_d3d11_compositor_pad_get_output_size (cpad,
1417 par_n, par_d, &width, &height, &x_offset, &y_offset);
1419 if (width == 0 || height == 0)
1422 /* {x,y}_offset represent padding size of each top and left area.
1423 * To calculate total resolution, count bottom and right padding area
1425 this_width = width + MAX (cpad->xpos + 2 * x_offset, 0);
1426 this_height = height + MAX (cpad->ypos + 2 * y_offset, 0);
1428 if (best_width < this_width)
1429 best_width = this_width;
1430 if (best_height < this_height)
1431 best_height = this_height;
1436 gst_util_fraction_to_double (fps_n, fps_d, &cur_fps);
1438 if (best_fps < cur_fps) {
1444 GST_OBJECT_UNLOCK (vagg);
1446 if (best_fps_n <= 0 || best_fps_d <= 0 || best_fps == 0.0) {
1452 gst_structure_fixate_field_nearest_int (s, "width", best_width);
1453 gst_structure_fixate_field_nearest_int (s, "height", best_height);
1454 gst_structure_fixate_field_nearest_fraction (s, "framerate", best_fps_n,
1456 ret = gst_caps_fixate (ret);
1458 GST_LOG_OBJECT (agg, "Fixated caps %" GST_PTR_FORMAT, ret);
1464 convert_info_gray_to_yuv (const GstVideoInfo * gray, GstVideoInfo * yuv)
1468 if (GST_VIDEO_INFO_IS_YUV (gray)) {
1473 if (gray->finfo->depth[0] == 8) {
1474 gst_video_info_set_format (&tmp,
1475 GST_VIDEO_FORMAT_Y444, gray->width, gray->height);
1477 gst_video_info_set_format (&tmp,
1478 GST_VIDEO_FORMAT_Y444_16LE, gray->width, gray->height);
1481 tmp.colorimetry.range = gray->colorimetry.range;
1482 if (tmp.colorimetry.range == GST_VIDEO_COLOR_RANGE_UNKNOWN)
1483 tmp.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
1485 tmp.colorimetry.primaries = gray->colorimetry.primaries;
1486 if (tmp.colorimetry.primaries == GST_VIDEO_COLOR_PRIMARIES_UNKNOWN)
1487 tmp.colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
1489 tmp.colorimetry.transfer = gray->colorimetry.transfer;
1490 if (tmp.colorimetry.transfer == GST_VIDEO_TRANSFER_UNKNOWN)
1491 tmp.colorimetry.transfer = GST_VIDEO_TRANSFER_BT709;
1493 tmp.colorimetry.matrix = gray->colorimetry.matrix;
1494 if (tmp.colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_UNKNOWN)
1495 tmp.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT709;
1501 gst_d3d11_compositor_calculate_background_color (GstD3D11Compositor * self,
1502 const GstVideoInfo * info)
1504 GstD3D11ColorMatrix clear_color_matrix;
1506 gdouble converted[3];
1507 GstVideoFormat format = GST_VIDEO_INFO_FORMAT (info);
1509 if (GST_VIDEO_INFO_IS_RGB (info)) {
1510 GstVideoInfo rgb_info = *info;
1511 rgb_info.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
1513 gst_d3d11_color_range_adjust_matrix_unorm (&rgb_info, info,
1514 &clear_color_matrix);
1516 GstVideoInfo rgb_info;
1517 GstVideoInfo yuv_info;
1519 gst_video_info_set_format (&rgb_info, GST_VIDEO_FORMAT_RGBA64_LE,
1520 info->width, info->height);
1521 convert_info_gray_to_yuv (info, &yuv_info);
1523 if (yuv_info.colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_UNKNOWN ||
1524 yuv_info.colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_RGB) {
1525 GST_WARNING_OBJECT (self, "Invalid matrix is detected");
1526 yuv_info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT709;
1529 gst_d3d11_rgb_to_yuv_matrix_unorm (&rgb_info,
1530 &yuv_info, &clear_color_matrix);
1533 /* Calculate black and white color values */
1534 for (guint i = 0; i < 2; i++) {
1535 GstD3D11CompositorClearColor *clear_color = &self->clear_color[i];
1536 rgb[0] = rgb[1] = rgb[2] = (gdouble) i;
1538 for (guint j = 0; j < 3; j++) {
1540 for (guint k = 0; k < 3; k++) {
1541 converted[j] += clear_color_matrix.matrix[j][k] * rgb[k];
1543 converted[j] += clear_color_matrix.offset[j];
1544 converted[j] = CLAMP (converted[j],
1545 clear_color_matrix.min[j], clear_color_matrix.max[j]);
1548 GST_DEBUG_OBJECT (self, "Calculated background color RGB: %f, %f, %f",
1549 converted[0], converted[1], converted[2]);
1551 if (GST_VIDEO_INFO_IS_RGB (info) || GST_VIDEO_INFO_IS_GRAY (info)) {
1552 for (guint j = 0; j < 3; j++)
1553 clear_color->color[0][j] = converted[j];
1554 clear_color->color[0][3] = 1.0;
1557 case GST_VIDEO_FORMAT_VUYA:
1558 clear_color->color[0][0] = converted[2];
1559 clear_color->color[0][1] = converted[1];
1560 clear_color->color[0][2] = converted[0];
1561 clear_color->color[0][3] = 1.0;
1563 case GST_VIDEO_FORMAT_NV12:
1564 case GST_VIDEO_FORMAT_NV21:
1565 case GST_VIDEO_FORMAT_P010_10LE:
1566 case GST_VIDEO_FORMAT_P012_LE:
1567 case GST_VIDEO_FORMAT_P016_LE:
1568 clear_color->color[0][0] = converted[0];
1569 clear_color->color[0][1] = 0;
1570 clear_color->color[0][2] = 0;
1571 clear_color->color[0][3] = 1.0;
1572 if (format == GST_VIDEO_FORMAT_NV21) {
1573 clear_color->color[1][0] = converted[2];
1574 clear_color->color[1][1] = converted[1];
1576 clear_color->color[1][0] = converted[1];
1577 clear_color->color[1][1] = converted[2];
1579 clear_color->color[1][2] = 0;
1580 clear_color->color[1][3] = 1.0;
1582 case GST_VIDEO_FORMAT_I420:
1583 case GST_VIDEO_FORMAT_YV12:
1584 case GST_VIDEO_FORMAT_I420_10LE:
1585 case GST_VIDEO_FORMAT_I420_12LE:
1586 case GST_VIDEO_FORMAT_Y42B:
1587 case GST_VIDEO_FORMAT_I422_10LE:
1588 case GST_VIDEO_FORMAT_I422_12LE:
1589 case GST_VIDEO_FORMAT_Y444:
1590 case GST_VIDEO_FORMAT_Y444_10LE:
1591 case GST_VIDEO_FORMAT_Y444_12LE:
1592 case GST_VIDEO_FORMAT_Y444_16LE:
1593 clear_color->color[0][0] = converted[0];
1594 clear_color->color[0][1] = 0;
1595 clear_color->color[0][2] = 0;
1596 clear_color->color[0][3] = 1.0;
1597 if (format == GST_VIDEO_FORMAT_YV12) {
1598 clear_color->color[1][0] = converted[2];
1599 clear_color->color[2][0] = converted[1];
1601 clear_color->color[1][0] = converted[1];
1602 clear_color->color[2][0] = converted[2];
1604 clear_color->color[1][1] = 0;
1605 clear_color->color[1][2] = 0;
1606 clear_color->color[1][3] = 1.0;
1607 clear_color->color[2][1] = 0;
1608 clear_color->color[2][2] = 0;
1609 clear_color->color[2][3] = 1.0;
1612 g_assert_not_reached ();
1620 gst_d3d11_compositor_negotiated_src_caps (GstAggregator * agg, GstCaps * caps)
1622 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (agg);
1623 GstCapsFeatures *features;
1626 if (!gst_video_info_from_caps (&info, caps)) {
1627 GST_ERROR_OBJECT (self, "Failed to convert caps to info");
1631 if (self->negotiated_caps && gst_caps_is_equal (self->negotiated_caps, caps)) {
1632 GST_DEBUG_OBJECT (self, "Negotiated caps is not changed");
1636 features = gst_caps_get_features (caps, 0);
1638 && gst_caps_features_contains (features,
1639 GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY)) {
1640 GST_DEBUG_OBJECT (self, "Negotiated with D3D11 memory caps");
1641 self->downstream_supports_d3d11 = TRUE;
1643 GST_DEBUG_OBJECT (self, "Negotiated with system memory caps");
1644 self->downstream_supports_d3d11 = FALSE;
1647 gst_element_foreach_sink_pad (GST_ELEMENT_CAST (self),
1648 (GstElementForeachPadFunc) gst_d3d11_compositor_pad_clear_resource,
1651 gst_clear_buffer (&self->fallback_buf);
1652 g_clear_pointer (&self->checker_background, gst_d3d11_compositor_quad_free);
1654 gst_d3d11_compositor_calculate_background_color (self, &info);
1656 if (!self->downstream_supports_d3d11) {
1657 GstD3D11AllocationParams *d3d11_params;
1658 GstBufferPool *pool;
1659 GstFlowReturn flow_ret;
1661 d3d11_params = gst_d3d11_allocation_params_new (self->device,
1662 &info, GST_D3D11_ALLOCATION_FLAG_DEFAULT,
1663 D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET, 0);
1665 pool = gst_d3d11_buffer_pool_new_with_options (self->device,
1666 caps, d3d11_params, 0, 0);
1667 gst_d3d11_allocation_params_free (d3d11_params);
1670 GST_ERROR_OBJECT (self, "Failed to create pool");
1674 if (!gst_buffer_pool_set_active (pool, TRUE)) {
1675 GST_ERROR_OBJECT (self, "Failed to set active");
1676 gst_object_unref (pool);
1680 flow_ret = gst_buffer_pool_acquire_buffer (pool, &self->fallback_buf,
1682 if (flow_ret != GST_FLOW_OK) {
1683 GST_ERROR_OBJECT (self, "Failed to acquire buffer");
1684 gst_object_unref (pool);
1688 gst_buffer_pool_set_active (pool, FALSE);
1689 gst_object_unref (pool);
1692 gst_caps_replace (&self->negotiated_caps, caps);
1695 return GST_AGGREGATOR_CLASS (parent_class)->negotiated_src_caps (agg, caps);
1699 gst_d3d11_compositor_propose_allocation (GstAggregator * agg,
1700 GstAggregatorPad * pad, GstQuery * decide_query, GstQuery * query)
1702 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (agg);
1704 GstBufferPool *pool;
1708 gst_query_parse_allocation (query, &caps, nullptr);
1710 if (caps == nullptr)
1713 if (!gst_video_info_from_caps (&info, caps))
1716 if (gst_query_get_n_allocation_pools (query) == 0) {
1717 GstCapsFeatures *features;
1718 GstStructure *config;
1719 gboolean is_d3d11 = FALSE;
1721 features = gst_caps_get_features (caps, 0);
1723 && gst_caps_features_contains (features,
1724 GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY)) {
1725 GST_DEBUG_OBJECT (pad, "upstream support d3d11 memory");
1726 pool = gst_d3d11_buffer_pool_new (self->device);
1729 pool = gst_video_buffer_pool_new ();
1733 GST_ERROR_OBJECT (self, "Failed to create buffer pool");
1737 config = gst_buffer_pool_get_config (pool);
1738 gst_buffer_pool_config_add_option (config,
1739 GST_BUFFER_POOL_OPTION_VIDEO_META);
1741 size = GST_VIDEO_INFO_SIZE (&info);
1743 GstD3D11AllocationParams *d3d11_params;
1746 gst_d3d11_allocation_params_new (self->device,
1747 &info, GST_D3D11_ALLOCATION_FLAG_DEFAULT, D3D11_BIND_SHADER_RESOURCE,
1750 gst_buffer_pool_config_set_d3d11_allocation_params (config, d3d11_params);
1751 gst_d3d11_allocation_params_free (d3d11_params);
1753 gst_buffer_pool_config_add_option (config,
1754 GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
1757 gst_buffer_pool_config_set_params (config, caps, (guint) size, 0, 0);
1759 if (!gst_buffer_pool_set_config (pool, config)) {
1760 GST_ERROR_OBJECT (pool, "Couldn't set config");
1761 gst_object_unref (pool);
1766 /* d3d11 buffer pool will update buffer size based on allocated texture,
1767 * get size from config again */
1768 config = gst_buffer_pool_get_config (pool);
1769 gst_buffer_pool_config_get_params (config,
1770 nullptr, &size, nullptr, nullptr);
1771 gst_structure_free (config);
1773 gst_query_add_allocation_pool (query, pool, size, 0, 0);
1774 gst_object_unref (pool);
1777 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, nullptr);
1778 gst_query_add_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE, nullptr);
1784 gst_d3d11_compositor_decide_allocation (GstAggregator * agg, GstQuery * query)
1786 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (agg);
1788 GstBufferPool *pool = nullptr;
1789 guint n, size, min, max;
1791 GstStructure *config;
1792 gboolean use_d3d11_pool;
1794 gst_query_parse_allocation (query, &caps, nullptr);
1797 GST_DEBUG_OBJECT (self, "No output caps");
1801 if (!gst_video_info_from_caps (&info, caps)) {
1802 GST_ERROR_OBJECT (self, "Invalid caps");
1806 use_d3d11_pool = self->downstream_supports_d3d11;
1808 n = gst_query_get_n_allocation_pools (query);
1810 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
1812 /* create our own pool */
1813 if (pool && use_d3d11_pool) {
1814 if (!GST_IS_D3D11_BUFFER_POOL (pool)) {
1815 GST_DEBUG_OBJECT (self,
1816 "Downstream pool is not d3d11, will create new one");
1817 gst_clear_object (&pool);
1819 GstD3D11BufferPool *dpool = GST_D3D11_BUFFER_POOL (pool);
1820 if (dpool->device != self->device) {
1821 GST_DEBUG_OBJECT (self, "Different device, will create new one");
1822 gst_clear_object (&pool);
1827 size = (guint) info.size;
1831 pool = gst_d3d11_buffer_pool_new (self->device);
1833 pool = gst_video_buffer_pool_new ();
1839 config = gst_buffer_pool_get_config (pool);
1840 gst_buffer_pool_config_set_params (config, caps, size, min, max);
1841 gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
1843 if (use_d3d11_pool) {
1844 GstD3D11AllocationParams *d3d11_params;
1846 d3d11_params = gst_buffer_pool_config_get_d3d11_allocation_params (config);
1847 if (!d3d11_params) {
1848 d3d11_params = gst_d3d11_allocation_params_new (self->device,
1849 &info, GST_D3D11_ALLOCATION_FLAG_DEFAULT, D3D11_BIND_RENDER_TARGET,
1854 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&info); i++) {
1855 d3d11_params->desc[i].BindFlags |= D3D11_BIND_RENDER_TARGET;
1859 gst_buffer_pool_config_set_d3d11_allocation_params (config, d3d11_params);
1860 gst_d3d11_allocation_params_free (d3d11_params);
1863 gst_buffer_pool_set_config (pool, config);
1865 /* d3d11 buffer pool will update buffer size based on allocated texture,
1866 * get size from config again */
1867 config = gst_buffer_pool_get_config (pool);
1868 gst_buffer_pool_config_get_params (config, nullptr, &size, nullptr, nullptr);
1869 gst_structure_free (config);
1872 gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
1874 gst_query_add_allocation_pool (query, pool, size, min, max);
1875 gst_object_unref (pool);
1895 static GstD3D11CompositorQuad *
1896 gst_d3d11_compositor_create_checker_quad (GstD3D11Compositor * self,
1897 const GstVideoInfo * info)
1899 GstD3D11CompositorQuad *quad = nullptr;
1900 VertexData *vertex_data;
1902 ID3D11Device *device_handle;
1903 ID3D11DeviceContext *context_handle;
1904 D3D11_MAPPED_SUBRESOURCE map;
1905 D3D11_INPUT_ELEMENT_DESC input_desc;
1906 D3D11_BUFFER_DESC buffer_desc;
1907 ComPtr < ID3D11Buffer > vertex_buffer;
1908 ComPtr < ID3D11Buffer > index_buffer;
1909 ComPtr < ID3D11PixelShader > ps;
1910 ComPtr < ID3D11VertexShader > vs;
1911 ComPtr < ID3D11InputLayout > layout;
1913 const gchar *ps_src;
1915 device_handle = gst_d3d11_device_get_device_handle (self->device);
1916 context_handle = gst_d3d11_device_get_device_context_handle (self->device);
1918 if (GST_VIDEO_INFO_IS_RGB (info)) {
1919 ps_src = checker_ps_src_rgb;
1920 } else if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_VUYA) {
1921 ps_src = checker_ps_src_vuya;
1923 ps_src = checker_ps_src_luma;
1926 hr = gst_d3d11_create_pixel_shader_simple (self->device, ps_src, "main", &ps);
1927 if (!gst_d3d11_result (hr, self->device)) {
1928 GST_ERROR_OBJECT (self, "Couldn't setup pixel shader");
1932 memset (&input_desc, 0, sizeof (D3D11_INPUT_ELEMENT_DESC));
1933 input_desc.SemanticName = "POSITION";
1934 input_desc.SemanticIndex = 0;
1935 input_desc.Format = DXGI_FORMAT_R32G32B32_FLOAT;
1936 input_desc.InputSlot = 0;
1937 input_desc.AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
1938 input_desc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
1939 input_desc.InstanceDataStepRate = 0;
1941 hr = gst_d3d11_create_vertex_shader_simple (self->device, checker_vs_src,
1942 "main", &input_desc, 1, &vs, &layout);
1943 if (!gst_d3d11_result (hr, self->device)) {
1944 GST_ERROR_OBJECT (self, "Couldn't setup vertex shader");
1948 memset (&buffer_desc, 0, sizeof (D3D11_BUFFER_DESC));
1949 buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
1950 buffer_desc.ByteWidth = sizeof (VertexData) * 4;
1951 buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
1952 buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1954 hr = device_handle->CreateBuffer (&buffer_desc, nullptr, &vertex_buffer);
1955 if (!gst_d3d11_result (hr, self->device)) {
1956 GST_ERROR_OBJECT (self,
1957 "Couldn't create vertex buffer, hr: 0x%x", (guint) hr);
1961 hr = context_handle->Map (vertex_buffer.Get (),
1962 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
1964 if (!gst_d3d11_result (hr, self->device)) {
1965 GST_ERROR_OBJECT (self, "Couldn't map vertex buffer, hr: 0x%x", (guint) hr);
1969 vertex_data = (VertexData *) map.pData;
1971 vertex_data[0].position.x = -1.0f;
1972 vertex_data[0].position.y = -1.0f;
1973 vertex_data[0].position.z = 0.0f;
1974 vertex_data[0].texture.u = 0.0f;
1975 vertex_data[0].texture.v = 1.0f;
1978 vertex_data[1].position.x = -1.0f;
1979 vertex_data[1].position.y = 1.0f;
1980 vertex_data[1].position.z = 0.0f;
1981 vertex_data[1].texture.u = 0.0f;
1982 vertex_data[1].texture.v = 0.0f;
1985 vertex_data[2].position.x = 1.0f;
1986 vertex_data[2].position.y = 1.0f;
1987 vertex_data[2].position.z = 0.0f;
1988 vertex_data[2].texture.u = 1.0f;
1989 vertex_data[2].texture.v = 0.0f;
1992 vertex_data[3].position.x = 1.0f;
1993 vertex_data[3].position.y = -1.0f;
1994 vertex_data[3].position.z = 0.0f;
1995 vertex_data[3].texture.u = 1.0f;
1996 vertex_data[3].texture.v = 1.0f;
1998 context_handle->Unmap (vertex_buffer.Get (), 0);
2000 buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
2001 buffer_desc.ByteWidth = sizeof (WORD) * 6;
2002 buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
2003 buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
2005 hr = device_handle->CreateBuffer (&buffer_desc, nullptr, &index_buffer);
2006 if (!gst_d3d11_result (hr, self->device)) {
2007 GST_ERROR_OBJECT (self,
2008 "Couldn't create index buffer, hr: 0x%x", (guint) hr);
2012 hr = context_handle->Map (index_buffer.Get (),
2013 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
2015 if (!gst_d3d11_result (hr, self->device)) {
2016 GST_ERROR_OBJECT (self, "Couldn't map index buffer, hr: 0x%x", (guint) hr);
2020 indices = (WORD *) map.pData;
2022 /* clockwise indexing */
2023 indices[0] = 0; /* bottom left */
2024 indices[1] = 1; /* top left */
2025 indices[2] = 2; /* top right */
2027 indices[3] = 3; /* bottom right */
2028 indices[4] = 0; /* bottom left */
2029 indices[5] = 2; /* top right */
2031 context_handle->Unmap (index_buffer.Get (), 0);
2032 quad = g_new0 (GstD3D11CompositorQuad, 1);
2033 quad->ps = ps.Detach ();
2034 quad->vs = vs.Detach ();
2035 quad->layout = layout.Detach ();
2036 quad->vertex_buffer = vertex_buffer.Detach ();
2037 quad->index_buffer = index_buffer.Detach ();
2039 quad->viewport.TopLeftX = 0;
2040 quad->viewport.TopLeftY = 0;
2041 quad->viewport.Width = GST_VIDEO_INFO_WIDTH (info);
2042 quad->viewport.Height = GST_VIDEO_INFO_HEIGHT (info);
2043 quad->viewport.MinDepth = 0.0f;
2044 quad->viewport.MaxDepth = 1.0f;
2050 gst_d3d11_compositor_quad_free (GstD3D11CompositorQuad * quad)
2055 GST_D3D11_CLEAR_COM (quad->ps);
2056 GST_D3D11_CLEAR_COM (quad->vs);
2057 GST_D3D11_CLEAR_COM (quad->layout);
2058 GST_D3D11_CLEAR_COM (quad->vertex_buffer);
2059 GST_D3D11_CLEAR_COM (quad->index_buffer);
2065 gst_d3d11_compositor_draw_background_checker (GstD3D11Compositor * self,
2066 ID3D11RenderTargetView * rtv)
2068 ID3D11DeviceContext *context =
2069 gst_d3d11_device_get_device_context_handle (self->device);
2071 UINT strides = sizeof (VertexData);
2072 GstD3D11CompositorQuad *quad;
2074 if (!self->checker_background) {
2075 GstVideoInfo *info = &GST_VIDEO_AGGREGATOR_CAST (self)->info;
2077 self->checker_background =
2078 gst_d3d11_compositor_create_checker_quad (self, info);
2079 if (!self->checker_background)
2083 quad = self->checker_background;
2084 context->IASetPrimitiveTopology (D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
2085 context->IASetInputLayout (quad->layout);
2086 context->IASetVertexBuffers (0, 1, &quad->vertex_buffer, &strides, &offsets);
2087 context->IASetIndexBuffer (quad->index_buffer, DXGI_FORMAT_R16_UINT, 0);
2088 context->VSSetShader (quad->vs, nullptr, 0);
2089 context->PSSetShader (quad->ps, nullptr, 0);
2090 context->RSSetViewports (1, &quad->viewport);
2091 context->OMSetRenderTargets (1, &rtv, nullptr);
2092 context->OMSetBlendState (nullptr, nullptr, 0xffffffff);
2093 context->DrawIndexed (6, 0, 0);
2094 context->OMSetRenderTargets (0, nullptr, nullptr);
2099 /* Must be called with d3d11 device lock */
2101 gst_d3d11_compositor_draw_background (GstD3D11Compositor * self,
2102 ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES], guint num_rtv)
2104 ID3D11DeviceContext *context =
2105 gst_d3d11_device_get_device_context_handle (self->device);
2106 GstD3D11CompositorClearColor *color = &self->clear_color[0];
2108 if (self->background == GST_D3D11_COMPOSITOR_BACKGROUND_CHECKER) {
2109 if (!gst_d3d11_compositor_draw_background_checker (self, rtv[0]))
2112 /* clear U and V components if needed */
2113 for (guint i = 1; i < num_rtv; i++)
2114 context->ClearRenderTargetView (rtv[i], color->color[i]);
2119 switch (self->background) {
2120 case GST_D3D11_COMPOSITOR_BACKGROUND_BLACK:
2121 color = &self->clear_color[0];
2123 case GST_D3D11_COMPOSITOR_BACKGROUND_WHITE:
2124 color = &self->clear_color[1];
2126 case GST_D3D11_COMPOSITOR_BACKGROUND_TRANSPARENT:
2127 color = &self->clear_color[2];
2130 g_assert_not_reached ();
2134 for (guint i = 0; i < num_rtv; i++)
2135 context->ClearRenderTargetView (rtv[i], color->color[i]);
2140 static GstFlowReturn
2141 gst_d3d11_compositor_aggregate_frames (GstVideoAggregator * vagg,
2144 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (vagg);
2146 GstBuffer *target_buf = outbuf;
2147 GstFlowReturn ret = GST_FLOW_OK;
2148 ID3D11RenderTargetView *rtv[GST_VIDEO_MAX_PLANES] = { nullptr, };
2149 GstVideoFrame target_frame;
2150 guint num_rtv = GST_VIDEO_INFO_N_PLANES (&vagg->info);
2151 GstD3D11DeviceLockGuard lk (self->device);
2153 if (!self->downstream_supports_d3d11)
2154 target_buf = self->fallback_buf;
2156 if (!gst_video_frame_map (&target_frame, &vagg->info, target_buf,
2157 (GstMapFlags) (GST_MAP_WRITE | GST_MAP_D3D11))) {
2158 GST_ERROR_OBJECT (self, "Failed to map render target frame");
2159 return GST_FLOW_ERROR;
2162 if (!gst_d3d11_buffer_get_render_target_view (target_buf, rtv)) {
2163 GST_ERROR_OBJECT (self, "RTV is unavailable");
2164 gst_video_frame_unmap (&target_frame);
2165 return GST_FLOW_ERROR;
2168 if (!gst_d3d11_compositor_draw_background (self, rtv, num_rtv)) {
2169 GST_ERROR_OBJECT (self, "Couldn't draw background");
2170 gst_video_frame_unmap (&target_frame);
2171 return GST_FLOW_ERROR;
2174 gst_video_frame_unmap (&target_frame);
2176 GST_OBJECT_LOCK (self);
2177 for (iter = GST_ELEMENT (vagg)->sinkpads; iter; iter = g_list_next (iter)) {
2178 GstVideoAggregatorPad *pad = GST_VIDEO_AGGREGATOR_PAD (iter->data);
2179 GstD3D11CompositorPad *cpad = GST_D3D11_COMPOSITOR_PAD (pad);
2180 GstVideoFrame *prepared_frame =
2181 gst_video_aggregator_pad_get_prepared_frame (pad);
2183 GstVideoCropMeta *crop_meta;
2185 if (!prepared_frame)
2188 if (!gst_d3d11_compositor_pad_setup_converter (pad, vagg)) {
2189 GST_ERROR_OBJECT (self, "Couldn't setup converter");
2190 ret = GST_FLOW_ERROR;
2194 crop_meta = gst_buffer_get_video_crop_meta (prepared_frame->buffer);
2198 w = crop_meta->width;
2199 h = crop_meta->height;
2202 w = pad->info.width;
2203 h = pad->info.height;
2206 g_object_set (cpad->convert, "src-x", x, "src-y", y, "src-width", w,
2207 "src-height", h, nullptr);
2209 if (!gst_d3d11_converter_convert_buffer_unlocked (cpad->convert,
2210 prepared_frame->buffer, target_buf)) {
2211 GST_ERROR_OBJECT (self, "Couldn't convert frame");
2212 ret = GST_FLOW_ERROR;
2216 GST_OBJECT_UNLOCK (self);
2218 if (ret != GST_FLOW_OK)
2221 if (!self->downstream_supports_d3d11) {
2222 if (!gst_d3d11_buffer_copy_into (outbuf, self->fallback_buf, &vagg->info)) {
2223 GST_ERROR_OBJECT (self, "Couldn't copy input buffer to fallback buffer");
2224 return GST_FLOW_ERROR;
2233 /* without holding ref */
2234 GstD3D11Device *other_device;
2235 gboolean have_same_device;
2239 gst_d3d11_compositor_check_device_update (GstElement * agg,
2240 GstVideoAggregatorPad * vpad, DeviceCheckData * data)
2242 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (agg);
2245 GstD3D11Memory *dmem;
2246 gboolean update_device = FALSE;
2248 buf = gst_video_aggregator_pad_get_current_buffer (vpad);
2252 /* Ignore gap buffer */
2253 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP) ||
2254 gst_buffer_get_size (buf) == 0) {
2258 mem = gst_buffer_peek_memory (buf, 0);
2259 if (!gst_is_d3d11_memory (mem))
2262 dmem = GST_D3D11_MEMORY_CAST (mem);
2264 /* We can use existing device */
2265 if (dmem->device == self->device) {
2266 data->have_same_device = TRUE;
2270 if (self->adapter < 0) {
2271 update_device = TRUE;
2275 g_object_get (dmem->device, "adapter", &adapter, nullptr);
2276 /* The same GPU as what user wanted, update */
2277 if (adapter == (guint) self->adapter)
2278 update_device = TRUE;
2284 data->other_device = dmem->device;
2286 /* Keep iterate since there might be one buffer which holds the same device
2291 static GstFlowReturn
2292 gst_d3d11_compositor_create_output_buffer (GstVideoAggregator * vagg,
2293 GstBuffer ** outbuffer)
2295 GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (vagg);
2296 DeviceCheckData data;
2298 /* Check whether there is at least one sinkpad which holds d3d11 buffer
2299 * with compatible device, and if not, update our device */
2300 data.other_device = nullptr;
2301 data.have_same_device = FALSE;
2303 gst_element_foreach_sink_pad (GST_ELEMENT_CAST (vagg),
2304 (GstElementForeachPadFunc) gst_d3d11_compositor_check_device_update,
2307 if (data.have_same_device || !data.other_device) {
2309 GST_VIDEO_AGGREGATOR_CLASS (parent_class)->create_output_buffer (vagg,
2313 /* Clear all device dependent resources */
2314 gst_element_foreach_sink_pad (GST_ELEMENT_CAST (vagg),
2315 (GstElementForeachPadFunc) gst_d3d11_compositor_pad_clear_resource,
2318 gst_clear_buffer (&self->fallback_buf);
2319 g_clear_pointer (&self->checker_background, gst_d3d11_compositor_quad_free);
2321 GST_INFO_OBJECT (self, "Updating device %" GST_PTR_FORMAT " -> %"
2322 GST_PTR_FORMAT, self->device, data.other_device);
2323 gst_object_unref (self->device);
2324 self->device = (GstD3D11Device *) gst_object_ref (data.other_device);
2326 /* We cannot call gst_aggregator_negotiate() here, since GstVideoAggregator
2327 * is holding GST_VIDEO_AGGREGATOR_LOCK() already.
2328 * Mark reconfigure and do reconfigure later */
2329 gst_pad_mark_reconfigure (GST_AGGREGATOR_SRC_PAD (vagg));
2331 return GST_AGGREGATOR_FLOW_NEED_DATA;