1 /* GStreamer
2 * Copyright (C) <2019> Seungha Yang <seungha.yang@navercorp.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include "gstd3d11overlaycompositor.h"
25 #include "gstd3d11shader.h"
26 #include "gstd3d11pluginutils.h"
27 #include <wrl.h>
28
29 GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_overlay_compositor_debug);
30 #define GST_CAT_DEFAULT gst_d3d11_overlay_compositor_debug
31
32 /* *INDENT-OFF* */
33 using namespace Microsoft::WRL;
34
35 typedef struct
36 {
37 struct {
38 FLOAT x;
39 FLOAT y;
40 FLOAT z;
41 } position;
42 struct {
43 FLOAT x;
44 FLOAT y;
45 } texture;
46 } VertexData;
47
48 static const gchar templ_pixel_shader[] =
49 "Texture2D shaderTexture;\n"
50 "SamplerState samplerState;\n"
51 "\n"
52 "struct PS_INPUT\n"
53 "{\n"
54 " float4 Position: SV_POSITION;\n"
55 " float3 Texture: TEXCOORD0;\n"
56 "};\n"
57 "\n"
58 "float4 main(PS_INPUT input): SV_TARGET\n"
59 "{\n"
60 " return shaderTexture.Sample(samplerState, input.Texture);\n"
61 "}\n";
62
63 static const gchar templ_vertex_shader[] =
64 "struct VS_INPUT\n"
65 "{\n"
66 " float4 Position : POSITION;\n"
67 " float4 Texture : TEXCOORD0;\n"
68 "};\n"
69 "\n"
70 "struct VS_OUTPUT\n"
71 "{\n"
72 " float4 Position: SV_POSITION;\n"
73 " float4 Texture: TEXCOORD0;\n"
74 "};\n"
75 "\n"
76 "VS_OUTPUT main(VS_INPUT input)\n"
77 "{\n"
78 " return input;\n"
79 "}\n";
80 /* *INDENT-ON* */
81
82 struct _GstD3D11OverlayCompositor
83 {
84 GstD3D11Device *device;
85 GstVideoInfo out_info;
86
87 D3D11_VIEWPORT viewport;
88
89 ID3D11PixelShader *ps;
90 ID3D11VertexShader *vs;
91 ID3D11InputLayout *layout;
92 ID3D11SamplerState *sampler;
93 ID3D11BlendState *blend;
94 ID3D11Buffer *index_buffer;
95
96 /* GstD3D11CompositionOverlay */
97 GList *overlays;
98 };
99
100 typedef struct
101 {
102 GstVideoOverlayRectangle *overlay_rect;
103 ID3D11Texture2D *texture;
104 ID3D11ShaderResourceView *srv;
105 GstD3D11Quad *quad;
106 } GstD3D11CompositionOverlay;
107
108 static GstD3D11CompositionOverlay *
gst_d3d11_composition_overlay_new(GstD3D11OverlayCompositor * self,GstVideoOverlayRectangle * overlay_rect)109 gst_d3d11_composition_overlay_new (GstD3D11OverlayCompositor * self,
110 GstVideoOverlayRectangle * overlay_rect)
111 {
112 GstD3D11CompositionOverlay *overlay = NULL;
113 gint x, y;
114 guint width, height;
115 D3D11_SUBRESOURCE_DATA subresource_data;
116 D3D11_TEXTURE2D_DESC texture_desc;
117 D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc;
118 D3D11_BUFFER_DESC buffer_desc;
119 D3D11_MAPPED_SUBRESOURCE map;
120 VertexData *vertex_data;
121 GstBuffer *buf;
122 GstVideoMeta *vmeta;
123 GstMapInfo info;
124 guint8 *data;
125 gint stride;
126 HRESULT hr;
127 ID3D11Device *device_handle;
128 ID3D11DeviceContext *context_handle;
129 GstD3D11Device *device = self->device;
130 const guint index_count = 2 * 3;
131 FLOAT x1, y1, x2, y2;
132 gdouble val;
133 /* *INDENT-OFF* */
134 ComPtr<ID3D11Texture2D> texture;
135 ComPtr<ID3D11ShaderResourceView> srv;
136 ComPtr<ID3D11Buffer> vertex_buffer;
137 /* *INDENT-ON* */
138
139 g_return_val_if_fail (overlay_rect != NULL, NULL);
140
141 memset (&subresource_data, 0, sizeof (subresource_data));
142 memset (&texture_desc, 0, sizeof (texture_desc));
143 memset (&srv_desc, 0, sizeof (srv_desc));
144 memset (&buffer_desc, 0, sizeof (buffer_desc));
145
146 device_handle = gst_d3d11_device_get_device_handle (device);
147 context_handle = gst_d3d11_device_get_device_context_handle (device);
148
149 if (!gst_video_overlay_rectangle_get_render_rectangle (overlay_rect, &x, &y,
150 &width, &height)) {
151 GST_ERROR ("Failed to get render rectangle");
152 return NULL;
153 }
154
155 buf = gst_video_overlay_rectangle_get_pixels_unscaled_argb (overlay_rect,
156 GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
157 if (!buf) {
158 GST_ERROR ("Failed to get overlay buffer");
159 return NULL;
160 }
161
162 vmeta = gst_buffer_get_video_meta (buf);
163 if (!vmeta) {
164 GST_ERROR ("Failed to get video meta");
165 return NULL;
166 }
167
168 if (!gst_video_meta_map (vmeta,
169 0, &info, (gpointer *) & data, &stride, GST_MAP_READ)) {
170 GST_ERROR ("Failed to map");
171 return NULL;
172 }
173
174 /* Do create texture and upload data at once, for create immutable texture */
175 subresource_data.pSysMem = data;
176 subresource_data.SysMemPitch = stride;
177 subresource_data.SysMemSlicePitch = 0;
178
179 texture_desc.Width = width;
180 texture_desc.Height = height;
181 texture_desc.MipLevels = 1;
182 texture_desc.ArraySize = 1;
183 /* FIXME: need to consider non-BGRA ? */
184 texture_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
185 texture_desc.SampleDesc.Count = 1;
186 texture_desc.SampleDesc.Quality = 0;
187 texture_desc.Usage = D3D11_USAGE_IMMUTABLE;
188 texture_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
189 texture_desc.CPUAccessFlags = 0;
190
191 hr = device_handle->CreateTexture2D (&texture_desc,
192 &subresource_data, &texture);
193 gst_video_meta_unmap (vmeta, 0, &info);
194
195 if (!gst_d3d11_result (hr, device)) {
196 GST_ERROR ("Failed to create texture");
197 return NULL;
198 }
199
200 srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
201 srv_desc.Texture2D.MipLevels = 1;
202
203 hr = device_handle->CreateShaderResourceView (texture.Get (), &srv_desc,
204 &srv);
205 if (!gst_d3d11_result (hr, device) || !srv) {
206 GST_ERROR ("Failed to create shader resource view");
207 return NULL;
208 }
209
210 buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
211 buffer_desc.ByteWidth = sizeof (VertexData) * 4;
212 buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
213 buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
214
215 hr = device_handle->CreateBuffer (&buffer_desc, NULL, &vertex_buffer);
216 if (!gst_d3d11_result (hr, device)) {
217 GST_ERROR ("Couldn't create vertex buffer, hr: 0x%x", (guint) hr);
218 return NULL;
219 }
220
221 gst_d3d11_device_lock (device);
222 hr = context_handle->Map (vertex_buffer.Get (),
223 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
224
225 if (!gst_d3d11_result (hr, device)) {
226 GST_ERROR ("Couldn't map vertex buffer, hr: 0x%x", (guint) hr);
227 gst_d3d11_device_unlock (device);
228 return NULL;
229 }
230
231 vertex_data = (VertexData *) map.pData;
232 /* bottom left */
233 gst_util_fraction_to_double (x, GST_VIDEO_INFO_WIDTH (&self->out_info), &val);
234 x1 = (val * 2.0f) - 1.0f;
235
236 gst_util_fraction_to_double (y + height,
237 GST_VIDEO_INFO_HEIGHT (&self->out_info), &val);
238 y1 = (val * -2.0f) + 1.0f;
239
240 /* top right */
241 gst_util_fraction_to_double (x + width,
242 GST_VIDEO_INFO_WIDTH (&self->out_info), &val);
243 x2 = (val * 2.0f) - 1.0f;
244
245 gst_util_fraction_to_double (y,
246 GST_VIDEO_INFO_HEIGHT (&self->out_info), &val);
247 y2 = (val * -2.0f) + 1.0f;
248
249 /* bottom left */
250 vertex_data[0].position.x = x1;
251 vertex_data[0].position.y = y1;
252 vertex_data[0].position.z = 0.0f;
253 vertex_data[0].texture.x = 0.0f;
254 vertex_data[0].texture.y = 1.0f;
255
256 /* top left */
257 vertex_data[1].position.x = x1;
258 vertex_data[1].position.y = y2;
259 vertex_data[1].position.z = 0.0f;
260 vertex_data[1].texture.x = 0.0f;
261 vertex_data[1].texture.y = 0.0f;
262
263 /* top right */
264 vertex_data[2].position.x = x2;
265 vertex_data[2].position.y = y2;
266 vertex_data[2].position.z = 0.0f;
267 vertex_data[2].texture.x = 1.0f;
268 vertex_data[2].texture.y = 0.0f;
269
270 /* bottom right */
271 vertex_data[3].position.x = x2;
272 vertex_data[3].position.y = y1;
273 vertex_data[3].position.z = 0.0f;
274 vertex_data[3].texture.x = 1.0f;
275 vertex_data[3].texture.y = 1.0f;
276
277 context_handle->Unmap (vertex_buffer.Get (), 0);
278 gst_d3d11_device_unlock (device);
279
280 overlay = g_new0 (GstD3D11CompositionOverlay, 1);
281 overlay->overlay_rect = gst_video_overlay_rectangle_ref (overlay_rect);
282 overlay->texture = texture.Detach ();
283 overlay->srv = srv.Detach ();
284 overlay->quad = gst_d3d11_quad_new (device,
285 self->ps, self->vs, self->layout, nullptr, 0,
286 vertex_buffer.Get (), sizeof (VertexData),
287 self->index_buffer, DXGI_FORMAT_R16_UINT, index_count);
288
289 return overlay;
290 }
291
292 static void
gst_d3d11_composition_overlay_free(GstD3D11CompositionOverlay * overlay)293 gst_d3d11_composition_overlay_free (GstD3D11CompositionOverlay * overlay)
294 {
295 if (!overlay)
296 return;
297
298 if (overlay->overlay_rect)
299 gst_video_overlay_rectangle_unref (overlay->overlay_rect);
300
301 GST_D3D11_CLEAR_COM (overlay->srv);
302 GST_D3D11_CLEAR_COM (overlay->texture);
303
304 if (overlay->quad)
305 gst_d3d11_quad_free (overlay->quad);
306
307 g_free (overlay);
308 }
309
310 static gboolean
gst_d3d11_overlay_compositor_setup_shader(GstD3D11OverlayCompositor * self,GstD3D11Device * device)311 gst_d3d11_overlay_compositor_setup_shader (GstD3D11OverlayCompositor * self,
312 GstD3D11Device * device)
313 {
314 HRESULT hr;
315 D3D11_SAMPLER_DESC sampler_desc;
316 D3D11_INPUT_ELEMENT_DESC input_desc[2];
317 D3D11_BUFFER_DESC buffer_desc;
318 D3D11_BLEND_DESC blend_desc;
319 D3D11_MAPPED_SUBRESOURCE map;
320 WORD *indices;
321 ID3D11Device *device_handle;
322 ID3D11DeviceContext *context_handle;
323 /* *INDENT-OFF* */
324 ComPtr<ID3D11PixelShader> ps;
325 ComPtr<ID3D11VertexShader> vs;
326 ComPtr<ID3D11InputLayout> layout;
327 ComPtr<ID3D11SamplerState> sampler;
328 ComPtr<ID3D11BlendState> blend;
329 ComPtr<ID3D11Buffer> index_buffer;
330 /* *INDENT-ON* */
331 const guint index_count = 2 * 3;
332
333 memset (&sampler_desc, 0, sizeof (sampler_desc));
334 memset (input_desc, 0, sizeof (input_desc));
335 memset (&buffer_desc, 0, sizeof (buffer_desc));
336 memset (&blend_desc, 0, sizeof (blend_desc));
337
338 device_handle = gst_d3d11_device_get_device_handle (device);
339 context_handle = gst_d3d11_device_get_device_context_handle (device);
340
341 /* bilinear filtering */
342 sampler_desc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
343 sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
344 sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
345 sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
346 sampler_desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
347 sampler_desc.MinLOD = 0;
348 sampler_desc.MaxLOD = D3D11_FLOAT32_MAX;
349
350 hr = device_handle->CreateSamplerState (&sampler_desc, &sampler);
351 if (!gst_d3d11_result (hr, device)) {
352 GST_ERROR ("Couldn't create sampler state, hr: 0x%x", (guint) hr);
353 return FALSE;
354 }
355
356 GST_LOG ("Create Pixel Shader \n%s", templ_pixel_shader);
357
358 if (!gst_d3d11_create_pixel_shader (device, templ_pixel_shader, &ps)) {
359 GST_ERROR ("Couldn't create pixel shader");
360 return FALSE;
361 }
362
363 input_desc[0].SemanticName = "POSITION";
364 input_desc[0].SemanticIndex = 0;
365 input_desc[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
366 input_desc[0].InputSlot = 0;
367 input_desc[0].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
368 input_desc[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
369 input_desc[0].InstanceDataStepRate = 0;
370
371 input_desc[1].SemanticName = "TEXCOORD";
372 input_desc[1].SemanticIndex = 0;
373 input_desc[1].Format = DXGI_FORMAT_R32G32_FLOAT;
374 input_desc[1].InputSlot = 0;
375 input_desc[1].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
376 input_desc[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
377 input_desc[1].InstanceDataStepRate = 0;
378
379 if (!gst_d3d11_create_vertex_shader (device, templ_vertex_shader,
380 input_desc, G_N_ELEMENTS (input_desc), &vs, &layout)) {
381 GST_ERROR ("Couldn't vertex pixel shader");
382 return FALSE;
383 }
384
385 blend_desc.AlphaToCoverageEnable = FALSE;
386 blend_desc.IndependentBlendEnable = FALSE;
387 blend_desc.RenderTarget[0].BlendEnable = TRUE;
388 blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
389 blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
390 blend_desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
391 blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
392 blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
393 blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
394 blend_desc.RenderTarget[0].RenderTargetWriteMask =
395 D3D11_COLOR_WRITE_ENABLE_ALL;
396
397 hr = device_handle->CreateBlendState (&blend_desc, &blend);
398 if (!gst_d3d11_result (hr, device)) {
399 GST_ERROR ("Couldn't create blend staten, hr: 0x%x", (guint) hr);
400 return FALSE;
401 }
402
403 buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
404 buffer_desc.ByteWidth = sizeof (WORD) * index_count;
405 buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
406 buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
407
408 hr = device_handle->CreateBuffer (&buffer_desc, NULL, &index_buffer);
409 if (!gst_d3d11_result (hr, device)) {
410 GST_ERROR ("Couldn't create index buffer, hr: 0x%x", (guint) hr);
411 return FALSE;
412 }
413
414 gst_d3d11_device_lock (device);
415 hr = context_handle->Map (index_buffer.Get (),
416 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
417
418 if (!gst_d3d11_result (hr, device)) {
419 GST_ERROR ("Couldn't map index buffer, hr: 0x%x", (guint) hr);
420 gst_d3d11_device_unlock (device);
421 return FALSE;
422 }
423
424 indices = (WORD *) map.pData;
425
426 /* clockwise indexing */
427 indices[0] = 0; /* bottom left */
428 indices[1] = 1; /* top left */
429 indices[2] = 2; /* top right */
430
431 indices[3] = 3; /* bottom right */
432 indices[4] = 0; /* bottom left */
433 indices[5] = 2; /* top right */
434
435 context_handle->Unmap (index_buffer.Get (), 0);
436 gst_d3d11_device_unlock (device);
437
438 self->ps = ps.Detach ();
439 self->vs = vs.Detach ();
440 self->layout = layout.Detach ();
441 self->sampler = sampler.Detach ();
442 self->blend = blend.Detach ();
443 self->index_buffer = index_buffer.Detach ();
444
445 return TRUE;
446 }
447
448
449 GstD3D11OverlayCompositor *
gst_d3d11_overlay_compositor_new(GstD3D11Device * device,GstVideoInfo * out_info)450 gst_d3d11_overlay_compositor_new (GstD3D11Device * device,
451 GstVideoInfo * out_info)
452 {
453 GstD3D11OverlayCompositor *compositor = NULL;
454
455 g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
456 g_return_val_if_fail (out_info != NULL, NULL);
457
458 compositor = g_new0 (GstD3D11OverlayCompositor, 1);
459
460 if (!gst_d3d11_overlay_compositor_setup_shader (compositor, device)) {
461 gst_d3d11_overlay_compositor_free (compositor);
462 return NULL;
463 }
464
465 compositor->device = (GstD3D11Device *) gst_object_ref (device);
466 compositor->out_info = *out_info;
467
468 compositor->viewport.TopLeftX = 0;
469 compositor->viewport.TopLeftY = 0;
470 compositor->viewport.Width = GST_VIDEO_INFO_WIDTH (out_info);
471 compositor->viewport.Height = GST_VIDEO_INFO_HEIGHT (out_info);
472 compositor->viewport.MinDepth = 0.0f;
473 compositor->viewport.MaxDepth = 1.0f;
474
475 return compositor;
476 }
477
478 void
gst_d3d11_overlay_compositor_free(GstD3D11OverlayCompositor * compositor)479 gst_d3d11_overlay_compositor_free (GstD3D11OverlayCompositor * compositor)
480 {
481 g_return_if_fail (compositor != NULL);
482
483 gst_d3d11_overlay_compositor_free_overlays (compositor);
484
485 GST_D3D11_CLEAR_COM (compositor->ps);
486 GST_D3D11_CLEAR_COM (compositor->vs);
487 GST_D3D11_CLEAR_COM (compositor->layout);
488 GST_D3D11_CLEAR_COM (compositor->sampler);
489 GST_D3D11_CLEAR_COM (compositor->blend);
490 GST_D3D11_CLEAR_COM (compositor->index_buffer);
491
492 gst_clear_object (&compositor->device);
493 g_free (compositor);
494 }
495
496 static gint
find_in_compositor(const GstD3D11CompositionOverlay * overlay,const GstVideoOverlayRectangle * rect)497 find_in_compositor (const GstD3D11CompositionOverlay * overlay,
498 const GstVideoOverlayRectangle * rect)
499 {
500 return !(overlay->overlay_rect == rect);
501 }
502
503 static gboolean
is_in_video_overlay_composition(GstVideoOverlayComposition * voc,GstD3D11CompositionOverlay * overlay)504 is_in_video_overlay_composition (GstVideoOverlayComposition * voc,
505 GstD3D11CompositionOverlay * overlay)
506 {
507 guint i;
508
509 for (i = 0; i < gst_video_overlay_composition_n_rectangles (voc); i++) {
510 GstVideoOverlayRectangle *rectangle =
511 gst_video_overlay_composition_get_rectangle (voc, i);
512 if (overlay->overlay_rect == rectangle)
513 return TRUE;
514 }
515 return FALSE;
516 }
517
518 gboolean
gst_d3d11_overlay_compositor_upload(GstD3D11OverlayCompositor * compositor,GstBuffer * buf)519 gst_d3d11_overlay_compositor_upload (GstD3D11OverlayCompositor * compositor,
520 GstBuffer * buf)
521 {
522 GstVideoOverlayCompositionMeta *meta;
523 gint i, num_overlays;
524 GList *iter;
525
526 g_return_val_if_fail (compositor != NULL, FALSE);
527 g_return_val_if_fail (GST_IS_BUFFER (buf), FALSE);
528
529 meta = gst_buffer_get_video_overlay_composition_meta (buf);
530
531 if (!meta) {
532 gst_d3d11_overlay_compositor_free_overlays (compositor);
533 return TRUE;
534 }
535
536 num_overlays = gst_video_overlay_composition_n_rectangles (meta->overlay);
537 if (!num_overlays) {
538 gst_d3d11_overlay_compositor_free_overlays (compositor);
539 return TRUE;
540 }
541
542 GST_LOG ("Upload %d overlay rectangles", num_overlays);
543
544 /* Upload new overlay */
545 for (i = 0; i < num_overlays; i++) {
546 GstVideoOverlayRectangle *rectangle =
547 gst_video_overlay_composition_get_rectangle (meta->overlay, i);
548
549 if (!g_list_find_custom (compositor->overlays,
550 rectangle, (GCompareFunc) find_in_compositor)) {
551 GstD3D11CompositionOverlay *overlay = NULL;
552
553 overlay = gst_d3d11_composition_overlay_new (compositor, rectangle);
554
555 if (!overlay)
556 return FALSE;
557
558 compositor->overlays = g_list_append (compositor->overlays, overlay);
559 }
560 }
561
562 /* Remove old overlay */
563 iter = compositor->overlays;
564 while (iter) {
565 GstD3D11CompositionOverlay *overlay =
566 (GstD3D11CompositionOverlay *) iter->data;
567 GList *next = iter->next;
568
569 if (!is_in_video_overlay_composition (meta->overlay, overlay)) {
570 compositor->overlays = g_list_delete_link (compositor->overlays, iter);
571 gst_d3d11_composition_overlay_free (overlay);
572 }
573
574 iter = next;
575 }
576
577 return TRUE;
578 }
579
580 void
gst_d3d11_overlay_compositor_free_overlays(GstD3D11OverlayCompositor * compositor)581 gst_d3d11_overlay_compositor_free_overlays (GstD3D11OverlayCompositor *
582 compositor)
583 {
584 g_return_if_fail (compositor != NULL);
585
586 if (compositor->overlays) {
587 g_list_free_full (compositor->overlays,
588 (GDestroyNotify) gst_d3d11_composition_overlay_free);
589
590 compositor->overlays = NULL;
591 }
592 }
593
594 gboolean
gst_d3d11_overlay_compositor_update_viewport(GstD3D11OverlayCompositor * compositor,D3D11_VIEWPORT * viewport)595 gst_d3d11_overlay_compositor_update_viewport (GstD3D11OverlayCompositor *
596 compositor, D3D11_VIEWPORT * viewport)
597 {
598 g_return_val_if_fail (compositor != NULL, FALSE);
599 g_return_val_if_fail (viewport != NULL, FALSE);
600
601 compositor->viewport = *viewport;
602
603 return TRUE;
604 }
605
606 gboolean
gst_d3d11_overlay_compositor_draw(GstD3D11OverlayCompositor * compositor,ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES])607 gst_d3d11_overlay_compositor_draw (GstD3D11OverlayCompositor * compositor,
608 ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES])
609 {
610 gboolean ret = TRUE;
611
612 g_return_val_if_fail (compositor != NULL, FALSE);
613 g_return_val_if_fail (rtv != NULL, FALSE);
614
615 gst_d3d11_device_lock (compositor->device);
616 ret = gst_d3d11_overlay_compositor_draw_unlocked (compositor, rtv);
617 gst_d3d11_device_unlock (compositor->device);
618
619 return ret;
620 }
621
622 gboolean
gst_d3d11_overlay_compositor_draw_unlocked(GstD3D11OverlayCompositor * compositor,ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES])623 gst_d3d11_overlay_compositor_draw_unlocked (GstD3D11OverlayCompositor *
624 compositor, ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES])
625 {
626 gboolean ret = TRUE;
627 GList *iter;
628
629 g_return_val_if_fail (compositor != NULL, FALSE);
630 g_return_val_if_fail (rtv != NULL, FALSE);
631
632 for (iter = compositor->overlays; iter; iter = g_list_next (iter)) {
633 GstD3D11CompositionOverlay *overlay =
634 (GstD3D11CompositionOverlay *) iter->data;
635
636 ret = gst_d3d11_draw_quad_unlocked (overlay->quad,
637 &compositor->viewport, 1, &overlay->srv, 1, rtv, 1,
638 compositor->blend, NULL, &compositor->sampler, 1);
639
640 if (!ret)
641 break;
642 }
643
644 return ret;
645 }
646