58026d364b18ac732f03f4e936c5049c4f66afef
[platform/upstream/gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapisurface.c
1 /*
2  *  gstvaapisurface.c - VA surface abstraction
3  *
4  *  gstreamer-vaapi (C) 2010 Splitted-Desktop Systems
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
19  */
20
21 /**
22  * SECTION:gstvaapisurface
23  * @short_description: VA surface abstraction
24  */
25
26 #include "config.h"
27 #include "gstvaapicompat.h"
28 #include "gstvaapiutils.h"
29 #include "gstvaapisurface.h"
30 #include "gstvaapiimage.h"
31 #include "gstvaapiobject_priv.h"
32
33 #define DEBUG 1
34 #include "gstvaapidebug.h"
35
36 G_DEFINE_TYPE(GstVaapiSurface, gst_vaapi_surface, GST_VAAPI_TYPE_OBJECT);
37
38 #define GST_VAAPI_SURFACE_GET_PRIVATE(obj)                      \
39     (G_TYPE_INSTANCE_GET_PRIVATE((obj),                         \
40                                  GST_VAAPI_TYPE_SURFACE,        \
41                                  GstVaapiSurfacePrivate))
42
43 struct _GstVaapiSurfacePrivate {
44     guint               width;
45     guint               height;
46     GstVaapiChromaType  chroma_type;
47     GPtrArray          *subpictures;
48 };
49
50 enum {
51     PROP_0,
52
53     PROP_WIDTH,
54     PROP_HEIGHT,
55     PROP_CHROMA_TYPE
56 };
57
58 static gboolean
59 _gst_vaapi_surface_associate_subpicture(
60     GstVaapiSurface         *surface,
61     GstVaapiSubpicture      *subpicture,
62     const GstVaapiRectangle *src_rect,
63     const GstVaapiRectangle *dst_rect
64 );
65
66 static gboolean
67 _gst_vaapi_surface_deassociate_subpicture(
68     GstVaapiSurface    *surface,
69     GstVaapiSubpicture *subpicture
70 );
71
72 static void
73 destroy_subpicture_cb(gpointer subpicture, gpointer surface)
74 {
75     _gst_vaapi_surface_deassociate_subpicture(surface, subpicture);
76     g_object_unref(subpicture);
77 }
78
79 static void
80 gst_vaapi_surface_destroy(GstVaapiSurface *surface)
81 {
82     GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(surface);
83     GstVaapiSurfacePrivate * const priv = surface->priv;
84     VASurfaceID surface_id;
85     VAStatus status;
86
87     surface_id = GST_VAAPI_OBJECT_ID(surface);
88     GST_DEBUG("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(surface_id));
89
90     if (priv->subpictures) {
91         g_ptr_array_foreach(priv->subpictures, destroy_subpicture_cb, surface);
92         g_ptr_array_free(priv->subpictures, TRUE);
93         priv->subpictures = NULL;
94     }
95
96     if (surface_id != VA_INVALID_SURFACE) {
97         GST_VAAPI_DISPLAY_LOCK(display);
98         status = vaDestroySurfaces(
99             GST_VAAPI_DISPLAY_VADISPLAY(display),
100             &surface_id, 1
101         );
102         GST_VAAPI_DISPLAY_UNLOCK(display);
103         if (!vaapi_check_status(status, "vaDestroySurfaces()"))
104             g_warning("failed to destroy surface %" GST_VAAPI_ID_FORMAT,
105                       GST_VAAPI_ID_ARGS(surface_id));
106         GST_VAAPI_OBJECT_ID(surface) = VA_INVALID_SURFACE;
107     }
108 }
109
110 static gboolean
111 gst_vaapi_surface_create(GstVaapiSurface *surface)
112 {
113     GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(surface);
114     GstVaapiSurfacePrivate * const priv = surface->priv;
115     VASurfaceID surface_id;
116     VAStatus status;
117     guint format;
118
119     switch (priv->chroma_type) {
120     case GST_VAAPI_CHROMA_TYPE_YUV420:
121         format = VA_RT_FORMAT_YUV420;
122         break;
123     case GST_VAAPI_CHROMA_TYPE_YUV422:
124         format = VA_RT_FORMAT_YUV422;
125         break;
126     case GST_VAAPI_CHROMA_TYPE_YUV444:
127         format = VA_RT_FORMAT_YUV444;
128         break;
129     default:
130         GST_DEBUG("unsupported chroma-type %u\n", priv->chroma_type);
131         return FALSE;
132     }
133
134     GST_VAAPI_DISPLAY_LOCK(display);
135     status = vaCreateSurfaces(
136         GST_VAAPI_DISPLAY_VADISPLAY(display),
137         priv->width,
138         priv->height,
139         format,
140         1, &surface_id
141     );
142     GST_VAAPI_DISPLAY_UNLOCK(display);
143     if (!vaapi_check_status(status, "vaCreateSurfaces()"))
144         return FALSE;
145
146     GST_DEBUG("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(surface_id));
147     GST_VAAPI_OBJECT_ID(surface) = surface_id;
148     return TRUE;
149 }
150
151 static void
152 gst_vaapi_surface_finalize(GObject *object)
153 {
154     gst_vaapi_surface_destroy(GST_VAAPI_SURFACE(object));
155
156     G_OBJECT_CLASS(gst_vaapi_surface_parent_class)->finalize(object);
157 }
158
159 static void
160 gst_vaapi_surface_set_property(
161     GObject      *object,
162     guint         prop_id,
163     const GValue *value,
164     GParamSpec   *pspec
165 )
166 {
167     GstVaapiSurface        * const surface = GST_VAAPI_SURFACE(object);
168     GstVaapiSurfacePrivate * const priv    = surface->priv;
169
170     switch (prop_id) {
171     case PROP_WIDTH:
172         priv->width = g_value_get_uint(value);
173         break;
174     case PROP_HEIGHT:
175         priv->height = g_value_get_uint(value);
176         break;
177     case PROP_CHROMA_TYPE:
178         priv->chroma_type = g_value_get_uint(value);
179         break;
180     default:
181         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
182         break;
183     }
184 }
185
186 static void
187 gst_vaapi_surface_get_property(
188     GObject    *object,
189     guint       prop_id,
190     GValue     *value,
191     GParamSpec *pspec
192 )
193 {
194     GstVaapiSurface * const surface = GST_VAAPI_SURFACE(object);
195
196     switch (prop_id) {
197     case PROP_WIDTH:
198         g_value_set_uint(value, gst_vaapi_surface_get_width(surface));
199         break;
200     case PROP_HEIGHT:
201         g_value_set_uint(value, gst_vaapi_surface_get_height(surface));
202         break;
203     case PROP_CHROMA_TYPE:
204         g_value_set_uint(value, gst_vaapi_surface_get_chroma_type(surface));
205         break;
206     default:
207         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
208         break;
209     }
210 }
211
212 static void
213 gst_vaapi_surface_constructed(GObject *object)
214 {
215     GstVaapiSurface * const surface = GST_VAAPI_SURFACE(object);
216     GObjectClass *parent_class;
217
218     gst_vaapi_surface_create(surface);
219
220     parent_class = G_OBJECT_CLASS(gst_vaapi_surface_parent_class);
221     if (parent_class->constructed)
222         parent_class->constructed(object);
223 }
224
225 static void
226 gst_vaapi_surface_class_init(GstVaapiSurfaceClass *klass)
227 {
228     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
229
230     g_type_class_add_private(klass, sizeof(GstVaapiSurfacePrivate));
231
232     object_class->finalize     = gst_vaapi_surface_finalize;
233     object_class->set_property = gst_vaapi_surface_set_property;
234     object_class->get_property = gst_vaapi_surface_get_property;
235     object_class->constructed  = gst_vaapi_surface_constructed;
236
237     g_object_class_install_property
238         (object_class,
239          PROP_WIDTH,
240          g_param_spec_uint("width",
241                            "Width",
242                            "The width of the surface",
243                            0, G_MAXINT32, 0,
244                            G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
245
246     g_object_class_install_property
247         (object_class,
248          PROP_HEIGHT,
249          g_param_spec_uint("height",
250                            "Height",
251                            "The height of the surface",
252                            0, G_MAXINT32, 0,
253                            G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
254
255     g_object_class_install_property
256         (object_class,
257          PROP_CHROMA_TYPE,
258          g_param_spec_uint("chroma-type",
259                            "Chroma type",
260                            "The chroma type of the surface",
261                            0, G_MAXUINT32, 0,
262                            G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
263 }
264
265 static void
266 gst_vaapi_surface_init(GstVaapiSurface *surface)
267 {
268     GstVaapiSurfacePrivate *priv = GST_VAAPI_SURFACE_GET_PRIVATE(surface);
269
270     surface->priv       = priv;
271     priv->width         = 0;
272     priv->height        = 0;
273     priv->chroma_type   = 0;
274     priv->subpictures   = NULL;
275 }
276
277 /**
278  * gst_vaapi_surface_new:
279  * @display: a #GstVaapiDisplay
280  * @chroma_type: the surface chroma format
281  * @width: the requested surface width
282  * @height: the requested surface height
283  *
284  * Creates a new #GstVaapiSurface with the specified chroma format and
285  * dimensions.
286  *
287  * Return value: the newly allocated #GstVaapiSurface object
288  */
289 GstVaapiSurface *
290 gst_vaapi_surface_new(
291     GstVaapiDisplay    *display,
292     GstVaapiChromaType  chroma_type,
293     guint               width,
294     guint               height
295 )
296 {
297     GST_DEBUG("size %ux%u, chroma type 0x%x", width, height, chroma_type);
298
299     return g_object_new(GST_VAAPI_TYPE_SURFACE,
300                         "display",      display,
301                         "id",           GST_VAAPI_ID(VA_INVALID_ID),
302                         "width",        width,
303                         "height",       height,
304                         "chroma-type",  chroma_type,
305                         NULL);
306 }
307
308 /**
309  * gst_vaapi_surface_get_chroma_type:
310  * @surface: a #GstVaapiSurface
311  *
312  * Returns the #GstVaapiChromaType the @surface was created with.
313  *
314  * Return value: the #GstVaapiChromaType
315  */
316 GstVaapiChromaType
317 gst_vaapi_surface_get_chroma_type(GstVaapiSurface *surface)
318 {
319     g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), 0);
320
321     return surface->priv->chroma_type;
322 }
323
324 /**
325  * gst_vaapi_surface_get_width:
326  * @surface: a #GstVaapiSurface
327  *
328  * Returns the @surface width.
329  *
330  * Return value: the surface width, in pixels
331  */
332 guint
333 gst_vaapi_surface_get_width(GstVaapiSurface *surface)
334 {
335     g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), 0);
336
337     return surface->priv->width;
338 }
339
340 /**
341  * gst_vaapi_surface_get_height:
342  * @surface: a #GstVaapiSurface
343  *
344  * Returns the @surface height.
345  *
346  * Return value: the surface height, in pixels.
347  */
348 guint
349 gst_vaapi_surface_get_height(GstVaapiSurface *surface)
350 {
351     g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), 0);
352
353     return surface->priv->height;
354 }
355
356 /**
357  * gst_vaapi_surface_get_size:
358  * @surface: a #GstVaapiSurface
359  * @pwidth: return location for the width, or %NULL
360  * @pheight: return location for the height, or %NULL
361  *
362  * Retrieves the dimensions of a #GstVaapiSurface.
363  */
364 void
365 gst_vaapi_surface_get_size(
366     GstVaapiSurface *surface,
367     guint           *pwidth,
368     guint           *pheight
369 )
370 {
371     g_return_if_fail(GST_VAAPI_IS_SURFACE(surface));
372
373     if (pwidth)
374         *pwidth = gst_vaapi_surface_get_width(surface);
375
376     if (pheight)
377         *pheight = gst_vaapi_surface_get_height(surface);
378 }
379
380 /**
381  * gst_vaapi_surface_derive_image:
382  * @surface: a #GstVaapiSurface
383  *
384  * Derives a #GstVaapiImage from the @surface. This image buffer can
385  * then be mapped/unmapped for direct CPU access. This operation is
386  * only possible if the underlying implementation supports direct
387  * rendering capabilities and internal surface formats that can be
388  * represented with a #GstVaapiImage.
389  *
390  * When the operation is not possible, the function returns %NULL and
391  * the user should then fallback to using gst_vaapi_surface_get_image()
392  * or gst_vaapi_surface_put_image() to accomplish the same task in an
393  * indirect manner (additional copy).
394  *
395  * An image created with gst_vaapi_surface_derive_image() should be
396  * unreferenced when it's no longer needed. The image and image buffer
397  * data structures will be destroyed. However, the surface contents
398  * will remain unchanged until destroyed through the last call to
399  * g_object_unref().
400  *
401  * Return value: the newly allocated #GstVaapiImage object, or %NULL
402  *   on failure
403  */
404 GstVaapiImage *
405 gst_vaapi_surface_derive_image(GstVaapiSurface *surface)
406 {
407     GstVaapiDisplay *display;
408     VAImage va_image;
409     VAStatus status;
410
411     g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), NULL);
412
413     display           = GST_VAAPI_OBJECT_DISPLAY(surface);
414     va_image.image_id = VA_INVALID_ID;
415     va_image.buf      = VA_INVALID_ID;
416
417     GST_VAAPI_DISPLAY_LOCK(display);
418     status = vaDeriveImage(
419         GST_VAAPI_DISPLAY_VADISPLAY(display),
420         GST_VAAPI_OBJECT_ID(surface),
421         &va_image
422     );
423     GST_VAAPI_DISPLAY_UNLOCK(display);
424     if (!vaapi_check_status(status, "vaDeriveImage()"))
425         return NULL;
426     if (va_image.image_id == VA_INVALID_ID || va_image.buf == VA_INVALID_ID)
427         return NULL;
428
429     return gst_vaapi_image_new_with_image(display, &va_image);
430 }
431
432 /**
433  * gst_vaapi_surface_get_image
434  * @surface: a #GstVaapiSurface
435  * @image: a #GstVaapiImage
436  *
437  * Retrieves surface data into a #GstVaapiImage. The @image must have
438  * a format supported by the @surface.
439  *
440  * Return value: %TRUE on success
441  */
442 gboolean
443 gst_vaapi_surface_get_image(GstVaapiSurface *surface, GstVaapiImage *image)
444 {
445     GstVaapiDisplay *display;
446     VAImageID image_id;
447     VAStatus status;
448     guint width, height;
449
450     g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
451     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
452
453     display = GST_VAAPI_OBJECT_DISPLAY(surface);
454     if (!display)
455         return FALSE;
456
457     gst_vaapi_image_get_size(image, &width, &height);
458     if (width != surface->priv->width || height != surface->priv->height)
459         return FALSE;
460
461     image_id = GST_VAAPI_OBJECT_ID(image);
462     if (image_id == VA_INVALID_ID)
463         return FALSE;
464
465     GST_VAAPI_DISPLAY_LOCK(display);
466     status = vaGetImage(
467         GST_VAAPI_DISPLAY_VADISPLAY(display),
468         GST_VAAPI_OBJECT_ID(surface),
469         0, 0, width, height,
470         image_id
471     );
472     GST_VAAPI_DISPLAY_UNLOCK(display);
473     if (!vaapi_check_status(status, "vaGetImage()"))
474         return FALSE;
475
476     return TRUE;
477 }
478
479 /**
480  * gst_vaapi_surface_put_image:
481  * @surface: a #GstVaapiSurface
482  * @image: a #GstVaapiImage
483  *
484  * Copies data from a #GstVaapiImage into a @surface. The @image must
485  * have a format supported by the @surface.
486  *
487  * Return value: %TRUE on success
488  */
489 gboolean
490 gst_vaapi_surface_put_image(GstVaapiSurface *surface, GstVaapiImage *image)
491 {
492     GstVaapiDisplay *display;
493     VAImageID image_id;
494     VAStatus status;
495     guint width, height;
496
497     g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
498     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
499
500     display = GST_VAAPI_OBJECT_DISPLAY(surface);
501     if (!display)
502         return FALSE;
503
504     gst_vaapi_image_get_size(image, &width, &height);
505     if (width != surface->priv->width || height != surface->priv->height)
506         return FALSE;
507
508     image_id = GST_VAAPI_OBJECT_ID(image);
509     if (image_id == VA_INVALID_ID)
510         return FALSE;
511
512     GST_VAAPI_DISPLAY_LOCK(display);
513     status = vaPutImage(
514         GST_VAAPI_DISPLAY_VADISPLAY(display),
515         GST_VAAPI_OBJECT_ID(surface),
516         image_id,
517         0, 0, width, height,
518         0, 0, width, height
519     );
520     GST_VAAPI_DISPLAY_UNLOCK(display);
521     if (!vaapi_check_status(status, "vaPutImage()"))
522         return FALSE;
523
524     return TRUE;
525 }
526
527 /**
528  * gst_vaapi_surface_associate_subpicture:
529  * @surface: a #GstVaapiSurface
530  * @subpicture: a #GstVaapiSubpicture
531  * @src_rect: the sub-rectangle of the source subpicture
532  *   image to extract and process. If %NULL, the entire image will be used.
533  * @dst_rect: the sub-rectangle of the destination
534  *   surface into which the image is rendered. If %NULL, the entire
535  *   surface will be used.
536  *
537  * Associates the @subpicture with the @surface. The @src_rect
538  * coordinates and size are relative to the source image bound to
539  * @subpicture. The @dst_rect coordinates and size are relative to the
540  * target @surface. Note that the @surface holds an additional
541  * reference to the @subpicture.
542  *
543  * Return value: %TRUE on success
544  */
545 gboolean
546 gst_vaapi_surface_associate_subpicture(
547     GstVaapiSurface         *surface,
548     GstVaapiSubpicture      *subpicture,
549     const GstVaapiRectangle *src_rect,
550     const GstVaapiRectangle *dst_rect
551 )
552 {
553     gboolean success;
554
555     g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
556     g_return_val_if_fail(GST_VAAPI_IS_SUBPICTURE(subpicture), FALSE);
557
558     if (!gst_vaapi_surface_deassociate_subpicture(surface, subpicture))
559         return FALSE;
560
561     if (!surface->priv->subpictures) {
562         surface->priv->subpictures = g_ptr_array_new();
563         if (!surface->priv->subpictures)
564             return FALSE;
565     }
566
567     success = _gst_vaapi_surface_associate_subpicture(
568         surface,
569         subpicture,
570         src_rect,
571         dst_rect
572     );
573     if (!success)
574         return FALSE;
575
576     g_ptr_array_add(surface->priv->subpictures, g_object_ref(subpicture));
577     return TRUE;
578 }
579
580 gboolean
581 _gst_vaapi_surface_associate_subpicture(
582     GstVaapiSurface         *surface,
583     GstVaapiSubpicture      *subpicture,
584     const GstVaapiRectangle *src_rect,
585     const GstVaapiRectangle *dst_rect
586 )
587 {
588     GstVaapiDisplay *display;
589     GstVaapiRectangle src_rect_default, dst_rect_default;
590     GstVaapiImage *image;
591     VASurfaceID surface_id;
592     VAStatus status;
593
594     display = GST_VAAPI_OBJECT_DISPLAY(surface);
595     if (!display)
596         return FALSE;
597
598     surface_id = GST_VAAPI_OBJECT_ID(surface);
599     if (surface_id == VA_INVALID_SURFACE)
600         return FALSE;
601
602     if (!src_rect) {
603         image = gst_vaapi_subpicture_get_image(subpicture);
604         if (!image)
605             return FALSE;
606         src_rect                = &src_rect_default;
607         src_rect_default.x      = 0;
608         src_rect_default.y      = 0;
609         gst_vaapi_image_get_size(
610             image,
611             &src_rect_default.width,
612             &src_rect_default.height
613         );
614     }
615
616     if (!dst_rect) {
617         dst_rect                = &dst_rect_default;
618         dst_rect_default.x      = 0;
619         dst_rect_default.y      = 0;
620         dst_rect_default.width  = surface->priv->width;
621         dst_rect_default.height = surface->priv->height;
622     }
623
624     GST_VAAPI_DISPLAY_LOCK(display);
625     status = vaAssociateSubpicture(
626         GST_VAAPI_DISPLAY_VADISPLAY(display),
627         GST_VAAPI_OBJECT_ID(subpicture),
628         &surface_id, 1,
629         src_rect->x, src_rect->y, src_rect->width, src_rect->height,
630         dst_rect->x, dst_rect->y, dst_rect->width, dst_rect->height,
631         0
632     );
633     GST_VAAPI_DISPLAY_UNLOCK(display);
634     if (!vaapi_check_status(status, "vaAssociateSubpicture()"))
635         return FALSE;
636
637     return TRUE;
638 }
639
640 /**
641  * gst_vaapi_surface_deassociate_subpicture:
642  * @surface: a #GstVaapiSurface
643  * @subpicture: a #GstVaapiSubpicture
644  *
645  * Deassociates @subpicture from @surface. Other associations are kept.
646  *
647  * Return value: %TRUE on success
648  */
649 gboolean
650 gst_vaapi_surface_deassociate_subpicture(
651     GstVaapiSurface         *surface,
652     GstVaapiSubpicture      *subpicture
653 )
654 {
655     gboolean success;
656
657     g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
658     g_return_val_if_fail(GST_VAAPI_IS_SUBPICTURE(subpicture), FALSE);
659
660     if (!surface->priv->subpictures)
661         return TRUE;
662
663     /* First, check subpicture was really associated with this surface */
664     if (!g_ptr_array_remove_fast(surface->priv->subpictures, subpicture)) {
665         GST_DEBUG("subpicture %" GST_VAAPI_ID_FORMAT "was not bound to "
666                   "surface %" GST_VAAPI_ID_FORMAT,
667                   GST_VAAPI_ID_ARGS(GST_VAAPI_OBJECT_ID(subpicture)),
668                   GST_VAAPI_ID_ARGS(GST_VAAPI_OBJECT_ID(surface)));
669         return TRUE;
670     }
671
672     success = _gst_vaapi_surface_deassociate_subpicture(surface, subpicture);
673     g_object_unref(subpicture);
674     return success;
675 }
676
677 gboolean
678 _gst_vaapi_surface_deassociate_subpicture(
679     GstVaapiSurface         *surface,
680     GstVaapiSubpicture      *subpicture
681 )
682 {
683     GstVaapiDisplay *display;
684     VASurfaceID surface_id;
685     VAStatus status;
686
687     display = GST_VAAPI_OBJECT_DISPLAY(surface);
688     if (!display)
689         return FALSE;
690
691     surface_id = GST_VAAPI_OBJECT_ID(surface);
692     if (surface_id == VA_INVALID_SURFACE)
693         return FALSE;
694
695     GST_VAAPI_DISPLAY_LOCK(display);
696     status = vaDeassociateSubpicture(
697         GST_VAAPI_DISPLAY_VADISPLAY(display),
698         GST_VAAPI_OBJECT_ID(subpicture),
699         &surface_id, 1
700     );
701     GST_VAAPI_DISPLAY_UNLOCK(display);
702     if (!vaapi_check_status(status, "vaDeassociateSubpicture()"))
703         return FALSE;
704
705     return TRUE;
706 }
707
708 /**
709  * gst_vaapi_surface_sync:
710  * @surface: a #GstVaapiSurface
711  *
712  * Blocks until all pending operations on the @surface have been
713  * completed.
714  *
715  * Return value: %TRUE on success
716  */
717 gboolean
718 gst_vaapi_surface_sync(GstVaapiSurface *surface)
719 {
720     GstVaapiDisplay *display;
721     VAStatus status;
722
723     g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
724
725     display = GST_VAAPI_OBJECT_DISPLAY(surface);
726     if (!display)
727         return FALSE;
728
729     GST_VAAPI_DISPLAY_LOCK(display);
730     status = vaSyncSurface(
731         GST_VAAPI_DISPLAY_VADISPLAY(display),
732         GST_VAAPI_OBJECT_ID(surface)
733     );
734     GST_VAAPI_DISPLAY_UNLOCK(display);
735     if (!vaapi_check_status(status, "vaSyncSurface()"))
736         return FALSE;
737
738     return TRUE;
739 }