va: Fix struct empty initialization syntax
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / va / plugin.c
1 /* GStreamer
2  * Copyright (C) 2020 Igalia, S.L.
3  *     Author: Víctor Jáquez <vjaquez@igalia.com>
4  *
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.
9  *
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.
14  *
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.
19  */
20 /**
21  * plugin-va:
22  *
23  * Since: 1.18
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
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"
45 #include "gstvavpp.h"
46
47 #define GST_CAT_DEFAULT gstva_debug
48 GST_DEBUG_CATEGORY (gstva_debug);
49
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, };
53
54 static void
55 plugin_add_dependencies (GstPlugin * plugin)
56 {
57   const gchar *env_vars[] = { "LIBVA_DRIVER_NAME", NULL };
58   const gchar *kernel_paths[] = { "/dev/dri", NULL };
59   const gchar *kernel_names[] = { "renderD", NULL };
60
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);
64
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);
68
69   /* features get updated upon changes in default VA drivers
70    * directory */
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);
75 }
76
77 static void
78 plugin_register_decoders (GstPlugin * plugin, GstVaDevice * device,
79     GHashTable * decoders)
80 {
81   GHashTableIter iter;
82   gpointer key, value;
83
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;
89
90     if (!profiles || profiles->len == 0)
91       continue;
92
93     if (!gst_va_caps_from_profiles (device->display, profiles, VAEntrypointVLD,
94             &sinkcaps, &srccaps))
95       continue;
96
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);
101
102     switch (codec) {
103       case H264:
104         if (!gst_va_h264_dec_register (plugin, device, sinkcaps, srccaps,
105                 GST_RANK_NONE)) {
106           GST_WARNING ("Failed to register H264 decoder: %s",
107               device->render_device_path);
108         }
109         break;
110       case HEVC:
111         if (!gst_va_h265_dec_register (plugin, device, sinkcaps, srccaps,
112                 GST_RANK_NONE)) {
113           GST_WARNING ("Failed to register H265 decoder: %s",
114               device->render_device_path);
115         }
116         break;
117       case VP8:
118         if (!gst_va_vp8_dec_register (plugin, device, sinkcaps, srccaps,
119                 GST_RANK_NONE)) {
120           GST_WARNING ("Failed to register VP8 decoder: %s",
121               device->render_device_path);
122         }
123         break;
124       case VP9:
125         if (!gst_va_vp9_dec_register (plugin, device, sinkcaps, srccaps,
126                 GST_RANK_NONE)) {
127           GST_WARNING ("Failed to register VP9 decoder: %s",
128               device->render_device_path);
129         }
130         break;
131       case MPEG2:
132         if (!gst_va_mpeg2_dec_register (plugin, device, sinkcaps, srccaps,
133                 GST_RANK_NONE)) {
134           GST_WARNING ("Failed to register Mpeg2 decoder: %s",
135               device->render_device_path);
136         }
137         break;
138 #if VA_CHECK_VERSION(1, 8, 0)
139       case AV1:
140         if (!gst_va_av1_dec_register (plugin, device, sinkcaps, srccaps,
141                 GST_RANK_NONE)) {
142           GST_WARNING ("Failed to register AV1 decoder: %s",
143               device->render_device_path);
144         }
145         break;
146 #endif
147       case JPEG:
148         if (!gst_va_jpeg_dec_register (plugin, device, sinkcaps, srccaps,
149                 GST_RANK_NONE)) {
150           GST_WARNING ("Failed to register JPEG decoder: %s",
151               device->render_device_path);
152         }
153         break;
154       default:
155         GST_DEBUG ("No decoder implementation for %" GST_FOURCC_FORMAT,
156             GST_FOURCC_ARGS (codec));
157         break;
158     }
159
160     gst_caps_unref (srccaps);
161     gst_caps_unref (sinkcaps);
162   }
163 }
164
165 static void
166 plugin_register_encoders (GstPlugin * plugin, GstVaDevice * device,
167     GHashTable * encoders, VAEntrypoint entrypoint)
168 {
169   GHashTableIter iter;
170   gpointer key, value;
171
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;
177
178     if (!profiles || profiles->len == 0)
179       continue;
180
181     if (!gst_va_caps_from_profiles (device->display, profiles, entrypoint,
182             &srccaps, &sinkcaps))
183       continue;
184
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);
190
191     switch (codec) {
192       case H264:
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);
197         }
198         break;
199       case HEVC:
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);
204         }
205         break;
206       default:
207         GST_DEBUG ("No encoder implementation for %" GST_FOURCC_FORMAT,
208             GST_FOURCC_ARGS (codec));
209         break;
210     }
211
212     gst_caps_unref (srccaps);
213     gst_caps_unref (sinkcaps);
214   }
215 }
216
217 static void
218 plugin_register_vpp (GstPlugin * plugin, GstVaDevice * device)
219 {
220   GstVaFilter *filter;
221   gboolean has_colorbalance, has_deinterlace, has_compose;
222
223   has_colorbalance = FALSE;
224   has_deinterlace = FALSE;
225   has_compose = FALSE;
226   filter = gst_va_filter_new (device->display);
227   if (gst_va_filter_open (filter)) {
228     has_colorbalance =
229         gst_va_filter_has_filter (filter, VAProcFilterColorBalance);
230     has_deinterlace =
231         gst_va_filter_has_filter (filter, VAProcFilterDeinterlacing);
232     has_compose = gst_va_filter_has_compose (filter);
233   } else {
234     GST_WARNING ("Failed open VA filter");
235     gst_object_unref (filter);
236     return;
237   }
238   gst_object_unref (filter);
239
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);
242
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);
247     }
248   }
249
250   if (has_compose) {
251     if (!gst_va_compositor_register (plugin, device, GST_RANK_NONE)) {
252       GST_WARNING ("Failed to register compositor: %s",
253           device->render_device_path);
254     }
255   }
256 }
257
258 static inline void
259 _insert_profile_in_table (GHashTable * table, VAProfile profile)
260 {
261   gint64 codec = gst_va_profile_codec (profile);
262   GArray *profiles;
263
264   if (codec == GST_MAKE_FOURCC ('N', 'O', 'N', 'E'))
265     return;
266
267   profiles = g_hash_table_lookup (table, &codec);
268   if (!profiles) {
269     gint64 *codec_ptr = g_new (gint64, 1);
270
271     *codec_ptr = codec;
272     profiles = g_array_new (FALSE, FALSE, sizeof (VAProfile));
273     g_hash_table_insert (table, codec_ptr, profiles);
274   }
275   g_array_append_val (profiles, profile);
276 }
277
278 static gboolean
279 plugin_register_elements (GstPlugin * plugin, GstVaDevice * device)
280 {
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));
284   VAStatus status;
285   GHashTable *decoders, *encoders, *encoderslp, *encodersimg;
286   gint i, j, num_entrypoints = 0, num_profiles = 0;
287   gboolean has_vpp = FALSE, ret = FALSE;
288
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);
297
298   status = vaQueryConfigProfiles (dpy, profiles, &num_profiles);
299   if (status != VA_STATUS_SUCCESS) {
300     GST_ERROR ("vaQueryConfigProfile: %s", vaErrorStr (status));
301     goto bail;
302   }
303
304   for (i = 0; i < num_profiles; i++) {
305     status = vaQueryConfigEntrypoints (dpy, profiles[i], entrypoints,
306         &num_entrypoints);
307     if (status != VA_STATUS_SUCCESS) {
308       GST_ERROR ("vaQueryConfigEntrypoints: %s", vaErrorStr (status));
309       goto bail;
310     }
311
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)
322         has_vpp = TRUE;
323     }
324   }
325
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);
331   if (has_vpp)
332     plugin_register_vpp (plugin, device);
333
334   ret = TRUE;
335
336 bail:
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);
342   g_free (profiles);
343
344   return ret;
345 }
346
347 static gboolean
348 plugin_init (GstPlugin * plugin)
349 {
350   GList *devices, *dev;
351   gboolean ret = TRUE;
352
353   GST_DEBUG_CATEGORY_INIT (gstva_debug, "va", 0, "VA general debug");
354
355   plugin_add_dependencies (plugin);
356
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)) {
360       ret = FALSE;
361       break;
362     }
363   }
364   gst_va_device_list_free (devices);
365
366   return ret;
367 }
368
369 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
370     GST_VERSION_MINOR,
371     va, "VA-API codecs plugin",
372     plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)