2 * Copyright (C) 2020 Igalia, S.L.
3 * Author: Víctor Jáquez <vjaquez@igalia.com>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
30 #include "gstvaav1dec.h"
31 #include "gstvacaps.h"
32 #include "gstvacompositor.h"
33 #include "gstvadeinterlace.h"
34 #include "gstvadevice.h"
35 #include "gstvafilter.h"
36 #include "gstvah264dec.h"
37 #include "gstvah264enc.h"
38 #include "gstvah265dec.h"
39 #include "gstvah265enc.h"
40 #include "gstvajpegdec.h"
41 #include "gstvampeg2dec.h"
42 #include "gstvaprofile.h"
43 #include "gstvavp8dec.h"
44 #include "gstvavp9dec.h"
47 #define GST_CAT_DEFAULT gstva_debug
48 GST_DEBUG_CATEGORY (gstva_debug);
50 /* big bad mutex to exclusive access to shared stream buffers, such as
51 * DMABuf after a tee */
52 GRecMutex GST_VA_SHARED_LOCK = { 0, };
55 plugin_add_dependencies (GstPlugin * plugin)
57 const gchar *env_vars[] = { "LIBVA_DRIVER_NAME", NULL };
58 const gchar *kernel_paths[] = { "/dev/dri", NULL };
59 const gchar *kernel_names[] = { "renderD", NULL };
61 /* features get updated upon changes in /dev/dri/renderD* */
62 gst_plugin_add_dependency (plugin, NULL, kernel_paths, kernel_names,
63 GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_PREFIX);
65 /* features get updated upon changes on LIBVA_DRIVER_NAME envvar */
66 gst_plugin_add_dependency (plugin, env_vars, NULL, NULL,
67 GST_PLUGIN_DEPENDENCY_FLAG_NONE);
69 /* features get updated upon changes in default VA drivers
71 gst_plugin_add_dependency_simple (plugin, "LIBVA_DRIVERS_PATH",
72 LIBVA_DRIVERS_PATH, "_drv_video.so",
73 GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_SUFFIX |
74 GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_DEFAULT_ONLY);
78 plugin_register_decoders (GstPlugin * plugin, GstVaDevice * device,
79 GHashTable * decoders)
84 g_hash_table_iter_init (&iter, decoders);
85 while (g_hash_table_iter_next (&iter, &key, &value)) {
86 guint32 codec = *((gint64 *) key);
87 GArray *profiles = (GArray *) value;
88 GstCaps *sinkcaps = NULL, *srccaps = NULL;
90 if (!profiles || profiles->len == 0)
93 if (!gst_va_caps_from_profiles (device->display, profiles, VAEntrypointVLD,
97 GST_LOG ("%d decoder codec: %" GST_FOURCC_FORMAT, profiles->len,
98 GST_FOURCC_ARGS (codec));
99 GST_LOG ("sink caps: %" GST_PTR_FORMAT, sinkcaps);
100 GST_LOG ("src caps: %" GST_PTR_FORMAT, srccaps);
104 if (!gst_va_h264_dec_register (plugin, device, sinkcaps, srccaps,
106 GST_WARNING ("Failed to register H264 decoder: %s",
107 device->render_device_path);
111 if (!gst_va_h265_dec_register (plugin, device, sinkcaps, srccaps,
113 GST_WARNING ("Failed to register H265 decoder: %s",
114 device->render_device_path);
118 if (!gst_va_vp8_dec_register (plugin, device, sinkcaps, srccaps,
120 GST_WARNING ("Failed to register VP8 decoder: %s",
121 device->render_device_path);
125 if (!gst_va_vp9_dec_register (plugin, device, sinkcaps, srccaps,
127 GST_WARNING ("Failed to register VP9 decoder: %s",
128 device->render_device_path);
132 if (!gst_va_mpeg2_dec_register (plugin, device, sinkcaps, srccaps,
134 GST_WARNING ("Failed to register Mpeg2 decoder: %s",
135 device->render_device_path);
138 #if VA_CHECK_VERSION(1, 8, 0)
140 if (!gst_va_av1_dec_register (plugin, device, sinkcaps, srccaps,
142 GST_WARNING ("Failed to register AV1 decoder: %s",
143 device->render_device_path);
148 if (!gst_va_jpeg_dec_register (plugin, device, sinkcaps, srccaps,
150 GST_WARNING ("Failed to register JPEG decoder: %s",
151 device->render_device_path);
155 GST_DEBUG ("No decoder implementation for %" GST_FOURCC_FORMAT,
156 GST_FOURCC_ARGS (codec));
160 gst_caps_unref (srccaps);
161 gst_caps_unref (sinkcaps);
166 plugin_register_encoders (GstPlugin * plugin, GstVaDevice * device,
167 GHashTable * encoders, VAEntrypoint entrypoint)
172 g_hash_table_iter_init (&iter, encoders);
173 while (g_hash_table_iter_next (&iter, &key, &value)) {
174 guint32 codec = *((gint64 *) key);
175 GArray *profiles = (GArray *) value;
176 GstCaps *sinkcaps = NULL, *srccaps = NULL;
178 if (!profiles || profiles->len == 0)
181 if (!gst_va_caps_from_profiles (device->display, profiles, entrypoint,
182 &srccaps, &sinkcaps))
185 GST_LOG ("%d encoder %scodec: %" GST_FOURCC_FORMAT, profiles->len,
186 (entrypoint == VAEntrypointEncSliceLP) ? "low power " : "",
187 GST_FOURCC_ARGS (codec));
188 GST_LOG ("sink caps: %" GST_PTR_FORMAT, sinkcaps);
189 GST_LOG ("src caps: %" GST_PTR_FORMAT, srccaps);
193 if (!gst_va_h264_enc_register (plugin, device, sinkcaps, srccaps,
194 GST_RANK_NONE, entrypoint)) {
195 GST_WARNING ("Failed to register H264 encoder: %s",
196 device->render_device_path);
200 if (!gst_va_h265_enc_register (plugin, device, sinkcaps, srccaps,
201 GST_RANK_NONE, entrypoint)) {
202 GST_WARNING ("Failed to register H265 encoder: %s",
203 device->render_device_path);
207 GST_DEBUG ("No encoder implementation for %" GST_FOURCC_FORMAT,
208 GST_FOURCC_ARGS (codec));
212 gst_caps_unref (srccaps);
213 gst_caps_unref (sinkcaps);
218 plugin_register_vpp (GstPlugin * plugin, GstVaDevice * device)
221 gboolean has_colorbalance, has_deinterlace, has_compose;
223 has_colorbalance = FALSE;
224 has_deinterlace = FALSE;
226 filter = gst_va_filter_new (device->display);
227 if (gst_va_filter_open (filter)) {
229 gst_va_filter_has_filter (filter, VAProcFilterColorBalance);
231 gst_va_filter_has_filter (filter, VAProcFilterDeinterlacing);
232 has_compose = gst_va_filter_has_compose (filter);
234 GST_WARNING ("Failed open VA filter");
235 gst_object_unref (filter);
238 gst_object_unref (filter);
240 if (!gst_va_vpp_register (plugin, device, has_colorbalance, GST_RANK_NONE))
241 GST_WARNING ("Failed to register postproc: %s", device->render_device_path);
243 if (has_deinterlace) {
244 if (!gst_va_deinterlace_register (plugin, device, GST_RANK_NONE)) {
245 GST_WARNING ("Failed to register deinterlace: %s",
246 device->render_device_path);
251 if (!gst_va_compositor_register (plugin, device, GST_RANK_NONE)) {
252 GST_WARNING ("Failed to register compositor: %s",
253 device->render_device_path);
259 _insert_profile_in_table (GHashTable * table, VAProfile profile)
261 gint64 codec = gst_va_profile_codec (profile);
264 if (codec == GST_MAKE_FOURCC ('N', 'O', 'N', 'E'))
267 profiles = g_hash_table_lookup (table, &codec);
269 gint64 *codec_ptr = g_new (gint64, 1);
272 profiles = g_array_new (FALSE, FALSE, sizeof (VAProfile));
273 g_hash_table_insert (table, codec_ptr, profiles);
275 g_array_append_val (profiles, profile);
279 plugin_register_elements (GstPlugin * plugin, GstVaDevice * device)
281 VADisplay dpy = gst_va_display_get_va_dpy (device->display);
282 VAEntrypoint *entrypoints = g_new (VAEntrypoint, vaMaxNumEntrypoints (dpy));
283 VAProfile *profiles = g_new (VAProfile, vaMaxNumProfiles (dpy));
285 GHashTable *decoders, *encoders, *encoderslp, *encodersimg;
286 gint i, j, num_entrypoints = 0, num_profiles = 0;
287 gboolean has_vpp = FALSE, ret = FALSE;
289 decoders = g_hash_table_new_full (g_int64_hash, g_int64_equal,
290 (GDestroyNotify) g_free, (GDestroyNotify) g_array_unref);
291 encoders = g_hash_table_new_full (g_int64_hash, g_int64_equal,
292 (GDestroyNotify) g_free, (GDestroyNotify) g_array_unref);
293 encoderslp = g_hash_table_new_full (g_int64_hash, g_int64_equal,
294 (GDestroyNotify) g_free, (GDestroyNotify) g_array_unref);
295 encodersimg = g_hash_table_new_full (g_int64_hash, g_int64_equal,
296 (GDestroyNotify) g_free, (GDestroyNotify) g_array_unref);
298 status = vaQueryConfigProfiles (dpy, profiles, &num_profiles);
299 if (status != VA_STATUS_SUCCESS) {
300 GST_ERROR ("vaQueryConfigProfile: %s", vaErrorStr (status));
304 for (i = 0; i < num_profiles; i++) {
305 status = vaQueryConfigEntrypoints (dpy, profiles[i], entrypoints,
307 if (status != VA_STATUS_SUCCESS) {
308 GST_ERROR ("vaQueryConfigEntrypoints: %s", vaErrorStr (status));
312 for (j = 0; j < num_entrypoints; j++) {
313 if (entrypoints[j] == VAEntrypointVLD)
314 _insert_profile_in_table (decoders, profiles[i]);
315 else if (entrypoints[j] == VAEntrypointEncSlice)
316 _insert_profile_in_table (encoders, profiles[i]);
317 else if (entrypoints[j] == VAEntrypointEncSliceLP)
318 _insert_profile_in_table (encoderslp, profiles[i]);
319 else if (entrypoints[j] == VAEntrypointEncPicture)
320 _insert_profile_in_table (encodersimg, profiles[i]);
321 else if (entrypoints[j] == VAEntrypointVideoProc)
326 plugin_register_decoders (plugin, device, decoders);
327 plugin_register_encoders (plugin, device, encoders, VAEntrypointEncSlice);
328 plugin_register_encoders (plugin, device, encoderslp, VAEntrypointEncSliceLP);
329 plugin_register_encoders (plugin, device, encodersimg,
330 VAEntrypointEncPicture);
332 plugin_register_vpp (plugin, device);
337 g_hash_table_unref (encodersimg);
338 g_hash_table_unref (encoderslp);
339 g_hash_table_unref (encoders);
340 g_hash_table_unref (decoders);
341 g_free (entrypoints);
348 plugin_init (GstPlugin * plugin)
350 GList *devices, *dev;
353 GST_DEBUG_CATEGORY_INIT (gstva_debug, "va", 0, "VA general debug");
355 plugin_add_dependencies (plugin);
357 devices = gst_va_device_find_devices ();
358 for (dev = devices; dev; dev = g_list_next (dev)) {
359 if (!plugin_register_elements (plugin, dev->data)) {
364 gst_va_device_list_free (devices);
369 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
371 va, "VA-API codecs plugin",
372 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)