1 /*
2  *  gstvaapicontext.c - VA context abstraction
3  *
4  *  Copyright (C) 2010-2011 Splitted-Desktop Systems
5  *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
6  *  Copyright (C) 2011-2014 Intel Corporation
7  *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
8  *
9  *  This library is free software; you can redistribute it and/or
10  *  modify it under the terms of the GNU Lesser General Public License
11  *  as published by the Free Software Foundation; either version 2.1
12  *  of the License, or (at your option) any later version.
13  *
14  *  This library is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  Lesser General Public License for more details.
18  *
19  *  You should have received a copy of the GNU Lesser General Public
20  *  License along with this library; if not, write to the Free
21  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  *  Boston, MA 02110-1301 USA
23  */
24 
25 /**
26  * SECTION:gstvaapicontext
27  * @short_description: VA context abstraction
28  */
29 
30 #include "sysdeps.h"
31 #include "gstvaapicompat.h"
32 #include "gstvaapicontext.h"
33 #include "gstvaapicontext_overlay.h"
34 #include "gstvaapidisplay_priv.h"
35 #include "gstvaapiobject_priv.h"
36 #include "gstvaapisurface.h"
37 #include "gstvaapisurface_priv.h"
38 #include "gstvaapisurfacepool.h"
39 #include "gstvaapisurfaceproxy.h"
40 #include "gstvaapivideopool_priv.h"
41 #include "gstvaapiutils.h"
42 #include "gstvaapiutils_core.h"
43 
44 #define DEBUG 1
45 #include "gstvaapidebug.h"
46 
47 /* Define default VA surface chroma format to YUV 4:2:0 */
48 #define DEFAULT_CHROMA_TYPE (GST_VAAPI_CHROMA_TYPE_YUV420)
49 
50 /* Number of scratch surfaces beyond those used as reference */
51 #define SCRATCH_SURFACES_COUNT (4)
52 
53 static gboolean
ensure_formats(GstVaapiContext * context)54 ensure_formats (GstVaapiContext * context)
55 {
56   if (G_LIKELY (context->formats))
57     return TRUE;
58 
59   context->formats =
60       gst_vaapi_get_surface_formats (GST_VAAPI_OBJECT_DISPLAY (context),
61       context->va_config);
62   return (context->formats != NULL);
63 }
64 
65 static void
unref_surface_cb(GstVaapiSurface * surface)66 unref_surface_cb (GstVaapiSurface * surface)
67 {
68   gst_vaapi_surface_set_parent_context (surface, NULL);
69   gst_vaapi_object_unref (surface);
70 }
71 
72 static inline gboolean
context_get_attribute(GstVaapiContext * context,VAConfigAttribType type,guint * out_value_ptr)73 context_get_attribute (GstVaapiContext * context, VAConfigAttribType type,
74     guint * out_value_ptr)
75 {
76   return gst_vaapi_get_config_attribute (GST_VAAPI_OBJECT_DISPLAY (context),
77       context->va_profile, context->va_entrypoint, type, out_value_ptr);
78 }
79 
80 static void
context_destroy_surfaces(GstVaapiContext * context)81 context_destroy_surfaces (GstVaapiContext * context)
82 {
83   gst_vaapi_context_overlay_reset (context);
84 
85   if (context->surfaces) {
86     g_ptr_array_unref (context->surfaces);
87     context->surfaces = NULL;
88   }
89   gst_vaapi_video_pool_replace (&context->surfaces_pool, NULL);
90 }
91 
92 static void
context_destroy(GstVaapiContext * context)93 context_destroy (GstVaapiContext * context)
94 {
95   GstVaapiDisplay *const display = GST_VAAPI_OBJECT_DISPLAY (context);
96   VAContextID context_id;
97   VAStatus status;
98 
99   context_id = GST_VAAPI_OBJECT_ID (context);
100   GST_DEBUG ("context 0x%08x", context_id);
101 
102   if (context_id != VA_INVALID_ID) {
103     GST_VAAPI_DISPLAY_LOCK (display);
104     status = vaDestroyContext (GST_VAAPI_DISPLAY_VADISPLAY (display),
105         context_id);
106     GST_VAAPI_DISPLAY_UNLOCK (display);
107     if (!vaapi_check_status (status, "vaDestroyContext()"))
108       GST_WARNING ("failed to destroy context 0x%08x", context_id);
109     GST_VAAPI_OBJECT_ID (context) = VA_INVALID_ID;
110   }
111 
112   if (context->va_config != VA_INVALID_ID) {
113     GST_VAAPI_DISPLAY_LOCK (display);
114     status = vaDestroyConfig (GST_VAAPI_DISPLAY_VADISPLAY (display),
115         context->va_config);
116     GST_VAAPI_DISPLAY_UNLOCK (display);
117     if (!vaapi_check_status (status, "vaDestroyConfig()"))
118       GST_WARNING ("failed to destroy config 0x%08x", context->va_config);
119     context->va_config = VA_INVALID_ID;
120   }
121 
122   if (context->formats) {
123     g_array_unref (context->formats);
124     context->formats = NULL;
125   }
126 }
127 
128 static gboolean
context_ensure_surfaces(GstVaapiContext * context)129 context_ensure_surfaces (GstVaapiContext * context)
130 {
131   const GstVaapiContextInfo *const cip = &context->info;
132   const guint num_surfaces = cip->ref_frames + SCRATCH_SURFACES_COUNT;
133   GstVaapiSurface *surface;
134   guint i;
135 
136   if (!ensure_formats (context))
137     return FALSE;
138 
139   for (i = context->surfaces->len; i < num_surfaces; i++) {
140     surface =
141         gst_vaapi_surface_new_from_formats (GST_VAAPI_OBJECT_DISPLAY (context),
142         cip->chroma_type, cip->width, cip->height, context->formats);
143     if (!surface)
144       return FALSE;
145     gst_vaapi_surface_set_parent_context (surface, context);
146     g_ptr_array_add (context->surfaces, surface);
147     if (!gst_vaapi_video_pool_add_object (context->surfaces_pool, surface))
148       return FALSE;
149   }
150   gst_vaapi_video_pool_set_capacity (context->surfaces_pool, num_surfaces);
151   return TRUE;
152 }
153 
154 static gboolean
context_create_surfaces(GstVaapiContext * context)155 context_create_surfaces (GstVaapiContext * context)
156 {
157   const GstVaapiContextInfo *const cip = &context->info;
158   GstVaapiDisplay *const display = GST_VAAPI_OBJECT_DISPLAY (context);
159   guint num_surfaces;
160 
161   if (!gst_vaapi_context_overlay_reset (context))
162     return FALSE;
163 
164   num_surfaces = cip->ref_frames + SCRATCH_SURFACES_COUNT;
165   if (!context->surfaces) {
166     context->surfaces = g_ptr_array_new_full (num_surfaces,
167         (GDestroyNotify) unref_surface_cb);
168     if (!context->surfaces)
169       return FALSE;
170   }
171 
172   if (!context->surfaces_pool) {
173     context->surfaces_pool =
174         gst_vaapi_surface_pool_new_with_chroma_type (display, cip->chroma_type,
175         cip->width, cip->height);
176 
177     if (!context->surfaces_pool)
178       return FALSE;
179   }
180   return context_ensure_surfaces (context);
181 }
182 
183 static gboolean
context_create(GstVaapiContext * context)184 context_create (GstVaapiContext * context)
185 {
186   const GstVaapiContextInfo *const cip = &context->info;
187   GstVaapiDisplay *const display = GST_VAAPI_OBJECT_DISPLAY (context);
188   VAContextID context_id;
189   VASurfaceID surface_id;
190   VAStatus status;
191   GArray *surfaces = NULL;
192   gboolean success = FALSE;
193   guint i;
194 
195   if (!context->surfaces && !context_create_surfaces (context))
196     goto cleanup;
197 
198   /* Create VA surfaces list for vaCreateContext() */
199   surfaces = g_array_sized_new (FALSE,
200       FALSE, sizeof (VASurfaceID), context->surfaces->len);
201   if (!surfaces)
202     goto cleanup;
203 
204   for (i = 0; i < context->surfaces->len; i++) {
205     GstVaapiSurface *const surface = g_ptr_array_index (context->surfaces, i);
206     if (!surface)
207       goto cleanup;
208     surface_id = GST_VAAPI_OBJECT_ID (surface);
209     g_array_append_val (surfaces, surface_id);
210   }
211   g_assert (surfaces->len == context->surfaces->len);
212 
213   GST_VAAPI_DISPLAY_LOCK (display);
214   status = vaCreateContext (GST_VAAPI_DISPLAY_VADISPLAY (display),
215       context->va_config, cip->width, cip->height, VA_PROGRESSIVE,
216       (VASurfaceID *) surfaces->data, surfaces->len, &context_id);
217   GST_VAAPI_DISPLAY_UNLOCK (display);
218   if (!vaapi_check_status (status, "vaCreateContext()"))
219     goto cleanup;
220 
221   GST_DEBUG ("context 0x%08x", context_id);
222   GST_VAAPI_OBJECT_ID (context) = context_id;
223   success = TRUE;
224 
225 cleanup:
226   if (surfaces)
227     g_array_free (surfaces, TRUE);
228   return success;
229 }
230 
231 static gboolean
config_create(GstVaapiContext * context)232 config_create (GstVaapiContext * context)
233 {
234   const GstVaapiContextInfo *const cip = &context->info;
235   GstVaapiDisplay *const display = GST_VAAPI_OBJECT_DISPLAY (context);
236   VAConfigAttrib attribs[7], *attrib;
237   VAStatus status;
238   guint value, va_chroma_format, attrib_index;
239 
240   /* Reset profile and entrypoint */
241   if (!cip->profile || !cip->entrypoint)
242     goto cleanup;
243   context->va_profile = gst_vaapi_profile_get_va_profile (cip->profile);
244   context->va_entrypoint =
245       gst_vaapi_entrypoint_get_va_entrypoint (cip->entrypoint);
246 
247   attrib_index = 0;
248   attrib = &attribs[attrib_index];
249   g_assert (attrib_index < G_N_ELEMENTS (attribs));
250 
251   /* Validate VA surface format */
252   va_chroma_format = from_GstVaapiChromaType (cip->chroma_type);
253   if (!va_chroma_format)
254     goto cleanup;
255   attrib->type = VAConfigAttribRTFormat;
256   if (!context_get_attribute (context, attrib->type, &value))
257     goto cleanup;
258   if (!(value & va_chroma_format)) {
259     GST_ERROR ("unsupported chroma format (%s)",
260         string_of_va_chroma_format (va_chroma_format));
261     goto cleanup;
262   }
263   attrib->value = va_chroma_format;
264   attrib = &attribs[++attrib_index];
265   g_assert (attrib_index < G_N_ELEMENTS (attribs));
266 
267   switch (cip->usage) {
268 #if USE_ENCODERS
269     case GST_VAAPI_CONTEXT_USAGE_ENCODE:
270     {
271       const GstVaapiConfigInfoEncoder *const config = &cip->config.encoder;
272       guint va_rate_control;
273 
274       /* Rate control */
275       va_rate_control = from_GstVaapiRateControl (config->rc_mode);
276       if (va_rate_control != VA_RC_NONE) {
277         attrib->type = VAConfigAttribRateControl;
278         if (!context_get_attribute (context, attrib->type, &value))
279           goto cleanup;
280 
281         if ((value & va_rate_control) != va_rate_control) {
282           GST_ERROR ("unsupported %s rate control",
283               string_of_VARateControl (va_rate_control));
284           goto cleanup;
285         }
286         attrib->value = va_rate_control;
287         attrib = &attribs[++attrib_index];
288         g_assert (attrib_index < G_N_ELEMENTS (attribs));
289       }
290       /* Packed headers */
291       if (config->packed_headers) {
292         attrib->type = VAConfigAttribEncPackedHeaders;
293         if (!context_get_attribute (context, attrib->type, &value))
294           goto cleanup;
295 
296         if ((value & config->packed_headers) != config->packed_headers) {
297           GST_ERROR ("unsupported packed headers 0x%08x",
298               config->packed_headers & ~(value & config->packed_headers));
299           goto cleanup;
300         }
301         attrib->value = config->packed_headers;
302         attrib = &attribs[++attrib_index];
303         g_assert (attrib_index < G_N_ELEMENTS (attribs));
304       }
305       if (cip->profile == GST_VAAPI_PROFILE_JPEG_BASELINE) {
306         attrib->type = VAConfigAttribEncJPEG;
307         if (!context_get_attribute (context, attrib->type, &value))
308           goto cleanup;
309         attrib->value = value;
310         attrib = &attribs[++attrib_index];
311         g_assert (attrib_index < G_N_ELEMENTS (attribs));
312       }
313 #if VA_CHECK_VERSION(0,39,1)
314       if (config->roi_capability) {
315         VAConfigAttribValEncROI *roi_config;
316 
317         attrib->type = VAConfigAttribEncROI;
318         if (!context_get_attribute (context, attrib->type, &value))
319           goto cleanup;
320         roi_config = (VAConfigAttribValEncROI *) & value;
321         if (roi_config->bits.num_roi_regions != config->roi_num_supported) {
322           GST_ERROR ("Mismatched ROI support: number of regions supported: %d",
323               roi_config->bits.num_roi_regions);
324           goto cleanup;
325         }
326         if (config->rc_mode != GST_VAAPI_RATECONTROL_CQP
327             && VA_ROI_RC_QP_DELTA_SUPPORT (roi_config) == 0) {
328           GST_ERROR ("Mismatched ROI support:  ROI delta QP: %d",
329               VA_ROI_RC_QP_DELTA_SUPPORT (roi_config));
330           goto cleanup;
331         }
332         attrib->value = value;
333         attrib = &attribs[++attrib_index];
334         g_assert (attrib_index < G_N_ELEMENTS (attribs));
335       }
336 #endif
337 #if USE_H264_FEI_ENCODER
338       if (cip->entrypoint == GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_FEI) {
339         attrib->type = (VAConfigAttribType) VAConfigAttribFEIFunctionType;
340         attrib = &attribs[++attrib_index];
341         g_assert (attrib_index < G_N_ELEMENTS (attribs));
342         /* FIXME: Query the read-only supported MV predictors */
343       }
344 #endif
345       break;
346     }
347 #endif
348     default:
349       break;
350   }
351 
352   GST_VAAPI_DISPLAY_LOCK (display);
353   status = vaCreateConfig (GST_VAAPI_DISPLAY_VADISPLAY (display),
354       context->va_profile, context->va_entrypoint, attribs, attrib_index,
355       &context->va_config);
356   GST_VAAPI_DISPLAY_UNLOCK (display);
357   if (!vaapi_check_status (status, "vaCreateConfig()"))
358     goto cleanup;
359 
360   return TRUE;
361 cleanup:
362   GST_WARNING ("Failed to create vaConfig");
363   return FALSE;
364 }
365 
366 /** Updates config for encoding. Returns %TRUE if config changed */
367 static gboolean
context_update_config_encoder(GstVaapiContext * context,const GstVaapiConfigInfoEncoder * new_config)368 context_update_config_encoder (GstVaapiContext * context,
369     const GstVaapiConfigInfoEncoder * new_config)
370 {
371   GstVaapiConfigInfoEncoder *const config = &context->info.config.encoder;
372   gboolean config_changed = FALSE;
373 
374   g_assert (context->info.usage == GST_VAAPI_CONTEXT_USAGE_ENCODE);
375 
376   if (config->rc_mode != new_config->rc_mode) {
377     config->rc_mode = new_config->rc_mode;
378     config_changed = TRUE;
379   }
380 
381   if (config->packed_headers != new_config->packed_headers) {
382     config->packed_headers = new_config->packed_headers;
383     config_changed = TRUE;
384   }
385 
386   if (config->roi_capability != new_config->roi_capability ||
387       config->roi_num_supported != new_config->roi_num_supported) {
388     config->roi_capability = new_config->roi_capability;
389     config->roi_num_supported = new_config->roi_num_supported;
390     config_changed = TRUE;
391   }
392 
393   return config_changed;
394 }
395 
396 static inline void
gst_vaapi_context_init(GstVaapiContext * context,const GstVaapiContextInfo * new_cip)397 gst_vaapi_context_init (GstVaapiContext * context,
398     const GstVaapiContextInfo * new_cip)
399 {
400   GstVaapiContextInfo *const cip = &context->info;
401 
402   *cip = *new_cip;
403   if (!cip->chroma_type)
404     cip->chroma_type = DEFAULT_CHROMA_TYPE;
405 
406   context->va_config = VA_INVALID_ID;
407   context->reset_on_resize = TRUE;
408   gst_vaapi_context_overlay_init (context);
409 
410   context->formats = NULL;
411 }
412 
413 static void
gst_vaapi_context_finalize(GstVaapiContext * context)414 gst_vaapi_context_finalize (GstVaapiContext * context)
415 {
416   context_destroy (context);
417   context_destroy_surfaces (context);
418   gst_vaapi_context_overlay_finalize (context);
419 }
420 
421 GST_VAAPI_OBJECT_DEFINE_CLASS (GstVaapiContext, gst_vaapi_context);
422 
423 /**
424  * gst_vaapi_context_new:
425  * @display: a #GstVaapiDisplay
426  * @cip: a pointer to the #GstVaapiContextInfo
427  *
428  * Creates a new #GstVaapiContext with the configuration specified by
429  * @cip, thus including profile, entry-point, encoded size and maximum
430  * number of reference frames reported by the bitstream.
431  *
432  * Return value: the newly allocated #GstVaapiContext object
433  */
434 GstVaapiContext *
gst_vaapi_context_new(GstVaapiDisplay * display,const GstVaapiContextInfo * cip)435 gst_vaapi_context_new (GstVaapiDisplay * display,
436     const GstVaapiContextInfo * cip)
437 {
438   GstVaapiContext *context;
439 
440   g_return_val_if_fail (cip->profile, NULL);
441   g_return_val_if_fail (cip->entrypoint, NULL);
442 
443   context = gst_vaapi_object_new (gst_vaapi_context_class (), display);
444   if (!context)
445     return NULL;
446 
447   gst_vaapi_context_init (context, cip);
448 
449   if (!config_create (context))
450     goto error;
451 
452   /* this means we don't want to create a VAcontext */
453   if (cip->width == 0 && cip->height == 0)
454     goto done;
455 
456   /* this is not valid */
457   if (cip->width == 0 || cip->height == 0)
458     goto error;
459 
460   if (!context_create (context))
461     goto error;
462 
463 done:
464   return context;
465 
466   /* ERRORS */
467 error:
468   {
469     gst_vaapi_object_unref (context);
470     return NULL;
471   }
472 }
473 
474 /**
475  * gst_vaapi_context_reset:
476  * @context: a #GstVaapiContext
477  * @new_cip: a pointer to the new #GstVaapiContextInfo details
478  *
479  * Resets @context to the configuration specified by @new_cip, thus
480  * including profile, entry-point, encoded size and maximum number of
481  * reference frames reported by the bitstream.
482  *
483  * Return value: %TRUE on success
484  */
485 gboolean
gst_vaapi_context_reset(GstVaapiContext * context,const GstVaapiContextInfo * new_cip)486 gst_vaapi_context_reset (GstVaapiContext * context,
487     const GstVaapiContextInfo * new_cip)
488 {
489   GstVaapiContextInfo *const cip = &context->info;
490   gboolean reset_surfaces = FALSE, reset_config = FALSE;
491   gboolean grow_surfaces = FALSE;
492   GstVaapiChromaType chroma_type;
493 
494   chroma_type = new_cip->chroma_type ? new_cip->chroma_type :
495       DEFAULT_CHROMA_TYPE;
496   if (cip->chroma_type != chroma_type) {
497     cip->chroma_type = chroma_type;
498     reset_surfaces = TRUE;
499   }
500 
501   if (cip->width != new_cip->width || cip->height != new_cip->height) {
502     cip->width = new_cip->width;
503     cip->height = new_cip->height;
504     reset_surfaces = TRUE;
505   }
506 
507   if (cip->profile != new_cip->profile ||
508       cip->entrypoint != new_cip->entrypoint) {
509     cip->profile = new_cip->profile;
510     cip->entrypoint = new_cip->entrypoint;
511     reset_config = TRUE;
512   }
513 
514   if (cip->ref_frames < new_cip->ref_frames) {
515     cip->ref_frames = new_cip->ref_frames;
516     grow_surfaces = TRUE;
517   }
518 
519   if (cip->usage != new_cip->usage) {
520     cip->usage = new_cip->usage;
521     reset_config = TRUE;
522     memcpy (&cip->config, &new_cip->config, sizeof (cip->config));
523   } else if (new_cip->usage == GST_VAAPI_CONTEXT_USAGE_ENCODE) {
524     if (context_update_config_encoder (context, &new_cip->config.encoder))
525       reset_config = TRUE;
526   } else if (new_cip->usage == GST_VAAPI_CONTEXT_USAGE_DECODE) {
527     if ((reset_surfaces && context->reset_on_resize) || grow_surfaces)
528       reset_config = TRUE;
529   }
530 
531   if (reset_surfaces)
532     context_destroy_surfaces (context);
533   if (reset_config)
534     context_destroy (context);
535 
536   if (reset_config && !(config_create (context) && context_create (context)))
537     return FALSE;
538   if (reset_surfaces && !context_create_surfaces (context))
539     return FALSE;
540   else if (grow_surfaces && !context_ensure_surfaces (context))
541     return FALSE;
542   return TRUE;
543 }
544 
545 /**
546  * gst_vaapi_context_get_id:
547  * @context: a #GstVaapiContext
548  *
549  * Returns the underlying VAContextID of the @context.
550  *
551  * Return value: the underlying VA context id
552  */
553 GstVaapiID
gst_vaapi_context_get_id(GstVaapiContext * context)554 gst_vaapi_context_get_id (GstVaapiContext * context)
555 {
556   g_return_val_if_fail (context != NULL, VA_INVALID_ID);
557 
558   return GST_VAAPI_OBJECT_ID (context);
559 }
560 
561 /**
562  * gst_vaapi_context_get_surface_proxy:
563  * @context: a #GstVaapiContext
564  *
565  * Acquires a free surface, wrapped into a #GstVaapiSurfaceProxy. The
566  * returned surface will be automatically released when the proxy is
567  * destroyed. So, it is enough to call gst_vaapi_surface_proxy_unref()
568  * after usage.
569  *
570  * This function returns %NULL if there is no free surface available
571  * in the pool. The surfaces are pre-allocated during context creation
572  * though.
573  *
574  * Return value: a free surface, or %NULL if none is available
575  */
576 GstVaapiSurfaceProxy *
gst_vaapi_context_get_surface_proxy(GstVaapiContext * context)577 gst_vaapi_context_get_surface_proxy (GstVaapiContext * context)
578 {
579   g_return_val_if_fail (context != NULL, NULL);
580 
581   return
582       gst_vaapi_surface_proxy_new_from_pool (GST_VAAPI_SURFACE_POOL
583       (context->surfaces_pool));
584 }
585 
586 /**
587  * gst_vaapi_context_get_surface_count:
588  * @context: a #GstVaapiContext
589  *
590  * Retrieves the number of free surfaces left in the pool.
591  *
592  * Return value: the number of free surfaces available in the pool
593  */
594 guint
gst_vaapi_context_get_surface_count(GstVaapiContext * context)595 gst_vaapi_context_get_surface_count (GstVaapiContext * context)
596 {
597   g_return_val_if_fail (context != NULL, 0);
598 
599   return gst_vaapi_video_pool_get_size (context->surfaces_pool);
600 }
601 
602 /**
603  * gst_vaapi_context_reset_on_resize:
604  * @context: a #GstVaapiContext
605  * @reset_on_resize: Should the context be reset on size change
606  *
607  * Sets whether the underlying context should be reset when a size change
608  * happens. The proper setting for this is codec dependent.
609  */
610 void
gst_vaapi_context_reset_on_resize(GstVaapiContext * context,gboolean reset_on_resize)611 gst_vaapi_context_reset_on_resize (GstVaapiContext * context,
612     gboolean reset_on_resize)
613 {
614   g_return_if_fail (context != NULL);
615 
616   context->reset_on_resize = reset_on_resize;
617 }
618 
619 /**
620  * gst_vaapi_context_get_surface_formats:
621  * @context: a #GstVaapiContext
622  *
623  * Determines the set of supported formats by the surfaces associated
624  * to @context. The caller owns an extra reference of the resulting
625  * array of #GstVideoFormat elements, so it shall be released with
626  * g_array_unref after usage.
627  *
628  * Return value: (transfer full): the set of target formats supported
629  * by the surfaces in @context.
630  */
631 GArray *
gst_vaapi_context_get_surface_formats(GstVaapiContext * context)632 gst_vaapi_context_get_surface_formats (GstVaapiContext * context)
633 {
634   g_return_val_if_fail (context, NULL);
635 
636   if (!ensure_formats (context))
637     return NULL;
638   return g_array_ref (context->formats);
639 }
640