decoder_device.c 7.4 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/*****************************************************************************
 * 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>
29
#include <vlc_fs.h>
30

31
#include "vlc_vaapi.h"
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#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

49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
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);
}

100
101
102
103
104
105
106
#ifdef HAVE_VA_X11
static void
x11_native_destroy_cb(VANativeDisplay native)
{
    XCloseDisplay(native);
}

107
static struct vaapi_instance *
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
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;
    }

125
126
    return vaapi_InitializeInstance(VLC_OBJECT(device), vadpy,
                                    x11dpy, x11_native_destroy_cb);
127
128
129
130
}
#endif

#ifdef HAVE_VA_DRM
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192

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 *
193
194
drm_init_vaapi_instance(vlc_decoder_device *device, VADisplay *vadpyp)
{
195
196
    return vaapi_InitializeInstanceDRM(VLC_OBJECT(device), vaGetDisplayDRM,
                                       vadpyp, NULL);
197
198
199
200
}
#endif

#ifdef HAVE_VA_WL
201
static struct vaapi_instance *
202
203
204
205
206
207
208
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;

209
    return vaapi_InitializeInstance(VLC_OBJECT(device), vadpy, NULL, NULL);
210
211
212
213
214
215
}
#endif

static void
Close(vlc_decoder_device *device)
{
216
    vaapi_DestroyInstance(device->sys);
217
218
}

219
220
221
222
static const struct vlc_decoder_device_operations ops = {
    .close = Close,
};

223
224
225
226
static int
Open(vlc_decoder_device *device, vout_window_t *window)
{
    VADisplay vadpy = NULL;
227
    struct vaapi_instance *vainst = NULL;
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
#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);

244
    device->ops = &ops;
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
    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)
267
    set_callback_dec_device(Open, PRIORITY)
268
269
270
271
    set_category(CAT_VIDEO)
    set_subcategory(SUBCAT_VIDEO_VOUT)
    add_shortcut("vaapi", SHORTCUT)
vlc_module_end ()