d3d11: Update build-time dependency
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / d3d11 / gstd3d11videoprocessor.cpp
1 /* GStreamer
2  * Copyright (C) <2020> 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 "gstd3d11videoprocessor.h"
25
26 #include <string.h>
27
28 GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_video_processor_debug);
29 #define GST_CAT_DEFAULT gst_d3d11_video_processor_debug
30
31 struct _GstD3D11VideoProcessor
32 {
33   GstD3D11Device *device;
34
35   ID3D11VideoDevice *video_device;
36   ID3D11VideoContext *video_context;
37   ID3D11VideoContext1 *video_context1;
38   ID3D11VideoContext2 *video_context2;
39   ID3D11VideoProcessor *processor;
40   ID3D11VideoProcessorEnumerator *enumerator;
41   ID3D11VideoProcessorEnumerator1 *enumerator1;
42   D3D11_VIDEO_PROCESSOR_CAPS processor_caps;
43 };
44
45 GstD3D11VideoProcessor *
46 gst_d3d11_video_processor_new (GstD3D11Device * device, guint in_width,
47     guint in_height, guint out_width, guint out_height)
48 {
49   GstD3D11VideoProcessor *self;
50   ID3D11VideoDevice *video_device;
51   ID3D11VideoContext *video_context;
52   HRESULT hr;
53   D3D11_VIDEO_PROCESSOR_CONTENT_DESC desc;
54
55   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
56
57   video_device = gst_d3d11_device_get_video_device_handle (device);
58   if (!video_device) {
59     GST_WARNING_OBJECT (device, "ID3D11VideoDevice is not available");
60     return NULL;
61   }
62
63   video_context = gst_d3d11_device_get_video_context_handle (device);
64   if (!video_context) {
65     GST_WARNING_OBJECT (device, "ID3D11VideoContext is not availale");
66     return NULL;
67   }
68
69   memset (&desc, 0, sizeof (desc));
70
71   self = g_new0 (GstD3D11VideoProcessor, 1);
72   self->device = (GstD3D11Device *) gst_object_ref (device);
73
74   self->video_device = video_device;
75   video_device->AddRef ();
76
77   self->video_context = video_context;
78   video_context->AddRef ();
79
80   /* FIXME: Add support intelace */
81   desc.InputFrameFormat = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE;
82   desc.InputWidth = in_width;
83   desc.InputHeight = in_height;
84   desc.OutputWidth = out_width;
85   desc.OutputHeight = out_height;
86   /* TODO: make option for this */
87   desc.Usage = D3D11_VIDEO_USAGE_PLAYBACK_NORMAL;
88
89   hr = self->video_device->CreateVideoProcessorEnumerator (&desc,
90       &self->enumerator);
91   if (!gst_d3d11_result (hr, device))
92     goto fail;
93
94   hr = self->enumerator->QueryInterface (IID_PPV_ARGS (&self->enumerator1));
95   if (gst_d3d11_result (hr, device)) {
96     GST_DEBUG ("ID3D11VideoProcessorEnumerator1 interface available");
97   }
98
99   hr = self->enumerator->GetVideoProcessorCaps (&self->processor_caps);
100   if (!gst_d3d11_result (hr, device))
101     goto fail;
102
103   hr = self->video_device->CreateVideoProcessor (self->enumerator, 0,
104       &self->processor);
105   if (!gst_d3d11_result (hr, device))
106     goto fail;
107
108   hr = self->video_context->
109       QueryInterface (IID_PPV_ARGS (&self->video_context1));
110   if (gst_d3d11_result (hr, device)) {
111     GST_DEBUG ("ID3D11VideoContext1 interface available");
112   }
113
114   hr = self->video_context->
115       QueryInterface (IID_PPV_ARGS (&self->video_context2));
116   if (gst_d3d11_result (hr, device)) {
117     GST_DEBUG ("ID3D11VideoContext2 interface available");
118   }
119
120   /* Setting up default options */
121   gst_d3d11_device_lock (self->device);
122   /* We don't want auto processing by driver */
123   self->video_context->VideoProcessorSetStreamAutoProcessingMode
124       (self->processor, 0, FALSE);
125   gst_d3d11_device_unlock (self->device);
126
127   return self;
128
129 fail:
130   gst_d3d11_video_processor_free (self);
131
132   return NULL;
133 }
134
135 void
136 gst_d3d11_video_processor_free (GstD3D11VideoProcessor * processor)
137 {
138   g_return_if_fail (processor != NULL);
139
140   GST_D3D11_CLEAR_COM (processor->video_device);
141   GST_D3D11_CLEAR_COM (processor->video_context);
142   GST_D3D11_CLEAR_COM (processor->video_context1);
143   GST_D3D11_CLEAR_COM (processor->video_context2);
144   GST_D3D11_CLEAR_COM (processor->processor);
145   GST_D3D11_CLEAR_COM (processor->enumerator);
146   GST_D3D11_CLEAR_COM (processor->enumerator1);
147
148   gst_clear_object (&processor->device);
149   g_free (processor);
150 }
151
152 static gboolean
153 gst_d3d11_video_processor_supports_format (GstD3D11VideoProcessor *
154     self, DXGI_FORMAT format, gboolean is_input)
155 {
156   HRESULT hr;
157   UINT flag = 0;
158
159   hr = self->enumerator->CheckVideoProcessorFormat (format, &flag);
160
161   if (!gst_d3d11_result (hr, self->device))
162     return FALSE;
163
164   if (is_input) {
165     /* D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_INPUT, missing in mingw header */
166     if ((flag & 0x1) != 0)
167       return TRUE;
168   } else {
169     /* D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT, missing in mingw header */
170     if ((flag & 0x2) != 0)
171       return TRUE;
172   }
173
174   return FALSE;
175 }
176
177 gboolean
178 gst_d3d11_video_processor_supports_input_format (GstD3D11VideoProcessor *
179     processor, DXGI_FORMAT format)
180 {
181   g_return_val_if_fail (processor != NULL, FALSE);
182
183   if (format == DXGI_FORMAT_UNKNOWN)
184     return FALSE;
185
186   return gst_d3d11_video_processor_supports_format (processor, format, TRUE);
187 }
188
189 gboolean
190 gst_d3d11_video_processor_supports_output_format (GstD3D11VideoProcessor *
191     processor, DXGI_FORMAT format)
192 {
193   g_return_val_if_fail (processor != NULL, FALSE);
194
195   if (format == DXGI_FORMAT_UNKNOWN)
196     return FALSE;
197
198   return gst_d3d11_video_processor_supports_format (processor, format, FALSE);
199 }
200
201 gboolean
202 gst_d3d11_video_processor_get_caps (GstD3D11VideoProcessor * processor,
203     D3D11_VIDEO_PROCESSOR_CAPS * caps)
204 {
205   g_return_val_if_fail (processor != NULL, FALSE);
206   g_return_val_if_fail (caps != NULL, FALSE);
207
208   *caps = processor->processor_caps;
209
210   return TRUE;
211 }
212
213 static void
214 video_processor_color_space_from_gst (GstD3D11VideoProcessor * self,
215     GstVideoColorimetry * color, D3D11_VIDEO_PROCESSOR_COLOR_SPACE * colorspace)
216 {
217   /* D3D11_VIDEO_PROCESSOR_DEVICE_CAPS_xvYCC */
218   UINT can_xvYCC = 2;
219
220   /* 0: playback, 1: video processing */
221   colorspace->Usage = 0;
222
223   if (color->range == GST_VIDEO_COLOR_RANGE_0_255) {
224     colorspace->RGB_Range = 0;
225     colorspace->Nominal_Range = D3D11_VIDEO_PROCESSOR_NOMINAL_RANGE_0_255;
226   } else {
227     /* 16-235 */
228     colorspace->RGB_Range = 1;
229     colorspace->Nominal_Range = D3D11_VIDEO_PROCESSOR_NOMINAL_RANGE_16_235;
230   }
231
232   if (color->matrix == GST_VIDEO_COLOR_MATRIX_BT601) {
233     colorspace->YCbCr_Matrix = 0;
234   } else {
235     /* BT.709, no other options (such as BT2020) */
236     colorspace->YCbCr_Matrix = 1;
237   }
238
239   if ((self->processor_caps.DeviceCaps & can_xvYCC) == can_xvYCC) {
240     colorspace->YCbCr_xvYCC = 1;
241   } else {
242     colorspace->YCbCr_xvYCC = 0;
243   }
244 }
245
246 gboolean
247 gst_d3d11_video_processor_set_input_color_space (GstD3D11VideoProcessor *
248     processor, GstVideoColorimetry * color)
249 {
250   D3D11_VIDEO_PROCESSOR_COLOR_SPACE color_space;
251
252   g_return_val_if_fail (processor != NULL, FALSE);
253   g_return_val_if_fail (color != NULL, FALSE);
254
255   video_processor_color_space_from_gst (processor, color, &color_space);
256
257   processor->video_context->VideoProcessorSetStreamColorSpace
258       (processor->processor, 0, &color_space);
259
260   return TRUE;
261 }
262
263 gboolean
264 gst_d3d11_video_processor_set_output_color_space (GstD3D11VideoProcessor *
265     processor, GstVideoColorimetry * color)
266 {
267   D3D11_VIDEO_PROCESSOR_COLOR_SPACE color_space;
268
269   g_return_val_if_fail (processor != NULL, FALSE);
270   g_return_val_if_fail (color != NULL, FALSE);
271
272   video_processor_color_space_from_gst (processor, color, &color_space);
273
274   processor->video_context->VideoProcessorSetOutputColorSpace
275       (processor->processor, &color_space);
276
277   return TRUE;
278 }
279
280 gboolean
281 gst_d3d11_video_processor_check_format_conversion (GstD3D11VideoProcessor *
282     processor, DXGI_FORMAT in_format, DXGI_COLOR_SPACE_TYPE in_color_space,
283     DXGI_FORMAT out_format, DXGI_COLOR_SPACE_TYPE out_color_space)
284 {
285   HRESULT hr;
286   BOOL supported = TRUE;
287
288   g_return_val_if_fail (processor != NULL, FALSE);
289
290   if (!processor->enumerator1)
291     return FALSE;
292
293   hr = processor->enumerator1->CheckVideoProcessorFormatConversion
294       (in_format, in_color_space, out_format, out_color_space, &supported);
295   if (!gst_d3d11_result (hr, processor->device)) {
296     GST_WARNING ("Failed to check conversion support");
297     return FALSE;
298   }
299
300   return supported;
301 }
302
303 gboolean
304 gst_d3d11_video_processor_set_input_dxgi_color_space (GstD3D11VideoProcessor *
305     processor, DXGI_COLOR_SPACE_TYPE color_space)
306 {
307   g_return_val_if_fail (processor != NULL, FALSE);
308
309   if (processor->video_context1) {
310     processor->video_context1->VideoProcessorSetStreamColorSpace1
311         (processor->processor, 0, color_space);
312     return TRUE;
313   }
314
315   return FALSE;
316 }
317
318 gboolean
319 gst_d3d11_video_processor_set_output_dxgi_color_space (GstD3D11VideoProcessor *
320     processor, DXGI_COLOR_SPACE_TYPE color_space)
321 {
322   g_return_val_if_fail (processor != NULL, FALSE);
323
324   if (processor->video_context1) {
325     processor->video_context1->VideoProcessorSetOutputColorSpace1
326         (processor->processor, color_space);
327     return TRUE;
328   }
329
330   return FALSE;
331 }
332
333 /* D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_METADATA_HDR10
334  * missing in mingw header */
335 #define FEATURE_CAPS_METADATA_HDR10 (0x800)
336
337 gboolean
338 gst_d3d11_video_processor_set_input_hdr10_metadata (GstD3D11VideoProcessor *
339     processor, DXGI_HDR_METADATA_HDR10 * hdr10_meta)
340 {
341   g_return_val_if_fail (processor != NULL, FALSE);
342
343   if (processor->video_context2 && (processor->processor_caps.FeatureCaps &
344           FEATURE_CAPS_METADATA_HDR10)) {
345     if (hdr10_meta) {
346       processor->video_context2->VideoProcessorSetStreamHDRMetaData
347           (processor->processor, 0,
348           DXGI_HDR_METADATA_TYPE_HDR10, sizeof (DXGI_HDR_METADATA_HDR10),
349           hdr10_meta);
350     } else {
351       processor->video_context2->VideoProcessorSetStreamHDRMetaData
352           (processor->processor, 0, DXGI_HDR_METADATA_TYPE_NONE, 0, NULL);
353     }
354
355     return TRUE;
356   }
357
358   return FALSE;
359 }
360
361 gboolean
362 gst_d3d11_video_processor_set_output_hdr10_metadata (GstD3D11VideoProcessor *
363     processor, DXGI_HDR_METADATA_HDR10 * hdr10_meta)
364 {
365   g_return_val_if_fail (processor != NULL, FALSE);
366
367   if (processor->video_context2 && (processor->processor_caps.FeatureCaps &
368           FEATURE_CAPS_METADATA_HDR10)) {
369     if (hdr10_meta) {
370       processor->video_context2->VideoProcessorSetOutputHDRMetaData
371           (processor->processor, DXGI_HDR_METADATA_TYPE_HDR10,
372           sizeof (DXGI_HDR_METADATA_HDR10), hdr10_meta);
373     } else {
374       processor->video_context2->VideoProcessorSetOutputHDRMetaData
375           (processor->processor, DXGI_HDR_METADATA_TYPE_NONE, 0, NULL);
376     }
377
378     return TRUE;
379   }
380
381   return FALSE;
382 }
383
384 gboolean
385 gst_d3d11_video_processor_create_input_view (GstD3D11VideoProcessor * processor,
386     D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC * desc, ID3D11Resource * resource,
387     ID3D11VideoProcessorInputView ** view)
388 {
389   HRESULT hr;
390
391   g_return_val_if_fail (processor != NULL, FALSE);
392   g_return_val_if_fail (desc != NULL, FALSE);
393   g_return_val_if_fail (resource != NULL, FALSE);
394   g_return_val_if_fail (view != NULL, FALSE);
395
396   hr = processor->video_device->CreateVideoProcessorInputView (resource,
397       processor->enumerator, desc, view);
398   if (!gst_d3d11_result (hr, processor->device))
399     return FALSE;
400
401   return TRUE;
402 }
403
404 ID3D11VideoProcessorInputView *
405 gst_d3d11_video_processor_get_input_view (GstD3D11VideoProcessor * processor,
406     GstD3D11Memory * mem)
407 {
408   return gst_d3d11_memory_get_processor_input_view (mem,
409       processor->video_device, processor->enumerator);
410 }
411
412 gboolean
413 gst_d3d11_video_processor_create_output_view (GstD3D11VideoProcessor *
414     processor, D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC * desc,
415     ID3D11Resource * resource, ID3D11VideoProcessorOutputView ** view)
416 {
417   HRESULT hr;
418
419   g_return_val_if_fail (processor != NULL, FALSE);
420   g_return_val_if_fail (desc != NULL, FALSE);
421   g_return_val_if_fail (resource != NULL, FALSE);
422   g_return_val_if_fail (view != NULL, FALSE);
423
424   hr = processor->video_device->CreateVideoProcessorOutputView
425       (resource, processor->enumerator, desc, view);
426   if (!gst_d3d11_result (hr, processor->device))
427     return FALSE;
428
429   return TRUE;
430 }
431
432 ID3D11VideoProcessorOutputView *
433 gst_d3d11_video_processor_get_output_view (GstD3D11VideoProcessor *
434     processor, GstD3D11Memory * mem)
435 {
436   return gst_d3d11_memory_get_processor_output_view (mem,
437       processor->video_device, processor->enumerator);
438 }
439
440 gboolean
441 gst_d3d11_video_processor_render (GstD3D11VideoProcessor * processor,
442     RECT * in_rect, ID3D11VideoProcessorInputView * in_view,
443     RECT * out_rect, ID3D11VideoProcessorOutputView * out_view)
444 {
445   gboolean ret;
446
447   g_return_val_if_fail (processor != NULL, FALSE);
448   g_return_val_if_fail (in_view != NULL, FALSE);
449   g_return_val_if_fail (out_view != NULL, FALSE);
450
451   gst_d3d11_device_lock (processor->device);
452   ret = gst_d3d11_video_processor_render_unlocked (processor, in_rect, in_view,
453       out_rect, out_view);
454   gst_d3d11_device_unlock (processor->device);
455
456   return ret;
457 }
458
459 gboolean
460 gst_d3d11_video_processor_render_unlocked (GstD3D11VideoProcessor * processor,
461     RECT * in_rect, ID3D11VideoProcessorInputView * in_view,
462     RECT * out_rect, ID3D11VideoProcessorOutputView * out_view)
463 {
464   HRESULT hr;
465   D3D11_VIDEO_PROCESSOR_STREAM stream = { 0, };
466   ID3D11VideoContext *context;
467   ID3D11VideoProcessor *proc;
468
469   g_return_val_if_fail (processor != NULL, FALSE);
470   g_return_val_if_fail (in_view != NULL, FALSE);
471   g_return_val_if_fail (out_view != NULL, FALSE);
472
473   stream.Enable = TRUE;
474   stream.pInputSurface = in_view;
475   context = processor->video_context;
476   proc = processor->processor;
477
478   if (in_rect) {
479     context->VideoProcessorSetStreamSourceRect (proc, 0, TRUE, in_rect);
480   } else {
481     context->VideoProcessorSetStreamSourceRect (proc, 0, FALSE, NULL);
482   }
483
484   if (out_rect) {
485     context->VideoProcessorSetStreamDestRect (proc, 0, TRUE, out_rect);
486     context->VideoProcessorSetOutputTargetRect (proc, TRUE, out_rect);
487   } else {
488     context->VideoProcessorSetStreamDestRect (proc, 0, FALSE, NULL);
489     context->VideoProcessorSetOutputTargetRect (proc, FALSE, NULL);
490   }
491
492   hr = context->VideoProcessorBlt (proc, out_view, 0, 1, &stream);
493   if (!gst_d3d11_result (hr, processor->device))
494     return FALSE;
495
496   return TRUE;
497 }
498
499 gboolean
500 gst_d3d11_video_processor_check_bind_flags_for_input_view (guint bind_flags)
501 {
502   static const guint compatible_flags = (D3D11_BIND_DECODER |
503       D3D11_BIND_VIDEO_ENCODER | D3D11_BIND_RENDER_TARGET |
504       D3D11_BIND_UNORDERED_ACCESS);
505
506   if (bind_flags == 0)
507     return TRUE;
508
509   if ((bind_flags & compatible_flags) != 0)
510     return TRUE;
511
512   return FALSE;
513 }
514
515 gboolean
516 gst_d3d11_video_processor_check_bind_flags_for_output_view (guint bind_flags)
517 {
518   if ((bind_flags & D3D11_BIND_RENDER_TARGET) == D3D11_BIND_RENDER_TARGET)
519     return TRUE;
520
521   return FALSE;
522 }