2 * gstvaapidisplay_drm.c - VA/DRM display abstraction
4 * Copyright (C) 2012 Intel Corporation
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either version 2.1
9 * of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free
18 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
23 * SECTION:gstvaapidisplay_drm
24 * @short_description: VA/DRM display abstraction
33 #include <va/va_drm.h>
34 #include "gstvaapiutils.h"
35 #include "gstvaapidisplay_priv.h"
36 #include "gstvaapidisplay_drm.h"
37 #include "gstvaapidisplay_drm_priv.h"
40 #include "gstvaapidebug.h"
42 G_DEFINE_TYPE(GstVaapiDisplayDRM,
43 gst_vaapi_display_drm,
44 GST_VAAPI_TYPE_DISPLAY);
53 #define NAME_PREFIX "DRM:"
54 #define NAME_PREFIX_LENGTH 4
56 static inline gboolean
57 is_device_path(const gchar *device_path)
59 return strncmp(device_path, NAME_PREFIX, NAME_PREFIX_LENGTH) == 0;
63 compare_device_path(gconstpointer a, gconstpointer b, gpointer user_data)
65 const gchar *cached_name = a;
66 const gchar *tested_name = b;
68 if (!cached_name || !is_device_path(cached_name))
70 g_return_val_if_fail(tested_name && is_device_path(tested_name), FALSE);
72 cached_name += NAME_PREFIX_LENGTH;
73 tested_name += NAME_PREFIX_LENGTH;
74 return strcmp(cached_name, tested_name) == 0;
78 gst_vaapi_display_drm_finalize(GObject *object)
80 G_OBJECT_CLASS(gst_vaapi_display_drm_parent_class)->finalize(object);
83 /* Get default device path. Actually, the first match in the DRM subsystem */
85 get_default_device_path(gpointer ptr)
87 GstVaapiDisplayDRM * const display = GST_VAAPI_DISPLAY_DRM(ptr);
88 GstVaapiDisplayDRMPrivate * const priv = display->priv;
89 const gchar *syspath, *devpath;
90 struct udev *udev = NULL;
91 struct udev_device *device, *parent;
92 struct udev_enumerate *e = NULL;
93 struct udev_list_entry *l;
96 if (!priv->device_path_default) {
101 e = udev_enumerate_new(udev);
105 udev_enumerate_add_match_subsystem(e, "drm");
106 udev_enumerate_scan_devices(e);
107 udev_list_entry_foreach(l, udev_enumerate_get_list_entry(e)) {
108 syspath = udev_list_entry_get_name(l);
109 device = udev_device_new_from_syspath(udev, syspath);
110 parent = udev_device_get_parent(device);
111 if (strcmp(udev_device_get_subsystem(parent), "pci") != 0) {
112 udev_device_unref(device);
116 devpath = udev_device_get_devnode(device);
117 fd = open(devpath, O_RDWR|O_CLOEXEC);
119 udev_device_unref(device);
123 priv->device_path_default = g_strdup(devpath);
125 udev_device_unref(device);
131 udev_enumerate_unref(e);
135 return priv->device_path_default;
138 /* Reconstruct a device path without our prefix */
140 get_device_path(gpointer ptr)
142 GstVaapiDisplayDRM * const display = GST_VAAPI_DISPLAY_DRM(ptr);
143 const gchar *device_path = display->priv->device_path;
148 g_return_val_if_fail(is_device_path(device_path), NULL);
150 device_path += NAME_PREFIX_LENGTH;
151 if (*device_path == '\0')
156 /* Mangle device path with our prefix */
158 set_device_path(GstVaapiDisplayDRM *display, const gchar *device_path)
160 GstVaapiDisplayDRMPrivate * const priv = display->priv;
162 g_free(priv->device_path);
163 priv->device_path = NULL;
166 device_path = get_default_device_path(display);
170 priv->device_path = g_strdup_printf("%s%s", NAME_PREFIX, device_path);
173 /* Set device path from file descriptor */
175 set_device_path_from_fd(GstVaapiDisplayDRM *display, gint drm_device)
177 GstVaapiDisplayDRMPrivate * const priv = display->priv;
178 const gchar *busid, *path, *str;
179 gsize busid_length, path_length;
180 struct udev *udev = NULL;
181 struct udev_device *device;
182 struct udev_enumerate *e = NULL;
183 struct udev_list_entry *l;
185 g_free(priv->device_path);
186 priv->device_path = NULL;
191 busid = drmGetBusid(drm_device);
194 if (strncmp(busid, "pci:", 4) != 0)
197 busid_length = strlen(busid);
203 e = udev_enumerate_new(udev);
207 udev_enumerate_add_match_subsystem(e, "drm");
208 udev_enumerate_scan_devices(e);
209 udev_list_entry_foreach(l, udev_enumerate_get_list_entry(e)) {
210 path = udev_list_entry_get_name(l);
211 str = strstr(path, busid);
212 if (!str || str <= path || str[-1] != '/')
215 path_length = strlen(path);
216 if (str + busid_length >= path + path_length)
218 if (strncmp(&str[busid_length], "/drm/card", 9) != 0)
221 device = udev_device_new_from_syspath(udev, path);
225 path = udev_device_get_devnode(device);
226 priv->device_path = g_strdup_printf("%s%s", NAME_PREFIX, path);
227 udev_device_unref(device);
233 udev_enumerate_unref(e);
239 gst_vaapi_display_drm_set_property(
246 GstVaapiDisplayDRM * const display = GST_VAAPI_DISPLAY_DRM(object);
249 case PROP_DEVICE_PATH:
250 set_device_path(display, g_value_get_string(value));
252 case PROP_DRM_DEVICE:
253 display->priv->drm_device = g_value_get_int(value);
256 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
262 gst_vaapi_display_drm_get_property(
269 GstVaapiDisplayDRM * const display = GST_VAAPI_DISPLAY_DRM(object);
272 case PROP_DEVICE_PATH:
273 g_value_set_string(value, get_device_path(display));
275 case PROP_DRM_DEVICE:
276 g_value_set_int(value, display->priv->drm_device);
279 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
285 gst_vaapi_display_drm_constructed(GObject *object)
287 GstVaapiDisplayDRM * const display = GST_VAAPI_DISPLAY_DRM(object);
288 GstVaapiDisplayDRMPrivate * const priv = display->priv;
289 GstVaapiDisplayCache * const cache = gst_vaapi_display_get_cache();
290 const GstVaapiDisplayInfo *info;
291 GObjectClass *parent_class;
293 priv->create_display = priv->drm_device < 0;
295 /* Don't create DRM display if there is one in the cache already */
296 if (priv->create_display) {
297 info = gst_vaapi_display_cache_lookup_by_name(
300 compare_device_path, NULL
303 priv->drm_device = GPOINTER_TO_INT(info->native_display);
304 priv->create_display = FALSE;
308 /* Reset device-path if the user provided his own DRM display */
309 if (!priv->create_display)
310 set_device_path_from_fd(display, priv->drm_device);
312 parent_class = G_OBJECT_CLASS(gst_vaapi_display_drm_parent_class);
313 if (parent_class->constructed)
314 parent_class->constructed(object);
318 gst_vaapi_display_drm_open_display(GstVaapiDisplay *display)
320 GstVaapiDisplayDRMPrivate * const priv =
321 GST_VAAPI_DISPLAY_DRM(display)->priv;
323 if (priv->create_display) {
324 const gchar *device_path = get_device_path(display);
327 priv->drm_device = open(device_path, O_RDWR|O_CLOEXEC);
328 if (priv->drm_device < 0)
331 if (priv->drm_device < 0)
337 gst_vaapi_display_drm_close_display(GstVaapiDisplay *display)
339 GstVaapiDisplayDRMPrivate * const priv =
340 GST_VAAPI_DISPLAY_DRM(display)->priv;
342 if (priv->drm_device >= 0) {
343 if (priv->create_display)
344 close(priv->drm_device);
345 priv->drm_device = -1;
348 if (priv->device_path) {
349 g_free(priv->device_path);
350 priv->device_path = NULL;
353 if (priv->device_path_default) {
354 g_free(priv->device_path_default);
355 priv->device_path_default = NULL;
360 gst_vaapi_display_drm_get_display_info(
361 GstVaapiDisplay *display,
362 GstVaapiDisplayInfo *info
365 GstVaapiDisplayDRMPrivate * const priv =
366 GST_VAAPI_DISPLAY_DRM(display)->priv;
367 GstVaapiDisplayCache *cache;
368 const GstVaapiDisplayInfo *cached_info;
370 /* Return any cached info even if child has its own VA display */
371 cache = gst_vaapi_display_get_cache();
374 cached_info = gst_vaapi_display_cache_lookup_by_native_display(
375 cache, GINT_TO_POINTER(priv->drm_device));
377 *info = *cached_info;
381 /* Otherwise, create VA display if there is none already */
382 info->native_display = GINT_TO_POINTER(priv->drm_device);
383 info->display_name = priv->device_path;
384 if (!info->va_display) {
385 info->va_display = vaGetDisplayDRM(priv->drm_device);
386 if (!info->va_display)
388 info->display_type = GST_VAAPI_DISPLAY_TYPE_DRM;
394 gst_vaapi_display_drm_class_init(GstVaapiDisplayDRMClass *klass)
396 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
397 GstVaapiDisplayClass * const dpy_class = GST_VAAPI_DISPLAY_CLASS(klass);
399 g_type_class_add_private(klass, sizeof(GstVaapiDisplayDRMPrivate));
401 object_class->finalize = gst_vaapi_display_drm_finalize;
402 object_class->set_property = gst_vaapi_display_drm_set_property;
403 object_class->get_property = gst_vaapi_display_drm_get_property;
404 object_class->constructed = gst_vaapi_display_drm_constructed;
406 dpy_class->open_display = gst_vaapi_display_drm_open_display;
407 dpy_class->close_display = gst_vaapi_display_drm_close_display;
408 dpy_class->get_display = gst_vaapi_display_drm_get_display_info;
411 * GstVaapiDisplayDRM:drm-device:
413 * The DRM device (file descriptor).
415 g_object_class_install_property
418 g_param_spec_int("drm-device",
422 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
425 * GstVaapiDisplayDRM:device-path:
427 * The DRM device path.
429 g_object_class_install_property
432 g_param_spec_string("device-path",
436 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
440 gst_vaapi_display_drm_init(GstVaapiDisplayDRM *display)
442 GstVaapiDisplayDRMPrivate * const priv =
443 GST_VAAPI_DISPLAY_DRM_GET_PRIVATE(display);
445 display->priv = priv;
446 priv->device_path_default = NULL;
447 priv->device_path = NULL;
448 priv->drm_device = -1;
449 priv->create_display = TRUE;
453 * gst_vaapi_display_drm_new:
454 * @device_path: the DRM device path
456 * Opens an DRM file descriptor using @device_path and returns a newly
457 * allocated #GstVaapiDisplay object. The DRM display will be cloed
458 * when the reference count of the object reaches zero.
460 * If @device_path is NULL, the DRM device path will be automatically
461 * determined as the first positive match in the list of available DRM
464 * Return value: a newly allocated #GstVaapiDisplay object
467 gst_vaapi_display_drm_new(const gchar *device_path)
469 return g_object_new(GST_VAAPI_TYPE_DISPLAY_DRM,
470 "device-path", device_path,
475 * gst_vaapi_display_drm_new_with_device:
476 * @device: an open DRM device (file descriptor)
478 * Creates a #GstVaapiDisplay based on the open DRM @device. The
479 * caller still owns the device file descriptor and must call close()
480 * when all #GstVaapiDisplay references are released. Doing so too
481 * early can yield undefined behaviour.
483 * Return value: a newly allocated #GstVaapiDisplay object
486 gst_vaapi_display_drm_new_with_device(gint device)
488 g_return_val_if_fail(device >= 0, NULL);
490 return g_object_new(GST_VAAPI_TYPE_DISPLAY_DRM,
491 "drm-device", device,
496 * gst_vaapi_display_drm_get_device:
497 * @display: a #GstVaapiDisplayDRM
499 * Returns the underlying DRM device file descriptor that was created
500 * by gst_vaapi_display_drm_new() or that was bound from
501 * gst_vaapi_display_drm_new_with_device().
503 * Return value: the DRM file descriptor attached to @display
506 gst_vaapi_display_drm_get_device(GstVaapiDisplayDRM *display)
508 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY_DRM(display), -1);
510 return display->priv->drm_device;
514 * gst_vaapi_display_drm_get_device_path:
515 * @display: a #GstVaapiDisplayDRM
517 * Returns the underlying DRM device path name was created by
518 * gst_vaapi_display_drm_new() or that was bound from
519 * gst_vaapi_display_drm_new_with_device().
521 * Note: the #GstVaapiDisplayDRM object owns the resulting string, so
522 * it shall not be deallocated.
524 * Return value: the DRM device path name attached to @display
527 gst_vaapi_display_drm_get_device_path(GstVaapiDisplayDRM *display)
529 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY_DRM(display), NULL);
531 return display->priv->device_path;