Restore the gst_vaapi_{surface,image,subpicture}_get_id() interfaces.
[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_id:
310  * @surface: a #GstVaapiSurface
311  *
312  * Returns the underlying VASurfaceID of the @surface.
313  *
314  * Return value: the underlying VA surface id
315  */
316 VASurfaceID
317 gst_vaapi_surface_get_id(GstVaapiSurface *surface)
318 {
319     g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), VA_INVALID_SURFACE);
320
321     return GST_VAAPI_OBJECT_ID(surface);
322 }
323
324 /**
325  * gst_vaapi_surface_get_chroma_type:
326  * @surface: a #GstVaapiSurface
327  *
328  * Returns the #GstVaapiChromaType the @surface was created with.
329  *
330  * Return value: the #GstVaapiChromaType
331  */
332 GstVaapiChromaType
333 gst_vaapi_surface_get_chroma_type(GstVaapiSurface *surface)
334 {
335     g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), 0);
336
337     return surface->priv->chroma_type;
338 }
339
340 /**
341  * gst_vaapi_surface_get_width:
342  * @surface: a #GstVaapiSurface
343  *
344  * Returns the @surface width.
345  *
346  * Return value: the surface width, in pixels
347  */
348 guint
349 gst_vaapi_surface_get_width(GstVaapiSurface *surface)
350 {
351     g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), 0);
352
353     return surface->priv->width;
354 }
355
356 /**
357  * gst_vaapi_surface_get_height:
358  * @surface: a #GstVaapiSurface
359  *
360  * Returns the @surface height.
361  *
362  * Return value: the surface height, in pixels.
363  */
364 guint
365 gst_vaapi_surface_get_height(GstVaapiSurface *surface)
366 {
367     g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), 0);
368
369     return surface->priv->height;
370 }
371
372 /**
373  * gst_vaapi_surface_get_size:
374  * @surface: a #GstVaapiSurface
375  * @pwidth: return location for the width, or %NULL
376  * @pheight: return location for the height, or %NULL
377  *
378  * Retrieves the dimensions of a #GstVaapiSurface.
379  */
380 void
381 gst_vaapi_surface_get_size(
382     GstVaapiSurface *surface,
383     guint           *pwidth,
384     guint           *pheight
385 )
386 {
387     g_return_if_fail(GST_VAAPI_IS_SURFACE(surface));
388
389     if (pwidth)
390         *pwidth = gst_vaapi_surface_get_width(surface);
391
392     if (pheight)
393         *pheight = gst_vaapi_surface_get_height(surface);
394 }
395
396 /**
397  * gst_vaapi_surface_derive_image:
398  * @surface: a #GstVaapiSurface
399  *
400  * Derives a #GstVaapiImage from the @surface. This image buffer can
401  * then be mapped/unmapped for direct CPU access. This operation is
402  * only possible if the underlying implementation supports direct
403  * rendering capabilities and internal surface formats that can be
404  * represented with a #GstVaapiImage.
405  *
406  * When the operation is not possible, the function returns %NULL and
407  * the user should then fallback to using gst_vaapi_surface_get_image()
408  * or gst_vaapi_surface_put_image() to accomplish the same task in an
409  * indirect manner (additional copy).
410  *
411  * An image created with gst_vaapi_surface_derive_image() should be
412  * unreferenced when it's no longer needed. The image and image buffer
413  * data structures will be destroyed. However, the surface contents
414  * will remain unchanged until destroyed through the last call to
415  * g_object_unref().
416  *
417  * Return value: the newly allocated #GstVaapiImage object, or %NULL
418  *   on failure
419  */
420 GstVaapiImage *
421 gst_vaapi_surface_derive_image(GstVaapiSurface *surface)
422 {
423     GstVaapiDisplay *display;
424     VAImage va_image;
425     VAStatus status;
426
427     g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), NULL);
428
429     display           = GST_VAAPI_OBJECT_DISPLAY(surface);
430     va_image.image_id = VA_INVALID_ID;
431     va_image.buf      = VA_INVALID_ID;
432
433     GST_VAAPI_DISPLAY_LOCK(display);
434     status = vaDeriveImage(
435         GST_VAAPI_DISPLAY_VADISPLAY(display),
436         GST_VAAPI_OBJECT_ID(surface),
437         &va_image
438     );
439     GST_VAAPI_DISPLAY_UNLOCK(display);
440     if (!vaapi_check_status(status, "vaDeriveImage()"))
441         return NULL;
442     if (va_image.image_id == VA_INVALID_ID || va_image.buf == VA_INVALID_ID)
443         return NULL;
444
445     return gst_vaapi_image_new_with_image(display, &va_image);
446 }
447
448 /**
449  * gst_vaapi_surface_get_image
450  * @surface: a #GstVaapiSurface
451  * @image: a #GstVaapiImage
452  *
453  * Retrieves surface data into a #GstVaapiImage. The @image must have
454  * a format supported by the @surface.
455  *
456  * Return value: %TRUE on success
457  */
458 gboolean
459 gst_vaapi_surface_get_image(GstVaapiSurface *surface, GstVaapiImage *image)
460 {
461     GstVaapiDisplay *display;
462     VAImageID image_id;
463     VAStatus status;
464     guint width, height;
465
466     g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
467     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
468
469     display = GST_VAAPI_OBJECT_DISPLAY(surface);
470     if (!display)
471         return FALSE;
472
473     gst_vaapi_image_get_size(image, &width, &height);
474     if (width != surface->priv->width || height != surface->priv->height)
475         return FALSE;
476
477     image_id = GST_VAAPI_OBJECT_ID(image);
478     if (image_id == VA_INVALID_ID)
479         return FALSE;
480
481     GST_VAAPI_DISPLAY_LOCK(display);
482     status = vaGetImage(
483         GST_VAAPI_DISPLAY_VADISPLAY(display),
484         GST_VAAPI_OBJECT_ID(surface),
485         0, 0, width, height,
486         image_id
487     );
488     GST_VAAPI_DISPLAY_UNLOCK(display);
489     if (!vaapi_check_status(status, "vaGetImage()"))
490         return FALSE;
491
492     return TRUE;
493 }
494
495 /**
496  * gst_vaapi_surface_put_image:
497  * @surface: a #GstVaapiSurface
498  * @image: a #GstVaapiImage
499  *
500  * Copies data from a #GstVaapiImage into a @surface. The @image must
501  * have a format supported by the @surface.
502  *
503  * Return value: %TRUE on success
504  */
505 gboolean
506 gst_vaapi_surface_put_image(GstVaapiSurface *surface, GstVaapiImage *image)
507 {
508     GstVaapiDisplay *display;
509     VAImageID image_id;
510     VAStatus status;
511     guint width, height;
512
513     g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
514     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
515
516     display = GST_VAAPI_OBJECT_DISPLAY(surface);
517     if (!display)
518         return FALSE;
519
520     gst_vaapi_image_get_size(image, &width, &height);
521     if (width != surface->priv->width || height != surface->priv->height)
522         return FALSE;
523
524     image_id = GST_VAAPI_OBJECT_ID(image);
525     if (image_id == VA_INVALID_ID)
526         return FALSE;
527
528     GST_VAAPI_DISPLAY_LOCK(display);
529     status = vaPutImage(
530         GST_VAAPI_DISPLAY_VADISPLAY(display),
531         GST_VAAPI_OBJECT_ID(surface),
532         image_id,
533         0, 0, width, height,
534         0, 0, width, height
535     );
536     GST_VAAPI_DISPLAY_UNLOCK(display);
537     if (!vaapi_check_status(status, "vaPutImage()"))
538         return FALSE;
539
540     return TRUE;
541 }
542
543 /**
544  * gst_vaapi_surface_associate_subpicture:
545  * @surface: a #GstVaapiSurface
546  * @subpicture: a #GstVaapiSubpicture
547  * @src_rect: the sub-rectangle of the source subpicture
548  *   image to extract and process. If %NULL, the entire image will be used.
549  * @dst_rect: the sub-rectangle of the destination
550  *   surface into which the image is rendered. If %NULL, the entire
551  *   surface will be used.
552  *
553  * Associates the @subpicture with the @surface. The @src_rect
554  * coordinates and size are relative to the source image bound to
555  * @subpicture. The @dst_rect coordinates and size are relative to the
556  * target @surface. Note that the @surface holds an additional
557  * reference to the @subpicture.
558  *
559  * Return value: %TRUE on success
560  */
561 gboolean
562 gst_vaapi_surface_associate_subpicture(
563     GstVaapiSurface         *surface,
564     GstVaapiSubpicture      *subpicture,
565     const GstVaapiRectangle *src_rect,
566     const GstVaapiRectangle *dst_rect
567 )
568 {
569     gboolean success;
570
571     g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
572     g_return_val_if_fail(GST_VAAPI_IS_SUBPICTURE(subpicture), FALSE);
573
574     if (!gst_vaapi_surface_deassociate_subpicture(surface, subpicture))
575         return FALSE;
576
577     if (!surface->priv->subpictures) {
578         surface->priv->subpictures = g_ptr_array_new();
579         if (!surface->priv->subpictures)
580             return FALSE;
581     }
582
583     success = _gst_vaapi_surface_associate_subpicture(
584         surface,
585         subpicture,
586         src_rect,
587         dst_rect
588     );
589     if (!success)
590         return FALSE;
591
592     g_ptr_array_add(surface->priv->subpictures, g_object_ref(subpicture));
593     return TRUE;
594 }
595
596 gboolean
597 _gst_vaapi_surface_associate_subpicture(
598     GstVaapiSurface         *surface,
599     GstVaapiSubpicture      *subpicture,
600     const GstVaapiRectangle *src_rect,
601     const GstVaapiRectangle *dst_rect
602 )
603 {
604     GstVaapiDisplay *display;
605     GstVaapiRectangle src_rect_default, dst_rect_default;
606     GstVaapiImage *image;
607     VASurfaceID surface_id;
608     VAStatus status;
609
610     display = GST_VAAPI_OBJECT_DISPLAY(surface);
611     if (!display)
612         return FALSE;
613
614     surface_id = GST_VAAPI_OBJECT_ID(surface);
615     if (surface_id == VA_INVALID_SURFACE)
616         return FALSE;
617
618     if (!src_rect) {
619         image = gst_vaapi_subpicture_get_image(subpicture);
620         if (!image)
621             return FALSE;
622         src_rect                = &src_rect_default;
623         src_rect_default.x      = 0;
624         src_rect_default.y      = 0;
625         gst_vaapi_image_get_size(
626             image,
627             &src_rect_default.width,
628             &src_rect_default.height
629         );
630     }
631
632     if (!dst_rect) {
633         dst_rect                = &dst_rect_default;
634         dst_rect_default.x      = 0;
635         dst_rect_default.y      = 0;
636         dst_rect_default.width  = surface->priv->width;
637         dst_rect_default.height = surface->priv->height;
638     }
639
640     GST_VAAPI_DISPLAY_LOCK(display);
641     status = vaAssociateSubpicture(
642         GST_VAAPI_DISPLAY_VADISPLAY(display),
643         GST_VAAPI_OBJECT_ID(subpicture),
644         &surface_id, 1,
645         src_rect->x, src_rect->y, src_rect->width, src_rect->height,
646         dst_rect->x, dst_rect->y, dst_rect->width, dst_rect->height,
647         0
648     );
649     GST_VAAPI_DISPLAY_UNLOCK(display);
650     if (!vaapi_check_status(status, "vaAssociateSubpicture()"))
651         return FALSE;
652
653     return TRUE;
654 }
655
656 /**
657  * gst_vaapi_surface_deassociate_subpicture:
658  * @surface: a #GstVaapiSurface
659  * @subpicture: a #GstVaapiSubpicture
660  *
661  * Deassociates @subpicture from @surface. Other associations are kept.
662  *
663  * Return value: %TRUE on success
664  */
665 gboolean
666 gst_vaapi_surface_deassociate_subpicture(
667     GstVaapiSurface         *surface,
668     GstVaapiSubpicture      *subpicture
669 )
670 {
671     gboolean success;
672
673     g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
674     g_return_val_if_fail(GST_VAAPI_IS_SUBPICTURE(subpicture), FALSE);
675
676     if (!surface->priv->subpictures)
677         return TRUE;
678
679     /* First, check subpicture was really associated with this surface */
680     if (!g_ptr_array_remove_fast(surface->priv->subpictures, subpicture)) {
681         GST_DEBUG("subpicture %" GST_VAAPI_ID_FORMAT "was not bound to "
682                   "surface %" GST_VAAPI_ID_FORMAT,
683                   GST_VAAPI_ID_ARGS(GST_VAAPI_OBJECT_ID(subpicture)),
684                   GST_VAAPI_ID_ARGS(GST_VAAPI_OBJECT_ID(surface)));
685         return TRUE;
686     }
687
688     success = _gst_vaapi_surface_deassociate_subpicture(surface, subpicture);
689     g_object_unref(subpicture);
690     return success;
691 }
692
693 gboolean
694 _gst_vaapi_surface_deassociate_subpicture(
695     GstVaapiSurface         *surface,
696     GstVaapiSubpicture      *subpicture
697 )
698 {
699     GstVaapiDisplay *display;
700     VASurfaceID surface_id;
701     VAStatus status;
702
703     display = GST_VAAPI_OBJECT_DISPLAY(surface);
704     if (!display)
705         return FALSE;
706
707     surface_id = GST_VAAPI_OBJECT_ID(surface);
708     if (surface_id == VA_INVALID_SURFACE)
709         return FALSE;
710
711     GST_VAAPI_DISPLAY_LOCK(display);
712     status = vaDeassociateSubpicture(
713         GST_VAAPI_DISPLAY_VADISPLAY(display),
714         GST_VAAPI_OBJECT_ID(subpicture),
715         &surface_id, 1
716     );
717     GST_VAAPI_DISPLAY_UNLOCK(display);
718     if (!vaapi_check_status(status, "vaDeassociateSubpicture()"))
719         return FALSE;
720
721     return TRUE;
722 }
723
724 /**
725  * gst_vaapi_surface_sync:
726  * @surface: a #GstVaapiSurface
727  *
728  * Blocks until all pending operations on the @surface have been
729  * completed.
730  *
731  * Return value: %TRUE on success
732  */
733 gboolean
734 gst_vaapi_surface_sync(GstVaapiSurface *surface)
735 {
736     GstVaapiDisplay *display;
737     VAStatus status;
738
739     g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
740
741     display = GST_VAAPI_OBJECT_DISPLAY(surface);
742     if (!display)
743         return FALSE;
744
745     GST_VAAPI_DISPLAY_LOCK(display);
746     status = vaSyncSurface(
747         GST_VAAPI_DISPLAY_VADISPLAY(display),
748         GST_VAAPI_OBJECT_ID(surface)
749     );
750     GST_VAAPI_DISPLAY_UNLOCK(display);
751     if (!vaapi_check_status(status, "vaSyncSurface()"))
752         return FALSE;
753
754     return TRUE;
755 }