• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) 2020 Igalia, S.L.
3  *     Author: Víctor Jáquez <vjaquez@igalia.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 /**
22  * SECTION:gstvadisplay
23  * @title: GstVaDisplay
24  * @short_description: Generic VADisplay wrapper.
25  * @sources:
26  * - gstvadisplay.h
27  *
28  * It is a generic wrapper for VADisplay. To create new instances
29  * subclasses are required, depending on the display type to use
30  * (v.gr. DRM, X11, Wayland, etc.).
31  *
32  * The purpose of this class is to be shared among pipelines via
33  * #GstContext so all the VA processing elements will use the same
34  * display entry. Application developers can create their own
35  * subclass, based on their display, and shared it via the synced bus
36  * message for the application.
37  */
38 
39 #ifdef HAVE_CONFIG_H
40 #include "config.h"
41 #endif
42 
43 #include "gstvadisplay.h"
44 #include <va/va.h>
45 
46 GST_DEBUG_CATEGORY (gst_va_display_debug);
47 #define GST_CAT_DEFAULT gst_va_display_debug
48 
49 typedef struct _GstVaDisplayPrivate GstVaDisplayPrivate;
50 struct _GstVaDisplayPrivate
51 {
52   GRecMutex lock;
53   VADisplay display;
54 
55   gboolean foreign;
56   gboolean init;
57   GstVaImplementation impl;
58 };
59 
60 #define gst_va_display_parent_class parent_class
61 G_DEFINE_TYPE_WITH_CODE (GstVaDisplay, gst_va_display, GST_TYPE_OBJECT,
62     G_ADD_PRIVATE (GstVaDisplay);
63     GST_DEBUG_CATEGORY_INIT (gst_va_display_debug, "vadisplay", 0,
64         "VA Display"));
65 enum
66 {
67   PROP_VA_DISPLAY = 1,
68   N_PROPERTIES
69 };
70 
71 static GParamSpec *g_properties[N_PROPERTIES];
72 
73 #define GET_PRIV(obj) gst_va_display_get_instance_private (GST_VA_DISPLAY (obj))
74 
75 static GstVaImplementation
_get_implementation(const char * vendor)76 _get_implementation (const char *vendor)
77 {
78   if (g_str_has_prefix (vendor, "Mesa Gallium driver"))
79     return GST_VA_IMPLEMENTATION_MESA_GALLIUM;
80   else if (g_str_has_prefix (vendor, "Intel i965 driver"))
81     return GST_VA_IMPLEMENTATION_INTEL_I965;
82   else if (g_str_has_prefix (vendor, "Intel iHD driver"))
83     return GST_VA_IMPLEMENTATION_INTEL_IHD;
84 
85   return GST_VA_IMPLEMENTATION_OTHER;
86 }
87 
88 static gboolean
_gst_va_display_filter_driver(GstVaDisplay * self,gpointer foreign_display)89 _gst_va_display_filter_driver (GstVaDisplay * self, gpointer foreign_display)
90 {
91   GstVaDisplayPrivate *priv = GET_PRIV (self);
92   VADisplay dpy;
93   const char *vendor;
94 
95   g_assert ((foreign_display != NULL) ^ (priv->display != NULL));
96   dpy = foreign_display ? foreign_display : priv->display;
97 
98   vendor = vaQueryVendorString (dpy);
99   GST_INFO ("VA-API driver vendor: %s", vendor);
100 
101   /* XXX(victor): driver allow list */
102 
103   if (foreign_display) {
104     priv->display = foreign_display;
105     priv->foreign = TRUE;
106   }
107   priv->impl = _get_implementation (vendor);
108 
109   return TRUE;
110 }
111 
112 static void
gst_va_display_set_display(GstVaDisplay * self,gpointer display)113 gst_va_display_set_display (GstVaDisplay * self, gpointer display)
114 {
115   GstVaDisplayPrivate *priv = GET_PRIV (self);
116 
117   if (!display)
118     return;
119 
120   if (vaDisplayIsValid (display) == 0) {
121     GST_WARNING_OBJECT (self,
122         "User's VA display is invalid. An internal one will be tried.");
123     return;
124   }
125 
126   /* assume driver is already initialized */
127   priv->init = TRUE;
128 
129   _gst_va_display_filter_driver (self, display);
130 }
131 
132 static void
gst_va_display_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)133 gst_va_display_set_property (GObject * object, guint prop_id,
134     const GValue * value, GParamSpec * pspec)
135 {
136   GstVaDisplay *self = GST_VA_DISPLAY (object);
137 
138   switch (prop_id) {
139     case PROP_VA_DISPLAY:{
140       gpointer display = g_value_get_pointer (value);
141       gst_va_display_set_display (self, display);
142       break;
143     }
144     default:
145       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
146       break;
147   }
148 }
149 
150 static void
gst_va_display_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)151 gst_va_display_get_property (GObject * object, guint prop_id, GValue * value,
152     GParamSpec * pspec)
153 {
154   GstVaDisplayPrivate *priv = GET_PRIV (object);
155 
156   switch (prop_id) {
157     case PROP_VA_DISPLAY:
158       g_value_set_pointer (value, priv->display);
159       break;
160     default:
161       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
162       break;
163   }
164 }
165 
166 static void
gst_va_display_constructed(GObject * object)167 gst_va_display_constructed (GObject * object)
168 {
169   GstVaDisplay *self = GST_VA_DISPLAY (object);
170   GstVaDisplayPrivate *priv = GET_PRIV (object);
171   GstVaDisplayClass *klass = GST_VA_DISPLAY_GET_CLASS (object);
172 
173   if (!priv->display && klass->create_va_display)
174     priv->display = klass->create_va_display (self);
175 
176   G_OBJECT_CLASS (parent_class)->constructed (object);
177 }
178 
179 static void
gst_va_display_dispose(GObject * object)180 gst_va_display_dispose (GObject * object)
181 {
182   GstVaDisplayPrivate *priv = GET_PRIV (object);
183 
184   if (priv->display && !priv->foreign)
185     vaTerminate (priv->display);
186   priv->display = NULL;
187 
188   G_OBJECT_CLASS (parent_class)->dispose (object);
189 }
190 
191 static void
gst_va_display_finalize(GObject * object)192 gst_va_display_finalize (GObject * object)
193 {
194   GstVaDisplayPrivate *priv = GET_PRIV (object);
195 
196   g_rec_mutex_clear (&priv->lock);
197 
198   G_OBJECT_CLASS (parent_class)->finalize (object);
199 }
200 
201 static void
gst_va_display_class_init(GstVaDisplayClass * klass)202 gst_va_display_class_init (GstVaDisplayClass * klass)
203 {
204   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
205 
206   gobject_class->set_property = gst_va_display_set_property;
207   gobject_class->get_property = gst_va_display_get_property;
208   gobject_class->constructed = gst_va_display_constructed;
209   gobject_class->dispose = gst_va_display_dispose;
210   gobject_class->finalize = gst_va_display_finalize;
211 
212   g_properties[PROP_VA_DISPLAY] =
213       g_param_spec_pointer ("va-display", "VADisplay", "VA Display handler",
214       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
215 
216   g_object_class_install_properties (gobject_class, N_PROPERTIES, g_properties);
217 }
218 
219 static void
gst_va_display_init(GstVaDisplay * self)220 gst_va_display_init (GstVaDisplay * self)
221 {
222   GstVaDisplayPrivate *priv = GET_PRIV (self);
223 
224   g_rec_mutex_init (&priv->lock);
225   priv->impl = GST_VA_IMPLEMENTATION_INVALID;
226 }
227 
228 /**
229  * gst_va_display_lock:
230  * @self: a #GstVaDisplay
231  *
232  * Lock the display. It will be used before we call the
233  * VA API functions to serialize the VA commands.
234  *
235  * Since: 1.20
236  **/
237 void
gst_va_display_lock(GstVaDisplay * self)238 gst_va_display_lock (GstVaDisplay * self)
239 {
240   GstVaDisplayPrivate *priv;
241 
242   g_return_if_fail (GST_IS_VA_DISPLAY (self));
243 
244   priv = GET_PRIV (self);
245 
246   g_rec_mutex_lock (&priv->lock);
247 }
248 
249 /**
250  * gst_va_display_unlock:
251  * @self: a #GstVaDisplay
252  *
253  * Unlock the display. It will be used after we call the
254  * VA API functions.
255  *
256  * Since: 1.20
257  **/
258 void
gst_va_display_unlock(GstVaDisplay * self)259 gst_va_display_unlock (GstVaDisplay * self)
260 {
261   GstVaDisplayPrivate *priv;
262 
263   g_return_if_fail (GST_IS_VA_DISPLAY (self));
264 
265   priv = GET_PRIV (self);
266 
267   g_rec_mutex_unlock (&priv->lock);
268 }
269 
270 #ifndef GST_DISABLE_GST_DEBUG
271 static gchar *
_strip_msg(const char * message)272 _strip_msg (const char *message)
273 {
274   gchar *msg = g_strdup (message);
275   if (!msg)
276     return NULL;
277   return g_strstrip (msg);
278 }
279 
280 static void
_va_warning(gpointer object,const char * message)281 _va_warning (gpointer object, const char *message)
282 {
283   GstVaDisplay *self = GST_VA_DISPLAY (object);
284   gchar *msg;
285 
286   if ((msg = _strip_msg (message))) {
287     GST_WARNING_OBJECT (self, "VA error: %s", msg);
288     g_free (msg);
289   }
290 }
291 
292 static void
_va_info(gpointer object,const char * message)293 _va_info (gpointer object, const char *message)
294 {
295   GstVaDisplay *self = GST_VA_DISPLAY (object);
296   gchar *msg;
297 
298   if ((msg = _strip_msg (message))) {
299     GST_INFO_OBJECT (self, "VA info: %s", msg);
300     g_free (msg);
301   }
302 }
303 #endif
304 
305 /**
306  * gst_va_display_initialize:
307  * @self: a #GstVaDisplay
308  *
309  * If the display is set by the user (foreign) it is assumed that the
310  * driver is already initialized, thus this function is noop.
311  *
312  * If the display is opened internally, this function will initialize
313  * the driver and it will set driver's message callbacks.
314  *
315  * NOTE: this function is supposed to be private, only used by
316  * GstVaDisplay descendants.
317  *
318  * Returns: %TRUE if the VA driver can be initialized; %FALSE
319  *     otherwise
320  *
321  * Since: 1.20
322  **/
323 gboolean
gst_va_display_initialize(GstVaDisplay * self)324 gst_va_display_initialize (GstVaDisplay * self)
325 {
326   GstVaDisplayPrivate *priv;
327   VAStatus status;
328   int major_version = -1, minor_version = -1;
329 
330   g_return_val_if_fail (GST_IS_VA_DISPLAY (self), FALSE);
331 
332   priv = GET_PRIV (self);
333 
334   if (priv->init)
335     return TRUE;
336 
337   if (!priv->display)
338     return FALSE;
339 
340 #ifndef GST_DISABLE_GST_DEBUG
341   vaSetErrorCallback (priv->display, _va_warning, self);
342   vaSetInfoCallback (priv->display, _va_info, self);
343 #endif
344 
345   status = vaInitialize (priv->display, &major_version, &minor_version);
346   if (status != VA_STATUS_SUCCESS) {
347     GST_WARNING_OBJECT (self, "vaInitialize: %s", vaErrorStr (status));
348     return FALSE;
349   }
350 
351   GST_INFO_OBJECT (self, "VA-API version %d.%d", major_version, minor_version);
352 
353   priv->init = TRUE;
354 
355   if (!_gst_va_display_filter_driver (self, NULL))
356     return FALSE;
357 
358   return TRUE;
359 }
360 
361 /**
362  * gst_va_display_get_va_dpy:
363  * @self: a #GstVaDisplay type display.
364  *
365  * Get the VA display handle of the @self.
366  *
367  * Returns: the VA display handle.
368  *
369  * Since: 1.20
370  */
371 gpointer
gst_va_display_get_va_dpy(GstVaDisplay * self)372 gst_va_display_get_va_dpy (GstVaDisplay * self)
373 {
374   VADisplay dpy;
375 
376   g_return_val_if_fail (GST_IS_VA_DISPLAY (self), NULL);
377 
378   g_object_get (self, "va-display", &dpy, NULL);
379   return dpy;
380 }
381 
382 /**
383  * gst_va_display_get_implementation:
384  * @self: a #GstVaDisplay type display.
385  *
386  * Get the the #GstVaImplementation type of @self.
387  *
388  * Returns: #GstVaImplementation.
389  *
390  * Since: 1.20
391  */
392 GstVaImplementation
gst_va_display_get_implementation(GstVaDisplay * self)393 gst_va_display_get_implementation (GstVaDisplay * self)
394 {
395   GstVaDisplayPrivate *priv;
396 
397   g_return_val_if_fail (GST_IS_VA_DISPLAY (self),
398       GST_VA_IMPLEMENTATION_INVALID);
399 
400   priv = GET_PRIV (self);
401   return priv->impl;
402 }
403