mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-30 12:10:37 +00:00
487 lines
12 KiB
C
487 lines
12 KiB
C
/* GStreamer
|
|
* Copyright (C) 2020 Igalia, S.L.
|
|
* Author: Víctor Jáquez <vjaquez@igalia.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 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
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
/**
|
|
* SECTION:gstvadisplay
|
|
* @title: GstVaDisplay
|
|
* @short_description: Generic VADisplay wrapper.
|
|
* @sources:
|
|
* - gstva.h
|
|
* - gstvadisplay.h
|
|
*
|
|
* It is a generic wrapper for VADisplay. To create new instances
|
|
* subclasses are required, depending on the display type to use
|
|
* (v.gr. DRM, X11, Wayland, etc.).
|
|
*
|
|
* The purpose of this class is to be shared among pipelines via
|
|
* #GstContext so all the VA processing elements will use the same
|
|
* display entry. Application developers can create their own
|
|
* subclass, based on their display, and shared it via the synced bus
|
|
* message for the application.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "gstvadisplay.h"
|
|
|
|
#include <stdio.h> /* sscanf */
|
|
#include <va/va.h>
|
|
|
|
GST_DEBUG_CATEGORY (gst_va_display_debug);
|
|
#define GST_CAT_DEFAULT gst_va_display_debug
|
|
|
|
typedef struct _GstVaDisplayPrivate GstVaDisplayPrivate;
|
|
struct _GstVaDisplayPrivate
|
|
{
|
|
VADisplay display;
|
|
|
|
gboolean foreign;
|
|
gboolean init;
|
|
GstVaImplementation impl;
|
|
gchar *vendor_desc;
|
|
|
|
guint driver_major;
|
|
guint driver_minor;
|
|
};
|
|
|
|
#define gst_va_display_parent_class parent_class
|
|
G_DEFINE_TYPE_WITH_CODE (GstVaDisplay, gst_va_display, GST_TYPE_OBJECT,
|
|
G_ADD_PRIVATE (GstVaDisplay);
|
|
GST_DEBUG_CATEGORY_INIT (gst_va_display_debug, "vadisplay", 0,
|
|
"VA Display"));
|
|
enum
|
|
{
|
|
PROP_VA_DISPLAY = 1,
|
|
PROP_DESC,
|
|
N_PROPERTIES
|
|
};
|
|
|
|
static GParamSpec *g_properties[N_PROPERTIES];
|
|
|
|
#define GET_PRIV(obj) gst_va_display_get_instance_private (GST_VA_DISPLAY (obj))
|
|
|
|
static GstVaImplementation
|
|
_get_implementation (const char *vendor)
|
|
{
|
|
if (g_str_has_prefix (vendor, "Mesa Gallium driver"))
|
|
return GST_VA_IMPLEMENTATION_MESA_GALLIUM;
|
|
else if (g_str_has_prefix (vendor, "Intel i965 driver"))
|
|
return GST_VA_IMPLEMENTATION_INTEL_I965;
|
|
else if (g_str_has_prefix (vendor, "Intel iHD driver"))
|
|
return GST_VA_IMPLEMENTATION_INTEL_IHD;
|
|
|
|
return GST_VA_IMPLEMENTATION_OTHER;
|
|
}
|
|
|
|
static char *
|
|
_get_desc (const char *vendor, GstVaImplementation impl)
|
|
{
|
|
char *end, *start;
|
|
char desc[1024];
|
|
size_t size;
|
|
|
|
if (impl == GST_VA_IMPLEMENTATION_OTHER)
|
|
return g_strdup (vendor);
|
|
|
|
start = strstr (vendor, "for ");
|
|
if (!start)
|
|
return g_strdup (vendor);
|
|
start += 4;
|
|
|
|
switch (impl) {
|
|
case GST_VA_IMPLEMENTATION_MESA_GALLIUM:
|
|
end = strchr (start, '(');
|
|
break;
|
|
default:
|
|
end = strstr (start, "- ");
|
|
break;
|
|
}
|
|
|
|
if (!end)
|
|
return g_strdup (vendor);
|
|
end -= 1;
|
|
|
|
size = MIN (1024, end - start);
|
|
memcpy (desc, start, size);
|
|
desc[size] = '\0';
|
|
return g_strdup (desc);
|
|
}
|
|
|
|
static gboolean
|
|
_get_driver_version (const char *vendor, GstVaImplementation impl,
|
|
guint * major, guint * minor)
|
|
{
|
|
guint maj, min;
|
|
|
|
if (!vendor)
|
|
return FALSE;
|
|
|
|
switch (impl) {
|
|
case GST_VA_IMPLEMENTATION_MESA_GALLIUM:
|
|
if (sscanf (vendor, "Mesa Gallium driver %d.%d.", &maj, &min) == 2) {
|
|
*major = maj;
|
|
*minor = min;
|
|
return TRUE;
|
|
}
|
|
break;
|
|
case GST_VA_IMPLEMENTATION_INTEL_IHD:
|
|
case GST_VA_IMPLEMENTATION_INTEL_I965:{
|
|
char *end = strstr (vendor, " - ");
|
|
if (end && sscanf (end, " - %d.%d.", &maj, &min) == 2) {
|
|
*major = maj;
|
|
*minor = min;
|
|
return TRUE;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
_gst_va_display_filter_driver (GstVaDisplay * self, gpointer foreign_display)
|
|
{
|
|
GstVaDisplayPrivate *priv = GET_PRIV (self);
|
|
VADisplay dpy;
|
|
const char *vendor;
|
|
GstVaImplementation impl;
|
|
guint major, minor;
|
|
|
|
g_assert ((foreign_display != NULL) ^ (priv->display != NULL));
|
|
dpy = foreign_display ? foreign_display : priv->display;
|
|
|
|
vendor = vaQueryVendorString (dpy);
|
|
GST_INFO ("VA-API driver vendor: %s", vendor);
|
|
|
|
impl = _get_implementation (vendor);
|
|
|
|
if (foreign_display) {
|
|
priv->display = foreign_display;
|
|
priv->foreign = TRUE;
|
|
} else {
|
|
if (g_getenv ("GST_VA_ALL_DRIVERS") == NULL
|
|
&& impl == GST_VA_IMPLEMENTATION_OTHER) {
|
|
GST_WARNING_OBJECT (self, "Unsupported driver: %s", vendor);
|
|
return FALSE;
|
|
}
|
|
}
|
|
priv->impl = impl;
|
|
priv->vendor_desc = _get_desc (vendor, priv->impl);
|
|
if (_get_driver_version (vendor, priv->impl, &major, &minor)) {
|
|
priv->driver_major = major;
|
|
priv->driver_minor = minor;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
gst_va_display_set_display (GstVaDisplay * self, gpointer display)
|
|
{
|
|
GstVaDisplayPrivate *priv = GET_PRIV (self);
|
|
|
|
if (!display)
|
|
return;
|
|
|
|
if (vaDisplayIsValid (display) == 0) {
|
|
GST_WARNING_OBJECT (self,
|
|
"User's VA display is invalid. An internal one will be tried.");
|
|
return;
|
|
}
|
|
|
|
/* assume driver is already initialized */
|
|
priv->init = TRUE;
|
|
|
|
/* assumed that user knows what's doing so all drivers are allowed */
|
|
_gst_va_display_filter_driver (self, display);
|
|
}
|
|
|
|
static void
|
|
gst_va_display_set_property (GObject * object, guint prop_id,
|
|
const GValue * value, GParamSpec * pspec)
|
|
{
|
|
GstVaDisplay *self = GST_VA_DISPLAY (object);
|
|
|
|
switch (prop_id) {
|
|
case PROP_VA_DISPLAY:{
|
|
gpointer display = g_value_get_pointer (value);
|
|
gst_va_display_set_display (self, display);
|
|
break;
|
|
}
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gst_va_display_get_property (GObject * object, guint prop_id, GValue * value,
|
|
GParamSpec * pspec)
|
|
{
|
|
GstVaDisplayPrivate *priv = GET_PRIV (object);
|
|
|
|
switch (prop_id) {
|
|
case PROP_VA_DISPLAY:
|
|
g_value_set_pointer (value, priv->display);
|
|
break;
|
|
case PROP_DESC:
|
|
g_value_set_string (value, priv->vendor_desc);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gst_va_display_constructed (GObject * object)
|
|
{
|
|
GstVaDisplay *self = GST_VA_DISPLAY (object);
|
|
GstVaDisplayPrivate *priv = GET_PRIV (object);
|
|
GstVaDisplayClass *klass = GST_VA_DISPLAY_GET_CLASS (object);
|
|
|
|
if (!priv->display && klass->create_va_display)
|
|
priv->display = klass->create_va_display (self);
|
|
|
|
G_OBJECT_CLASS (parent_class)->constructed (object);
|
|
}
|
|
|
|
static void
|
|
gst_va_display_dispose (GObject * object)
|
|
{
|
|
GstVaDisplayPrivate *priv = GET_PRIV (object);
|
|
|
|
if (priv->display && !priv->foreign)
|
|
vaTerminate (priv->display);
|
|
priv->display = NULL;
|
|
|
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
gst_va_display_finalize (GObject * object)
|
|
{
|
|
GstVaDisplayPrivate *priv = GET_PRIV (object);
|
|
|
|
g_free (priv->vendor_desc);
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
gst_va_display_class_init (GstVaDisplayClass * klass)
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
gobject_class->set_property = gst_va_display_set_property;
|
|
gobject_class->get_property = gst_va_display_get_property;
|
|
gobject_class->constructed = gst_va_display_constructed;
|
|
gobject_class->dispose = gst_va_display_dispose;
|
|
gobject_class->finalize = gst_va_display_finalize;
|
|
|
|
g_properties[PROP_VA_DISPLAY] =
|
|
g_param_spec_pointer ("va-display", "VADisplay", "VA Display handler",
|
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
|
|
|
|
g_properties[PROP_DESC] =
|
|
g_param_spec_string ("description", "Description",
|
|
"Vendor specific VA implementation description", NULL,
|
|
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
|
|
|
g_object_class_install_properties (gobject_class, N_PROPERTIES, g_properties);
|
|
}
|
|
|
|
static void
|
|
gst_va_display_init (GstVaDisplay * self)
|
|
{
|
|
GstVaDisplayPrivate *priv = GET_PRIV (self);
|
|
|
|
priv->impl = GST_VA_IMPLEMENTATION_INVALID;
|
|
}
|
|
|
|
#ifndef GST_DISABLE_GST_DEBUG
|
|
static gchar *
|
|
_strip_msg (const char *message)
|
|
{
|
|
gchar *msg = g_strdup (message);
|
|
if (!msg)
|
|
return NULL;
|
|
return g_strstrip (msg);
|
|
}
|
|
|
|
static void
|
|
_va_warning (gpointer object, const char *message)
|
|
{
|
|
GstVaDisplay *self = GST_VA_DISPLAY (object);
|
|
gchar *msg;
|
|
|
|
if ((msg = _strip_msg (message))) {
|
|
GST_WARNING_OBJECT (self, "VA error: %s", msg);
|
|
g_free (msg);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_va_info (gpointer object, const char *message)
|
|
{
|
|
GstVaDisplay *self = GST_VA_DISPLAY (object);
|
|
gchar *msg;
|
|
|
|
if ((msg = _strip_msg (message))) {
|
|
GST_INFO_OBJECT (self, "VA info: %s", msg);
|
|
g_free (msg);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* gst_va_display_initialize:
|
|
* @self: a #GstVaDisplay
|
|
*
|
|
* If the display is set by the user (foreign) it is assumed that the
|
|
* driver is already initialized, thus this function is noop.
|
|
*
|
|
* If the display is opened internally, this function will initialize
|
|
* the driver and it will set driver's message callbacks.
|
|
*
|
|
* NOTE: this function is supposed to be private, only used by
|
|
* GstVaDisplay descendants.
|
|
*
|
|
* Returns: %TRUE if the VA driver can be initialized; %FALSE
|
|
* otherwise
|
|
*
|
|
* Since: 1.20
|
|
**/
|
|
gboolean
|
|
gst_va_display_initialize (GstVaDisplay * self)
|
|
{
|
|
GstVaDisplayPrivate *priv;
|
|
VAStatus status;
|
|
int major_version = -1, minor_version = -1;
|
|
|
|
g_return_val_if_fail (GST_IS_VA_DISPLAY (self), FALSE);
|
|
|
|
priv = GET_PRIV (self);
|
|
|
|
if (priv->init)
|
|
return TRUE;
|
|
|
|
if (!priv->display)
|
|
return FALSE;
|
|
|
|
#ifndef GST_DISABLE_GST_DEBUG
|
|
vaSetErrorCallback (priv->display, _va_warning, self);
|
|
vaSetInfoCallback (priv->display, _va_info, self);
|
|
#endif
|
|
|
|
status = vaInitialize (priv->display, &major_version, &minor_version);
|
|
if (status != VA_STATUS_SUCCESS) {
|
|
GST_WARNING_OBJECT (self, "vaInitialize: %s", vaErrorStr (status));
|
|
return FALSE;
|
|
}
|
|
|
|
GST_INFO_OBJECT (self, "VA-API version %d.%d", major_version, minor_version);
|
|
|
|
priv->init = TRUE;
|
|
|
|
if (!_gst_va_display_filter_driver (self, NULL))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* gst_va_display_get_va_dpy:
|
|
* @self: a #GstVaDisplay type display.
|
|
*
|
|
* Get the VA display handle of the @self.
|
|
*
|
|
* Returns: the VA display handle.
|
|
*
|
|
* Since: 1.20
|
|
*/
|
|
gpointer
|
|
gst_va_display_get_va_dpy (GstVaDisplay * self)
|
|
{
|
|
VADisplay dpy;
|
|
|
|
g_return_val_if_fail (GST_IS_VA_DISPLAY (self), NULL);
|
|
|
|
g_object_get (self, "va-display", &dpy, NULL);
|
|
return dpy;
|
|
}
|
|
|
|
/**
|
|
* gst_va_display_get_implementation:
|
|
* @self: a #GstVaDisplay type display.
|
|
*
|
|
* Get the the #GstVaImplementation type of @self.
|
|
*
|
|
* Returns: #GstVaImplementation.
|
|
*
|
|
* Since: 1.20
|
|
*/
|
|
GstVaImplementation
|
|
gst_va_display_get_implementation (GstVaDisplay * self)
|
|
{
|
|
GstVaDisplayPrivate *priv;
|
|
|
|
g_return_val_if_fail (GST_IS_VA_DISPLAY (self),
|
|
GST_VA_IMPLEMENTATION_INVALID);
|
|
|
|
priv = GET_PRIV (self);
|
|
return priv->impl;
|
|
}
|
|
|
|
/**
|
|
* gst_va_display_check_version:
|
|
* @self: a #GstVaDisplay
|
|
* @major: major version to check
|
|
* @minor: minor version to check
|
|
*
|
|
* Returns: whether driver version is equal or greater than @major.@minor
|
|
*
|
|
* Since: 1.24
|
|
*/
|
|
gboolean
|
|
gst_va_display_check_version (GstVaDisplay * self, guint major, guint minor)
|
|
{
|
|
GstVaDisplayPrivate *priv;
|
|
|
|
g_return_val_if_fail (GST_IS_VA_DISPLAY (self), FALSE);
|
|
|
|
priv = GET_PRIV (self);
|
|
|
|
/* if cannot parse the version, all it's valid */
|
|
if (priv->driver_major == 0 && priv->driver_minor == 0)
|
|
return TRUE;
|
|
|
|
if (priv->driver_major < major)
|
|
return FALSE;
|
|
if (priv->driver_major == major && priv->driver_minor < minor)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|