2 * gstvaapicontext.c - VA context abstraction
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>
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.
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.
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
26 * SECTION:gstvaapicontext
27 * @short_description: VA context abstraction
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"
40 /* Define default VA surface chroma format to YUV 4:2:0 */
41 #define DEFAULT_CHROMA_TYPE (GST_VAAPI_CHROMA_TYPE_YUV420)
43 /* Number of scratch surfaces beyond those used as reference */
44 #define SCRATCH_SURFACES_COUNT (4)
46 /* Debug category for GstVaapiContext */
47 GST_DEBUG_CATEGORY (gst_debug_vaapi_context);
48 #define GST_CAT_DEFAULT gst_debug_vaapi_context
51 _init_vaapi_context_debug (void)
53 #ifndef GST_DISABLE_GST_DEBUG
54 static gsize _init = 0;
56 if (g_once_init_enter (&_init)) {
57 GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi_context, "vaapicontext", 0,
59 g_once_init_leave (&_init, 1);
64 static inline gboolean
65 _context_is_broken_jpeg_decoder (GstVaapiContext * context)
67 GstVaapiDisplay *const display = GST_VAAPI_CONTEXT_DISPLAY (context);
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));
76 ensure_attributes (GstVaapiContext * context)
78 if (G_LIKELY (context->attribs))
82 gst_vaapi_config_surface_attributes_get (GST_VAAPI_CONTEXT_DISPLAY
83 (context), context->va_config);
85 if (!context->attribs)
88 if (_context_is_broken_jpeg_decoder (context)) {
89 GstVideoFormat fmt = GST_VIDEO_FORMAT_NV12;
90 g_array_prepend_val (context->attribs->formats, fmt);
92 context->attribs->mem_types &= ~VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
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 */
102 ensure_preferred_format (GstVaapiContext * context)
104 const GstVaapiContextInfo *const cip = &context->info;
108 if (context->preferred_format != GST_VIDEO_FORMAT_UNKNOWN)
111 if (_context_is_broken_jpeg_decoder (context))
114 if (!ensure_attributes (context) || !context->attribs->formats)
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;
129 static inline gboolean
130 context_get_attribute (GstVaapiContext * context, VAConfigAttribType type,
131 guint * out_value_ptr)
133 return gst_vaapi_get_config_attribute (GST_VAAPI_CONTEXT_DISPLAY (context),
134 context->va_profile, context->va_entrypoint, type, out_value_ptr);
138 context_destroy_surfaces (GstVaapiContext * context)
140 if (context->surfaces) {
141 g_ptr_array_unref (context->surfaces);
142 context->surfaces = NULL;
145 context->preferred_format = GST_VIDEO_FORMAT_UNKNOWN;
147 gst_vaapi_video_pool_replace (&context->surfaces_pool, NULL);
151 context_destroy (GstVaapiContext * context)
153 GstVaapiDisplay *const display = GST_VAAPI_CONTEXT_DISPLAY (context);
154 VAContextID context_id;
157 context_id = GST_VAAPI_CONTEXT_ID (context);
158 GST_DEBUG ("context 0x%08x / config 0x%08x", context_id, context->va_config);
160 if (context_id != VA_INVALID_ID) {
161 GST_VAAPI_DISPLAY_LOCK (display);
162 status = vaDestroyContext (GST_VAAPI_DISPLAY_VADISPLAY (display),
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;
170 if (context->va_config != VA_INVALID_ID) {
171 GST_VAAPI_DISPLAY_LOCK (display);
172 status = vaDestroyConfig (GST_VAAPI_DISPLAY_VADISPLAY (display),
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;
180 if (context->attribs) {
181 gst_vaapi_config_surface_attributes_free (context->attribs);
182 context->attribs = NULL;
187 context_ensure_surfaces (GstVaapiContext * context)
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;
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,
203 surface = gst_vaapi_surface_new (display, cip->chroma_type, cip->width,
208 g_ptr_array_add (context->surfaces, surface);
209 if (!gst_vaapi_video_pool_add_object (context->surfaces_pool, surface))
213 capacity = cip->usage == GST_VAAPI_CONTEXT_USAGE_DECODE ? 0 : num_surfaces;
214 gst_vaapi_video_pool_set_capacity (context->surfaces_pool, capacity);
219 context_create_surfaces (GstVaapiContext * context)
221 const GstVaapiContextInfo *const cip = &context->info;
222 GstVaapiDisplay *const display = GST_VAAPI_CONTEXT_DISPLAY (context);
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)
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);
238 if (!context->surfaces_pool)
241 return context_ensure_surfaces (context);
245 context_create (GstVaapiContext * context)
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;
253 GArray *surfaces = NULL;
254 gboolean success = FALSE;
256 gint num_surfaces = 0;
258 if (!context->surfaces && !context_create_surfaces (context))
261 /* Create VA surfaces list for vaCreateContext() */
262 surfaces = g_array_sized_new (FALSE,
263 FALSE, sizeof (VASurfaceID), context->surfaces->len);
267 for (i = 0; i < context->surfaces->len; i++) {
268 GstVaapiSurface *const surface = g_ptr_array_index (context->surfaces, i);
271 surface_id = GST_VAAPI_SURFACE_ID (surface);
272 g_array_append_val (surfaces, surface_id);
275 g_assert (surfaces->len == context->surfaces->len);
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;
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()"))
294 GST_VAAPI_CONTEXT_ID (context) = context_id;
299 g_array_unref (surfaces);
304 config_create (GstVaapiContext * context)
306 const GstVaapiContextInfo *const cip = &context->info;
307 GstVaapiDisplay *const display = GST_VAAPI_CONTEXT_DISPLAY (context);
308 VAConfigAttrib attribs[7], *attrib;
310 guint value, va_chroma_format, attrib_index;
312 /* Reset profile and entrypoint */
313 if (cip->profile == GST_VAAPI_PROFILE_UNKNOWN
314 || cip->entrypoint == GST_VAAPI_ENTRYPOINT_INVALID)
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);
321 attrib = &attribs[attrib_index];
322 g_assert (attrib_index < G_N_ELEMENTS (attribs));
324 /* Validate VA surface format */
325 va_chroma_format = from_GstVaapiChromaType (cip->chroma_type);
326 if (!va_chroma_format)
328 attrib->type = VAConfigAttribRTFormat;
329 if (!context_get_attribute (context, attrib->type, &value))
331 if (!(value & va_chroma_format)) {
332 GST_ERROR ("unsupported chroma format (%s)",
333 string_of_va_chroma_format (va_chroma_format));
336 attrib->value = value;
337 attrib = &attribs[++attrib_index];
338 g_assert (attrib_index < G_N_ELEMENTS (attribs));
340 switch (cip->usage) {
341 #if GST_VAAPI_USE_ENCODERS
342 case GST_VAAPI_CONTEXT_USAGE_ENCODE:
344 const GstVaapiConfigInfoEncoder *const config = &cip->config.encoder;
345 guint va_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))
354 if ((value & va_rate_control) != va_rate_control) {
355 GST_ERROR ("unsupported %s rate control",
356 string_of_VARateControl (va_rate_control));
359 attrib->value = va_rate_control;
360 attrib = &attribs[++attrib_index];
361 g_assert (attrib_index < G_N_ELEMENTS (attribs));
364 if (config->packed_headers) {
365 attrib->type = VAConfigAttribEncPackedHeaders;
366 if (!context_get_attribute (context, attrib->type, &value))
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));
374 attrib->value = config->packed_headers;
375 attrib = &attribs[++attrib_index];
376 g_assert (attrib_index < G_N_ELEMENTS (attribs));
378 if (cip->profile == GST_VAAPI_PROFILE_JPEG_BASELINE) {
379 attrib->type = VAConfigAttribEncJPEG;
380 if (!context_get_attribute (context, attrib->type, &value))
382 attrib->value = value;
383 attrib = &attribs[++attrib_index];
384 g_assert (attrib_index < G_N_ELEMENTS (attribs));
386 #if VA_CHECK_VERSION(0,39,1)
387 if (config->roi_capability) {
388 VAConfigAttribValEncROI *roi_config;
390 attrib->type = VAConfigAttribEncROI;
391 if (!context_get_attribute (context, attrib->type, &value))
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);
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));
405 attrib->value = value;
406 attrib = &attribs[++attrib_index];
407 g_assert (attrib_index < G_N_ELEMENTS (attribs));
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()"))
427 GST_WARNING ("Failed to create vaConfig");
431 /** Updates config for encoding. Returns %TRUE if config changed */
433 context_update_config_encoder (GstVaapiContext * context,
434 const GstVaapiConfigInfoEncoder * new_config)
436 GstVaapiConfigInfoEncoder *const config = &context->info.config.encoder;
437 gboolean config_changed = FALSE;
439 g_assert (context->info.usage == GST_VAAPI_CONTEXT_USAGE_ENCODE);
441 if (config->rc_mode != new_config->rc_mode) {
442 config->rc_mode = new_config->rc_mode;
443 config_changed = TRUE;
446 if (config->packed_headers != new_config->packed_headers) {
447 config->packed_headers = new_config->packed_headers;
448 config_changed = TRUE;
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;
458 return config_changed;
462 gst_vaapi_context_init (GstVaapiContext * context,
463 const GstVaapiContextInfo * new_cip)
465 GstVaapiContextInfo *const cip = &context->info;
468 if (!cip->chroma_type)
469 cip->chroma_type = DEFAULT_CHROMA_TYPE;
471 context->va_config = VA_INVALID_ID;
472 context->reset_on_resize = TRUE;
474 context->attribs = NULL;
475 context->preferred_format = GST_VIDEO_FORMAT_UNKNOWN;
479 * gst_vaapi_context_new:
480 * @display: a #GstVaapiDisplay
481 * @cip: a pointer to the #GstVaapiContextInfo
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.
487 * Return value: the newly allocated #GstVaapiContext object
490 gst_vaapi_context_new (GstVaapiDisplay * display,
491 const GstVaapiContextInfo * cip)
493 GstVaapiContext *context;
495 g_return_val_if_fail (display, NULL);
497 _init_vaapi_context_debug ();
499 if (cip->profile == GST_VAAPI_PROFILE_UNKNOWN
500 || cip->entrypoint == GST_VAAPI_ENTRYPOINT_INVALID)
503 context = g_slice_new (GstVaapiContext);
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;
513 gst_vaapi_context_init (context, cip);
515 if (!config_create (context))
518 /* this means we don't want to create a VAcontext */
519 if (cip->width == 0 && cip->height == 0)
522 /* this is not valid */
523 if (cip->width == 0 || cip->height == 0)
526 if (!context_create (context))
530 GST_DEBUG ("context 0x%08" G_GSIZE_MODIFIER "x / config 0x%08x",
531 GST_VAAPI_CONTEXT_ID (context), context->va_config);
537 gst_vaapi_context_unref (context);
543 * gst_vaapi_context_reset:
544 * @context: a #GstVaapiContext
545 * @new_cip: a pointer to the new #GstVaapiContextInfo details
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.
551 * Return value: %TRUE on success
554 gst_vaapi_context_reset (GstVaapiContext * context,
555 const GstVaapiContextInfo * new_cip)
557 GstVaapiContextInfo *const cip = &context->info;
558 gboolean reset_surfaces = FALSE, reset_config = FALSE;
559 gboolean grow_surfaces = FALSE;
560 GstVaapiChromaType chroma_type;
562 if (new_cip->profile == GST_VAAPI_PROFILE_UNKNOWN
563 || new_cip->entrypoint == GST_VAAPI_ENTRYPOINT_INVALID)
566 chroma_type = new_cip->chroma_type ? new_cip->chroma_type :
568 if (cip->chroma_type != chroma_type) {
569 cip->chroma_type = chroma_type;
570 reset_surfaces = TRUE;
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;
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;
586 if (cip->ref_frames < new_cip->ref_frames) {
587 cip->ref_frames = new_cip->ref_frames;
588 grow_surfaces = TRUE;
591 if (cip->usage != new_cip->usage) {
592 cip->usage = new_cip->usage;
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))
598 } else if (new_cip->usage == GST_VAAPI_CONTEXT_USAGE_DECODE) {
599 if ((reset_surfaces && context->reset_on_resize) || grow_surfaces)
604 context_destroy_surfaces (context);
606 context_destroy (context);
608 if (reset_config && !(config_create (context) && context_create (context)))
610 if (reset_surfaces && !context_create_surfaces (context))
612 else if (grow_surfaces && !context_ensure_surfaces (context))
618 * gst_vaapi_context_get_id:
619 * @context: a #GstVaapiContext
621 * Returns the underlying VAContextID of the @context.
623 * Return value: the underlying VA context id
626 gst_vaapi_context_get_id (GstVaapiContext * context)
628 g_return_val_if_fail (context != NULL, VA_INVALID_ID);
630 return GST_VAAPI_CONTEXT_ID (context);
634 * gst_vaapi_context_get_surface_proxy:
635 * @context: a #GstVaapiContext
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()
642 * This function returns %NULL if there is no free surface available
643 * in the pool. The surfaces are pre-allocated during context creation
646 * Return value: a free surface, or %NULL if none is available
648 GstVaapiSurfaceProxy *
649 gst_vaapi_context_get_surface_proxy (GstVaapiContext * context)
651 g_return_val_if_fail (context != NULL, NULL);
654 gst_vaapi_surface_proxy_new_from_pool (GST_VAAPI_SURFACE_POOL
655 (context->surfaces_pool));
659 * gst_vaapi_context_get_surface_count:
660 * @context: a #GstVaapiContext
662 * Retrieves the number of free surfaces left in the pool.
664 * Return value: the number of free surfaces available in the pool
667 gst_vaapi_context_get_surface_count (GstVaapiContext * context)
669 g_return_val_if_fail (context != NULL, 0);
671 if (gst_vaapi_video_pool_get_capacity (context->surfaces_pool) == 0)
673 return gst_vaapi_video_pool_get_size (context->surfaces_pool);
677 * gst_vaapi_context_reset_on_resize:
678 * @context: a #GstVaapiContext
679 * @reset_on_resize: Should the context be reset on size change
681 * Sets whether the underlying context should be reset when a size change
682 * happens. The proper setting for this is codec dependent.
685 gst_vaapi_context_reset_on_resize (GstVaapiContext * context,
686 gboolean reset_on_resize)
688 g_return_if_fail (context != NULL);
690 context->reset_on_resize = reset_on_resize;
694 * gst_vaapi_context_get_surface_formats:
695 * @context: a #GstVaapiContext
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.
702 * Return value: (transfer full): the set of target formats supported
703 * by the surfaces in @context.
706 gst_vaapi_context_get_surface_formats (GstVaapiContext * context)
708 g_return_val_if_fail (context, NULL);
710 if (!ensure_attributes (context))
713 if (context->attribs->formats)
714 return g_array_ref (context->attribs->formats);
719 * gst_vaapi_context_get_surface_attributes:
720 * @context: a #GstVaapiContext
721 * @out_attribs: an allocated #GstVaapiConfigSurfaceAttributes
723 * Copy context's surface restrictions to @out_attribs, EXCEPT the
724 * color formats. Use gst_vaapi_context_get_surface_formats() to get
727 * Returns: %TRUE if the attributes were extracted and copied; %FALSE,
731 gst_vaapi_context_get_surface_attributes (GstVaapiContext * context,
732 GstVaapiConfigSurfaceAttributes * out_attribs)
734 g_return_val_if_fail (context, FALSE);
736 if (!ensure_attributes (context))
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;
752 * gst_vaapi_context_ref:
753 * @context: a #GstVaapiContext
755 * Atomically increases the reference count of the given @context by one.
757 * Returns: The same @context argument
760 gst_vaapi_context_ref (GstVaapiContext * context)
762 g_return_val_if_fail (context != NULL, NULL);
764 g_atomic_int_inc (&context->ref_count);
770 * gst_vaapi_context_unref:
771 * @context: a #GstVaapiContext
773 * Atomically decreases the reference count of the @context by one. If
774 * the reference count reaches zero, the object will be free'd.
777 gst_vaapi_context_unref (GstVaapiContext * context)
779 g_return_if_fail (context != NULL);
780 g_return_if_fail (context->ref_count > 0);
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);