1 /* GStreamer
2 * Copyright (C) <2019> Seungha Yang <seungha.yang@navercorp.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include "gstd3d11basefilter.h"
25
26 GST_DEBUG_CATEGORY_STATIC (gst_d3d11_base_filter_debug);
27 #define GST_CAT_DEFAULT gst_d3d11_base_filter_debug
28
29 enum
30 {
31 PROP_0,
32 PROP_ADAPTER,
33 };
34
35 #define DEFAULT_ADAPTER -1
36
37 #define gst_d3d11_base_filter_parent_class parent_class
38 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstD3D11BaseFilter, gst_d3d11_base_filter,
39 GST_TYPE_BASE_TRANSFORM, GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT,
40 "d3d11basefilter", 0, "d3d11 basefilter"));
41
42 static void gst_d3d11_base_filter_set_property (GObject * object, guint prop_id,
43 const GValue * value, GParamSpec * pspec);
44 static void gst_d3d11_base_filter_get_property (GObject * object, guint prop_id,
45 GValue * value, GParamSpec * pspec);
46 static void gst_d3d11_base_filter_dispose (GObject * object);
47 static void gst_d3d11_base_filter_set_context (GstElement * element,
48 GstContext * context);
49 static gboolean gst_d3d11_base_filter_start (GstBaseTransform * trans);
50 static gboolean gst_d3d11_base_filter_stop (GstBaseTransform * trans);
51 static gboolean gst_d3d11_base_filter_set_caps (GstBaseTransform * trans,
52 GstCaps * incaps, GstCaps * outcaps);
53 static gboolean gst_d3d11_base_filter_get_unit_size (GstBaseTransform * trans,
54 GstCaps * caps, gsize * size);
55 static gboolean
56 gst_d3d11_base_filter_query (GstBaseTransform * trans,
57 GstPadDirection direction, GstQuery * query);
58 static void gst_d3d11_base_filter_before_transform (GstBaseTransform * trans,
59 GstBuffer * buffer);
60
61 static void
gst_d3d11_base_filter_class_init(GstD3D11BaseFilterClass * klass)62 gst_d3d11_base_filter_class_init (GstD3D11BaseFilterClass * klass)
63 {
64 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
65 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
66 GstBaseTransformClass *trans_class = GST_BASE_TRANSFORM_CLASS (klass);
67
68 gobject_class->set_property = gst_d3d11_base_filter_set_property;
69 gobject_class->get_property = gst_d3d11_base_filter_get_property;
70 gobject_class->dispose = gst_d3d11_base_filter_dispose;
71
72 /**
73 * GstD3D11BaseFilter:adapter:
74 *
75 * Adapter index for creating device (-1 for default)
76 *
77 * Since: 1.18
78 */
79 g_object_class_install_property (gobject_class, PROP_ADAPTER,
80 g_param_spec_int ("adapter", "Adapter",
81 "Adapter index for creating device (-1 for default)",
82 -1, G_MAXINT32, DEFAULT_ADAPTER,
83 (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY |
84 G_PARAM_STATIC_STRINGS)));
85
86 element_class->set_context =
87 GST_DEBUG_FUNCPTR (gst_d3d11_base_filter_set_context);
88
89 trans_class->passthrough_on_same_caps = TRUE;
90
91 trans_class->start = GST_DEBUG_FUNCPTR (gst_d3d11_base_filter_start);
92 trans_class->stop = GST_DEBUG_FUNCPTR (gst_d3d11_base_filter_stop);
93 trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_d3d11_base_filter_set_caps);
94 trans_class->get_unit_size =
95 GST_DEBUG_FUNCPTR (gst_d3d11_base_filter_get_unit_size);
96 trans_class->query = GST_DEBUG_FUNCPTR (gst_d3d11_base_filter_query);
97 trans_class->before_transform =
98 GST_DEBUG_FUNCPTR (gst_d3d11_base_filter_before_transform);
99
100 gst_type_mark_as_plugin_api (GST_TYPE_D3D11_BASE_FILTER,
101 (GstPluginAPIFlags) 0);
102 }
103
104 static void
gst_d3d11_base_filter_init(GstD3D11BaseFilter * filter)105 gst_d3d11_base_filter_init (GstD3D11BaseFilter * filter)
106 {
107 filter->adapter = DEFAULT_ADAPTER;
108 }
109
110 static void
gst_d3d11_base_filter_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)111 gst_d3d11_base_filter_set_property (GObject * object, guint prop_id,
112 const GValue * value, GParamSpec * pspec)
113 {
114 GstD3D11BaseFilter *filter = GST_D3D11_BASE_FILTER (object);
115
116 switch (prop_id) {
117 case PROP_ADAPTER:
118 filter->adapter = g_value_get_int (value);
119 break;
120 default:
121 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
122 break;
123 }
124 }
125
126 static void
gst_d3d11_base_filter_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)127 gst_d3d11_base_filter_get_property (GObject * object, guint prop_id,
128 GValue * value, GParamSpec * pspec)
129 {
130 GstD3D11BaseFilter *filter = GST_D3D11_BASE_FILTER (object);
131
132 switch (prop_id) {
133 case PROP_ADAPTER:
134 g_value_set_int (value, filter->adapter);
135 break;
136 default:
137 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
138 break;
139 }
140 }
141
142 static void
gst_d3d11_base_filter_dispose(GObject * object)143 gst_d3d11_base_filter_dispose (GObject * object)
144 {
145 GstD3D11BaseFilter *filter = GST_D3D11_BASE_FILTER (object);
146
147 gst_clear_object (&filter->device);
148
149 G_OBJECT_CLASS (parent_class)->dispose (object);
150 }
151
152 static void
gst_d3d11_base_filter_set_context(GstElement * element,GstContext * context)153 gst_d3d11_base_filter_set_context (GstElement * element, GstContext * context)
154 {
155 GstD3D11BaseFilter *filter = GST_D3D11_BASE_FILTER (element);
156
157 gst_d3d11_handle_set_context (element,
158 context, filter->adapter, &filter->device);
159
160 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
161 }
162
163 static gboolean
gst_d3d11_base_filter_start(GstBaseTransform * trans)164 gst_d3d11_base_filter_start (GstBaseTransform * trans)
165 {
166 GstD3D11BaseFilter *filter = GST_D3D11_BASE_FILTER (trans);
167
168 if (!gst_d3d11_ensure_element_data (GST_ELEMENT_CAST (filter),
169 filter->adapter, &filter->device)) {
170 GST_ERROR_OBJECT (filter, "Failed to get D3D11 device");
171 return FALSE;
172 }
173
174 return TRUE;
175 }
176
177 static gboolean
gst_d3d11_base_filter_stop(GstBaseTransform * trans)178 gst_d3d11_base_filter_stop (GstBaseTransform * trans)
179 {
180 GstD3D11BaseFilter *filter = GST_D3D11_BASE_FILTER (trans);
181
182 gst_clear_object (&filter->device);
183
184 return TRUE;
185 }
186
187 static gboolean
gst_d3d11_base_filter_set_caps(GstBaseTransform * trans,GstCaps * incaps,GstCaps * outcaps)188 gst_d3d11_base_filter_set_caps (GstBaseTransform * trans, GstCaps * incaps,
189 GstCaps * outcaps)
190 {
191 GstD3D11BaseFilter *filter = GST_D3D11_BASE_FILTER (trans);
192 GstVideoInfo in_info, out_info;
193 GstD3D11BaseFilterClass *klass;
194 gboolean res;
195
196 if (!filter->device) {
197 GST_ERROR_OBJECT (filter, "No available D3D11 device");
198 return FALSE;
199 }
200
201 /* input caps */
202 if (!gst_video_info_from_caps (&in_info, incaps))
203 goto invalid_caps;
204
205 /* output caps */
206 if (!gst_video_info_from_caps (&out_info, outcaps))
207 goto invalid_caps;
208
209 klass = GST_D3D11_BASE_FILTER_GET_CLASS (filter);
210 if (klass->set_info)
211 res = klass->set_info (filter, incaps, &in_info, outcaps, &out_info);
212 else
213 res = TRUE;
214
215 if (res) {
216 filter->in_info = in_info;
217 filter->out_info = out_info;
218 }
219
220 return res;
221
222 /* ERRORS */
223 invalid_caps:
224 {
225 GST_ERROR_OBJECT (filter, "invalid caps");
226 return FALSE;
227 }
228 }
229
230 static gboolean
gst_d3d11_base_filter_get_unit_size(GstBaseTransform * trans,GstCaps * caps,gsize * size)231 gst_d3d11_base_filter_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
232 gsize * size)
233 {
234 gboolean ret = FALSE;
235 GstVideoInfo info;
236
237 ret = gst_video_info_from_caps (&info, caps);
238 if (ret)
239 *size = GST_VIDEO_INFO_SIZE (&info);
240
241 return TRUE;
242 }
243
244 static gboolean
gst_d3d11_base_filter_query(GstBaseTransform * trans,GstPadDirection direction,GstQuery * query)245 gst_d3d11_base_filter_query (GstBaseTransform * trans,
246 GstPadDirection direction, GstQuery * query)
247 {
248 GstD3D11BaseFilter *filter = GST_D3D11_BASE_FILTER (trans);
249
250 switch (GST_QUERY_TYPE (query)) {
251 case GST_QUERY_CONTEXT:
252 {
253 gboolean ret;
254 ret = gst_d3d11_handle_context_query (GST_ELEMENT (filter), query,
255 filter->device);
256 if (ret)
257 return TRUE;
258 break;
259 }
260 default:
261 break;
262 }
263
264 return GST_BASE_TRANSFORM_CLASS (parent_class)->query (trans, direction,
265 query);
266 }
267
268 static void
gst_d3d11_base_filter_before_transform(GstBaseTransform * trans,GstBuffer * buffer)269 gst_d3d11_base_filter_before_transform (GstBaseTransform * trans,
270 GstBuffer * buffer)
271 {
272 GstD3D11BaseFilter *self = GST_D3D11_BASE_FILTER (trans);
273 GstD3D11Memory *dmem;
274 GstMemory *mem;
275 gboolean update_device = FALSE;
276 GstCaps *in_caps = NULL;
277 GstCaps *out_caps = NULL;
278
279 mem = gst_buffer_peek_memory (buffer, 0);
280 /* Can happens (e.g., d3d11upload) */
281 if (!gst_is_d3d11_memory (mem))
282 return;
283
284 dmem = GST_D3D11_MEMORY_CAST (mem);
285 /* Same device, nothing to do */
286 if (dmem->device == self->device)
287 return;
288
289 /* Can accept any device, update */
290 if (self->adapter < 0) {
291 update_device = TRUE;
292 } else {
293 guint adapter = 0;
294
295 g_object_get (dmem->device, "adapter", &adapter, NULL);
296 /* The same GPU as what user wanted, update */
297 if (adapter == (guint) self->adapter)
298 update_device = TRUE;
299 }
300
301 if (!update_device)
302 return;
303
304 GST_INFO_OBJECT (self, "Updating device %" GST_PTR_FORMAT " -> %"
305 GST_PTR_FORMAT, self->device, dmem->device);
306
307 gst_object_unref (self->device);
308 self->device = (GstD3D11Device *) gst_object_ref (dmem->device);
309
310 in_caps = gst_pad_get_current_caps (GST_BASE_TRANSFORM_SINK_PAD (trans));
311 if (!in_caps) {
312 GST_WARNING_OBJECT (self, "sinkpad has null caps");
313 goto out;
314 }
315
316 out_caps = gst_pad_get_current_caps (GST_BASE_TRANSFORM_SRC_PAD (trans));
317 if (!out_caps) {
318 GST_WARNING_OBJECT (self, "Has no configured output caps");
319 goto out;
320 }
321
322 /* subclass will update internal object.
323 * Note that gst_base_transform_reconfigure() might not trigger this
324 * unless caps was changed meanwhile */
325 gst_d3d11_base_filter_set_caps (trans, in_caps, out_caps);
326
327 /* Mark reconfigure so that we can update pool */
328 gst_base_transform_reconfigure_src (trans);
329
330 out:
331 gst_clear_caps (&in_caps);
332 gst_clear_caps (&out_caps);
333
334 return;
335 }
336