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