• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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