From 657f0a4a6f76e121043d022c0f8be1cfdb4834d9 Mon Sep 17 00:00:00 2001 From: Gwenole Beauchesne Date: Wed, 1 Aug 2012 15:44:02 +0200 Subject: [PATCH] Add initial support for VA/DRM. --- NEWS | 1 + configure.ac | 38 +- debian.upstream/Makefile.am | 3 + debian.upstream/control.in | 9 + debian.upstream/libgstvaapi-drm.install.in | 1 + gst-libs/gst/vaapi/Makefile.am | 55 ++ gst-libs/gst/vaapi/gstvaapidisplay.c | 4 + gst-libs/gst/vaapi/gstvaapidisplay.h | 2 + gst-libs/gst/vaapi/gstvaapidisplay_drm.c | 532 ++++++++++++++++++ gst-libs/gst/vaapi/gstvaapidisplay_drm.h | 97 ++++ gst-libs/gst/vaapi/gstvaapidisplay_drm_priv.h | 55 ++ gst-libs/gst/vaapi/gstvaapiwindow_drm.c | 161 ++++++ gst-libs/gst/vaapi/gstvaapiwindow_drm.h | 85 +++ pkgconfig/Makefile.am | 4 + pkgconfig/gstreamer-vaapi-drm.pc.in | 12 + 15 files changed, 1058 insertions(+), 1 deletion(-) create mode 100644 debian.upstream/libgstvaapi-drm.install.in create mode 100644 gst-libs/gst/vaapi/gstvaapidisplay_drm.c create mode 100644 gst-libs/gst/vaapi/gstvaapidisplay_drm.h create mode 100644 gst-libs/gst/vaapi/gstvaapidisplay_drm_priv.h create mode 100644 gst-libs/gst/vaapi/gstvaapiwindow_drm.c create mode 100644 gst-libs/gst/vaapi/gstvaapiwindow_drm.h create mode 100644 pkgconfig/gstreamer-vaapi-drm.pc.in diff --git a/NEWS b/NEWS index 39e6572862..2ad1dbe6c0 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ Copyright (C) 2011 Collabora Version 0.4.0 - DD.Aug.2012 * Add support for Wayland +* Add support for headless pipelines (VA/DRM API) * Drop FFmpeg-based decoders Version 0.3.7 - 26.Jun.2012 diff --git a/configure.ac b/configure.ac index 0f696ddf52..8138ccc312 100644 --- a/configure.ac +++ b/configure.ac @@ -43,11 +43,13 @@ m4_define([gst_plugins_bad_version], # VA-API minimum version number m4_define([va_api_version], [0.30.4]) +m4_define([va_api_drm_version], [0.34.0]) m4_define([va_api_x11_version], [0.31.0]) m4_define([va_api_glx_version], [0.32.0]) m4_define([va_api_wld_version], [0.34.0]) # libva package version number +m4_define([libva_drm_package_version], [1.2.0]) m4_define([libva_x11_package_version], [1.0.3]) m4_define([libva_glx_package_version], [1.0.9]) m4_define([libva_wld_package_version], [1.2.0]) @@ -102,6 +104,11 @@ AC_PROG_CC AM_PROG_CC_C_O AC_PROG_LIBTOOL +AC_ARG_ENABLE(drm, + AS_HELP_STRING([--enable-drm], + [enable DRM backend @<:@default=yes@:>@]), + [], [enable_drm="yes"]) + AC_ARG_ENABLE(x11, AS_HELP_STRING([--enable-x11], [enable X11 output @<:@default=yes@:>@]), @@ -276,6 +283,20 @@ dnl --------------------------------------------------------------------------- dnl -- Renderers -- dnl --------------------------------------------------------------------------- +dnl Check for DRM/libudev +USE_DRM=0 +if test "$enable_drm" = "yes"; then + PKG_CHECK_MODULES(DRM, [libdrm], [USE_DRM=1], [USE_DRM=0]) + PKG_CHECK_MODULES(UDEV, [libudev], [:], [USE_DRM=0]) + + if test $USE_DRM -eq 1; then + saved_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $DRM_CFLAGS" + AC_CHECK_HEADERS([drm_fourcc.h], [:], [USE_DRM=0]) + CPPFLAGS="$saved_CPPFLAGS" + fi +fi + dnl Check for X11 USE_X11=0 if test "$enable_x11" = "yes"; then @@ -355,6 +376,12 @@ VA_MINOR_VERSION=`echo "$VA_VERSION" | cut -d'.' -f2` VA_MICRO_VERSION=`echo "$VA_VERSION" | cut -d'.' -f3` VA_VERSION_STR="$VA_VERSION" +dnl VA/DRM API +if test "$enable_drm" = "yes"; then + PKG_CHECK_MODULES([LIBVA_DRM], [libva-drm >= va_api_drm_version], + [:], [USE_DRM=0]) +fi + dnl VA/X11 API HAVE_VA_X11=0 LIBVA_X11_PKGNAME="libva-x11" @@ -412,7 +439,7 @@ dnl --------------------------------------------------------------------------- dnl -- Generate files and summary -- dnl --------------------------------------------------------------------------- -case ":$USE_X11:$USE_GLX:$USE_WAYLAND:" in +case ":$USE_X11:$USE_GLX:$USE_WAYLAND:$USE_DRM:" in *:1:*) ;; *) @@ -424,6 +451,10 @@ AC_DEFINE_UNQUOTED(USE_JPEG_DECODER, $USE_JPEG_DECODER, [Defined to 1 if JPEG decoder is used]) AM_CONDITIONAL(USE_JPEG_DECODER, test $USE_JPEG_DECODER -eq 1) +AC_DEFINE_UNQUOTED(USE_DRM, $USE_DRM, + [Defined to 1 if DRM is enabled]) +AM_CONDITIONAL(USE_DRM, test $USE_DRM -eq 1) + AC_DEFINE_UNQUOTED(USE_X11, $USE_X11, [Defined to 1 if X11 is enabled]) AM_CONDITIONAL(USE_X11, test $USE_X11 -eq 1) @@ -451,6 +482,8 @@ debian.upstream/gstreamer-vaapi.install.in debian.upstream/libgstvaapi$GST_VAAPI_MAJOR_VERSION.install:\ debian.upstream/libgstvaapi.install.in debian.upstream/libgstvaapi-dev.install + debian.upstream/libgstvaapi-drm-$GST_VAAPI_MAJOR_VERSION.install:\ +debian.upstream/libgstvaapi-drm.install.in debian.upstream/libgstvaapi-glx-$GST_VAAPI_MAJOR_VERSION.install:\ debian.upstream/libgstvaapi-glx.install.in debian.upstream/libgstvaapi-wayland-$GST_VAAPI_MAJOR_VERSION.install:\ @@ -472,6 +505,8 @@ debian.upstream/libgstvaapi-x11.install.in pkgconfig/Makefile pkgconfig/gstreamer-vaapi-$GST_MAJORMINOR.pc:\ pkgconfig/gstreamer-vaapi.pc.in + pkgconfig/gstreamer-vaapi-drm-$GST_MAJORMINOR.pc:\ +pkgconfig/gstreamer-vaapi-drm.pc.in pkgconfig/gstreamer-vaapi-glx-$GST_MAJORMINOR.pc:\ pkgconfig/gstreamer-vaapi-glx.pc.in pkgconfig/gstreamer-vaapi-wayland-$GST_MAJORMINOR.pc:\ @@ -488,6 +523,7 @@ yesno() { } VIDEO_OUTPUTS="" +AS_IF([test $USE_DRM -eq 1], [VIDEO_OUTPUTS="$VIDEO_OUTPUTS drm"]) AS_IF([test $USE_X11 -eq 1], [VIDEO_OUTPUTS="$VIDEO_OUTPUTS x11"]) AS_IF([test $USE_GLX -eq 1], [VIDEO_OUTPUTS="$VIDEO_OUTPUTS glx"]) AS_IF([test $USE_WAYLAND -eq 1], [VIDEO_OUTPUTS="$VIDEO_OUTPUTS wayland"]) diff --git a/debian.upstream/Makefile.am b/debian.upstream/Makefile.am index cf3bc3ef67..cacc5192b2 100644 --- a/debian.upstream/Makefile.am +++ b/debian.upstream/Makefile.am @@ -21,6 +21,8 @@ DEBIANFILES = \ libgstvaapi$(GST_VAAPI_MAJOR_VERSION).install \ libgstvaapi-dev.install.in \ libgstvaapi-dev.install \ + libgstvaapi-drm.install.in \ + libgstvaapi-drm-$(GST_VAAPI_MAJOR_VERSION).install \ libgstvaapi-x11.install.in \ libgstvaapi-x11-$(GST_VAAPI_MAJOR_VERSION).install \ libgstvaapi-glx.install.in \ @@ -37,6 +39,7 @@ DEBIANGENFILES = \ gstreamer$(GST_MAJORMINOR)-vaapi-doc.install \ libgstvaapi$(GST_VAAPI_MAJOR_VERSION).install \ libgstvaapi-dev.install \ + libgstvaapi-drm-$(GST_VAAPI_MAJOR_VERSION).install \ libgstvaapi-x11-$(GST_VAAPI_MAJOR_VERSION).install \ libgstvaapi-glx-$(GST_VAAPI_MAJOR_VERSION).install \ libgstvaapi-wayland-$(GST_VAAPI_MAJOR_VERSION).install \ diff --git a/debian.upstream/control.in b/debian.upstream/control.in index bd812abeed..960f72ebb7 100644 --- a/debian.upstream/control.in +++ b/debian.upstream/control.in @@ -49,6 +49,15 @@ Description: GStreamer libraries from the "vaapi" set . This package contains common libraries for the "vaapi" set. +Package: libgstvaapi-drm-@GST_VAAPI_MAJOR_VERSION@ +Section: libs +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: GStreamer libraries from the "vaapi" set + VA-API support libraries for GStreamer. + . + This package contains headless libraries for the "vaapi" set. + Package: libgstvaapi-x11-@GST_VAAPI_MAJOR_VERSION@ Section: libs Architecture: any diff --git a/debian.upstream/libgstvaapi-drm.install.in b/debian.upstream/libgstvaapi-drm.install.in new file mode 100644 index 0000000000..de8b898c1b --- /dev/null +++ b/debian.upstream/libgstvaapi-drm.install.in @@ -0,0 +1 @@ +debian/tmp/usr/lib/libgstvaapi-drm-@GST_MAJORMINOR@.so.* diff --git a/gst-libs/gst/vaapi/Makefile.am b/gst-libs/gst/vaapi/Makefile.am index b9fc07debe..5719222f25 100644 --- a/gst-libs/gst/vaapi/Makefile.am +++ b/gst-libs/gst/vaapi/Makefile.am @@ -1,5 +1,9 @@ lib_LTLIBRARIES = libgstvaapi-@GST_MAJORMINOR@.la +if USE_DRM +lib_LTLIBRARIES += libgstvaapi-drm-@GST_MAJORMINOR@.la +endif + if USE_X11 lib_LTLIBRARIES += libgstvaapi-x11-@GST_MAJORMINOR@.la endif @@ -115,6 +119,23 @@ libgstvaapi_source_c += gstvaapidecoder_jpeg.c libgstvaapi_source_h += gstvaapidecoder_jpeg.h endif +libgstvaapi_drm_source_c = \ + gstvaapidisplay_drm.c \ + gstvaapiwindow_drm.c \ + gstvaapiutils.c \ + $(NULL) + +libgstvaapi_drm_source_h = \ + gstvaapidisplay_drm.h \ + gstvaapiwindow_drm.h \ + $(NULL) + +libgstvaapi_drm_source_priv_h = \ + gstvaapicompat.h \ + gstvaapidisplay_drm_priv.h \ + gstvaapiutils.h \ + $(NULL) + libgstvaapi_x11_source_c = \ gstvaapidisplay_x11.c \ gstvaapiutils.c \ @@ -207,6 +228,40 @@ libgstvaapi_@GST_MAJORMINOR@_la_LDFLAGS = \ $(GST_ALL_LDFLAGS) \ $(NULL) +libgstvaapi_drm_@GST_MAJORMINOR@_la_SOURCES = \ + $(libgstvaapi_drm_source_c) \ + $(libgstvaapi_drm_source_priv_h) \ + $(NULL) + +libgstvaapi_drm_@GST_MAJORMINOR@include_HEADERS = \ + $(libgstvaapi_drm_source_h) \ + $(NULL) + +libgstvaapi_drm_@GST_MAJORMINOR@includedir = \ + $(libgstvaapi_includedir) + +libgstvaapi_drm_@GST_MAJORMINOR@_la_CFLAGS = \ + -DGST_USE_UNSTABLE_API \ + -I$(top_srcdir)/gst-libs \ + $(GLIB_CFLAGS) \ + $(GST_BASE_CFLAGS) \ + $(UDEV_CFLAGS) \ + $(DRM_CFLAGS) \ + $(LIBVA_DRM_CFLAGS) \ + $(NULL) + +libgstvaapi_drm_@GST_MAJORMINOR@_la_LIBADD = \ + $(GLIB_LIBS) \ + $(UDEV_LIBS) \ + $(DRM_LIBS) \ + $(LIBVA_DRM_LIBS) \ + libgstvaapi-@GST_MAJORMINOR@.la \ + $(NULL) + +libgstvaapi_drm_@GST_MAJORMINOR@_la_LDFLAGS = \ + $(GST_ALL_LDFLAGS) \ + $(NULL) + libgstvaapi_x11_@GST_MAJORMINOR@_la_SOURCES = \ $(libgstvaapi_x11_source_c) \ $(libgstvaapi_x11_source_priv_h) \ diff --git a/gst-libs/gst/vaapi/gstvaapidisplay.c b/gst-libs/gst/vaapi/gstvaapidisplay.c index 7238518fc2..6f9c75f428 100644 --- a/gst-libs/gst/vaapi/gstvaapidisplay.c +++ b/gst-libs/gst/vaapi/gstvaapidisplay.c @@ -101,6 +101,10 @@ gst_vaapi_display_type_get_type(void) #if USE_WAYLAND { GST_VAAPI_DISPLAY_TYPE_WAYLAND, "VA/Wayland display", "wayland" }, +#endif +#if USE_DRM + { GST_VAAPI_DISPLAY_TYPE_DRM, + "VA/DRM display", "drm" }, #endif { 0, NULL, NULL }, }; diff --git a/gst-libs/gst/vaapi/gstvaapidisplay.h b/gst-libs/gst/vaapi/gstvaapidisplay.h index d8fa9a38e4..2b826665b0 100644 --- a/gst-libs/gst/vaapi/gstvaapidisplay.h +++ b/gst-libs/gst/vaapi/gstvaapidisplay.h @@ -66,12 +66,14 @@ typedef struct _GstVaapiDisplayClass GstVaapiDisplayClass; * @GST_VAAPI_DISPLAY_TYPE_X11: VA/X11 display. * @GST_VAAPI_DISPLAY_TYPE_GLX: VA/GLX display. * @GST_VAAPI_DISPLAY_TYPE_WAYLAND: VA/Wayland display. + * @GST_VAAPI_DISPLAY_TYPE_DRM: VA/DRM display. */ enum _GstVaapiDisplayType { GST_VAAPI_DISPLAY_TYPE_ANY = 0, GST_VAAPI_DISPLAY_TYPE_X11, GST_VAAPI_DISPLAY_TYPE_GLX, GST_VAAPI_DISPLAY_TYPE_WAYLAND, + GST_VAAPI_DISPLAY_TYPE_DRM, }; #define GST_VAAPI_TYPE_DISPLAY_TYPE \ diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_drm.c b/gst-libs/gst/vaapi/gstvaapidisplay_drm.c new file mode 100644 index 0000000000..6a1d148272 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_drm.c @@ -0,0 +1,532 @@ +/* + * gstvaapidisplay_drm.c - VA/DRM display abstraction + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapidisplay_drm + * @short_description: VA/DRM display abstraction + */ + +#include "sysdeps.h" +#include +#include +#include +#include +#include +#include +#include "gstvaapiutils.h" +#include "gstvaapidisplay_priv.h" +#include "gstvaapidisplay_drm.h" +#include "gstvaapidisplay_drm_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiDisplayDRM, + gst_vaapi_display_drm, + GST_VAAPI_TYPE_DISPLAY); + +enum { + PROP_0, + + PROP_DEVICE_PATH, + PROP_DRM_DEVICE +}; + +#define NAME_PREFIX "DRM:" +#define NAME_PREFIX_LENGTH 4 + +static inline gboolean +is_device_path(const gchar *device_path) +{ + return strncmp(device_path, NAME_PREFIX, NAME_PREFIX_LENGTH) == 0; +} + +static gboolean +compare_device_path(gconstpointer a, gconstpointer b, gpointer user_data) +{ + const gchar *cached_name = a; + const gchar *tested_name = b; + + if (!cached_name || !is_device_path(cached_name)) + return FALSE; + g_return_val_if_fail(tested_name && is_device_path(tested_name), FALSE); + + cached_name += NAME_PREFIX_LENGTH; + tested_name += NAME_PREFIX_LENGTH; + return strcmp(cached_name, tested_name) == 0; +} + +static void +gst_vaapi_display_drm_finalize(GObject *object) +{ + G_OBJECT_CLASS(gst_vaapi_display_drm_parent_class)->finalize(object); +} + +/* Get default device path. Actually, the first match in the DRM subsystem */ +static const gchar * +get_default_device_path(gpointer ptr) +{ + GstVaapiDisplayDRM * const display = GST_VAAPI_DISPLAY_DRM(ptr); + GstVaapiDisplayDRMPrivate * const priv = display->priv; + const gchar *syspath, *devpath; + struct udev *udev = NULL; + struct udev_device *device, *parent; + struct udev_enumerate *e = NULL; + struct udev_list_entry *l; + int fd; + + if (!priv->device_path_default) { + udev = udev_new(); + if (!udev) + goto end; + + e = udev_enumerate_new(udev); + if (!e) + goto end; + + udev_enumerate_add_match_subsystem(e, "drm"); + udev_enumerate_scan_devices(e); + udev_list_entry_foreach(l, udev_enumerate_get_list_entry(e)) { + syspath = udev_list_entry_get_name(l); + device = udev_device_new_from_syspath(udev, syspath); + parent = udev_device_get_parent(device); + if (strcmp(udev_device_get_subsystem(parent), "pci") != 0) { + udev_device_unref(device); + continue; + } + + devpath = udev_device_get_devnode(device); + fd = open(devpath, O_RDWR|O_CLOEXEC); + if (fd < 0) { + udev_device_unref(device); + continue; + } + + priv->device_path_default = g_strdup(devpath); + close(fd); + udev_device_unref(device); + break; + } + + end: + if (e) + udev_enumerate_unref(e); + if (udev) + udev_unref(udev); + } + return priv->device_path_default; +} + +/* Reconstruct a device path without our prefix */ +static const gchar * +get_device_path(gpointer ptr) +{ + GstVaapiDisplayDRM * const display = GST_VAAPI_DISPLAY_DRM(ptr); + const gchar *device_path = display->priv->device_path; + + if (!device_path) + return NULL; + + g_return_val_if_fail(is_device_path(device_path), NULL); + + device_path += NAME_PREFIX_LENGTH; + if (*device_path == '\0') + return NULL; + return device_path; +} + +/* Mangle device path with our prefix */ +static void +set_device_path(GstVaapiDisplayDRM *display, const gchar *device_path) +{ + GstVaapiDisplayDRMPrivate * const priv = display->priv; + + g_free(priv->device_path); + priv->device_path = NULL; + + if (!device_path) { + device_path = get_default_device_path(display); + if (!device_path) + return; + } + priv->device_path = g_strdup_printf("%s%s", NAME_PREFIX, device_path); +} + +/* Set device path from file descriptor */ +static void +set_device_path_from_fd(GstVaapiDisplayDRM *display, gint drm_device) +{ + GstVaapiDisplayDRMPrivate * const priv = display->priv; + const gchar *busid, *path, *str; + gsize busid_length, path_length; + struct udev *udev = NULL; + struct udev_device *device; + struct udev_enumerate *e = NULL; + struct udev_list_entry *l; + + g_free(priv->device_path); + priv->device_path = NULL; + + if (drm_device < 0) + return; + + busid = drmGetBusid(drm_device); + if (!busid) + return; + if (strncmp(busid, "pci:", 4) != 0) + return; + busid += 4; + busid_length = strlen(busid); + + udev = udev_new(); + if (!udev) + goto end; + + e = udev_enumerate_new(udev); + if (!e) + goto end; + + udev_enumerate_add_match_subsystem(e, "drm"); + udev_enumerate_scan_devices(e); + udev_list_entry_foreach(l, udev_enumerate_get_list_entry(e)) { + path = udev_list_entry_get_name(l); + str = strstr(path, busid); + if (!str || str <= path || str[-1] != '/') + continue; + + path_length = strlen(path); + if (str + busid_length >= path + path_length) + continue; + if (strncmp(&str[busid_length], "/drm/card", 9) != 0) + continue; + + device = udev_device_new_from_syspath(udev, path); + if (!device) + continue; + + path = udev_device_get_devnode(device); + priv->device_path = g_strdup_printf("%s%s", NAME_PREFIX, path); + udev_device_unref(device); + break; + } + +end: + if (e) + udev_enumerate_unref(e); + if (udev) + udev_unref(udev); +} + +static void +gst_vaapi_display_drm_set_property( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) +{ + GstVaapiDisplayDRM * const display = GST_VAAPI_DISPLAY_DRM(object); + + switch (prop_id) { + case PROP_DEVICE_PATH: + set_device_path(display, g_value_get_string(value)); + break; + case PROP_DRM_DEVICE: + display->priv->drm_device = g_value_get_int(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_display_drm_get_property( + GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec +) +{ + GstVaapiDisplayDRM * const display = GST_VAAPI_DISPLAY_DRM(object); + + switch (prop_id) { + case PROP_DEVICE_PATH: + g_value_set_string(value, get_device_path(display)); + break; + case PROP_DRM_DEVICE: + g_value_set_int(value, display->priv->drm_device); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_display_drm_constructed(GObject *object) +{ + GstVaapiDisplayDRM * const display = GST_VAAPI_DISPLAY_DRM(object); + GstVaapiDisplayDRMPrivate * const priv = display->priv; + GstVaapiDisplayCache * const cache = gst_vaapi_display_get_cache(); + const GstVaapiDisplayInfo *info; + GObjectClass *parent_class; + + priv->create_display = priv->drm_device < 0; + + /* Don't create DRM display if there is one in the cache already */ + if (priv->create_display) { + info = gst_vaapi_display_cache_lookup_by_name( + cache, + priv->device_path, + compare_device_path, NULL + ); + if (info) { + priv->drm_device = GPOINTER_TO_INT(info->native_display); + priv->create_display = FALSE; + } + } + + /* Reset device-path if the user provided his own DRM display */ + if (!priv->create_display) + set_device_path_from_fd(display, priv->drm_device); + + parent_class = G_OBJECT_CLASS(gst_vaapi_display_drm_parent_class); + if (parent_class->constructed) + parent_class->constructed(object); +} + +static gboolean +gst_vaapi_display_drm_open_display(GstVaapiDisplay *display) +{ + GstVaapiDisplayDRMPrivate * const priv = + GST_VAAPI_DISPLAY_DRM(display)->priv; + + if (priv->create_display) { + const gchar *device_path = get_device_path(display); + if (!device_path) + return FALSE; + priv->drm_device = open(device_path, O_RDWR|O_CLOEXEC); + if (priv->drm_device < 0) + return FALSE; + } + if (priv->drm_device < 0) + return FALSE; + return TRUE; +} + +static void +gst_vaapi_display_drm_close_display(GstVaapiDisplay *display) +{ + GstVaapiDisplayDRMPrivate * const priv = + GST_VAAPI_DISPLAY_DRM(display)->priv; + + if (priv->drm_device >= 0) { + if (priv->create_display) + close(priv->drm_device); + priv->drm_device = -1; + } + + if (priv->device_path) { + g_free(priv->device_path); + priv->device_path = NULL; + } + + if (priv->device_path_default) { + g_free(priv->device_path_default); + priv->device_path_default = NULL; + } +} + +static gboolean +gst_vaapi_display_drm_get_display_info( + GstVaapiDisplay *display, + GstVaapiDisplayInfo *info +) +{ + GstVaapiDisplayDRMPrivate * const priv = + GST_VAAPI_DISPLAY_DRM(display)->priv; + GstVaapiDisplayCache *cache; + const GstVaapiDisplayInfo *cached_info; + + /* Return any cached info even if child has its own VA display */ + cache = gst_vaapi_display_get_cache(); + if (!cache) + return FALSE; + cached_info = gst_vaapi_display_cache_lookup_by_native_display( + cache, GINT_TO_POINTER(priv->drm_device)); + if (cached_info) { + *info = *cached_info; + return TRUE; + } + + /* Otherwise, create VA display if there is none already */ + info->native_display = GINT_TO_POINTER(priv->drm_device); + info->display_name = priv->device_path; + if (!info->va_display) { + info->va_display = vaGetDisplayDRM(priv->drm_device); + if (!info->va_display) + return FALSE; + info->display_type = GST_VAAPI_DISPLAY_TYPE_DRM; + } + return TRUE; +} + +static void +gst_vaapi_display_drm_class_init(GstVaapiDisplayDRMClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiDisplayClass * const dpy_class = GST_VAAPI_DISPLAY_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiDisplayDRMPrivate)); + + object_class->finalize = gst_vaapi_display_drm_finalize; + object_class->set_property = gst_vaapi_display_drm_set_property; + object_class->get_property = gst_vaapi_display_drm_get_property; + object_class->constructed = gst_vaapi_display_drm_constructed; + + dpy_class->open_display = gst_vaapi_display_drm_open_display; + dpy_class->close_display = gst_vaapi_display_drm_close_display; + dpy_class->get_display = gst_vaapi_display_drm_get_display_info; + + /** + * GstVaapiDisplayDRM:drm-device: + * + * The DRM device (file descriptor). + */ + g_object_class_install_property + (object_class, + PROP_DRM_DEVICE, + g_param_spec_int("drm-device", + "DRM device", + "DRM device", + -1, G_MAXINT32, -1, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + + /** + * GstVaapiDisplayDRM:device-path: + * + * The DRM device path. + */ + g_object_class_install_property + (object_class, + PROP_DEVICE_PATH, + g_param_spec_string("device-path", + "DRM device path", + "DRM device path", + NULL, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); +} + +static void +gst_vaapi_display_drm_init(GstVaapiDisplayDRM *display) +{ + GstVaapiDisplayDRMPrivate * const priv = + GST_VAAPI_DISPLAY_DRM_GET_PRIVATE(display); + + display->priv = priv; + priv->device_path_default = NULL; + priv->device_path = NULL; + priv->drm_device = -1; + priv->create_display = TRUE; +} + +/** + * gst_vaapi_display_drm_new: + * @device_path: the DRM device path + * + * Opens an DRM file descriptor using @device_path and returns a newly + * allocated #GstVaapiDisplay object. The DRM display will be cloed + * when the reference count of the object reaches zero. + * + * If @device_path is NULL, the DRM device path will be automatically + * determined as the first positive match in the list of available DRM + * devices. + * + * Return value: a newly allocated #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_display_drm_new(const gchar *device_path) +{ + return g_object_new(GST_VAAPI_TYPE_DISPLAY_DRM, + "device-path", device_path, + NULL); +} + +/** + * gst_vaapi_display_drm_new_with_device: + * @device: an open DRM device (file descriptor) + * + * Creates a #GstVaapiDisplay based on the open DRM @device. The + * caller still owns the device file descriptor and must call close() + * when all #GstVaapiDisplay references are released. Doing so too + * early can yield undefined behaviour. + * + * Return value: a newly allocated #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_display_drm_new_with_device(gint device) +{ + g_return_val_if_fail(device >= 0, NULL); + + return g_object_new(GST_VAAPI_TYPE_DISPLAY_DRM, + "drm-device", device, + NULL); +} + +/** + * gst_vaapi_display_drm_get_device: + * @display: a #GstVaapiDisplayDRM + * + * Returns the underlying DRM device file descriptor that was created + * by gst_vaapi_display_drm_new() or that was bound from + * gst_vaapi_display_drm_new_with_device(). + * + * Return value: the DRM file descriptor attached to @display + */ +gint +gst_vaapi_display_drm_get_device(GstVaapiDisplayDRM *display) +{ + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY_DRM(display), -1); + + return display->priv->drm_device; +} + +/** + * gst_vaapi_display_drm_get_device_path: + * @display: a #GstVaapiDisplayDRM + * + * Returns the underlying DRM device path name was created by + * gst_vaapi_display_drm_new() or that was bound from + * gst_vaapi_display_drm_new_with_device(). + * + * Note: the #GstVaapiDisplayDRM object owns the resulting string, so + * it shall not be deallocated. + * + * Return value: the DRM device path name attached to @display + */ +const gchar * +gst_vaapi_display_drm_get_device_path(GstVaapiDisplayDRM *display) +{ + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY_DRM(display), NULL); + + return display->priv->device_path; +} diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_drm.h b/gst-libs/gst/vaapi/gstvaapidisplay_drm.h new file mode 100644 index 0000000000..fad0d530c1 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_drm.h @@ -0,0 +1,97 @@ +/* + * gstvaapidisplay_drm.h - VA/DRM display abstraction + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DISPLAY_DRM_H +#define GST_VAAPI_DISPLAY_DRM_H + +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_DISPLAY_DRM \ + (gst_vaapi_display_drm_get_type()) + +#define GST_VAAPI_DISPLAY_DRM(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_DISPLAY_DRM, \ + GstVaapiDisplayDRM)) + +#define GST_VAAPI_DISPLAY_DRM_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_DISPLAY_DRM, \ + GstVaapiDisplayDRMClass)) + +#define GST_VAAPI_IS_DISPLAY_DRM(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_DISPLAY_DRM)) + +#define GST_VAAPI_IS_DISPLAY_DRM_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_DISPLAY_DRM)) + +#define GST_VAAPI_DISPLAY_DRM_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_DISPLAY_DRM, \ + GstVaapiDisplayDRMClass)) + +typedef struct _GstVaapiDisplayDRM GstVaapiDisplayDRM; +typedef struct _GstVaapiDisplayDRMPrivate GstVaapiDisplayDRMPrivate; +typedef struct _GstVaapiDisplayDRMClass GstVaapiDisplayDRMClass; + +/** + * GstVaapiDisplayDRM: + * + * VA/DRM display wrapper. + */ +struct _GstVaapiDisplayDRM { + /*< private >*/ + GstVaapiDisplay parent_instance; + + GstVaapiDisplayDRMPrivate *priv; +}; + + +/** + * GstVaapiDisplayDRMClass: + * + * VA/DRM display wrapper clas. + */ +struct _GstVaapiDisplayDRMClass { + /*< private >*/ + GstVaapiDisplayClass parent_class; +}; + +GType +gst_vaapi_display_drm_get_type(void) G_GNUC_CONST; + +GstVaapiDisplay * +gst_vaapi_display_drm_new(const gchar *device_path); + +GstVaapiDisplay * +gst_vaapi_display_drm_new_with_device(gint device); + +gint +gst_vaapi_display_drm_get_device(GstVaapiDisplayDRM *display); + +const gchar * +gst_vaapi_display_drm_get_device_path(GstVaapiDisplayDRM *display); + +G_END_DECLS + +#endif /* GST_VAAPI_DISPLAY_DRM_H */ diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_drm_priv.h b/gst-libs/gst/vaapi/gstvaapidisplay_drm_priv.h new file mode 100644 index 0000000000..f6211a73ad --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_drm_priv.h @@ -0,0 +1,55 @@ +/* + * gstvaapidisplay_drm_priv.h - Internal VA/DRM interface + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_DISPLAY_DRM_PRIV_H +#define GST_VAAPI_DISPLAY_DRM_PRIV_H + +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_DISPLAY_DRM_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_DISPLAY_DRM, \ + GstVaapiDisplayDRMPrivate)) + +#define GST_VAAPI_DISPLAY_DRM_CAST(display) ((GstVaapiDisplayDRM *)(display)) + +/** + * GST_VAAPI_DISPLAY_DRM_DEVICE: + * @display: a #GstVaapiDisplay + * + * Macro that evaluates to the underlying DRM file descriptor of @display + */ +#undef GST_VAAPI_DISPLAY_DRM_DEVICE +#define GST_VAAPI_DISPLAY_DRM_DEVICE(display) \ + GST_VAAPI_DISPLAY_DRM_CAST(display)->priv->drm_device + +struct _GstVaapiDisplayDRMPrivate { + gchar *device_path_default; + gchar *device_path; + gint drm_device; + guint create_display : 1; +}; + +G_END_DECLS + +#endif /* GST_VAAPI_DISPLAY_DRM_PRIV_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_drm.c b/gst-libs/gst/vaapi/gstvaapiwindow_drm.c new file mode 100644 index 0000000000..6303480e65 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow_drm.c @@ -0,0 +1,161 @@ +/* + * gstvaapiwindow_drm.c - VA/DRM window abstraction + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/** + * SECTION:gstvaapiwindow_drm + * @short_description: VA/DRM dummy window abstraction + */ + +#include "sysdeps.h" +#include "gstvaapiwindow_drm.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiWindowDRM, + gst_vaapi_window_drm, + GST_VAAPI_TYPE_WINDOW); + +static gboolean +gst_vaapi_window_drm_show(GstVaapiWindow *window) +{ + return TRUE; +} + +static gboolean +gst_vaapi_window_drm_hide(GstVaapiWindow *window) +{ + return TRUE; +} + +static gboolean +gst_vaapi_window_drm_create( + GstVaapiWindow *window, + guint *width, + guint *height +) +{ + return TRUE; +} + +static void +gst_vaapi_window_drm_destroy(GstVaapiWindow * window) +{ +} + +static gboolean +gst_vaapi_window_drm_resize( + GstVaapiWindow * window, + guint width, + guint height +) +{ + return TRUE; +} + +static gboolean +gst_vaapi_window_drm_render( + GstVaapiWindow *window, + GstVaapiSurface *surface, + const GstVaapiRectangle *src_rect, + const GstVaapiRectangle *dst_rect, + guint flags +) +{ + return TRUE; +} + +static void +gst_vaapi_window_drm_finalize(GObject *object) +{ + G_OBJECT_CLASS(gst_vaapi_window_drm_parent_class)->finalize(object); +} + +static void +gst_vaapi_window_drm_constructed(GObject *object) +{ + GObjectClass *parent_class; + + parent_class = G_OBJECT_CLASS(gst_vaapi_window_drm_parent_class); + if (parent_class->constructed) + parent_class->constructed(object); +} + +static void +gst_vaapi_window_drm_class_init(GstVaapiWindowDRMClass * klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiWindowClass * const window_class = GST_VAAPI_WINDOW_CLASS(klass); + + object_class->finalize = gst_vaapi_window_drm_finalize; + object_class->constructed = gst_vaapi_window_drm_constructed; + + window_class->create = gst_vaapi_window_drm_create; + window_class->destroy = gst_vaapi_window_drm_destroy; + window_class->show = gst_vaapi_window_drm_show; + window_class->hide = gst_vaapi_window_drm_hide; + window_class->render = gst_vaapi_window_drm_render; + window_class->resize = gst_vaapi_window_drm_resize; +} + +static void +gst_vaapi_window_drm_init(GstVaapiWindowDRM * window) +{ +} + +/** + * gst_vaapi_window_drm_new: + * @display: a #GstVaapiDisplay + * @width: the requested window width, in pixels (unused) + * @height: the requested windo height, in pixels (unused) + * + * Creates a dummy window. The window will be attached to the @display. + * All rendering functions will return success since VA/DRM is a + * renderless API. + * + * Note: this dummy window object is only necessary to fulfill cases + * where the client application wants to automatically determine the + * best display to use for the current system. As such, it provides + * utility functions with the same API (function arguments) to help + * implement uniform function tables. + * + * Return value: the newly allocated #GstVaapiWindow object + */ +GstVaapiWindow * +gst_vaapi_window_drm_new( + GstVaapiDisplay *display, + guint width, + guint height +) +{ + GST_DEBUG("new window, size %ux%u", width, height); + + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL); + g_return_val_if_fail(width > 0, NULL); + g_return_val_if_fail(height > 0, NULL); + + return g_object_new(GST_VAAPI_TYPE_WINDOW_DRM, + "display", display, + "id", GST_VAAPI_ID(0), + "width", width, + "height", height, + NULL); +} diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_drm.h b/gst-libs/gst/vaapi/gstvaapiwindow_drm.h new file mode 100644 index 0000000000..47e053a31f --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow_drm.h @@ -0,0 +1,85 @@ +/* + * gstvaapiwindow_drm.h - VA/DRM window abstraction + * + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_WINDOW_DRM_H +#define GST_VAAPI_WINDOW_DRM_H + +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_WINDOW_DRM \ + (gst_vaapi_window_drm_get_type()) + +#define GST_VAAPI_WINDOW_DRM(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_WINDOW_DRM, \ + GstVaapiWindowDRM)) + +#define GST_VAAPI_WINDOW_DRM_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_WINDOW_DRM, \ + GstVaapiWindowDRMClass)) + +#define GST_VAAPI_IS_WINDOW_DRM(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_WINDOW_DRM)) + +#define GST_VAAPI_IS_WINDOW_DRM_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_WINDOW_DRM)) + +#define GST_VAAPI_WINDOW_DRM_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_WINDOW_DRM, \ + GstVaapiWindowDRMClass)) + +typedef struct _GstVaapiWindowDRM GstVaapiWindowDRM; +typedef struct _GstVaapiWindowDRMClass GstVaapiWindowDRMClass; + +/** + * GstVaapiWindowDRM: + * + * A dummy DRM window abstraction. + */ +struct _GstVaapiWindowDRM { + /*< private >*/ + GstVaapiWindow parent_instance; +}; + +/** + * GstVaapiWindowDRMClass: + * + * A DRM window class. + */ +struct _GstVaapiWindowDRMClass { + /*< private >*/ + GstVaapiWindowClass parent_class; +}; + +GType +gst_vaapi_window_drm_get_type(void) G_GNUC_CONST; + +GstVaapiWindow * +gst_vaapi_window_drm_new(GstVaapiDisplay *display, guint width, guint height); + +G_END_DECLS + +#endif /* GST_VAAPI_WINDOW_DRM_H */ diff --git a/pkgconfig/Makefile.am b/pkgconfig/Makefile.am index 7d6741379e..04537d1776 100644 --- a/pkgconfig/Makefile.am +++ b/pkgconfig/Makefile.am @@ -1,4 +1,7 @@ pcfiles_in = gstreamer-vaapi.pc.in +if USE_DRM +pcfiles_in += gstreamer-vaapi-drm.pc.in +endif if USE_X11 pcfiles_in += gstreamer-vaapi-x11.pc.in endif @@ -12,6 +15,7 @@ endif pcfiles = $(pcfiles_in:%.pc.in=%-@GST_MAJORMINOR@.pc) all_pcfiles_in = gstreamer-vaapi.pc.in +all_pcfiles_in += gstreamer-vaapi-drm.pc.in all_pcfiles_in += gstreamer-vaapi-x11.pc.in all_pcfiles_in += gstreamer-vaapi-glx.pc.in all_pcfiles_in += gstreamer-vaapi-wayland.pc.in diff --git a/pkgconfig/gstreamer-vaapi-drm.pc.in b/pkgconfig/gstreamer-vaapi-drm.pc.in new file mode 100644 index 0000000000..3ebfadfc87 --- /dev/null +++ b/pkgconfig/gstreamer-vaapi-drm.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@/gstreamer-@GST_MAJORMINOR@ +pluginsdir=@libdir@/gstreamer-@GST_MAJORMINOR@ + +Name: GStreamer VA-API (DRM) Plugins Libraries +Description: Streaming media framework, VA-API (DRM) plugins libraries +Requires: gstreamer-vaapi-@GST_MAJORMINOR@ libva-drm +Version: @VERSION@ +Libs: -L${libdir} -lgstvaapi-drm-@GST_MAJORMINOR@ +Cflags: -I${includedir}