vaapi: prefix USE_FOO defines to fix build with mesa 22.3.0
[platform/upstream/gstreamer.git] / subprojects / gstreamer-vaapi / gst-libs / gst / vaapi / gstvaapicontext.c
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 "gstvaapidisplay_priv.h"
34 #include "gstvaapisurface_priv.h"
35 #include "gstvaapisurfacepool.h"
36 #include "gstvaapisurfaceproxy.h"
37 #include "gstvaapivideopool_priv.h"
38 #include "gstvaapiutils.h"
39
40 /* Define default VA surface chroma format to YUV 4:2:0 */
41 #define DEFAULT_CHROMA_TYPE (GST_VAAPI_CHROMA_TYPE_YUV420)
42
43 /* Number of scratch surfaces beyond those used as reference */
44 #define SCRATCH_SURFACES_COUNT (4)
45
46 /* Debug category for GstVaapiContext */
47 GST_DEBUG_CATEGORY (gst_debug_vaapi_context);
48 #define GST_CAT_DEFAULT gst_debug_vaapi_context
49
50 static void
51 _init_vaapi_context_debug (void)
52 {
53 #ifndef GST_DISABLE_GST_DEBUG
54   static gsize _init = 0;
55
56   if (g_once_init_enter (&_init)) {
57     GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi_context, "vaapicontext", 0,
58         "VA-API context");
59     g_once_init_leave (&_init, 1);
60   }
61 #endif
62 }
63
64 static inline gboolean
65 _context_is_broken_jpeg_decoder (GstVaapiContext * context)
66 {
67   GstVaapiDisplay *const display = GST_VAAPI_CONTEXT_DISPLAY (context);
68
69   return (context->info.profile == GST_VAAPI_PROFILE_JPEG_BASELINE
70       && context->info.entrypoint == GST_VAAPI_ENTRYPOINT_VLD
71       && gst_vaapi_display_has_driver_quirks (display,
72           GST_VAAPI_DRIVER_QUIRK_JPEG_DEC_BROKEN_FORMATS));
73 }
74
75 static gboolean
76 ensure_attributes (GstVaapiContext * context)
77 {
78   if (G_LIKELY (context->attribs))
79     return TRUE;
80
81   context->attribs =
82       gst_vaapi_config_surface_attributes_get (GST_VAAPI_CONTEXT_DISPLAY
83       (context), context->va_config);
84
85   if (!context->attribs)
86     return FALSE;
87
88   if (_context_is_broken_jpeg_decoder (context)) {
89     GstVideoFormat fmt = GST_VIDEO_FORMAT_NV12;
90     g_array_prepend_val (context->attribs->formats, fmt);
91
92     context->attribs->mem_types &= ~VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
93   }
94   return TRUE;
95 }
96
97 /* XXX(victor): verify the preferred video format concords with the
98  * chroma type; otherwise it is changed for the (very arbritrary)
99  * preferred format from the requested context chroma type, in the
100  * context attributes */
101 static void
102 ensure_preferred_format (GstVaapiContext * context)
103 {
104   const GstVaapiContextInfo *const cip = &context->info;
105   GArray *formats;
106   guint i;
107
108   if (context->preferred_format != GST_VIDEO_FORMAT_UNKNOWN)
109     return;
110
111   if (_context_is_broken_jpeg_decoder (context))
112     return;
113
114   if (!ensure_attributes (context) || !context->attribs->formats)
115     return;
116
117   formats = context->attribs->formats;
118   for (i = 0; i < formats->len; i++) {
119     GstVideoFormat format = g_array_index (formats, GstVideoFormat, i);
120     if (format == gst_vaapi_video_format_from_chroma (cip->chroma_type)) {
121       context->preferred_format = format;
122       break;
123     }
124   }
125
126   return;
127 }
128
129 static inline gboolean
130 context_get_attribute (GstVaapiContext * context, VAConfigAttribType type,
131     guint * out_value_ptr)
132 {
133   return gst_vaapi_get_config_attribute (GST_VAAPI_CONTEXT_DISPLAY (context),
134       context->va_profile, context->va_entrypoint, type, out_value_ptr);
135 }
136
137 static void
138 context_destroy_surfaces (GstVaapiContext * context)
139 {
140   if (context->surfaces) {
141     g_ptr_array_unref (context->surfaces);
142     context->surfaces = NULL;
143   }
144
145   context->preferred_format = GST_VIDEO_FORMAT_UNKNOWN;
146
147   gst_vaapi_video_pool_replace (&context->surfaces_pool, NULL);
148 }
149
150 static void
151 context_destroy (GstVaapiContext * context)
152 {
153   GstVaapiDisplay *const display = GST_VAAPI_CONTEXT_DISPLAY (context);
154   VAContextID context_id;
155   VAStatus status;
156
157   context_id = GST_VAAPI_CONTEXT_ID (context);
158   GST_DEBUG ("context 0x%08x / config 0x%08x", context_id, context->va_config);
159
160   if (context_id != VA_INVALID_ID) {
161     GST_VAAPI_DISPLAY_LOCK (display);
162     status = vaDestroyContext (GST_VAAPI_DISPLAY_VADISPLAY (display),
163         context_id);
164     GST_VAAPI_DISPLAY_UNLOCK (display);
165     if (!vaapi_check_status (status, "vaDestroyContext()"))
166       GST_WARNING ("failed to destroy context 0x%08x", context_id);
167     GST_VAAPI_CONTEXT_ID (context) = VA_INVALID_ID;
168   }
169
170   if (context->va_config != VA_INVALID_ID) {
171     GST_VAAPI_DISPLAY_LOCK (display);
172     status = vaDestroyConfig (GST_VAAPI_DISPLAY_VADISPLAY (display),
173         context->va_config);
174     GST_VAAPI_DISPLAY_UNLOCK (display);
175     if (!vaapi_check_status (status, "vaDestroyConfig()"))
176       GST_WARNING ("failed to destroy config 0x%08x", context->va_config);
177     context->va_config = VA_INVALID_ID;
178   }
179
180   if (context->attribs) {
181     gst_vaapi_config_surface_attributes_free (context->attribs);
182     context->attribs = NULL;
183   }
184 }
185
186 static gboolean
187 context_ensure_surfaces (GstVaapiContext * context)
188 {
189   GstVaapiDisplay *display = GST_VAAPI_CONTEXT_DISPLAY (context);
190   const GstVaapiContextInfo *const cip = &context->info;
191   const guint num_surfaces = cip->ref_frames + SCRATCH_SURFACES_COUNT;
192   GstVaapiSurface *surface;
193   GstVideoFormat format;
194   guint i, capacity;
195
196   ensure_preferred_format (context);
197   format = context->preferred_format;
198   for (i = context->surfaces->len; i < num_surfaces; i++) {
199     if (format != GST_VIDEO_FORMAT_UNKNOWN) {
200       surface = gst_vaapi_surface_new_with_format (display, format, cip->width,
201           cip->height, 0);
202     } else {
203       surface = gst_vaapi_surface_new (display, cip->chroma_type, cip->width,
204           cip->height);
205     }
206     if (!surface)
207       return FALSE;
208     g_ptr_array_add (context->surfaces, surface);
209     if (!gst_vaapi_video_pool_add_object (context->surfaces_pool, surface))
210       return FALSE;
211   }
212
213   capacity = cip->usage == GST_VAAPI_CONTEXT_USAGE_DECODE ? 0 : num_surfaces;
214   gst_vaapi_video_pool_set_capacity (context->surfaces_pool, capacity);
215   return TRUE;
216 }
217
218 static gboolean
219 context_create_surfaces (GstVaapiContext * context)
220 {
221   const GstVaapiContextInfo *const cip = &context->info;
222   GstVaapiDisplay *const display = GST_VAAPI_CONTEXT_DISPLAY (context);
223   guint num_surfaces;
224
225   num_surfaces = cip->ref_frames + SCRATCH_SURFACES_COUNT;
226   if (!context->surfaces) {
227     context->surfaces = g_ptr_array_new_full (num_surfaces,
228         (GDestroyNotify) gst_mini_object_unref);
229     if (!context->surfaces)
230       return FALSE;
231   }
232
233   if (!context->surfaces_pool) {
234     context->surfaces_pool =
235         gst_vaapi_surface_pool_new_with_chroma_type (display, cip->chroma_type,
236         cip->width, cip->height, 0);
237
238     if (!context->surfaces_pool)
239       return FALSE;
240   }
241   return context_ensure_surfaces (context);
242 }
243
244 static gboolean
245 context_create (GstVaapiContext * context)
246 {
247   const GstVaapiContextInfo *const cip = &context->info;
248   GstVaapiDisplay *const display = GST_VAAPI_CONTEXT_DISPLAY (context);
249   VAContextID context_id;
250   VASurfaceID surface_id;
251   VASurfaceID *surfaces_data = NULL;
252   VAStatus status;
253   GArray *surfaces = NULL;
254   gboolean success = FALSE;
255   guint i;
256   gint num_surfaces = 0;
257
258   if (!context->surfaces && !context_create_surfaces (context))
259     goto cleanup;
260
261   /* Create VA surfaces list for vaCreateContext() */
262   surfaces = g_array_sized_new (FALSE,
263       FALSE, sizeof (VASurfaceID), context->surfaces->len);
264   if (!surfaces)
265     goto cleanup;
266
267   for (i = 0; i < context->surfaces->len; i++) {
268     GstVaapiSurface *const surface = g_ptr_array_index (context->surfaces, i);
269     if (!surface)
270       goto cleanup;
271     surface_id = GST_VAAPI_SURFACE_ID (surface);
272     g_array_append_val (surfaces, surface_id);
273   }
274
275   g_assert (surfaces->len == context->surfaces->len);
276
277   /* vaCreateContext() doesn't really need an array of VASurfaceIDs (see
278    * https://lists.01.org/pipermail/intel-vaapi-media/2017-July/000052.html and
279    * https://github.com/intel/libva/issues/251); pass a dummy list of valid
280    * (non-null) IDs until the signature gets updated. */
281   if (cip->usage != GST_VAAPI_CONTEXT_USAGE_DECODE) {
282     surfaces_data = (VASurfaceID *) surfaces->data;
283     num_surfaces = surfaces->len;
284   }
285
286   GST_VAAPI_DISPLAY_LOCK (display);
287   status = vaCreateContext (GST_VAAPI_DISPLAY_VADISPLAY (display),
288       context->va_config, cip->width, cip->height, VA_PROGRESSIVE,
289       surfaces_data, num_surfaces, &context_id);
290   GST_VAAPI_DISPLAY_UNLOCK (display);
291   if (!vaapi_check_status (status, "vaCreateContext()"))
292     goto cleanup;
293
294   GST_VAAPI_CONTEXT_ID (context) = context_id;
295   success = TRUE;
296
297 cleanup:
298   if (surfaces)
299     g_array_unref (surfaces);
300   return success;
301 }
302
303 static gboolean
304 config_create (GstVaapiContext * context)
305 {
306   const GstVaapiContextInfo *const cip = &context->info;
307   GstVaapiDisplay *const display = GST_VAAPI_CONTEXT_DISPLAY (context);
308   VAConfigAttrib attribs[7], *attrib;
309   VAStatus status;
310   guint value, va_chroma_format, attrib_index;
311
312   /* Reset profile and entrypoint */
313   if (cip->profile == GST_VAAPI_PROFILE_UNKNOWN
314       || cip->entrypoint == GST_VAAPI_ENTRYPOINT_INVALID)
315     goto cleanup;
316   context->va_profile = gst_vaapi_profile_get_va_profile (cip->profile);
317   context->va_entrypoint =
318       gst_vaapi_entrypoint_get_va_entrypoint (cip->entrypoint);
319
320   attrib_index = 0;
321   attrib = &attribs[attrib_index];
322   g_assert (attrib_index < G_N_ELEMENTS (attribs));
323
324   /* Validate VA surface format */
325   va_chroma_format = from_GstVaapiChromaType (cip->chroma_type);
326   if (!va_chroma_format)
327     goto cleanup;
328   attrib->type = VAConfigAttribRTFormat;
329   if (!context_get_attribute (context, attrib->type, &value))
330     goto cleanup;
331   if (!(value & va_chroma_format)) {
332     GST_ERROR ("unsupported chroma format (%s)",
333         string_of_va_chroma_format (va_chroma_format));
334     goto cleanup;
335   }
336   attrib->value = value;
337   attrib = &attribs[++attrib_index];
338   g_assert (attrib_index < G_N_ELEMENTS (attribs));
339
340   switch (cip->usage) {
341 #if GST_VAAPI_USE_ENCODERS
342     case GST_VAAPI_CONTEXT_USAGE_ENCODE:
343     {
344       const GstVaapiConfigInfoEncoder *const config = &cip->config.encoder;
345       guint va_rate_control;
346
347       /* Rate control */
348       va_rate_control = from_GstVaapiRateControl (config->rc_mode);
349       if (va_rate_control != VA_RC_NONE) {
350         attrib->type = VAConfigAttribRateControl;
351         if (!context_get_attribute (context, attrib->type, &value))
352           goto cleanup;
353
354         if ((value & va_rate_control) != va_rate_control) {
355           GST_ERROR ("unsupported %s rate control",
356               string_of_VARateControl (va_rate_control));
357           goto cleanup;
358         }
359         attrib->value = va_rate_control;
360         attrib = &attribs[++attrib_index];
361         g_assert (attrib_index < G_N_ELEMENTS (attribs));
362       }
363       /* Packed headers */
364       if (config->packed_headers) {
365         attrib->type = VAConfigAttribEncPackedHeaders;
366         if (!context_get_attribute (context, attrib->type, &value))
367           goto cleanup;
368
369         if ((value & config->packed_headers) != config->packed_headers) {
370           GST_ERROR ("unsupported packed headers 0x%08x",
371               config->packed_headers & ~(value & config->packed_headers));
372           goto cleanup;
373         }
374         attrib->value = config->packed_headers;
375         attrib = &attribs[++attrib_index];
376         g_assert (attrib_index < G_N_ELEMENTS (attribs));
377       }
378       if (cip->profile == GST_VAAPI_PROFILE_JPEG_BASELINE) {
379         attrib->type = VAConfigAttribEncJPEG;
380         if (!context_get_attribute (context, attrib->type, &value))
381           goto cleanup;
382         attrib->value = value;
383         attrib = &attribs[++attrib_index];
384         g_assert (attrib_index < G_N_ELEMENTS (attribs));
385       }
386 #if VA_CHECK_VERSION(0,39,1)
387       if (config->roi_capability) {
388         VAConfigAttribValEncROI *roi_config;
389
390         attrib->type = VAConfigAttribEncROI;
391         if (!context_get_attribute (context, attrib->type, &value))
392           goto cleanup;
393         roi_config = (VAConfigAttribValEncROI *) & value;
394         if (roi_config->bits.num_roi_regions != config->roi_num_supported) {
395           GST_ERROR ("Mismatched ROI support: number of regions supported: %d",
396               roi_config->bits.num_roi_regions);
397           goto cleanup;
398         }
399         if (config->rc_mode != GST_VAAPI_RATECONTROL_CQP
400             && VA_ROI_RC_QP_DELTA_SUPPORT (roi_config) == 0) {
401           GST_ERROR ("Mismatched ROI support:  ROI delta QP: %d",
402               VA_ROI_RC_QP_DELTA_SUPPORT (roi_config));
403           goto cleanup;
404         }
405         attrib->value = value;
406         attrib = &attribs[++attrib_index];
407         g_assert (attrib_index < G_N_ELEMENTS (attribs));
408       }
409 #endif
410       break;
411     }
412 #endif
413     default:
414       break;
415   }
416
417   GST_VAAPI_DISPLAY_LOCK (display);
418   status = vaCreateConfig (GST_VAAPI_DISPLAY_VADISPLAY (display),
419       context->va_profile, context->va_entrypoint, attribs, attrib_index,
420       &context->va_config);
421   GST_VAAPI_DISPLAY_UNLOCK (display);
422   if (!vaapi_check_status (status, "vaCreateConfig()"))
423     goto cleanup;
424
425   return TRUE;
426 cleanup:
427   GST_WARNING ("Failed to create vaConfig");
428   return FALSE;
429 }
430
431 /** Updates config for encoding. Returns %TRUE if config changed */
432 static gboolean
433 context_update_config_encoder (GstVaapiContext * context,
434     const GstVaapiConfigInfoEncoder * new_config)
435 {
436   GstVaapiConfigInfoEncoder *const config = &context->info.config.encoder;
437   gboolean config_changed = FALSE;
438
439   g_assert (context->info.usage == GST_VAAPI_CONTEXT_USAGE_ENCODE);
440
441   if (config->rc_mode != new_config->rc_mode) {
442     config->rc_mode = new_config->rc_mode;
443     config_changed = TRUE;
444   }
445
446   if (config->packed_headers != new_config->packed_headers) {
447     config->packed_headers = new_config->packed_headers;
448     config_changed = TRUE;
449   }
450
451   if (config->roi_capability != new_config->roi_capability ||
452       config->roi_num_supported != new_config->roi_num_supported) {
453     config->roi_capability = new_config->roi_capability;
454     config->roi_num_supported = new_config->roi_num_supported;
455     config_changed = TRUE;
456   }
457
458   return config_changed;
459 }
460
461 static inline void
462 gst_vaapi_context_init (GstVaapiContext * context,
463     const GstVaapiContextInfo * new_cip)
464 {
465   GstVaapiContextInfo *const cip = &context->info;
466
467   *cip = *new_cip;
468   if (!cip->chroma_type)
469     cip->chroma_type = DEFAULT_CHROMA_TYPE;
470
471   context->va_config = VA_INVALID_ID;
472   context->reset_on_resize = TRUE;
473
474   context->attribs = NULL;
475   context->preferred_format = GST_VIDEO_FORMAT_UNKNOWN;
476 }
477
478 /**
479  * gst_vaapi_context_new:
480  * @display: a #GstVaapiDisplay
481  * @cip: a pointer to the #GstVaapiContextInfo
482  *
483  * Creates a new #GstVaapiContext with the configuration specified by
484  * @cip, thus including profile, entry-point, encoded size and maximum
485  * number of reference frames reported by the bitstream.
486  *
487  * Return value: the newly allocated #GstVaapiContext object
488  */
489 GstVaapiContext *
490 gst_vaapi_context_new (GstVaapiDisplay * display,
491     const GstVaapiContextInfo * cip)
492 {
493   GstVaapiContext *context;
494
495   g_return_val_if_fail (display, NULL);
496
497   _init_vaapi_context_debug ();
498
499   if (cip->profile == GST_VAAPI_PROFILE_UNKNOWN
500       || cip->entrypoint == GST_VAAPI_ENTRYPOINT_INVALID)
501     return NULL;
502
503   context = g_slice_new (GstVaapiContext);
504   if (!context)
505     return NULL;
506
507   GST_VAAPI_CONTEXT_DISPLAY (context) = gst_object_ref (display);
508   GST_VAAPI_CONTEXT_ID (context) = VA_INVALID_ID;
509   g_atomic_int_set (&context->ref_count, 1);
510   context->surfaces = NULL;
511   context->surfaces_pool = NULL;
512
513   gst_vaapi_context_init (context, cip);
514
515   if (!config_create (context))
516     goto error;
517
518   /* this means we don't want to create a VAcontext */
519   if (cip->width == 0 && cip->height == 0)
520     goto done;
521
522   /* this is not valid */
523   if (cip->width == 0 || cip->height == 0)
524     goto error;
525
526   if (!context_create (context))
527     goto error;
528
529 done:
530   GST_DEBUG ("context 0x%08" G_GSIZE_MODIFIER "x / config 0x%08x",
531       GST_VAAPI_CONTEXT_ID (context), context->va_config);
532   return context;
533
534   /* ERRORS */
535 error:
536   {
537     gst_vaapi_context_unref (context);
538     return NULL;
539   }
540 }
541
542 /**
543  * gst_vaapi_context_reset:
544  * @context: a #GstVaapiContext
545  * @new_cip: a pointer to the new #GstVaapiContextInfo details
546  *
547  * Resets @context to the configuration specified by @new_cip, thus
548  * including profile, entry-point, encoded size and maximum number of
549  * reference frames reported by the bitstream.
550  *
551  * Return value: %TRUE on success
552  */
553 gboolean
554 gst_vaapi_context_reset (GstVaapiContext * context,
555     const GstVaapiContextInfo * new_cip)
556 {
557   GstVaapiContextInfo *const cip = &context->info;
558   gboolean reset_surfaces = FALSE, reset_config = FALSE;
559   gboolean grow_surfaces = FALSE;
560   GstVaapiChromaType chroma_type;
561
562   if (new_cip->profile == GST_VAAPI_PROFILE_UNKNOWN
563       || new_cip->entrypoint == GST_VAAPI_ENTRYPOINT_INVALID)
564     return FALSE;
565
566   chroma_type = new_cip->chroma_type ? new_cip->chroma_type :
567       DEFAULT_CHROMA_TYPE;
568   if (cip->chroma_type != chroma_type) {
569     cip->chroma_type = chroma_type;
570     reset_surfaces = TRUE;
571   }
572
573   if (cip->width != new_cip->width || cip->height != new_cip->height) {
574     cip->width = new_cip->width;
575     cip->height = new_cip->height;
576     reset_surfaces = TRUE;
577   }
578
579   if (cip->profile != new_cip->profile ||
580       cip->entrypoint != new_cip->entrypoint) {
581     cip->profile = new_cip->profile;
582     cip->entrypoint = new_cip->entrypoint;
583     reset_config = TRUE;
584   }
585
586   if (cip->ref_frames < new_cip->ref_frames) {
587     cip->ref_frames = new_cip->ref_frames;
588     grow_surfaces = TRUE;
589   }
590
591   if (cip->usage != new_cip->usage) {
592     cip->usage = new_cip->usage;
593     reset_config = TRUE;
594     memcpy (&cip->config, &new_cip->config, sizeof (cip->config));
595   } else if (new_cip->usage == GST_VAAPI_CONTEXT_USAGE_ENCODE) {
596     if (context_update_config_encoder (context, &new_cip->config.encoder))
597       reset_config = TRUE;
598   } else if (new_cip->usage == GST_VAAPI_CONTEXT_USAGE_DECODE) {
599     if ((reset_surfaces && context->reset_on_resize) || grow_surfaces)
600       reset_config = TRUE;
601   }
602
603   if (reset_surfaces)
604     context_destroy_surfaces (context);
605   if (reset_config)
606     context_destroy (context);
607
608   if (reset_config && !(config_create (context) && context_create (context)))
609     return FALSE;
610   if (reset_surfaces && !context_create_surfaces (context))
611     return FALSE;
612   else if (grow_surfaces && !context_ensure_surfaces (context))
613     return FALSE;
614   return TRUE;
615 }
616
617 /**
618  * gst_vaapi_context_get_id:
619  * @context: a #GstVaapiContext
620  *
621  * Returns the underlying VAContextID of the @context.
622  *
623  * Return value: the underlying VA context id
624  */
625 GstVaapiID
626 gst_vaapi_context_get_id (GstVaapiContext * context)
627 {
628   g_return_val_if_fail (context != NULL, VA_INVALID_ID);
629
630   return GST_VAAPI_CONTEXT_ID (context);
631 }
632
633 /**
634  * gst_vaapi_context_get_surface_proxy:
635  * @context: a #GstVaapiContext
636  *
637  * Acquires a free surface, wrapped into a #GstVaapiSurfaceProxy. The
638  * returned surface will be automatically released when the proxy is
639  * destroyed. So, it is enough to call gst_vaapi_surface_proxy_unref()
640  * after usage.
641  *
642  * This function returns %NULL if there is no free surface available
643  * in the pool. The surfaces are pre-allocated during context creation
644  * though.
645  *
646  * Return value: a free surface, or %NULL if none is available
647  */
648 GstVaapiSurfaceProxy *
649 gst_vaapi_context_get_surface_proxy (GstVaapiContext * context)
650 {
651   g_return_val_if_fail (context != NULL, NULL);
652
653   return
654       gst_vaapi_surface_proxy_new_from_pool (GST_VAAPI_SURFACE_POOL
655       (context->surfaces_pool));
656 }
657
658 /**
659  * gst_vaapi_context_get_surface_count:
660  * @context: a #GstVaapiContext
661  *
662  * Retrieves the number of free surfaces left in the pool.
663  *
664  * Return value: the number of free surfaces available in the pool
665  */
666 guint
667 gst_vaapi_context_get_surface_count (GstVaapiContext * context)
668 {
669   g_return_val_if_fail (context != NULL, 0);
670
671   if (gst_vaapi_video_pool_get_capacity (context->surfaces_pool) == 0)
672     return G_MAXUINT;
673   return gst_vaapi_video_pool_get_size (context->surfaces_pool);
674 }
675
676 /**
677  * gst_vaapi_context_reset_on_resize:
678  * @context: a #GstVaapiContext
679  * @reset_on_resize: Should the context be reset on size change
680  *
681  * Sets whether the underlying context should be reset when a size change
682  * happens. The proper setting for this is codec dependent.
683  */
684 void
685 gst_vaapi_context_reset_on_resize (GstVaapiContext * context,
686     gboolean reset_on_resize)
687 {
688   g_return_if_fail (context != NULL);
689
690   context->reset_on_resize = reset_on_resize;
691 }
692
693 /**
694  * gst_vaapi_context_get_surface_formats:
695  * @context: a #GstVaapiContext
696  *
697  * Determines the set of supported formats by the surfaces associated
698  * to @context. The caller owns an extra reference of the resulting
699  * array of #GstVideoFormat elements, so it shall be released with
700  * g_array_unref after usage.
701  *
702  * Return value: (transfer full): the set of target formats supported
703  * by the surfaces in @context.
704  */
705 GArray *
706 gst_vaapi_context_get_surface_formats (GstVaapiContext * context)
707 {
708   g_return_val_if_fail (context, NULL);
709
710   if (!ensure_attributes (context))
711     return NULL;
712
713   if (context->attribs->formats)
714     return g_array_ref (context->attribs->formats);
715   return NULL;
716 }
717
718 /**
719  * gst_vaapi_context_get_surface_attributes:
720  * @context: a #GstVaapiContext
721  * @out_attribs: an allocated #GstVaapiConfigSurfaceAttributes
722  *
723  * Copy context's surface restrictions to @out_attribs, EXCEPT the
724  * color formats. Use gst_vaapi_context_get_surface_formats() to get
725  * them.
726  *
727  * Returns: %TRUE if the attributes were extracted and copied; %FALSE,
728  * otherwise
729  **/
730 gboolean
731 gst_vaapi_context_get_surface_attributes (GstVaapiContext * context,
732     GstVaapiConfigSurfaceAttributes * out_attribs)
733 {
734   g_return_val_if_fail (context, FALSE);
735
736   if (!ensure_attributes (context))
737     return FALSE;
738
739   if (out_attribs) {
740     out_attribs->min_width = context->attribs->min_width;
741     out_attribs->min_height = context->attribs->min_height;
742     out_attribs->max_width = context->attribs->max_width;
743     out_attribs->max_height = context->attribs->max_height;
744     out_attribs->mem_types = context->attribs->mem_types;
745     out_attribs->formats = NULL;
746   }
747
748   return TRUE;
749 }
750
751 /**
752  * gst_vaapi_context_ref:
753  * @context: a #GstVaapiContext
754  *
755  * Atomically increases the reference count of the given @context by one.
756  *
757  * Returns: The same @context argument
758  */
759 GstVaapiContext *
760 gst_vaapi_context_ref (GstVaapiContext * context)
761 {
762   g_return_val_if_fail (context != NULL, NULL);
763
764   g_atomic_int_inc (&context->ref_count);
765
766   return context;
767 }
768
769 /**
770  * gst_vaapi_context_unref:
771  * @context: a #GstVaapiContext
772  *
773  * Atomically decreases the reference count of the @context by one. If
774  * the reference count reaches zero, the object will be free'd.
775  */
776 void
777 gst_vaapi_context_unref (GstVaapiContext * context)
778 {
779   g_return_if_fail (context != NULL);
780   g_return_if_fail (context->ref_count > 0);
781
782   if (g_atomic_int_dec_and_test (&context->ref_count)) {
783     context_destroy (context);
784     context_destroy_surfaces (context);
785     gst_vaapi_display_replace (&context->display, NULL);
786     g_slice_free (GstVaapiContext, context);
787   }
788 }