• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) <2019> Seungha Yang <seungha.yang@navercorp.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #  include <config.h>
22 #endif
23 
24 #include "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