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 * NOTE: some of implementations are copied/modified from Chromium code
20 *
21 * Copyright 2015 The Chromium Authors. All rights reserved.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions are
25 * met:
26 *
27 * * Redistributions of source code must retain the above copyright
28 * notice, this list of conditions and the following disclaimer.
29 * * Redistributions in binary form must reproduce the above
30 * copyright notice, this list of conditions and the following disclaimer
31 * in the documentation and/or other materials provided with the
32 * distribution.
33 * * Neither the name of Google Inc. nor the names of its
34 * contributors may be used to endorse or promote products derived from
35 * this software without specific prior written permission.
36 *
37 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
38 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
39 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
40 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
41 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
44 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
45 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
47 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48 */
49
50 #ifdef HAVE_CONFIG_H
51 #include <config.h>
52 #endif
53
54 #include "gstd3d11decoder.h"
55 #include "gstd3d11converter.h"
56 #include "gstd3d11pluginutils.h"
57 #include <string.h>
58 #include <string>
59
60 #ifdef HAVE_WINMM
61 #include <mmsystem.h>
62 #endif
63
64 GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_decoder_debug);
65 #define GST_CAT_DEFAULT gst_d3d11_decoder_debug
66
67 /* GUID might not be defined in MinGW header */
68 DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_H264_IDCT_FGT, 0x1b81be67, 0xa0c7,
69 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5);
70 DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_H264_VLD_NOFGT, 0x1b81be68, 0xa0c7,
71 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5);
72 DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_H264_VLD_FGT, 0x1b81be69, 0xa0c7,
73 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5);
74 DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_HEVC_VLD_MAIN,
75 0x5b11d51b, 0x2f4c, 0x4452, 0xbc, 0xc3, 0x09, 0xf2, 0xa1, 0x16, 0x0c, 0xc0);
76 DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_HEVC_VLD_MAIN10,
77 0x107af0e0, 0xef1a, 0x4d19, 0xab, 0xa8, 0x67, 0xa1, 0x63, 0x07, 0x3d, 0x13);
78 DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_VP8_VLD,
79 0x90b899ea, 0x3a62, 0x4705, 0x88, 0xb3, 0x8d, 0xf0, 0x4b, 0x27, 0x44, 0xe7);
80 DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0,
81 0x463707f8, 0xa1d0, 0x4585, 0x87, 0x6d, 0x83, 0xaa, 0x6d, 0x60, 0xb8, 0x9e);
82 DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_VP9_VLD_10BIT_PROFILE2,
83 0xa4c749ef, 0x6ecf, 0x48aa, 0x84, 0x48, 0x50, 0xa7, 0xa1, 0x16, 0x5f, 0xf7);
84 DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_MPEG2_VLD, 0xee27417f, 0x5e28,
85 0x4e65, 0xbe, 0xea, 0x1d, 0x26, 0xb5, 0x08, 0xad, 0xc9);
86 DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_MPEG2and1_VLD, 0x86695f12, 0x340e,
87 0x4f04, 0x9f, 0xd3, 0x92, 0x53, 0xdd, 0x32, 0x74, 0x60);
88 DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_AV1_VLD_PROFILE0, 0xb8be4ccb,
89 0xcf53, 0x46ba, 0x8d, 0x59, 0xd6, 0xb8, 0xa6, 0xda, 0x5d, 0x2a);
90
91 static const GUID *profile_h264_list[] = {
92 &GST_GUID_D3D11_DECODER_PROFILE_H264_IDCT_FGT,
93 &GST_GUID_D3D11_DECODER_PROFILE_H264_VLD_NOFGT,
94 &GST_GUID_D3D11_DECODER_PROFILE_H264_VLD_FGT,
95 };
96
97 static const GUID *profile_hevc_list[] = {
98 &GST_GUID_D3D11_DECODER_PROFILE_HEVC_VLD_MAIN,
99 };
100
101 static const GUID *profile_hevc_10_list[] = {
102 &GST_GUID_D3D11_DECODER_PROFILE_HEVC_VLD_MAIN10,
103 };
104
105 static const GUID *profile_vp8_list[] = {
106 &GST_GUID_D3D11_DECODER_PROFILE_VP8_VLD,
107 };
108
109 static const GUID *profile_vp9_list[] = {
110 &GST_GUID_D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0,
111 };
112
113 static const GUID *profile_vp9_10_list[] = {
114 &GST_GUID_D3D11_DECODER_PROFILE_VP9_VLD_10BIT_PROFILE2,
115 };
116
117 static const GUID *profile_mpeg2_list[] = {
118 &GST_GUID_D3D11_DECODER_PROFILE_MPEG2_VLD,
119 &GST_GUID_D3D11_DECODER_PROFILE_MPEG2and1_VLD
120 };
121
122 static const GUID *profile_av1_list[] = {
123 &GST_GUID_D3D11_DECODER_PROFILE_AV1_VLD_PROFILE0,
124 /* TODO: add more profile */
125 };
126
127 enum
128 {
129 PROP_0,
130 PROP_DEVICE,
131 };
132
133 struct _GstD3D11Decoder
134 {
135 GstObject parent;
136
137 gboolean configured;
138 gboolean opened;
139
140 GstD3D11Device *device;
141
142 ID3D11VideoDevice *video_device;
143 ID3D11VideoContext *video_context;
144
145 ID3D11VideoDecoder *decoder_handle;
146
147 GstVideoInfo info;
148 GstVideoInfo output_info;
149 GstDXVACodec codec;
150 gint coded_width;
151 gint coded_height;
152 DXGI_FORMAT decoder_format;
153 gboolean downstream_supports_d3d11;
154
155 GstVideoCodecState *input_state;
156 GstVideoCodecState *output_state;
157
158 /* Protect internal pool */
159 GMutex internal_pool_lock;
160
161 GstBufferPool *internal_pool;
162 /* Internal pool params */
163 gint aligned_width;
164 gint aligned_height;
165 gboolean use_array_of_texture;
166 guint dpb_size;
167 guint downstream_min_buffers;
168 gboolean wait_on_pool_full;
169
170 /* Used for array-of-texture */
171 guint8 next_view_id;
172
173 /* for staging */
174 ID3D11Texture2D *staging;
175 gsize staging_texture_offset[GST_VIDEO_MAX_PLANES];
176 gint stating_texture_stride[GST_VIDEO_MAX_PLANES];
177
178 GUID decoder_profile;
179
180 /* For device specific workaround */
181 gboolean can_direct_rendering;
182
183 /* For high precision clock */
184 guint timer_resolution;
185 };
186
187 static void gst_d3d11_decoder_constructed (GObject * object);
188 static void gst_d3d11_decoder_set_property (GObject * object, guint prop_id,
189 const GValue * value, GParamSpec * pspec);
190 static void gst_d3d11_decoder_get_property (GObject * object, guint prop_id,
191 GValue * value, GParamSpec * pspec);
192 static void gst_d3d11_decoder_dispose (GObject * obj);
193 static void gst_d3d11_decoder_finalize (GObject * obj);
194 static gboolean gst_d3d11_decoder_can_direct_render (GstD3D11Decoder * decoder,
195 GstVideoDecoder * videodec, GstBuffer * view_buffer,
196 gint display_width, gint display_height);
197
198 #define parent_class gst_d3d11_decoder_parent_class
199 G_DEFINE_TYPE (GstD3D11Decoder, gst_d3d11_decoder, GST_TYPE_OBJECT);
200
201 static void
gst_d3d11_decoder_class_init(GstD3D11DecoderClass * klass)202 gst_d3d11_decoder_class_init (GstD3D11DecoderClass * klass)
203 {
204 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
205
206 gobject_class->constructed = gst_d3d11_decoder_constructed;
207 gobject_class->set_property = gst_d3d11_decoder_set_property;
208 gobject_class->get_property = gst_d3d11_decoder_get_property;
209 gobject_class->dispose = gst_d3d11_decoder_dispose;
210 gobject_class->finalize = gst_d3d11_decoder_finalize;
211
212 g_object_class_install_property (gobject_class, PROP_DEVICE,
213 g_param_spec_object ("device", "Device",
214 "D3D11 Devicd to use", GST_TYPE_D3D11_DEVICE,
215 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
216 G_PARAM_STATIC_STRINGS)));
217 }
218
219 static void
gst_d3d11_decoder_init(GstD3D11Decoder * self)220 gst_d3d11_decoder_init (GstD3D11Decoder * self)
221 {
222 g_mutex_init (&self->internal_pool_lock);
223 }
224
225 static void
gst_d3d11_decoder_constructed(GObject * object)226 gst_d3d11_decoder_constructed (GObject * object)
227 {
228 GstD3D11Decoder *self = GST_D3D11_DECODER (object);
229 ID3D11VideoDevice *video_device;
230 ID3D11VideoContext *video_context;
231
232 if (!self->device) {
233 GST_ERROR_OBJECT (self, "No D3D11Device available");
234 return;
235 }
236
237 video_device = gst_d3d11_device_get_video_device_handle (self->device);
238 if (!video_device) {
239 GST_WARNING_OBJECT (self, "ID3D11VideoDevice is not available");
240 return;
241 }
242
243 video_context = gst_d3d11_device_get_video_context_handle (self->device);
244 if (!video_context) {
245 GST_WARNING_OBJECT (self, "ID3D11VideoContext is not available");
246 return;
247 }
248
249 self->video_device = video_device;
250 video_device->AddRef ();
251
252 self->video_context = video_context;
253 video_context->AddRef ();
254
255 return;
256 }
257
258 static void
gst_d3d11_decoder_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)259 gst_d3d11_decoder_set_property (GObject * object, guint prop_id,
260 const GValue * value, GParamSpec * pspec)
261 {
262 GstD3D11Decoder *self = GST_D3D11_DECODER (object);
263
264 switch (prop_id) {
265 case PROP_DEVICE:
266 self->device = (GstD3D11Device *) g_value_dup_object (value);
267 break;
268 default:
269 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
270 break;
271 }
272 }
273
274 static void
gst_d3d11_decoder_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)275 gst_d3d11_decoder_get_property (GObject * object, guint prop_id,
276 GValue * value, GParamSpec * pspec)
277 {
278 GstD3D11Decoder *self = GST_D3D11_DECODER (object);
279
280 switch (prop_id) {
281 case PROP_DEVICE:
282 g_value_set_object (value, self->device);
283 break;
284 default:
285 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
286 break;
287 }
288 }
289
290 static void
gst_d3d11_decoder_clear_resource(GstD3D11Decoder * self)291 gst_d3d11_decoder_clear_resource (GstD3D11Decoder * self)
292 {
293 g_mutex_lock (&self->internal_pool_lock);
294 if (self->internal_pool) {
295 gst_buffer_pool_set_active (self->internal_pool, FALSE);
296 gst_clear_object (&self->internal_pool);
297 }
298 g_mutex_unlock (&self->internal_pool_lock);
299
300 GST_D3D11_CLEAR_COM (self->decoder_handle);
301 GST_D3D11_CLEAR_COM (self->staging);
302
303 memset (self->staging_texture_offset,
304 0, sizeof (self->staging_texture_offset));
305 memset (self->stating_texture_stride,
306 0, sizeof (self->stating_texture_stride));
307 }
308
309 static void
gst_d3d11_decoder_reset(GstD3D11Decoder * self)310 gst_d3d11_decoder_reset (GstD3D11Decoder * self)
311 {
312 gst_d3d11_decoder_clear_resource (self);
313
314 self->dpb_size = 0;
315 self->downstream_min_buffers = 0;
316
317 self->configured = FALSE;
318 self->opened = FALSE;
319
320 self->use_array_of_texture = FALSE;
321 self->downstream_supports_d3d11 = FALSE;
322
323 g_clear_pointer (&self->output_state, gst_video_codec_state_unref);
324 g_clear_pointer (&self->input_state, gst_video_codec_state_unref);
325 }
326
327 static void
gst_d3d11_decoder_dispose(GObject * obj)328 gst_d3d11_decoder_dispose (GObject * obj)
329 {
330 GstD3D11Decoder *self = GST_D3D11_DECODER (obj);
331
332 gst_d3d11_decoder_reset (self);
333
334 GST_D3D11_CLEAR_COM (self->video_device);
335 GST_D3D11_CLEAR_COM (self->video_context);
336
337 gst_clear_object (&self->device);
338
339 G_OBJECT_CLASS (parent_class)->dispose (obj);
340 }
341
342 static void
gst_d3d11_decoder_finalize(GObject * obj)343 gst_d3d11_decoder_finalize (GObject * obj)
344 {
345 GstD3D11Decoder *self = GST_D3D11_DECODER (obj);
346
347 #if HAVE_WINMM
348 /* Restore clock precision */
349 if (self->timer_resolution)
350 timeEndPeriod (self->timer_resolution);
351 #endif
352
353 g_mutex_clear (&self->internal_pool_lock);
354
355 G_OBJECT_CLASS (parent_class)->finalize (obj);
356 }
357
358 GstD3D11Decoder *
gst_d3d11_decoder_new(GstD3D11Device * device,GstDXVACodec codec)359 gst_d3d11_decoder_new (GstD3D11Device * device, GstDXVACodec codec)
360 {
361 GstD3D11Decoder *self;
362
363 g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), nullptr);
364 g_return_val_if_fail (codec > GST_DXVA_CODEC_NONE, nullptr);
365 g_return_val_if_fail (codec < GST_DXVA_CODEC_LAST, nullptr);
366
367 self = (GstD3D11Decoder *)
368 g_object_new (GST_TYPE_D3D11_DECODER, "device", device, NULL);
369
370 if (!self->video_device || !self->video_context) {
371 gst_object_unref (self);
372 return NULL;
373 }
374
375 self->codec = codec;
376
377 gst_object_ref_sink (self);
378
379 return self;
380 }
381
382 gboolean
gst_d3d11_decoder_is_configured(GstD3D11Decoder * decoder)383 gst_d3d11_decoder_is_configured (GstD3D11Decoder * decoder)
384 {
385 g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
386
387 return decoder->configured;
388 }
389
390 static GQuark
gst_d3d11_decoder_view_id_quark(void)391 gst_d3d11_decoder_view_id_quark (void)
392 {
393 static gsize id_quark = 0;
394
395 if (g_once_init_enter (&id_quark)) {
396 GQuark quark = g_quark_from_string ("GstD3D11DecoderViewId");
397 g_once_init_leave (&id_quark, quark);
398 }
399
400 return (GQuark) id_quark;
401 }
402
403 static gboolean
gst_d3d11_decoder_ensure_output_view(GstD3D11Decoder * self,GstBuffer * buffer)404 gst_d3d11_decoder_ensure_output_view (GstD3D11Decoder * self,
405 GstBuffer * buffer)
406 {
407 GstD3D11Memory *mem;
408 gpointer val = NULL;
409
410 mem = (GstD3D11Memory *) gst_buffer_peek_memory (buffer, 0);
411 if (!gst_d3d11_memory_get_decoder_output_view (mem, self->video_device,
412 self->decoder_handle, &self->decoder_profile)) {
413 GST_ERROR_OBJECT (self, "Decoder output view is unavailable");
414 return FALSE;
415 }
416
417 if (!self->use_array_of_texture)
418 return TRUE;
419
420 val = gst_mini_object_get_qdata (GST_MINI_OBJECT (mem),
421 gst_d3d11_decoder_view_id_quark ());
422 if (!val) {
423 g_assert (self->next_view_id < 128);
424 g_assert (self->next_view_id > 0);
425
426 gst_mini_object_set_qdata (GST_MINI_OBJECT (mem),
427 gst_d3d11_decoder_view_id_quark (),
428 GUINT_TO_POINTER (self->next_view_id), NULL);
429
430 self->next_view_id++;
431 /* valid view range is [0, 126], but 0 is not used to here
432 * (it's NULL as well) */
433 self->next_view_id %= 128;
434 if (self->next_view_id == 0)
435 self->next_view_id = 1;
436 }
437
438
439 return TRUE;
440 }
441
442 static gboolean
gst_d3d11_decoder_prepare_output_view_pool(GstD3D11Decoder * self)443 gst_d3d11_decoder_prepare_output_view_pool (GstD3D11Decoder * self)
444 {
445 GstD3D11AllocationParams *alloc_params = NULL;
446 GstBufferPool *pool = NULL;
447 GstCaps *caps = NULL;
448 GstVideoAlignment align;
449 GstD3D11AllocationFlags alloc_flags = (GstD3D11AllocationFlags) 0;
450 gint bind_flags = D3D11_BIND_DECODER;
451 GstVideoInfo *info = &self->info;
452 guint pool_size;
453
454 g_mutex_lock (&self->internal_pool_lock);
455 if (self->internal_pool) {
456 gst_buffer_pool_set_active (self->internal_pool, FALSE);
457 gst_clear_object (&self->internal_pool);
458 }
459 g_mutex_unlock (&self->internal_pool_lock);
460
461 if (!self->use_array_of_texture) {
462 alloc_flags = GST_D3D11_ALLOCATION_FLAG_TEXTURE_ARRAY;
463 } else {
464 /* array of texture can have shader resource view */
465 bind_flags |= D3D11_BIND_SHADER_RESOURCE;
466 }
467
468 alloc_params = gst_d3d11_allocation_params_new (self->device, info,
469 alloc_flags, bind_flags);
470
471 if (!alloc_params) {
472 GST_ERROR_OBJECT (self, "Failed to create allocation param");
473 goto error;
474 }
475
476 pool_size = self->dpb_size + self->downstream_min_buffers;
477 GST_DEBUG_OBJECT (self,
478 "Configuring internal pool with size %d "
479 "(dpb size: %d, downstream min buffers: %d)", pool_size, self->dpb_size,
480 self->downstream_min_buffers);
481
482 if (!self->use_array_of_texture) {
483 alloc_params->desc[0].ArraySize = pool_size;
484 } else {
485 /* Valid view id is [0, 126], but we will use [1, 127] range so that
486 * it can be used by qdata, because zero is equal to null */
487 self->next_view_id = 1;
488
489 /* our pool size can be increased as much as possbile */
490 pool_size = 0;
491 }
492
493 gst_video_alignment_reset (&align);
494
495 align.padding_right = self->aligned_width - GST_VIDEO_INFO_WIDTH (info);
496 align.padding_bottom = self->aligned_height - GST_VIDEO_INFO_HEIGHT (info);
497 if (!gst_d3d11_allocation_params_alignment (alloc_params, &align)) {
498 GST_ERROR_OBJECT (self, "Cannot set alignment");
499 goto error;
500 }
501
502 caps = gst_video_info_to_caps (info);
503 if (!caps) {
504 GST_ERROR_OBJECT (self, "Couldn't convert video info to caps");
505 goto error;
506 }
507
508 pool = gst_d3d11_buffer_pool_new_with_options (self->device,
509 caps, alloc_params, 0, pool_size);
510 gst_clear_caps (&caps);
511 g_clear_pointer (&alloc_params, gst_d3d11_allocation_params_free);
512
513 if (!pool) {
514 GST_ERROR_OBJECT (self, "Failed to create buffer pool");
515 goto error;
516 }
517
518 if (!gst_buffer_pool_set_active (pool, TRUE)) {
519 GST_ERROR_OBJECT (self, "Couldn't activate pool");
520 goto error;
521 }
522
523 g_mutex_lock (&self->internal_pool_lock);
524 self->internal_pool = pool;
525 g_mutex_unlock (&self->internal_pool_lock);
526
527 return TRUE;
528
529 error:
530 if (alloc_params)
531 gst_d3d11_allocation_params_free (alloc_params);
532 if (pool)
533 gst_object_unref (pool);
534 if (caps)
535 gst_caps_unref (caps);
536
537 return FALSE;
538 }
539
540 static const gchar *
gst_dxva_codec_to_string(GstDXVACodec codec)541 gst_dxva_codec_to_string (GstDXVACodec codec)
542 {
543 switch (codec) {
544 case GST_DXVA_CODEC_NONE:
545 return "none";
546 case GST_DXVA_CODEC_H264:
547 return "H.264";
548 case GST_DXVA_CODEC_VP9:
549 return "VP9";
550 case GST_DXVA_CODEC_H265:
551 return "H.265";
552 case GST_DXVA_CODEC_VP8:
553 return "VP8";
554 case GST_DXVA_CODEC_MPEG2:
555 return "MPEG2";
556 case GST_DXVA_CODEC_AV1:
557 return "AV1";
558 default:
559 g_assert_not_reached ();
560 break;
561 }
562
563 return "Unknown";
564 }
565
566 gboolean
gst_d3d11_decoder_get_supported_decoder_profile(GstD3D11Device * device,GstDXVACodec codec,GstVideoFormat format,const GUID ** selected_profile)567 gst_d3d11_decoder_get_supported_decoder_profile (GstD3D11Device * device,
568 GstDXVACodec codec, GstVideoFormat format, const GUID ** selected_profile)
569 {
570 GUID *guid_list = nullptr;
571 const GUID *profile = nullptr;
572 guint available_profile_count;
573 guint i, j;
574 HRESULT hr;
575 ID3D11VideoDevice *video_device;
576 const GUID **profile_list = nullptr;
577 guint profile_size = 0;
578
579 g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), FALSE);
580 g_return_val_if_fail (selected_profile != nullptr, FALSE);
581
582 video_device = gst_d3d11_device_get_video_device_handle (device);
583 if (!video_device)
584 return FALSE;
585
586 switch (codec) {
587 case GST_DXVA_CODEC_H264:
588 if (format == GST_VIDEO_FORMAT_NV12) {
589 profile_list = profile_h264_list;
590 profile_size = G_N_ELEMENTS (profile_h264_list);
591 }
592 break;
593 case GST_DXVA_CODEC_H265:
594 if (format == GST_VIDEO_FORMAT_NV12) {
595 profile_list = profile_hevc_list;
596 profile_size = G_N_ELEMENTS (profile_hevc_list);
597 } else if (format == GST_VIDEO_FORMAT_P010_10LE) {
598 profile_list = profile_hevc_10_list;
599 profile_size = G_N_ELEMENTS (profile_hevc_10_list);
600 }
601 break;
602 case GST_DXVA_CODEC_VP8:
603 if (format == GST_VIDEO_FORMAT_NV12) {
604 profile_list = profile_vp8_list;
605 profile_size = G_N_ELEMENTS (profile_vp8_list);
606 }
607 break;
608 case GST_DXVA_CODEC_VP9:
609 if (format == GST_VIDEO_FORMAT_NV12) {
610 profile_list = profile_vp9_list;
611 profile_size = G_N_ELEMENTS (profile_vp9_list);
612 } else if (format == GST_VIDEO_FORMAT_P010_10LE) {
613 profile_list = profile_vp9_10_list;
614 profile_size = G_N_ELEMENTS (profile_vp9_10_list);
615 }
616 break;
617 case GST_DXVA_CODEC_MPEG2:
618 if (format == GST_VIDEO_FORMAT_NV12) {
619 profile_list = profile_mpeg2_list;
620 profile_size = G_N_ELEMENTS (profile_mpeg2_list);
621 }
622 break;
623 case GST_DXVA_CODEC_AV1:
624 profile_list = profile_av1_list;
625 profile_size = G_N_ELEMENTS (profile_av1_list);
626 break;
627 default:
628 break;
629 }
630
631 if (!profile_list) {
632 GST_ERROR_OBJECT (device,
633 "Not supported codec (%d) and format (%s) configuration", codec,
634 gst_video_format_to_string (format));
635 return FALSE;
636 }
637
638 available_profile_count = video_device->GetVideoDecoderProfileCount ();
639
640 if (available_profile_count == 0) {
641 GST_INFO_OBJECT (device, "No available decoder profile");
642 return FALSE;
643 }
644
645 GST_DEBUG_OBJECT (device,
646 "Have %u available decoder profiles", available_profile_count);
647 guid_list = (GUID *) g_alloca (sizeof (GUID) * available_profile_count);
648
649 for (i = 0; i < available_profile_count; i++) {
650 hr = video_device->GetVideoDecoderProfile (i, &guid_list[i]);
651 if (!gst_d3d11_result (hr, device)) {
652 GST_WARNING_OBJECT (device, "Failed to get %d th decoder profile", i);
653 return FALSE;
654 }
655 }
656
657 #ifndef GST_DISABLE_GST_DEBUG
658 GST_LOG_OBJECT (device, "Supported decoder GUID");
659 for (i = 0; i < available_profile_count; i++) {
660 const GUID *guid = &guid_list[i];
661
662 GST_LOG_OBJECT (device,
663 "\t { %8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x }",
664 (guint) guid->Data1, (guint) guid->Data2, (guint) guid->Data3,
665 guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
666 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
667 }
668
669 GST_LOG_OBJECT (device, "Requested decoder GUID");
670 for (i = 0; i < profile_size; i++) {
671 const GUID *guid = profile_list[i];
672
673 GST_LOG_OBJECT (device,
674 "\t { %8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x }",
675 (guint) guid->Data1, (guint) guid->Data2, (guint) guid->Data3,
676 guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
677 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
678 }
679 #endif
680
681 for (i = 0; i < profile_size; i++) {
682 for (j = 0; j < available_profile_count; j++) {
683 if (IsEqualGUID (*profile_list[i], guid_list[j])) {
684 profile = profile_list[i];
685 break;
686 }
687 }
688 }
689
690 if (!profile) {
691 GST_INFO_OBJECT (device, "No supported decoder profile for %s codec",
692 gst_dxva_codec_to_string (codec));
693 return FALSE;
694 }
695
696 *selected_profile = profile;
697
698 GST_DEBUG_OBJECT (device,
699 "Selected guid "
700 "{ %8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x }",
701 (guint) profile->Data1, (guint) profile->Data2, (guint) profile->Data3,
702 profile->Data4[0], profile->Data4[1], profile->Data4[2],
703 profile->Data4[3], profile->Data4[4], profile->Data4[5],
704 profile->Data4[6], profile->Data4[7]);
705
706 return TRUE;
707 }
708
709
710 gboolean
gst_d3d11_decoder_configure(GstD3D11Decoder * decoder,GstVideoCodecState * input_state,GstVideoInfo * info,gint coded_width,gint coded_height,guint dpb_size)711 gst_d3d11_decoder_configure (GstD3D11Decoder * decoder,
712 GstVideoCodecState * input_state, GstVideoInfo * info, gint coded_width,
713 gint coded_height, guint dpb_size)
714 {
715 const GstD3D11Format *d3d11_format;
716
717 g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
718 g_return_val_if_fail (info != NULL, FALSE);
719 g_return_val_if_fail (input_state != NULL, FALSE);
720 g_return_val_if_fail (coded_width >= GST_VIDEO_INFO_WIDTH (info), FALSE);
721 g_return_val_if_fail (coded_height >= GST_VIDEO_INFO_HEIGHT (info), FALSE);
722 g_return_val_if_fail (dpb_size > 0, FALSE);
723
724 gst_d3d11_decoder_reset (decoder);
725
726 d3d11_format = gst_d3d11_device_format_from_gst (decoder->device,
727 GST_VIDEO_INFO_FORMAT (info));
728 if (!d3d11_format || d3d11_format->dxgi_format == DXGI_FORMAT_UNKNOWN) {
729 GST_ERROR_OBJECT (decoder, "Could not determine dxgi format from %s",
730 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (info)));
731 return FALSE;
732 }
733
734 decoder->input_state = gst_video_codec_state_ref (input_state);
735 decoder->info = decoder->output_info = *info;
736 decoder->coded_width = coded_width;
737 decoder->coded_height = coded_height;
738 decoder->dpb_size = dpb_size;
739 decoder->decoder_format = d3d11_format->dxgi_format;
740
741 decoder->configured = TRUE;
742
743 return TRUE;
744 }
745
746 static gboolean
gst_d3d11_decoder_ensure_staging_texture(GstD3D11Decoder * self)747 gst_d3d11_decoder_ensure_staging_texture (GstD3D11Decoder * self)
748 {
749 ID3D11Device *device_handle;
750 D3D11_TEXTURE2D_DESC desc = { 0, };
751 HRESULT hr;
752
753 if (self->staging)
754 return TRUE;
755
756 device_handle = gst_d3d11_device_get_device_handle (self->device);
757
758 /* create stage texture to copy out */
759 desc.Width = self->aligned_width;
760 desc.Height = self->aligned_height;
761 desc.MipLevels = 1;
762 desc.Format = self->decoder_format;
763 desc.SampleDesc.Count = 1;
764 desc.ArraySize = 1;
765 desc.Usage = D3D11_USAGE_STAGING;
766 desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
767
768 hr = device_handle->CreateTexture2D (&desc, NULL, &self->staging);
769 if (!gst_d3d11_result (hr, self->device)) {
770 GST_ERROR_OBJECT (self, "Couldn't create staging texture");
771 return FALSE;
772 }
773
774 return TRUE;
775 }
776
777 static void
gst_d3d11_decoder_enable_high_precision_timer(GstD3D11Decoder * self)778 gst_d3d11_decoder_enable_high_precision_timer (GstD3D11Decoder * self)
779 {
780 #if HAVE_WINMM
781 GstD3D11DeviceVendor vendor;
782
783 if (self->timer_resolution)
784 return;
785
786 vendor = gst_d3d11_get_device_vendor (self->device);
787 /* Do this only for NVIDIA at the moment, other vendors doesn't seem to be
788 * requiring retry for BeginFrame() */
789 if (vendor == GST_D3D11_DEVICE_VENDOR_NVIDIA) {
790 TIMECAPS time_caps;
791 if (timeGetDevCaps (&time_caps, sizeof (TIMECAPS)) == TIMERR_NOERROR) {
792 guint resolution;
793 MMRESULT ret;
794
795 resolution = MIN (MAX (time_caps.wPeriodMin, 1), time_caps.wPeriodMax);
796
797 ret = timeBeginPeriod (resolution);
798 if (ret == TIMERR_NOERROR) {
799 self->timer_resolution = resolution;
800 GST_INFO_OBJECT (self, "Updated timer resolution to %d", resolution);
801 }
802 }
803 }
804 #endif
805 }
806
807 static gboolean
gst_d3d11_decoder_open(GstD3D11Decoder * self)808 gst_d3d11_decoder_open (GstD3D11Decoder * self)
809 {
810 HRESULT hr;
811 BOOL can_support = FALSE;
812 guint config_count;
813 D3D11_VIDEO_DECODER_CONFIG *config_list;
814 D3D11_VIDEO_DECODER_CONFIG *best_config = NULL;
815 D3D11_VIDEO_DECODER_DESC decoder_desc = { 0, };
816 const GUID *selected_profile = NULL;
817 guint i;
818 gint aligned_width, aligned_height;
819 guint alignment;
820 GstD3D11DeviceVendor vendor;
821 ID3D11VideoDevice *video_device;
822 GstVideoInfo *info = &self->info;
823
824 if (self->opened)
825 return TRUE;
826
827 if (!self->configured) {
828 GST_ERROR_OBJECT (self, "Should configure first");
829 return FALSE;
830 }
831
832 video_device = self->video_device;
833
834 gst_d3d11_device_lock (self->device);
835 if (!gst_d3d11_decoder_get_supported_decoder_profile (self->device,
836 self->codec, GST_VIDEO_INFO_FORMAT (info), &selected_profile)) {
837 goto error;
838 }
839
840 hr = video_device->CheckVideoDecoderFormat (selected_profile,
841 self->decoder_format, &can_support);
842 if (!gst_d3d11_result (hr, self->device) || !can_support) {
843 GST_ERROR_OBJECT (self,
844 "VideoDevice could not support dxgi format %d, hr: 0x%x",
845 self->decoder_format, (guint) hr);
846 goto error;
847 }
848
849 gst_d3d11_decoder_clear_resource (self);
850 self->can_direct_rendering = TRUE;
851
852 vendor = gst_d3d11_get_device_vendor (self->device);
853 switch (vendor) {
854 case GST_D3D11_DEVICE_VENDOR_XBOX:
855 /* FIXME: Need to figure out Xbox device's behavior
856 * https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/issues/1312
857 */
858 self->can_direct_rendering = FALSE;
859 break;
860 default:
861 break;
862 }
863
864 /* NOTE: other dxva implementations (ffmpeg and vlc) do this
865 * and they say the required alignment were mentioned by dxva spec.
866 * See ff_dxva2_common_frame_params() in dxva.c of ffmpeg and
867 * directx_va_Setup() in directx_va.c of vlc.
868 * But... where it is? */
869 switch (self->codec) {
870 case GST_DXVA_CODEC_H265:
871 case GST_DXVA_CODEC_AV1:
872 /* See directx_va_Setup() impl. in vlc */
873 if (vendor != GST_D3D11_DEVICE_VENDOR_XBOX)
874 alignment = 128;
875 else
876 alignment = 16;
877 break;
878 case GST_DXVA_CODEC_MPEG2:
879 /* XXX: ffmpeg does this */
880 alignment = 32;
881 break;
882 default:
883 alignment = 16;
884 break;
885 }
886
887 aligned_width = GST_ROUND_UP_N (self->coded_width, alignment);
888 aligned_height = GST_ROUND_UP_N (self->coded_height, alignment);
889 if (aligned_width != self->coded_width ||
890 aligned_height != self->coded_height) {
891 GST_DEBUG_OBJECT (self,
892 "coded resolution %dx%d is not aligned to %d, adjust to %dx%d",
893 self->coded_width, self->coded_height, alignment, aligned_width,
894 aligned_height);
895 }
896
897 self->aligned_width = aligned_width;
898 self->aligned_height = aligned_height;
899
900 decoder_desc.SampleWidth = aligned_width;
901 decoder_desc.SampleHeight = aligned_height;
902 decoder_desc.OutputFormat = self->decoder_format;
903 decoder_desc.Guid = *selected_profile;
904
905 hr = video_device->GetVideoDecoderConfigCount (&decoder_desc, &config_count);
906 if (!gst_d3d11_result (hr, self->device) || config_count == 0) {
907 GST_ERROR_OBJECT (self, "Could not get decoder config count, hr: 0x%x",
908 (guint) hr);
909 goto error;
910 }
911
912 GST_DEBUG_OBJECT (self, "Total %d config available", config_count);
913
914 config_list = (D3D11_VIDEO_DECODER_CONFIG *)
915 g_alloca (sizeof (D3D11_VIDEO_DECODER_CONFIG) * config_count);
916
917 for (i = 0; i < config_count; i++) {
918 hr = video_device->GetVideoDecoderConfig (&decoder_desc, i,
919 &config_list[i]);
920 if (!gst_d3d11_result (hr, self->device)) {
921 GST_ERROR_OBJECT (self, "Could not get decoder %dth config, hr: 0x%x",
922 i, (guint) hr);
923 goto error;
924 }
925
926 /* FIXME: need support DXVA_Slice_H264_Long ?? */
927 /* this config uses DXVA_Slice_H264_Short */
928 switch (self->codec) {
929 case GST_DXVA_CODEC_H264:
930 if (config_list[i].ConfigBitstreamRaw == 2)
931 best_config = &config_list[i];
932 break;
933 case GST_DXVA_CODEC_H265:
934 case GST_DXVA_CODEC_VP9:
935 case GST_DXVA_CODEC_VP8:
936 case GST_DXVA_CODEC_MPEG2:
937 case GST_DXVA_CODEC_AV1:
938 if (config_list[i].ConfigBitstreamRaw == 1)
939 best_config = &config_list[i];
940 break;
941 default:
942 g_assert_not_reached ();
943 goto error;
944 }
945
946 if (best_config)
947 break;
948 }
949
950 if (best_config == NULL) {
951 GST_ERROR_OBJECT (self, "Could not determine decoder config");
952 goto error;
953 }
954
955 GST_DEBUG_OBJECT (self, "ConfigDecoderSpecific 0x%x",
956 best_config->ConfigDecoderSpecific);
957
958 /* bit 14 is equal to 1b means this config support array of texture and
959 * it's recommended type as per DXVA spec */
960 if ((best_config->ConfigDecoderSpecific & 0x4000) == 0x4000) {
961 GST_DEBUG_OBJECT (self, "Config support array of texture");
962 self->use_array_of_texture = TRUE;
963 }
964
965 hr = video_device->CreateVideoDecoder (&decoder_desc,
966 best_config, &self->decoder_handle);
967 if (!gst_d3d11_result (hr, self->device) || !self->decoder_handle) {
968 GST_ERROR_OBJECT (self,
969 "Could not create decoder object, hr: 0x%x", (guint) hr);
970 goto error;
971 }
972
973 GST_DEBUG_OBJECT (self, "Decoder object %p created", self->decoder_handle);
974
975 if (!self->downstream_supports_d3d11 &&
976 !gst_d3d11_decoder_ensure_staging_texture (self)) {
977 GST_ERROR_OBJECT (self, "Couldn't prepare staging texture");
978 goto error;
979 }
980
981 self->decoder_profile = *selected_profile;
982
983 /* Store pool related information here, then we will setup internal pool
984 * later once the number of min buffer size required by downstream is known.
985 * Actual buffer pool size will be "dpb_size + downstream_min_buffers"
986 */
987 self->downstream_min_buffers = 0;
988 self->wait_on_pool_full = FALSE;
989
990 self->opened = TRUE;
991 gst_d3d11_device_unlock (self->device);
992
993 gst_d3d11_decoder_enable_high_precision_timer (self);
994
995 return TRUE;
996
997 error:
998 gst_d3d11_decoder_reset (self);
999 gst_d3d11_device_unlock (self->device);
1000
1001 return FALSE;
1002 }
1003
1004 static gboolean
gst_d3d11_decoder_begin_frame(GstD3D11Decoder * decoder,ID3D11VideoDecoderOutputView * output_view,guint content_key_size,gconstpointer content_key)1005 gst_d3d11_decoder_begin_frame (GstD3D11Decoder * decoder,
1006 ID3D11VideoDecoderOutputView * output_view, guint content_key_size,
1007 gconstpointer content_key)
1008 {
1009 ID3D11VideoContext *video_context;
1010 guint retry_count = 0;
1011 HRESULT hr;
1012 guint retry_threshold = 100;
1013
1014 /* if we have high resolution timer, do more retry */
1015 if (decoder->timer_resolution)
1016 retry_threshold = 500;
1017
1018 video_context = decoder->video_context;
1019
1020 do {
1021 GST_LOG_OBJECT (decoder, "Try begin frame, retry count %d", retry_count);
1022 hr = video_context->DecoderBeginFrame (decoder->decoder_handle,
1023 output_view, content_key_size, content_key);
1024
1025 /* HACK: Do retry with 1ms sleep per failure, since DXVA/D3D11
1026 * doesn't provide API for "GPU-IS-READY-TO-DECODE" like signal.
1027 */
1028 if (hr == E_PENDING && retry_count < retry_threshold) {
1029 GST_LOG_OBJECT (decoder, "GPU is busy, try again. Retry count %d",
1030 retry_count);
1031 g_usleep (1000);
1032 } else {
1033 if (gst_d3d11_result (hr, decoder->device))
1034 GST_LOG_OBJECT (decoder, "Succeeded with retry count %d", retry_count);
1035 break;
1036 }
1037
1038 retry_count++;
1039 } while (TRUE);
1040
1041 if (!gst_d3d11_result (hr, decoder->device)) {
1042 GST_ERROR_OBJECT (decoder, "Failed to begin frame, hr: 0x%x", (guint) hr);
1043 return FALSE;
1044 }
1045
1046 return TRUE;
1047 }
1048
1049 static gboolean
gst_d3d11_decoder_end_frame(GstD3D11Decoder * decoder)1050 gst_d3d11_decoder_end_frame (GstD3D11Decoder * decoder)
1051 {
1052 HRESULT hr;
1053 ID3D11VideoContext *video_context;
1054
1055 video_context = decoder->video_context;
1056 hr = video_context->DecoderEndFrame (decoder->decoder_handle);
1057
1058 if (!gst_d3d11_result (hr, decoder->device)) {
1059 GST_WARNING_OBJECT (decoder, "EndFrame failed, hr: 0x%x", (guint) hr);
1060 return FALSE;
1061 }
1062
1063 return TRUE;
1064 }
1065
1066 static gboolean
gst_d3d11_decoder_get_decoder_buffer(GstD3D11Decoder * decoder,D3D11_VIDEO_DECODER_BUFFER_TYPE type,guint * buffer_size,gpointer * buffer)1067 gst_d3d11_decoder_get_decoder_buffer (GstD3D11Decoder * decoder,
1068 D3D11_VIDEO_DECODER_BUFFER_TYPE type, guint * buffer_size,
1069 gpointer * buffer)
1070 {
1071 UINT size;
1072 void *decoder_buffer;
1073 HRESULT hr;
1074 ID3D11VideoContext *video_context;
1075
1076 video_context = decoder->video_context;
1077 hr = video_context->GetDecoderBuffer (decoder->decoder_handle,
1078 type, &size, &decoder_buffer);
1079
1080 if (!gst_d3d11_result (hr, decoder->device)) {
1081 GST_WARNING_OBJECT (decoder, "Getting buffer type %d error, hr: 0x%x",
1082 type, (guint) hr);
1083 return FALSE;
1084 }
1085
1086 *buffer_size = size;
1087 *buffer = decoder_buffer;
1088
1089 return TRUE;
1090 }
1091
1092 static gboolean
gst_d3d11_decoder_release_decoder_buffer(GstD3D11Decoder * decoder,D3D11_VIDEO_DECODER_BUFFER_TYPE type)1093 gst_d3d11_decoder_release_decoder_buffer (GstD3D11Decoder * decoder,
1094 D3D11_VIDEO_DECODER_BUFFER_TYPE type)
1095 {
1096 HRESULT hr;
1097 ID3D11VideoContext *video_context;
1098
1099 video_context = decoder->video_context;
1100 hr = video_context->ReleaseDecoderBuffer (decoder->decoder_handle, type);
1101
1102 if (!gst_d3d11_result (hr, decoder->device)) {
1103 GST_WARNING_OBJECT (decoder, "ReleaseDecoderBuffer failed, hr: 0x%x",
1104 (guint) hr);
1105 return FALSE;
1106 }
1107
1108 return TRUE;
1109 }
1110
1111 static gboolean
gst_d3d11_decoder_submit_decoder_buffers(GstD3D11Decoder * decoder,guint buffer_count,const D3D11_VIDEO_DECODER_BUFFER_DESC * buffers)1112 gst_d3d11_decoder_submit_decoder_buffers (GstD3D11Decoder * decoder,
1113 guint buffer_count, const D3D11_VIDEO_DECODER_BUFFER_DESC * buffers)
1114 {
1115 HRESULT hr;
1116 ID3D11VideoContext *video_context;
1117
1118 video_context = decoder->video_context;
1119 hr = video_context->SubmitDecoderBuffers (decoder->decoder_handle,
1120 buffer_count, buffers);
1121 if (!gst_d3d11_result (hr, decoder->device)) {
1122 GST_WARNING_OBJECT (decoder, "SubmitDecoderBuffers failed, hr: 0x%x",
1123 (guint) hr);
1124 return FALSE;
1125 }
1126
1127 return TRUE;
1128 }
1129
1130 gboolean
gst_d3d11_decoder_decode_frame(GstD3D11Decoder * decoder,ID3D11VideoDecoderOutputView * output_view,GstD3D11DecodeInputStreamArgs * input_args)1131 gst_d3d11_decoder_decode_frame (GstD3D11Decoder * decoder,
1132 ID3D11VideoDecoderOutputView * output_view,
1133 GstD3D11DecodeInputStreamArgs * input_args)
1134 {
1135 guint d3d11_buffer_size;
1136 gpointer d3d11_buffer;
1137 D3D11_VIDEO_DECODER_BUFFER_DESC buffer_desc[4];
1138 guint buffer_desc_size;
1139
1140 g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
1141 g_return_val_if_fail (output_view != nullptr, FALSE);
1142 g_return_val_if_fail (input_args != nullptr, FALSE);
1143
1144 memset (buffer_desc, 0, sizeof (buffer_desc));
1145
1146 buffer_desc[0].BufferType = D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS;
1147 buffer_desc[0].DataSize = input_args->picture_params_size;
1148
1149 buffer_desc[1].BufferType = D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL;
1150 buffer_desc[1].DataSize = input_args->slice_control_size;
1151
1152 buffer_desc[2].BufferType = D3D11_VIDEO_DECODER_BUFFER_BITSTREAM;
1153 buffer_desc[2].DataOffset = 0;
1154 buffer_desc[2].DataSize = input_args->bitstream_size;
1155
1156 buffer_desc_size = 3;
1157 if (input_args->inverse_quantization_matrix &&
1158 input_args->inverse_quantization_matrix_size > 0) {
1159 buffer_desc[3].BufferType =
1160 D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX;
1161 buffer_desc[3].DataSize = input_args->inverse_quantization_matrix_size;
1162 buffer_desc_size++;
1163 }
1164
1165 gst_d3d11_device_lock (decoder->device);
1166 if (!gst_d3d11_decoder_begin_frame (decoder, output_view, 0, nullptr)) {
1167 gst_d3d11_device_unlock (decoder->device);
1168
1169 return FALSE;
1170 }
1171
1172 if (!gst_d3d11_decoder_get_decoder_buffer (decoder,
1173 D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS, &d3d11_buffer_size,
1174 &d3d11_buffer)) {
1175 GST_ERROR_OBJECT (decoder,
1176 "Failed to get decoder buffer for picture parameters");
1177 goto error;
1178 }
1179
1180 if (d3d11_buffer_size < input_args->picture_params_size) {
1181 GST_ERROR_OBJECT (decoder,
1182 "Too small picture param buffer size %d", d3d11_buffer_size);
1183
1184 gst_d3d11_decoder_release_decoder_buffer (decoder,
1185 D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS);
1186 goto error;
1187 }
1188
1189 memcpy (d3d11_buffer, input_args->picture_params,
1190 input_args->picture_params_size);
1191
1192 if (!gst_d3d11_decoder_release_decoder_buffer (decoder,
1193 D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS)) {
1194 GST_ERROR_OBJECT (decoder, "Failed to release picture param buffer");
1195 goto error;
1196 }
1197
1198 if (!gst_d3d11_decoder_get_decoder_buffer (decoder,
1199 D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL, &d3d11_buffer_size,
1200 &d3d11_buffer)) {
1201 GST_ERROR_OBJECT (decoder, "Failed to get slice control buffer");
1202 goto error;
1203 }
1204
1205 if (d3d11_buffer_size < input_args->slice_control_size) {
1206 GST_ERROR_OBJECT (decoder,
1207 "Too small slice control buffer size %d", d3d11_buffer_size);
1208
1209 gst_d3d11_decoder_release_decoder_buffer (decoder,
1210 D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL);
1211 goto error;
1212 }
1213
1214 memcpy (d3d11_buffer,
1215 input_args->slice_control, input_args->slice_control_size);
1216
1217 if (!gst_d3d11_decoder_release_decoder_buffer (decoder,
1218 D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL)) {
1219 GST_ERROR_OBJECT (decoder, "Failed to release slice control buffer");
1220 goto error;
1221 }
1222
1223 if (!gst_d3d11_decoder_get_decoder_buffer (decoder,
1224 D3D11_VIDEO_DECODER_BUFFER_BITSTREAM, &d3d11_buffer_size,
1225 &d3d11_buffer)) {
1226 GST_ERROR_OBJECT (decoder, "Failed to get bitstream buffer");
1227 goto error;
1228 }
1229
1230 if (d3d11_buffer_size < input_args->bitstream_size) {
1231 GST_ERROR_OBJECT (decoder, "Too small bitstream buffer size %d",
1232 d3d11_buffer_size);
1233
1234 gst_d3d11_decoder_release_decoder_buffer (decoder,
1235 D3D11_VIDEO_DECODER_BUFFER_BITSTREAM);
1236 goto error;
1237 }
1238
1239 memcpy (d3d11_buffer, input_args->bitstream, input_args->bitstream_size);
1240
1241 if (!gst_d3d11_decoder_release_decoder_buffer (decoder,
1242 D3D11_VIDEO_DECODER_BUFFER_BITSTREAM)) {
1243 GST_ERROR_OBJECT (decoder, "Failed to release bitstream buffer");
1244 goto error;
1245 }
1246
1247 if (input_args->inverse_quantization_matrix_size > 0) {
1248 if (!gst_d3d11_decoder_get_decoder_buffer (decoder,
1249 D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX,
1250 &d3d11_buffer_size, &d3d11_buffer)) {
1251 GST_ERROR_OBJECT (decoder,
1252 "Failed to get inverse quantization matrix buffer");
1253 goto error;
1254 }
1255
1256 if (d3d11_buffer_size < input_args->inverse_quantization_matrix_size) {
1257 GST_ERROR_OBJECT (decoder,
1258 "Too small inverse quantization matrix buffer buffer %d",
1259 d3d11_buffer_size);
1260
1261 gst_d3d11_decoder_release_decoder_buffer (decoder,
1262 D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX);
1263 goto error;
1264 }
1265
1266 memcpy (d3d11_buffer, input_args->inverse_quantization_matrix,
1267 input_args->inverse_quantization_matrix_size);
1268
1269 if (!gst_d3d11_decoder_release_decoder_buffer (decoder,
1270 D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX)) {
1271 GST_ERROR_OBJECT (decoder,
1272 "Failed to release inverse quantization matrix buffer");
1273 goto error;
1274 }
1275 }
1276
1277 if (!gst_d3d11_decoder_submit_decoder_buffers (decoder,
1278 buffer_desc_size, buffer_desc)) {
1279 GST_ERROR_OBJECT (decoder, "Failed to submit decoder buffers");
1280 goto error;
1281 }
1282
1283 if (!gst_d3d11_decoder_end_frame (decoder)) {
1284 gst_d3d11_device_unlock (decoder->device);
1285 return FALSE;
1286 }
1287
1288 gst_d3d11_device_unlock (decoder->device);
1289
1290 return TRUE;
1291
1292 error:
1293 gst_d3d11_decoder_end_frame (decoder);
1294 gst_d3d11_device_unlock (decoder->device);
1295 return FALSE;
1296 }
1297
1298 GstBuffer *
gst_d3d11_decoder_get_output_view_buffer(GstD3D11Decoder * decoder,GstVideoDecoder * videodec)1299 gst_d3d11_decoder_get_output_view_buffer (GstD3D11Decoder * decoder,
1300 GstVideoDecoder * videodec)
1301 {
1302 GstBuffer *buf = NULL;
1303 GstFlowReturn ret;
1304
1305 g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
1306
1307 if (!decoder->internal_pool) {
1308 /* Try negotiate again whatever the previous negotiation result was.
1309 * There could be updated field(s) in sinkpad caps after we negotiated with
1310 * downstream on new_sequence() call. For example, h264/h265 parse
1311 * will be able to update HDR10 related caps field after parsing
1312 * corresponding SEI messages which are usually placed after the essential
1313 * headers */
1314 gst_video_decoder_negotiate (videodec);
1315
1316 if (!gst_d3d11_decoder_prepare_output_view_pool (decoder)) {
1317 GST_ERROR_OBJECT (videodec, "Failed to setup internal pool");
1318 return NULL;
1319 }
1320 } else if (!gst_buffer_pool_set_active (decoder->internal_pool, TRUE)) {
1321 GST_ERROR_OBJECT (videodec, "Couldn't set active internal pool");
1322 return NULL;
1323 }
1324
1325 ret = gst_buffer_pool_acquire_buffer (decoder->internal_pool, &buf, NULL);
1326
1327 if (ret != GST_FLOW_OK || !buf) {
1328 if (ret != GST_FLOW_FLUSHING) {
1329 GST_ERROR_OBJECT (videodec, "Couldn't get buffer from pool, ret %s",
1330 gst_flow_get_name (ret));
1331 } else {
1332 GST_DEBUG_OBJECT (videodec, "We are flusing");
1333 }
1334
1335 return NULL;
1336 }
1337
1338 if (!gst_d3d11_decoder_ensure_output_view (decoder, buf)) {
1339 GST_ERROR_OBJECT (videodec, "Output view unavailable");
1340 gst_buffer_unref (buf);
1341
1342 return NULL;
1343 }
1344
1345 return buf;
1346 }
1347
1348 ID3D11VideoDecoderOutputView *
gst_d3d11_decoder_get_output_view_from_buffer(GstD3D11Decoder * decoder,GstBuffer * buffer,guint8 * index)1349 gst_d3d11_decoder_get_output_view_from_buffer (GstD3D11Decoder * decoder,
1350 GstBuffer * buffer, guint8 * index)
1351 {
1352 GstMemory *mem;
1353 GstD3D11Memory *dmem;
1354 ID3D11VideoDecoderOutputView *view;
1355
1356 g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), NULL);
1357 g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
1358
1359 mem = gst_buffer_peek_memory (buffer, 0);
1360 if (!gst_is_d3d11_memory (mem)) {
1361 GST_WARNING_OBJECT (decoder, "Not a d3d11 memory");
1362 return NULL;
1363 }
1364
1365 dmem = (GstD3D11Memory *) mem;
1366 view = gst_d3d11_memory_get_decoder_output_view (dmem, decoder->video_device,
1367 decoder->decoder_handle, &decoder->decoder_profile);
1368
1369 if (!view) {
1370 GST_ERROR_OBJECT (decoder, "Decoder output view is unavailable");
1371 return NULL;
1372 }
1373
1374 if (index) {
1375 if (decoder->use_array_of_texture) {
1376 guint8 id;
1377 gpointer val = gst_mini_object_get_qdata (GST_MINI_OBJECT (mem),
1378 gst_d3d11_decoder_view_id_quark ());
1379 if (!val) {
1380 GST_ERROR_OBJECT (decoder, "memory has no qdata");
1381 return NULL;
1382 }
1383
1384 id = (guint8) GPOINTER_TO_UINT (val);
1385 g_assert (id < 128);
1386
1387 *index = (id - 1);
1388 } else {
1389 *index = gst_d3d11_memory_get_subresource_index (dmem);
1390 }
1391 }
1392
1393 return view;
1394 }
1395
1396 static gboolean
copy_to_system(GstD3D11Decoder * self,GstBuffer * decoder_buffer,GstBuffer * output)1397 copy_to_system (GstD3D11Decoder * self, GstBuffer * decoder_buffer,
1398 GstBuffer * output)
1399 {
1400 GstVideoFrame out_frame;
1401 GstVideoInfo *info = &self->output_info;
1402 guint i;
1403 GstD3D11Memory *in_mem;
1404 D3D11_MAPPED_SUBRESOURCE map;
1405 HRESULT hr;
1406 ID3D11Texture2D *in_texture;
1407 guint in_subresource_index;
1408 ID3D11DeviceContext *device_context =
1409 gst_d3d11_device_get_device_context_handle (self->device);
1410
1411 if (!gst_d3d11_decoder_ensure_staging_texture (self)) {
1412 GST_ERROR_OBJECT (self, "Staging texture is not available");
1413 return FALSE;
1414 }
1415
1416 if (!gst_video_frame_map (&out_frame, info, output, GST_MAP_WRITE)) {
1417 GST_ERROR_OBJECT (self, "Couldn't map output buffer");
1418 return FALSE;
1419 }
1420
1421 in_mem = (GstD3D11Memory *) gst_buffer_peek_memory (decoder_buffer, 0);
1422
1423 in_texture = gst_d3d11_memory_get_texture_handle (in_mem);
1424 in_subresource_index = gst_d3d11_memory_get_subresource_index (in_mem);
1425
1426 gst_d3d11_device_lock (self->device);
1427 device_context->CopySubresourceRegion (self->staging, 0, 0, 0, 0,
1428 in_texture, in_subresource_index, NULL);
1429
1430 hr = device_context->Map (self->staging, 0, D3D11_MAP_READ, 0, &map);
1431
1432 if (!gst_d3d11_result (hr, self->device)) {
1433 GST_ERROR_OBJECT (self, "Failed to map, hr: 0x%x", (guint) hr);
1434
1435 gst_d3d11_device_unlock (self->device);
1436 gst_video_frame_unmap (&out_frame);
1437
1438 return FALSE;
1439 }
1440
1441 /* calculate stride and offset only once */
1442 if (self->stating_texture_stride[0] == 0) {
1443 D3D11_TEXTURE2D_DESC desc;
1444 gsize dummy;
1445
1446 self->staging->GetDesc (&desc);
1447
1448 gst_d3d11_dxgi_format_get_size (desc.Format, desc.Width, desc.Height,
1449 map.RowPitch, self->staging_texture_offset,
1450 self->stating_texture_stride, &dummy);
1451 }
1452
1453 for (i = 0; i < GST_VIDEO_FRAME_N_PLANES (&out_frame); i++) {
1454 guint8 *src, *dst;
1455 gint j;
1456 gint width;
1457
1458 src = (guint8 *) map.pData + self->staging_texture_offset[i];
1459 dst = (guint8 *) GST_VIDEO_FRAME_PLANE_DATA (&out_frame, i);
1460 width = GST_VIDEO_FRAME_COMP_WIDTH (&out_frame, i) *
1461 GST_VIDEO_FRAME_COMP_PSTRIDE (&out_frame, i);
1462
1463 for (j = 0; j < GST_VIDEO_FRAME_COMP_HEIGHT (&out_frame, i); j++) {
1464 memcpy (dst, src, width);
1465 dst += GST_VIDEO_FRAME_PLANE_STRIDE (&out_frame, i);
1466 src += self->stating_texture_stride[i];
1467 }
1468 }
1469
1470 gst_video_frame_unmap (&out_frame);
1471 device_context->Unmap (self->staging, 0);
1472 gst_d3d11_device_unlock (self->device);
1473
1474 return TRUE;
1475 }
1476
1477 static gboolean
copy_to_d3d11(GstD3D11Decoder * self,GstBuffer * decoder_buffer,GstBuffer * output)1478 copy_to_d3d11 (GstD3D11Decoder * self, GstBuffer * decoder_buffer,
1479 GstBuffer * output)
1480 {
1481 GstVideoInfo *info = &self->output_info;
1482 GstD3D11Memory *in_mem;
1483 GstD3D11Memory *out_mem;
1484 GstMapInfo out_map;
1485 D3D11_BOX src_box;
1486 ID3D11Texture2D *in_texture;
1487 guint in_subresource_index, out_subresource_index;
1488 ID3D11DeviceContext *device_context =
1489 gst_d3d11_device_get_device_context_handle (self->device);
1490
1491 in_mem = (GstD3D11Memory *) gst_buffer_peek_memory (decoder_buffer, 0);
1492 out_mem = (GstD3D11Memory *) gst_buffer_peek_memory (output, 0);
1493
1494 if (!gst_memory_map (GST_MEMORY_CAST (out_mem),
1495 &out_map, (GstMapFlags) (GST_MAP_WRITE | GST_MAP_D3D11))) {
1496 GST_ERROR_OBJECT (self, "Couldn't map output d3d11 memory");
1497 return FALSE;
1498 }
1499
1500 gst_d3d11_device_lock (self->device);
1501 in_texture = gst_d3d11_memory_get_texture_handle (in_mem);
1502 in_subresource_index = gst_d3d11_memory_get_subresource_index (in_mem);
1503
1504 src_box.left = 0;
1505 src_box.top = 0;
1506 src_box.front = 0;
1507 src_box.back = 1;
1508
1509 src_box.right = GST_ROUND_UP_2 (GST_VIDEO_INFO_WIDTH (info));
1510 src_box.bottom = GST_ROUND_UP_2 (GST_VIDEO_INFO_HEIGHT (info));
1511
1512 out_subresource_index = gst_d3d11_memory_get_subresource_index (out_mem);
1513 device_context->CopySubresourceRegion ((ID3D11Resource *) out_map.data,
1514 out_subresource_index, 0, 0, 0, in_texture, in_subresource_index,
1515 &src_box);
1516
1517 gst_d3d11_device_unlock (self->device);
1518 gst_memory_unmap (GST_MEMORY_CAST (out_mem), &out_map);
1519
1520 return TRUE;
1521 }
1522
1523 gboolean
gst_d3d11_decoder_process_output(GstD3D11Decoder * decoder,GstVideoDecoder * videodec,gint display_width,gint display_height,GstBuffer * decoder_buffer,GstBuffer ** output)1524 gst_d3d11_decoder_process_output (GstD3D11Decoder * decoder,
1525 GstVideoDecoder * videodec, gint display_width, gint display_height,
1526 GstBuffer * decoder_buffer, GstBuffer ** output)
1527 {
1528 gboolean can_device_copy = TRUE;
1529
1530 g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
1531 g_return_val_if_fail (GST_IS_VIDEO_DECODER (videodec), FALSE);
1532 g_return_val_if_fail (GST_IS_BUFFER (decoder_buffer), FALSE);
1533 g_return_val_if_fail (output != NULL, FALSE);
1534
1535 if (display_width != GST_VIDEO_INFO_WIDTH (&decoder->output_info) ||
1536 display_height != GST_VIDEO_INFO_HEIGHT (&decoder->output_info)) {
1537 GST_INFO_OBJECT (videodec, "Frame size changed, do renegotiate");
1538
1539 gst_video_info_set_format (&decoder->output_info,
1540 GST_VIDEO_INFO_FORMAT (&decoder->info), display_width, display_height);
1541 GST_VIDEO_INFO_INTERLACE_MODE (&decoder->output_info) =
1542 GST_VIDEO_INFO_INTERLACE_MODE (&decoder->info);
1543
1544 if (!gst_video_decoder_negotiate (videodec)) {
1545 GST_ERROR_OBJECT (videodec, "Failed to re-negotiate with new frame size");
1546 return FALSE;
1547 }
1548 }
1549
1550 if (gst_d3d11_decoder_can_direct_render (decoder, videodec, decoder_buffer,
1551 display_width, display_height)) {
1552 GstMemory *mem;
1553
1554 mem = gst_buffer_peek_memory (decoder_buffer, 0);
1555 GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
1556
1557 *output = gst_buffer_ref (decoder_buffer);
1558
1559 return TRUE;
1560 }
1561
1562 *output = gst_video_decoder_allocate_output_buffer (videodec);
1563 if (*output == NULL) {
1564 GST_ERROR_OBJECT (videodec, "Couldn't allocate output buffer");
1565
1566 return FALSE;
1567 }
1568
1569 /* decoder buffer must have single memory */
1570 if (gst_buffer_n_memory (decoder_buffer) == gst_buffer_n_memory (*output)) {
1571 GstMemory *mem;
1572 GstD3D11Memory *dmem;
1573
1574 mem = gst_buffer_peek_memory (*output, 0);
1575 if (!gst_is_d3d11_memory (mem)) {
1576 can_device_copy = FALSE;
1577 goto do_process;
1578 }
1579
1580 dmem = (GstD3D11Memory *) mem;
1581 if (dmem->device != decoder->device)
1582 can_device_copy = FALSE;
1583 } else {
1584 can_device_copy = FALSE;
1585 }
1586
1587 do_process:
1588 if (can_device_copy) {
1589 return copy_to_d3d11 (decoder, decoder_buffer, *output);
1590 }
1591
1592 return copy_to_system (decoder, decoder_buffer, *output);
1593 }
1594
1595 gboolean
gst_d3d11_decoder_negotiate(GstD3D11Decoder * decoder,GstVideoDecoder * videodec)1596 gst_d3d11_decoder_negotiate (GstD3D11Decoder * decoder,
1597 GstVideoDecoder * videodec)
1598 {
1599 GstVideoInfo *info;
1600 GstCaps *peer_caps;
1601 GstVideoCodecState *state = NULL;
1602 gboolean alternate_interlaced;
1603 gboolean alternate_supported = FALSE;
1604 gboolean d3d11_supported = FALSE;
1605 /* No d3d11 element supports alternate now */
1606 gboolean d3d11_alternate_supported = FALSE;
1607 GstVideoCodecState *input_state;
1608 GstStructure *s;
1609 const gchar *str;
1610
1611 g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
1612 g_return_val_if_fail (GST_IS_VIDEO_DECODER (videodec), FALSE);
1613
1614 info = &decoder->output_info;
1615 input_state = decoder->input_state;
1616
1617 alternate_interlaced =
1618 (GST_VIDEO_INFO_INTERLACE_MODE (info) ==
1619 GST_VIDEO_INTERLACE_MODE_ALTERNATE);
1620
1621 peer_caps = gst_pad_get_allowed_caps (GST_VIDEO_DECODER_SRC_PAD (videodec));
1622 GST_DEBUG_OBJECT (videodec, "Allowed caps %" GST_PTR_FORMAT, peer_caps);
1623
1624 if (!peer_caps || gst_caps_is_any (peer_caps)) {
1625 GST_DEBUG_OBJECT (videodec,
1626 "cannot determine output format, use system memory");
1627 } else {
1628 GstCapsFeatures *features;
1629 guint size = gst_caps_get_size (peer_caps);
1630 guint i;
1631
1632 for (i = 0; i < size; i++) {
1633 features = gst_caps_get_features (peer_caps, i);
1634
1635 if (!features)
1636 continue;
1637
1638 if (gst_caps_features_contains (features,
1639 GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY)) {
1640 d3d11_supported = TRUE;
1641
1642 if (gst_caps_features_contains (features,
1643 GST_CAPS_FEATURE_FORMAT_INTERLACED)) {
1644 d3d11_alternate_supported = TRUE;
1645 }
1646 }
1647
1648 if (gst_caps_features_contains (features,
1649 GST_CAPS_FEATURE_FORMAT_INTERLACED)) {
1650 alternate_supported = TRUE;
1651 }
1652 }
1653 }
1654 gst_clear_caps (&peer_caps);
1655
1656 GST_DEBUG_OBJECT (videodec,
1657 "Downstream feature support, D3D11 memory: %d, interlaced format %d",
1658 d3d11_supported, alternate_supported);
1659
1660 if (alternate_interlaced) {
1661 /* FIXME: D3D11 cannot support alternating interlaced stream yet */
1662 GST_FIXME_OBJECT (videodec,
1663 "Implement alternating interlaced stream for D3D11");
1664
1665 if (d3d11_alternate_supported || (!d3d11_supported && alternate_supported)) {
1666 gint height = GST_VIDEO_INFO_HEIGHT (info);
1667
1668 /* Set caps resolution with display size, that's how we designed
1669 * for alternating interlaced stream */
1670 height = 2 * height;
1671 state = gst_video_decoder_set_interlaced_output_state (videodec,
1672 GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_INTERLACE_MODE (info),
1673 GST_VIDEO_INFO_WIDTH (info), height, input_state);
1674 } else {
1675 GST_WARNING_OBJECT (videodec,
1676 "Downstream doesn't support alternating interlaced stream");
1677
1678 state = gst_video_decoder_set_output_state (videodec,
1679 GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info),
1680 GST_VIDEO_INFO_HEIGHT (info), input_state);
1681
1682 /* XXX: adjust PAR, this would produce output similar to that of
1683 * "line doubling" (so called bob deinterlacing) processing.
1684 * apart from missing anchor line (top-field or bottom-field) information.
1685 * Potentially flickering could happen. So this might not be correct.
1686 * But it would be better than negotiation error of half-height squeezed
1687 * image */
1688 state->info.par_d *= 2;
1689 state->info.fps_n *= 2;
1690 }
1691 } else {
1692 state = gst_video_decoder_set_interlaced_output_state (videodec,
1693 GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_INTERLACE_MODE (info),
1694 GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info), input_state);
1695 }
1696
1697 if (!state) {
1698 GST_ERROR_OBJECT (decoder, "Couldn't set output state");
1699 return FALSE;
1700 }
1701
1702 state->caps = gst_video_info_to_caps (&state->info);
1703
1704 s = gst_caps_get_structure (input_state->caps, 0);
1705 str = gst_structure_get_string (s, "mastering-display-info");
1706 if (str) {
1707 gst_caps_set_simple (state->caps,
1708 "mastering-display-info", G_TYPE_STRING, str, nullptr);
1709 }
1710
1711 str = gst_structure_get_string (s, "content-light-level");
1712 if (str) {
1713 gst_caps_set_simple (state->caps,
1714 "content-light-level", G_TYPE_STRING, str, nullptr);
1715 }
1716
1717 g_clear_pointer (&decoder->output_state, gst_video_codec_state_unref);
1718 decoder->output_state = state;
1719
1720 if (d3d11_supported) {
1721 gst_caps_set_features (state->caps, 0,
1722 gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, NULL));
1723 }
1724
1725 decoder->downstream_supports_d3d11 = d3d11_supported;
1726
1727 return gst_d3d11_decoder_open (decoder);
1728 }
1729
1730 gboolean
gst_d3d11_decoder_decide_allocation(GstD3D11Decoder * decoder,GstVideoDecoder * videodec,GstQuery * query)1731 gst_d3d11_decoder_decide_allocation (GstD3D11Decoder * decoder,
1732 GstVideoDecoder * videodec, GstQuery * query)
1733 {
1734 GstCaps *outcaps;
1735 GstBufferPool *pool = NULL;
1736 guint n, size, min = 0, max = 0;
1737 GstVideoInfo vinfo = { 0, };
1738 GstStructure *config;
1739 GstD3D11AllocationParams *d3d11_params;
1740 gboolean use_d3d11_pool;
1741
1742 g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
1743 g_return_val_if_fail (GST_IS_VIDEO_DECODER (videodec), FALSE);
1744 g_return_val_if_fail (query != NULL, FALSE);
1745
1746 if (!decoder->opened) {
1747 GST_ERROR_OBJECT (videodec, "Should open decoder first");
1748 return FALSE;
1749 }
1750
1751 gst_query_parse_allocation (query, &outcaps, NULL);
1752
1753 if (!outcaps) {
1754 GST_DEBUG_OBJECT (decoder, "No output caps");
1755 return FALSE;
1756 }
1757
1758 use_d3d11_pool = decoder->downstream_supports_d3d11;
1759
1760 gst_video_info_from_caps (&vinfo, outcaps);
1761 n = gst_query_get_n_allocation_pools (query);
1762 if (n > 0)
1763 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
1764
1765 /* create our own pool */
1766 if (pool && use_d3d11_pool) {
1767 if (!GST_IS_D3D11_BUFFER_POOL (pool)) {
1768 GST_DEBUG_OBJECT (videodec,
1769 "Downstream pool is not d3d11, will create new one");
1770 gst_clear_object (&pool);
1771 } else {
1772 GstD3D11BufferPool *dpool = GST_D3D11_BUFFER_POOL (pool);
1773 if (dpool->device != decoder->device) {
1774 GST_DEBUG_OBJECT (videodec, "Different device, will create new one");
1775 gst_clear_object (&pool);
1776 }
1777 }
1778 }
1779
1780 if (!pool) {
1781 if (use_d3d11_pool)
1782 pool = gst_d3d11_buffer_pool_new (decoder->device);
1783 else
1784 pool = gst_video_buffer_pool_new ();
1785
1786 size = (guint) vinfo.size;
1787 }
1788
1789 config = gst_buffer_pool_get_config (pool);
1790 gst_buffer_pool_config_set_params (config, outcaps, size, min, max);
1791 gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
1792
1793 if (use_d3d11_pool) {
1794 GstVideoAlignment align;
1795 gint width, height;
1796
1797 gst_video_alignment_reset (&align);
1798
1799 d3d11_params = gst_buffer_pool_config_get_d3d11_allocation_params (config);
1800 if (!d3d11_params)
1801 d3d11_params = gst_d3d11_allocation_params_new (decoder->device, &vinfo,
1802 (GstD3D11AllocationFlags) 0, 0);
1803
1804 width = GST_VIDEO_INFO_WIDTH (&vinfo);
1805 height = GST_VIDEO_INFO_HEIGHT (&vinfo);
1806
1807 /* need alignment to copy decoder output texture to downstream texture */
1808 align.padding_right = GST_ROUND_UP_16 (width) - width;
1809 align.padding_bottom = GST_ROUND_UP_16 (height) - height;
1810 if (!gst_d3d11_allocation_params_alignment (d3d11_params, &align)) {
1811 GST_ERROR_OBJECT (videodec, "Cannot set alignment");
1812 return FALSE;
1813 }
1814
1815 /* Needs render target bind flag so that it can be used for
1816 * output of shader pipeline if internal resizing is required.
1817 * Also, downstream can keep using video processor even if we copy
1818 * some decoded textures into downstream buffer */
1819 d3d11_params->desc[0].BindFlags |= D3D11_BIND_RENDER_TARGET;
1820
1821 gst_buffer_pool_config_set_d3d11_allocation_params (config, d3d11_params);
1822 gst_d3d11_allocation_params_free (d3d11_params);
1823
1824 /* Store min buffer size. We need to take account of the amount of buffers
1825 * which might be held by downstream in case of zero-copy playback */
1826 if (!decoder->internal_pool) {
1827 if (n > 0) {
1828 GST_DEBUG_OBJECT (videodec, "Downstream proposed pool");
1829 decoder->wait_on_pool_full = TRUE;
1830 /* XXX: hardcoded bound 16, to avoid too large pool size */
1831 decoder->downstream_min_buffers = MIN (min, 16);
1832 } else {
1833 GST_DEBUG_OBJECT (videodec, "Downstream didn't propose pool");
1834 decoder->wait_on_pool_full = FALSE;
1835 /* don't know how many buffers would be queued by downstream */
1836 decoder->downstream_min_buffers = 4;
1837 }
1838 } else {
1839 /* We configured our DPB pool already, let's check if our margin can
1840 * cover min size */
1841 decoder->wait_on_pool_full = FALSE;
1842
1843 if (n > 0) {
1844 if (decoder->downstream_min_buffers >= min)
1845 decoder->wait_on_pool_full = TRUE;
1846
1847 GST_DEBUG_OBJECT (videodec,
1848 "Pre-allocated margin %d can%s cover downstream min size %d",
1849 decoder->downstream_min_buffers,
1850 decoder->wait_on_pool_full ? "" : "not", min);
1851 } else {
1852 GST_DEBUG_OBJECT (videodec, "Downstream min size is unknown");
1853 }
1854 }
1855
1856 GST_DEBUG_OBJECT (videodec, "Downstream min buffres: %d", min);
1857
1858 /* We will not use downstream pool for decoding, and therefore preallocation
1859 * is unnecessary. So, Non-zero min buffer will be a waste of GPU memory */
1860 min = 0;
1861 }
1862
1863 gst_buffer_pool_set_config (pool, config);
1864 if (use_d3d11_pool) {
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,
1869 nullptr, &size, nullptr, nullptr);
1870 gst_structure_free (config);
1871 }
1872
1873 if (n > 0)
1874 gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
1875 else
1876 gst_query_add_allocation_pool (query, pool, size, min, max);
1877 gst_object_unref (pool);
1878
1879 return TRUE;
1880 }
1881
1882 gboolean
gst_d3d11_decoder_set_flushing(GstD3D11Decoder * decoder,GstVideoDecoder * videodec,gboolean flushing)1883 gst_d3d11_decoder_set_flushing (GstD3D11Decoder * decoder,
1884 GstVideoDecoder * videodec, gboolean flushing)
1885 {
1886 g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
1887
1888 g_mutex_lock (&decoder->internal_pool_lock);
1889 if (decoder->internal_pool)
1890 gst_buffer_pool_set_flushing (decoder->internal_pool, flushing);
1891 g_mutex_unlock (&decoder->internal_pool_lock);
1892
1893 return TRUE;
1894 }
1895
1896 static gboolean
gst_d3d11_decoder_can_direct_render(GstD3D11Decoder * decoder,GstVideoDecoder * videodec,GstBuffer * view_buffer,gint display_width,gint display_height)1897 gst_d3d11_decoder_can_direct_render (GstD3D11Decoder * decoder,
1898 GstVideoDecoder * videodec, GstBuffer * view_buffer,
1899 gint display_width, gint display_height)
1900 {
1901 GstMemory *mem;
1902 GstD3D11PoolAllocator *alloc;
1903 guint max_size = 0, outstanding_size = 0;
1904
1905 /* We don't support direct render for reverse playback */
1906 if (videodec->input_segment.rate < 0)
1907 return FALSE;
1908
1909 if (!decoder->can_direct_rendering || !decoder->downstream_supports_d3d11)
1910 return FALSE;
1911
1912 /* different size, need copy */
1913 /* TODO: crop meta */
1914 if (display_width != GST_VIDEO_INFO_WIDTH (&decoder->info) ||
1915 display_height != GST_VIDEO_INFO_HEIGHT (&decoder->info))
1916 return FALSE;
1917
1918 /* we can do direct render in this case, since there is no DPB pool size
1919 * limit */
1920 if (decoder->use_array_of_texture)
1921 return TRUE;
1922
1923 /* Let's believe downstream info */
1924 if (decoder->wait_on_pool_full)
1925 return TRUE;
1926
1927 /* Check if we are about to full */
1928 mem = gst_buffer_peek_memory (view_buffer, 0);
1929
1930 /* something went wrong */
1931 if (!gst_is_d3d11_memory (mem)) {
1932 GST_ERROR_OBJECT (decoder, "Not a D3D11 memory");
1933 return FALSE;
1934 }
1935
1936 alloc = GST_D3D11_POOL_ALLOCATOR (mem->allocator);
1937 if (!gst_d3d11_pool_allocator_get_pool_size (alloc, &max_size,
1938 &outstanding_size)) {
1939 GST_ERROR_OBJECT (decoder, "Couldn't query pool size");
1940 return FALSE;
1941 }
1942
1943 /* 2 buffer margin */
1944 if (max_size <= outstanding_size + 1) {
1945 GST_DEBUG_OBJECT (decoder, "memory pool is about to full (%u/%u)",
1946 outstanding_size, max_size);
1947 return FALSE;
1948 }
1949
1950 GST_LOG_OBJECT (decoder, "Can do direct rendering");
1951
1952 return TRUE;
1953 }
1954
1955 /* Keep sync with chromium and keep in sorted order.
1956 * See supported_profile_helpers.cc in chromium */
1957 static const guint legacy_amd_list[] = {
1958 0x130f, 0x6700, 0x6701, 0x6702, 0x6703, 0x6704, 0x6705, 0x6706, 0x6707,
1959 0x6708, 0x6709, 0x6718, 0x6719, 0x671c, 0x671d, 0x671f, 0x6720, 0x6721,
1960 0x6722, 0x6723, 0x6724, 0x6725, 0x6726, 0x6727, 0x6728, 0x6729, 0x6738,
1961 0x6739, 0x673e, 0x6740, 0x6741, 0x6742, 0x6743, 0x6744, 0x6745, 0x6746,
1962 0x6747, 0x6748, 0x6749, 0x674a, 0x6750, 0x6751, 0x6758, 0x6759, 0x675b,
1963 0x675d, 0x675f, 0x6760, 0x6761, 0x6762, 0x6763, 0x6764, 0x6765, 0x6766,
1964 0x6767, 0x6768, 0x6770, 0x6771, 0x6772, 0x6778, 0x6779, 0x677b, 0x6798,
1965 0x67b1, 0x6821, 0x683d, 0x6840, 0x6841, 0x6842, 0x6843, 0x6849, 0x6850,
1966 0x6858, 0x6859, 0x6880, 0x6888, 0x6889, 0x688a, 0x688c, 0x688d, 0x6898,
1967 0x6899, 0x689b, 0x689c, 0x689d, 0x689e, 0x68a0, 0x68a1, 0x68a8, 0x68a9,
1968 0x68b0, 0x68b8, 0x68b9, 0x68ba, 0x68be, 0x68bf, 0x68c0, 0x68c1, 0x68c7,
1969 0x68c8, 0x68c9, 0x68d8, 0x68d9, 0x68da, 0x68de, 0x68e0, 0x68e1, 0x68e4,
1970 0x68e5, 0x68e8, 0x68e9, 0x68f1, 0x68f2, 0x68f8, 0x68f9, 0x68fa, 0x68fe,
1971 0x9400, 0x9401, 0x9402, 0x9403, 0x9405, 0x940a, 0x940b, 0x940f, 0x9440,
1972 0x9441, 0x9442, 0x9443, 0x9444, 0x9446, 0x944a, 0x944b, 0x944c, 0x944e,
1973 0x9450, 0x9452, 0x9456, 0x945a, 0x945b, 0x945e, 0x9460, 0x9462, 0x946a,
1974 0x946b, 0x947a, 0x947b, 0x9480, 0x9487, 0x9488, 0x9489, 0x948a, 0x948f,
1975 0x9490, 0x9491, 0x9495, 0x9498, 0x949c, 0x949e, 0x949f, 0x94a0, 0x94a1,
1976 0x94a3, 0x94b1, 0x94b3, 0x94b4, 0x94b5, 0x94b9, 0x94c0, 0x94c1, 0x94c3,
1977 0x94c4, 0x94c5, 0x94c6, 0x94c7, 0x94c8, 0x94c9, 0x94cb, 0x94cc, 0x94cd,
1978 0x9500, 0x9501, 0x9504, 0x9505, 0x9506, 0x9507, 0x9508, 0x9509, 0x950f,
1979 0x9511, 0x9515, 0x9517, 0x9519, 0x9540, 0x9541, 0x9542, 0x954e, 0x954f,
1980 0x9552, 0x9553, 0x9555, 0x9557, 0x955f, 0x9580, 0x9581, 0x9583, 0x9586,
1981 0x9587, 0x9588, 0x9589, 0x958a, 0x958b, 0x958c, 0x958d, 0x958e, 0x958f,
1982 0x9590, 0x9591, 0x9593, 0x9595, 0x9596, 0x9597, 0x9598, 0x9599, 0x959b,
1983 0x95c0, 0x95c2, 0x95c4, 0x95c5, 0x95c6, 0x95c7, 0x95c9, 0x95cc, 0x95cd,
1984 0x95ce, 0x95cf, 0x9610, 0x9611, 0x9612, 0x9613, 0x9614, 0x9615, 0x9616,
1985 0x9640, 0x9641, 0x9642, 0x9643, 0x9644, 0x9645, 0x9647, 0x9648, 0x9649,
1986 0x964a, 0x964b, 0x964c, 0x964e, 0x964f, 0x9710, 0x9711, 0x9712, 0x9713,
1987 0x9714, 0x9715, 0x9802, 0x9803, 0x9804, 0x9805, 0x9806, 0x9807, 0x9808,
1988 0x9809, 0x980a, 0x9830, 0x983d, 0x9850, 0x9851, 0x9874, 0x9900, 0x9901,
1989 0x9903, 0x9904, 0x9905, 0x9906, 0x9907, 0x9908, 0x9909, 0x990a, 0x990b,
1990 0x990c, 0x990d, 0x990e, 0x990f, 0x9910, 0x9913, 0x9917, 0x9918, 0x9919,
1991 0x9990, 0x9991, 0x9992, 0x9993, 0x9994, 0x9995, 0x9996, 0x9997, 0x9998,
1992 0x9999, 0x999a, 0x999b, 0x999c, 0x999d, 0x99a0, 0x99a2, 0x99a4
1993 };
1994
1995 static const guint legacy_intel_list[] = {
1996 0x102, 0x106, 0x116, 0x126, 0x152, 0x156, 0x166,
1997 0x402, 0x406, 0x416, 0x41e, 0xa06, 0xa16, 0xf31,
1998 };
1999
2000 static gint
binary_search_compare(const guint * a,const guint * b)2001 binary_search_compare (const guint * a, const guint * b)
2002 {
2003 return *a - *b;
2004 }
2005
2006 /* Certain AMD GPU drivers like R600, R700, Evergreen and Cayman and some second
2007 * generation Intel GPU drivers crash if we create a video device with a
2008 * resolution higher then 1920 x 1088. This function checks if the GPU is in
2009 * this list and if yes returns true. */
2010 gboolean
gst_d3d11_decoder_util_is_legacy_device(GstD3D11Device * device)2011 gst_d3d11_decoder_util_is_legacy_device (GstD3D11Device * device)
2012 {
2013 const guint amd_id[] = { 0x1002, 0x1022 };
2014 const guint intel_id = 0x8086;
2015 guint device_id = 0;
2016 guint vendor_id = 0;
2017 guint *match = NULL;
2018
2019 g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), FALSE);
2020
2021 g_object_get (device, "device-id", &device_id, "vendor-id", &vendor_id, NULL);
2022
2023 if (vendor_id == amd_id[0] || vendor_id == amd_id[1]) {
2024 match =
2025 (guint *) gst_util_array_binary_search ((gpointer) legacy_amd_list,
2026 G_N_ELEMENTS (legacy_amd_list), sizeof (guint),
2027 (GCompareDataFunc) binary_search_compare,
2028 GST_SEARCH_MODE_EXACT, &device_id, NULL);
2029 } else if (vendor_id == intel_id) {
2030 match =
2031 (guint *) gst_util_array_binary_search ((gpointer) legacy_intel_list,
2032 G_N_ELEMENTS (legacy_intel_list), sizeof (guint),
2033 (GCompareDataFunc) binary_search_compare,
2034 GST_SEARCH_MODE_EXACT, &device_id, NULL);
2035 }
2036
2037 if (match) {
2038 GST_DEBUG_OBJECT (device, "it's legacy device");
2039 return TRUE;
2040 }
2041
2042 return FALSE;
2043 }
2044
2045 gboolean
gst_d3d11_decoder_supports_format(GstD3D11Device * device,const GUID * decoder_profile,DXGI_FORMAT format)2046 gst_d3d11_decoder_supports_format (GstD3D11Device * device,
2047 const GUID * decoder_profile, DXGI_FORMAT format)
2048 {
2049 HRESULT hr;
2050 BOOL can_support = FALSE;
2051 ID3D11VideoDevice *video_device;
2052
2053 g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), FALSE);
2054 g_return_val_if_fail (decoder_profile != NULL, FALSE);
2055 g_return_val_if_fail (format != DXGI_FORMAT_UNKNOWN, FALSE);
2056
2057 video_device = gst_d3d11_device_get_video_device_handle (device);
2058 if (!video_device)
2059 return FALSE;
2060
2061 hr = video_device->CheckVideoDecoderFormat (decoder_profile, format,
2062 &can_support);
2063 if (!gst_d3d11_result (hr, device) || !can_support) {
2064 GST_DEBUG_OBJECT (device,
2065 "VideoDevice could not support dxgi format %d, hr: 0x%x",
2066 format, (guint) hr);
2067
2068 return FALSE;
2069 }
2070
2071 return TRUE;
2072 }
2073
2074 /* Don't call this method with legacy device */
2075 gboolean
gst_d3d11_decoder_supports_resolution(GstD3D11Device * device,const GUID * decoder_profile,DXGI_FORMAT format,guint width,guint height)2076 gst_d3d11_decoder_supports_resolution (GstD3D11Device * device,
2077 const GUID * decoder_profile, DXGI_FORMAT format, guint width, guint height)
2078 {
2079 D3D11_VIDEO_DECODER_DESC desc;
2080 HRESULT hr;
2081 UINT config_count;
2082 ID3D11VideoDevice *video_device;
2083
2084 g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), FALSE);
2085 g_return_val_if_fail (decoder_profile != NULL, FALSE);
2086 g_return_val_if_fail (format != DXGI_FORMAT_UNKNOWN, FALSE);
2087
2088 video_device = gst_d3d11_device_get_video_device_handle (device);
2089 if (!video_device)
2090 return FALSE;
2091
2092 desc.SampleWidth = width;
2093 desc.SampleHeight = height;
2094 desc.OutputFormat = format;
2095 desc.Guid = *decoder_profile;
2096
2097 hr = video_device->GetVideoDecoderConfigCount (&desc, &config_count);
2098 if (!gst_d3d11_result (hr, device) || config_count == 0) {
2099 GST_DEBUG_OBJECT (device, "Could not get decoder config count, hr: 0x%x",
2100 (guint) hr);
2101 return FALSE;
2102 }
2103
2104 return TRUE;
2105 }
2106
2107 enum
2108 {
2109 PROP_DECODER_ADAPTER_LUID = 1,
2110 PROP_DECODER_DEVICE_ID,
2111 PROP_DECODER_VENDOR_ID,
2112 };
2113
2114 struct _GstD3D11DecoderClassData
2115 {
2116 GstD3D11DecoderSubClassData subclass_data;
2117 GstCaps *sink_caps;
2118 GstCaps *src_caps;
2119 gchar *description;
2120 };
2121
2122 /**
2123 * gst_d3d11_decoder_class_data_new:
2124 * @device: (transfer none): a #GstD3D11Device
2125 * @sink_caps: (transfer full): a #GstCaps
2126 * @src_caps: (transfer full): a #GstCaps
2127 *
2128 * Create new #GstD3D11DecoderClassData
2129 *
2130 * Returns: (transfer full): the new #GstD3D11DecoderClassData
2131 */
2132 GstD3D11DecoderClassData *
gst_d3d11_decoder_class_data_new(GstD3D11Device * device,GstDXVACodec codec,GstCaps * sink_caps,GstCaps * src_caps)2133 gst_d3d11_decoder_class_data_new (GstD3D11Device * device, GstDXVACodec codec,
2134 GstCaps * sink_caps, GstCaps * src_caps)
2135 {
2136 GstD3D11DecoderClassData *ret;
2137
2138 g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
2139 g_return_val_if_fail (sink_caps != NULL, NULL);
2140 g_return_val_if_fail (src_caps != NULL, NULL);
2141
2142 ret = g_new0 (GstD3D11DecoderClassData, 1);
2143
2144 /* class data will be leaked if the element never gets instantiated */
2145 GST_MINI_OBJECT_FLAG_SET (sink_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
2146 GST_MINI_OBJECT_FLAG_SET (src_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
2147
2148 ret->subclass_data.codec = codec;
2149 g_object_get (device, "adapter-luid", &ret->subclass_data.adapter_luid,
2150 "device-id", &ret->subclass_data.device_id,
2151 "vendor-id", &ret->subclass_data.vendor_id,
2152 "description", &ret->description, nullptr);
2153 ret->sink_caps = sink_caps;
2154 ret->src_caps = src_caps;
2155
2156 return ret;
2157 }
2158
2159 void
gst_d3d11_decoder_class_data_fill_subclass_data(GstD3D11DecoderClassData * data,GstD3D11DecoderSubClassData * subclass_data)2160 gst_d3d11_decoder_class_data_fill_subclass_data (GstD3D11DecoderClassData *
2161 data, GstD3D11DecoderSubClassData * subclass_data)
2162 {
2163 g_return_if_fail (data != nullptr);
2164 g_return_if_fail (subclass_data != nullptr);
2165
2166 *subclass_data = data->subclass_data;
2167 }
2168
2169 static void
gst_d3d11_decoder_class_data_free(GstD3D11DecoderClassData * data)2170 gst_d3d11_decoder_class_data_free (GstD3D11DecoderClassData * data)
2171 {
2172 if (!data)
2173 return;
2174
2175 gst_clear_caps (&data->sink_caps);
2176 gst_clear_caps (&data->src_caps);
2177 g_free (data->description);
2178 g_free (data);
2179 }
2180
2181 void
gst_d3d11_decoder_proxy_class_init(GstElementClass * klass,GstD3D11DecoderClassData * data,const gchar * author)2182 gst_d3d11_decoder_proxy_class_init (GstElementClass * klass,
2183 GstD3D11DecoderClassData * data, const gchar * author)
2184 {
2185 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
2186 GstD3D11DecoderSubClassData *cdata = &data->subclass_data;
2187 std::string long_name;
2188 std::string description;
2189 const gchar *codec_name;
2190
2191 g_object_class_install_property (gobject_class, PROP_DECODER_ADAPTER_LUID,
2192 g_param_spec_int64 ("adapter-luid", "Adapter LUID",
2193 "DXGI Adapter LUID (Locally Unique Identifier) of created device",
2194 G_MININT64, G_MAXINT64, cdata->adapter_luid,
2195 (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
2196
2197 g_object_class_install_property (gobject_class, PROP_DECODER_DEVICE_ID,
2198 g_param_spec_uint ("device-id", "Device Id",
2199 "DXGI Device ID", 0, G_MAXUINT32, 0,
2200 (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
2201
2202 g_object_class_install_property (gobject_class, PROP_DECODER_VENDOR_ID,
2203 g_param_spec_uint ("vendor-id", "Vendor Id",
2204 "DXGI Vendor ID", 0, G_MAXUINT32, 0,
2205 (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
2206
2207 codec_name = gst_dxva_codec_to_string (cdata->codec);
2208 long_name = "Direct3D11/DXVA " + std::string (codec_name) + " " +
2209 std::string (data->description) + " Decoder";
2210 description = "Direct3D11/DXVA based " + std::string (codec_name) +
2211 " video decoder";
2212
2213 gst_element_class_set_metadata (klass, long_name.c_str (),
2214 "Codec/Decoder/Video/Hardware", description.c_str (), author);
2215
2216 gst_element_class_add_pad_template (klass,
2217 gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
2218 data->sink_caps));
2219 gst_element_class_add_pad_template (klass,
2220 gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
2221 data->src_caps));
2222
2223 gst_d3d11_decoder_class_data_free (data);
2224 }
2225
2226 void
gst_d3d11_decoder_proxy_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec,GstD3D11DecoderSubClassData * subclass_data)2227 gst_d3d11_decoder_proxy_get_property (GObject * object, guint prop_id,
2228 GValue * value, GParamSpec * pspec,
2229 GstD3D11DecoderSubClassData * subclass_data)
2230 {
2231 switch (prop_id) {
2232 case PROP_DECODER_ADAPTER_LUID:
2233 g_value_set_int64 (value, subclass_data->adapter_luid);
2234 break;
2235 case PROP_DECODER_DEVICE_ID:
2236 g_value_set_uint (value, subclass_data->device_id);
2237 break;
2238 case PROP_DECODER_VENDOR_ID:
2239 g_value_set_uint (value, subclass_data->vendor_id);
2240 break;
2241 default:
2242 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2243 break;
2244 }
2245 }
2246
2247 gboolean
gst_d3d11_decoder_proxy_open(GstVideoDecoder * videodec,GstD3D11DecoderSubClassData * subclass_data,GstD3D11Device ** device,GstD3D11Decoder ** decoder)2248 gst_d3d11_decoder_proxy_open (GstVideoDecoder * videodec,
2249 GstD3D11DecoderSubClassData * subclass_data, GstD3D11Device ** device,
2250 GstD3D11Decoder ** decoder)
2251 {
2252 GstElement *elem = GST_ELEMENT (videodec);
2253
2254 if (!gst_d3d11_ensure_element_data_for_adapter_luid (elem,
2255 subclass_data->adapter_luid, device)) {
2256 GST_ERROR_OBJECT (elem, "Cannot create d3d11device");
2257 return FALSE;
2258 }
2259
2260 *decoder = gst_d3d11_decoder_new (*device, subclass_data->codec);
2261
2262 if (*decoder == nullptr) {
2263 GST_ERROR_OBJECT (elem, "Cannot create d3d11 decoder");
2264 gst_clear_object (device);
2265 return FALSE;
2266 }
2267
2268 return TRUE;
2269 }
2270