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