You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

272 lines
7.4 KiB

/*****************************************************************************
* decoder_device.c: VAAPI decoder_device
*****************************************************************************
* Copyright (C) 2017-2019 VLC authors and VideoLAN
*
* This program 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 program 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_vout_window.h>
#include <vlc_codec.h>
#include <vlc_fs.h>
#include "vlc_vaapi.h"
#include <va/va_drmcommon.h>
#ifdef HAVE_VA_WL
# include <va/va_wayland.h>
#endif
#ifdef HAVE_VA_X11
# include <va/va_x11.h>
# include <vlc_xlib.h>
#endif
#ifdef HAVE_VA_DRM
# include <va/va_drm.h>
# include <vlc_fs.h>
# include <fcntl.h>
#endif
typedef void (*vaapi_native_destroy_cb)(VANativeDisplay);
struct vaapi_instance;
struct vaapi_instance
{
VADisplay dpy;
VANativeDisplay native;
vaapi_native_destroy_cb native_destroy_cb;
};
/* Initializes the VADisplay. If not NULL, native_destroy_cb will be called
* when the instance is released in order to destroy the native holder (that
* can be a drm/x11/wl). On error, dpy is terminated and the destroy callback
* is called. */
static struct vaapi_instance *
vaapi_InitializeInstance(vlc_object_t *o, VADisplay dpy,
VANativeDisplay native,
vaapi_native_destroy_cb native_destroy_cb)
{
int major = 0, minor = 0;
VAStatus s = vaInitialize(dpy, &major, &minor);
if (s != VA_STATUS_SUCCESS)
{
msg_Err(o, "vaInitialize: %s", vaErrorStr(s));
goto error;
}
struct vaapi_instance *inst = malloc(sizeof(*inst));
if (unlikely(inst == NULL))
goto error;
inst->dpy = dpy;
inst->native = native;
inst->native_destroy_cb = native_destroy_cb;
return inst;
error:
vaTerminate(dpy);
if (native != NULL && native_destroy_cb != NULL)
native_destroy_cb(native);
return NULL;
}
static void
vaapi_DestroyInstance(struct vaapi_instance *inst)
{
vaTerminate(inst->dpy);
if (inst->native != NULL && inst->native_destroy_cb != NULL)
inst->native_destroy_cb(inst->native);
free(inst);
}
#ifdef HAVE_VA_X11
static void
x11_native_destroy_cb(VANativeDisplay native)
{
XCloseDisplay(native);
}
static struct vaapi_instance *
x11_init_vaapi_instance(vlc_decoder_device *device, vout_window_t *window,
VADisplay *vadpyp)
{
if (!vlc_xlib_init(VLC_OBJECT(window)))
return NULL;
Display *x11dpy = XOpenDisplay(window->display.x11);
if (x11dpy == NULL)
return NULL;
VADisplay vadpy = *vadpyp = vaGetDisplay(x11dpy);
if (vadpy == NULL)
{
x11_native_destroy_cb(x11dpy);
return NULL;
}
return vaapi_InitializeInstance(VLC_OBJECT(device), vadpy,
x11dpy, x11_native_destroy_cb);
}
#endif
#ifdef HAVE_VA_DRM
static void
native_drm_destroy_cb(VANativeDisplay native)
{
vlc_close((intptr_t) native);
}
/* Get and Initializes a VADisplay from a DRM device. If device is NULL, this
* function will try to open default devices. */
static struct vaapi_instance *
vaapi_InitializeInstanceDRM(vlc_object_t *o,
VADisplay (*pf_getDisplayDRM)(int),
VADisplay *pdpy, const char *device)
{
static const char *default_drm_device_paths[] = {
"/dev/dri/renderD128",
"/dev/dri/card0",
"/dev/dri/renderD129",
"/dev/dri/card1",
};
const char *user_drm_device_paths[] = { device };
const char **drm_device_paths;
size_t drm_device_paths_count;
if (device != NULL)
{
drm_device_paths = user_drm_device_paths;
drm_device_paths_count = 1;
}
else
{
drm_device_paths = default_drm_device_paths;
drm_device_paths_count = ARRAY_SIZE(default_drm_device_paths);
}
for (size_t i = 0; i < drm_device_paths_count; i++)
{
int drm_fd = vlc_open(drm_device_paths[i], O_RDWR);
if (drm_fd < 0)
continue;
VADisplay dpy = pf_getDisplayDRM(drm_fd);
if (dpy)
{
struct vaapi_instance *va_inst =
vaapi_InitializeInstance(o, dpy,
(VANativeDisplay)(intptr_t)drm_fd,
native_drm_destroy_cb);
if (va_inst)
{
*pdpy = dpy;
return va_inst;
}
}
else
vlc_close(drm_fd);
}
return NULL;
}
static struct vaapi_instance *
drm_init_vaapi_instance(vlc_decoder_device *device, VADisplay *vadpyp)
{
return vaapi_InitializeInstanceDRM(VLC_OBJECT(device), vaGetDisplayDRM,
vadpyp, NULL);
}
#endif
#ifdef HAVE_VA_WL
static struct vaapi_instance *
wl_init_vaapi_instance(vlc_decoder_device *device, vout_window_t *window,
VADisplay *vadpyp)
{
VADisplay vadpy = *vadpyp = vaGetDisplayWl(window->display.wl);
if (vadpy == NULL)
return NULL;
return vaapi_InitializeInstance(VLC_OBJECT(device), vadpy, NULL, NULL);
}
#endif
static void
Close(vlc_decoder_device *device)
{
vaapi_DestroyInstance(device->sys);
}
static const struct vlc_decoder_device_operations ops = {
.close = Close,
};
static int
Open(vlc_decoder_device *device, vout_window_t *window)
{
VADisplay vadpy = NULL;
struct vaapi_instance *vainst = NULL;
#if defined (HAVE_VA_X11)
if (window && window->type == VOUT_WINDOW_TYPE_XID)
vainst = x11_init_vaapi_instance(device, window, &vadpy);
#elif defined(HAVE_VA_WL)
if (window && window->type == VOUT_WINDOW_TYPE_WAYLAND)
vainst = wl_init_vaapi_instance(device, window, &vadpy);
#elif defined (HAVE_VA_DRM)
(void) window;
vainst = drm_init_vaapi_instance(device, &vadpy);
#else
# error need X11/WL/DRM support
#endif
if (!vainst)
return VLC_EGENERIC;
assert(vadpy != NULL);
device->ops = &ops;
device->sys = vainst;
device->type = VLC_DECODER_DEVICE_VAAPI;
device->opaque = vadpy;
return VLC_SUCCESS;
}
#if defined (HAVE_VA_X11)
# define PRIORITY 2
# define SHORTCUT "vaapi_x11"
# define DESCRIPTION_SUFFIX "X11"
#elif defined(HAVE_VA_WL)
# define PRIORITY 2
# define SHORTCUT "vaapi_wl"
# define DESCRIPTION_SUFFIX "Wayland"
#elif defined (HAVE_VA_DRM)
# define PRIORITY 1
# define SHORTCUT "vaapi_drm"
# define DESCRIPTION_SUFFIX "DRM"
#endif
vlc_module_begin ()
set_description("VA-API decoder device for " DESCRIPTION_SUFFIX)
set_capability("decoder device", PRIORITY)
set_callbacks(Open, NULL)
set_category(CAT_VIDEO)
set_subcategory(SUBCAT_VIDEO_VOUT)
add_shortcut("vaapi", SHORTCUT)
vlc_module_end ()