Tizen 2.0 Release
[framework/multimedia/gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapivideobuffer.c
1 /*
2  *  gstvaapivideobuffer.c - Gst VA video buffer
3  *
4  *  Copyright (C) 2010-2011 Splitted-Desktop Systems
5  *  Copyright (C) 2011 Intel Corporation
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser General Public License
9  *  as published by the Free Software Foundation; either version 2.1
10  *  of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free
19  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  *  Boston, MA 02110-1301 USA
21  */
22
23 /**
24  * SECTION:gstvaapivideobuffer
25  * @short_description: VA video buffer for GStreamer
26  */
27
28 #include "sysdeps.h"
29 #include "gstvaapivideobuffer.h"
30 #include "gstvaapivideobuffer_priv.h"
31 #include "gstvaapiimagepool.h"
32 #include "gstvaapisurfacepool.h"
33 #include "gstvaapiobject_priv.h"
34
35 #define DEBUG 1
36 #include "gstvaapidebug.h"
37
38 G_DEFINE_TYPE(GstVaapiVideoBuffer, gst_vaapi_video_buffer, GST_TYPE_SURFACE_BUFFER);
39
40 #define GST_VAAPI_VIDEO_BUFFER_GET_PRIVATE(obj)                 \
41     (G_TYPE_INSTANCE_GET_PRIVATE((obj),                         \
42                                  GST_VAAPI_TYPE_VIDEO_BUFFER,   \
43                                  GstVaapiVideoBufferPrivate))
44
45 struct _GstVaapiVideoBufferPrivate {
46     GstVaapiDisplay            *display;
47     GstVaapiVideoPool          *image_pool;
48     GstVaapiImage              *image;
49     GstVaapiVideoPool          *surface_pool;
50     GstVaapiSurface            *surface;
51     GstVaapiSurfaceProxy       *proxy;
52     GstBuffer                  *buffer;
53     guint                       render_flags;
54 };
55
56 static void
57 set_display(GstVaapiVideoBuffer *buffer, GstVaapiDisplay *display)
58 {
59     GstVaapiVideoBufferPrivate * const priv = buffer->priv;
60
61     g_clear_object(&priv->display);
62
63     if (display)
64         priv->display = g_object_ref(display);
65 }
66
67 static inline void
68 set_image(GstVaapiVideoBuffer *buffer, GstVaapiImage *image)
69 {
70     buffer->priv->image = g_object_ref(image);
71     set_display(buffer, GST_VAAPI_OBJECT_DISPLAY(image));
72 }
73
74 static inline void
75 set_surface(GstVaapiVideoBuffer *buffer, GstVaapiSurface *surface)
76 {
77     buffer->priv->surface = g_object_ref(surface);
78     set_display(buffer, GST_VAAPI_OBJECT_DISPLAY(surface));
79 }
80
81 static void
82 gst_vaapi_video_buffer_destroy_image(GstVaapiVideoBuffer *buffer)
83 {
84     GstVaapiVideoBufferPrivate * const priv = buffer->priv;
85
86     if (priv->image) {
87         if (priv->image_pool)
88             gst_vaapi_video_pool_put_object(priv->image_pool, priv->image);
89         g_object_unref(priv->image);
90         priv->image = NULL;
91     }
92
93     g_clear_object(&priv->image_pool);
94 }
95
96 static void
97 gst_vaapi_video_buffer_destroy_surface(GstVaapiVideoBuffer *buffer)
98 {
99     GstVaapiVideoBufferPrivate * const priv = buffer->priv;
100
101     g_clear_object(&priv->proxy);
102
103     if (priv->surface) {
104         if (priv->surface_pool)
105             gst_vaapi_video_pool_put_object(priv->surface_pool, priv->surface);
106         g_object_unref(priv->surface);
107         priv->surface = NULL;
108     }
109
110     g_clear_object(&priv->surface_pool);
111
112     if (priv->buffer) {
113         gst_buffer_unref(priv->buffer);
114         priv->buffer = NULL;
115     }
116 }
117
118 static void
119 gst_vaapi_video_buffer_finalize(GstMiniObject *object)
120 {
121     GstVaapiVideoBuffer * const buffer = GST_VAAPI_VIDEO_BUFFER(object);
122     GstMiniObjectClass *parent_class;
123
124     gst_vaapi_video_buffer_destroy_image(buffer);
125     gst_vaapi_video_buffer_destroy_surface(buffer);
126
127     set_display(buffer, NULL);
128
129     parent_class = GST_MINI_OBJECT_CLASS(gst_vaapi_video_buffer_parent_class);
130     if (parent_class->finalize)
131         parent_class->finalize(object);
132 }
133
134 static void
135 gst_vaapi_video_buffer_class_init(GstVaapiVideoBufferClass *klass)
136 {
137     GstMiniObjectClass * const object_class = GST_MINI_OBJECT_CLASS(klass);
138
139     g_type_class_add_private(klass, sizeof(GstVaapiVideoBufferPrivate));
140
141     object_class->finalize = gst_vaapi_video_buffer_finalize;
142 }
143
144 static void
145 gst_vaapi_video_buffer_init(GstVaapiVideoBuffer *buffer)
146 {
147     GstVaapiVideoBufferPrivate *priv;
148
149     priv                = GST_VAAPI_VIDEO_BUFFER_GET_PRIVATE(buffer);
150     buffer->priv        = priv;
151     priv->display       = NULL;
152     priv->image_pool    = NULL;
153     priv->image         = NULL;
154     priv->surface_pool  = NULL;
155     priv->surface       = NULL;
156     priv->proxy         = NULL;
157     priv->buffer        = NULL;
158     priv->render_flags  = 0;
159 }
160
161 static inline gboolean
162 gst_vaapi_video_buffer_is_a(GstBuffer *buffer, GType type)
163 {
164     return G_TYPE_CHECK_INSTANCE_TYPE(buffer, type);
165 }
166
167 static inline gpointer
168 _gst_vaapi_video_buffer_typed_new(GType type)
169 {
170     g_return_val_if_fail(g_type_is_a(type, GST_VAAPI_TYPE_VIDEO_BUFFER), NULL);
171
172     return gst_mini_object_new(type);
173 }
174
175 /**
176  * gst_vaapi_video_buffer_typed_new:
177  * @display: a #GstVaapiDisplay
178  *
179  * Creates an empty #GstBuffer. The caller is responsible for completing
180  * the initialization of the buffer with the gst_vaapi_video_buffer_set_*()
181  * functions.
182  *
183  * This function shall only be called from within gstreamer-vaapi
184  * plugin elements.
185  *
186  * Return value: the newly allocated #GstBuffer, or %NULL or error
187  */
188 GstBuffer *
189 gst_vaapi_video_buffer_typed_new(GType type, GstVaapiDisplay *display)
190 {
191     GstBuffer *buffer;
192
193     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
194
195     buffer = _gst_vaapi_video_buffer_typed_new(type);
196     if (!buffer)
197         return NULL;
198
199     set_display(GST_VAAPI_VIDEO_BUFFER(buffer), display);
200     return buffer;
201 }
202
203 /**
204  * gst_vaapi_video_buffer_typed_new_from_pool:
205  * @pool: a #GstVaapiVideoPool
206  *
207  * Creates a #GstBuffer with a video object allocated from a @pool.
208  * Only #GstVaapiSurfacePool and #GstVaapiImagePool pools are supported.
209  *
210  * The buffer is destroyed through the last call to gst_buffer_unref()
211  * and the video objects are pushed back to their respective pools.
212  *
213  * Return value: the newly allocated #GstBuffer, or %NULL on error
214  */
215 GstBuffer *
216 gst_vaapi_video_buffer_typed_new_from_pool(GType type, GstVaapiVideoPool *pool)
217 {
218     GstVaapiVideoBuffer *buffer;
219     gboolean is_image_pool, is_surface_pool;
220
221     g_return_val_if_fail(GST_VAAPI_IS_VIDEO_POOL(pool), NULL);
222
223     is_image_pool   = GST_VAAPI_IS_IMAGE_POOL(pool);
224     is_surface_pool = GST_VAAPI_IS_SURFACE_POOL(pool);
225
226     if (!is_image_pool && !is_surface_pool)
227         return NULL;
228
229     buffer = _gst_vaapi_video_buffer_typed_new(type);
230     if (buffer &&
231         ((is_image_pool &&
232           gst_vaapi_video_buffer_set_image_from_pool(buffer, pool)) ||
233          (is_surface_pool &&
234           gst_vaapi_video_buffer_set_surface_from_pool(buffer, pool)))) {
235         set_display(buffer, gst_vaapi_video_pool_get_display(pool));
236         return GST_BUFFER(buffer);
237     }
238
239     gst_mini_object_unref(GST_MINI_OBJECT(buffer));
240     return NULL;
241 }
242
243 /**
244  * gst_vaapi_video_buffer_typed_new_from_buffer:
245  * @buffer: a #GstBuffer
246  *
247  * Creates a #GstBuffer with video objects bound to @buffer video
248  * objects, if any.
249  *
250  * This function shall only be called from within gstreamer-vaapi
251  * plugin elements.
252  *
253  * Return value: the newly allocated #GstBuffer, or %NULL on error
254  */
255 GstBuffer *
256 gst_vaapi_video_buffer_typed_new_from_buffer(GType type, GstBuffer *buffer)
257 {
258     GstVaapiVideoBuffer *inbuf, *outbuf;
259
260     if (!gst_vaapi_video_buffer_is_a(buffer, type)) {
261         if (!buffer->parent ||
262             !gst_vaapi_video_buffer_is_a(buffer->parent, type))
263             return NULL;
264         buffer = buffer->parent;
265     }
266     inbuf = GST_VAAPI_VIDEO_BUFFER(buffer);
267
268     outbuf = _gst_vaapi_video_buffer_typed_new(type);
269     if (!outbuf)
270         return NULL;
271
272     if (inbuf->priv->image)
273         gst_vaapi_video_buffer_set_image(outbuf, inbuf->priv->image);
274     if (inbuf->priv->surface)
275         gst_vaapi_video_buffer_set_surface(outbuf, inbuf->priv->surface);
276     if (inbuf->priv->proxy)
277         gst_vaapi_video_buffer_set_surface_proxy(outbuf, inbuf->priv->proxy);
278
279     outbuf->priv->buffer = gst_buffer_ref(buffer);
280     return GST_BUFFER(outbuf);
281 }
282
283 /**
284  * gst_vaapi_video_buffer_typed_new_with_image:
285  * @image: a #GstVaapiImage
286  *
287  * Creates a #GstBuffer with the specified @image. The resulting
288  * buffer holds an additional reference to the @image.
289  *
290  * This function shall only be called from within gstreamer-vaapi
291  * plugin elements.
292  *
293  * Return value: the newly allocated #GstBuffer, or %NULL on error
294  */
295 GstBuffer *
296 gst_vaapi_video_buffer_typed_new_with_image(GType type, GstVaapiImage *image)
297 {
298     GstVaapiVideoBuffer *buffer;
299
300     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), NULL);
301
302     buffer = _gst_vaapi_video_buffer_typed_new(type);
303     if (buffer)
304         gst_vaapi_video_buffer_set_image(buffer, image);
305     return GST_BUFFER(buffer);
306 }
307
308 /**
309  * gst_vaapi_video_buffer_typed_new_with_surface:
310  * @surface: a #GstVaapiSurface
311  *
312  * Creates a #GstBuffer with the specified @surface. The resulting
313  * buffer holds an additional reference to the @surface.
314  *
315  * This function shall only be called from within gstreamer-vaapi
316  * plugin elements.
317  *
318  * Return value: the newly allocated #GstBuffer, or %NULL on error
319  */
320 GstBuffer *
321 gst_vaapi_video_buffer_typed_new_with_surface(
322     GType            type,
323     GstVaapiSurface *surface
324 )
325 {
326     GstVaapiVideoBuffer *buffer;
327
328     g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), NULL);
329
330     buffer = _gst_vaapi_video_buffer_typed_new(type);
331     if (buffer)
332         gst_vaapi_video_buffer_set_surface(buffer, surface);
333     return GST_BUFFER(buffer);
334 }
335
336 /**
337  * gst_vaapi_video_buffer_typed_new_with_surface_proxy:
338  * @proxy: a #GstVaapiSurfaceProxy
339  *
340  * Creates a #GstBuffer with the specified surface @proxy. The
341  * resulting buffer holds an additional reference to the @proxy.
342  *
343  * This function shall only be called from within gstreamer-vaapi
344  * plugin elements.
345  *
346  * Return value: the newly allocated #GstBuffer, or %NULL on error
347  */
348 GstBuffer *
349 gst_vaapi_video_buffer_typed_new_with_surface_proxy(
350     GType                 type,
351     GstVaapiSurfaceProxy *proxy
352 )
353 {
354     GstVaapiVideoBuffer *buffer;
355
356     g_return_val_if_fail(GST_VAAPI_IS_SURFACE_PROXY(proxy), NULL);
357
358     buffer = _gst_vaapi_video_buffer_typed_new(type);
359     if (buffer)
360         gst_vaapi_video_buffer_set_surface_proxy(buffer, proxy);
361     return GST_BUFFER(buffer);
362 }
363
364 /**
365  * gst_vaapi_video_buffer_get_display:
366  * @buffer: a #GstVaapiVideoBuffer
367  *
368  * Retrieves the #GstVaapiDisplay the @buffer is bound to. The @buffer
369  * owns the returned #GstVaapiDisplay object so the caller is
370  * responsible for calling g_object_ref() when needed.
371  *
372  * Return value: the #GstVaapiDisplay the @buffer is bound to
373  */
374 GstVaapiDisplay *
375 gst_vaapi_video_buffer_get_display(GstVaapiVideoBuffer *buffer)
376 {
377     g_return_val_if_fail(GST_VAAPI_IS_VIDEO_BUFFER(buffer), NULL);
378
379     return buffer->priv->display;
380 }
381
382 /**
383  * gst_vaapi_video_buffer_get_image:
384  * @buffer: a #GstVaapiVideoBuffer
385  *
386  * Retrieves the #GstVaapiImage bound to the @buffer. The @buffer owns
387  * the #GstVaapiImage so the caller is responsible for calling
388  * g_object_ref() when needed.
389  *
390  * Return value: the #GstVaapiImage bound to the @buffer, or %NULL if
391  *   there is none
392  */
393 GstVaapiImage *
394 gst_vaapi_video_buffer_get_image(GstVaapiVideoBuffer *buffer)
395 {
396     g_return_val_if_fail(GST_VAAPI_IS_VIDEO_BUFFER(buffer), NULL);
397
398     return buffer->priv->image;
399 }
400
401 /**
402  * gst_vaapi_video_buffer_set_image:
403  * @buffer: a #GstVaapiVideoBuffer
404  * @image: a #GstVaapiImage
405  *
406  * Binds @image to the @buffer. If the @buffer contains another image
407  * previously allocated from a pool, it's pushed back to its parent
408  * pool and the pool is also released.
409  */
410 void
411 gst_vaapi_video_buffer_set_image(
412     GstVaapiVideoBuffer *buffer,
413     GstVaapiImage       *image
414 )
415 {
416     g_return_if_fail(GST_VAAPI_IS_VIDEO_BUFFER(buffer));
417     g_return_if_fail(GST_VAAPI_IS_IMAGE(image));
418
419     gst_vaapi_video_buffer_destroy_image(buffer);
420
421     if (image)
422         set_image(buffer, image);
423 }
424
425 /**
426  * gst_vaapi_video_buffer_set_image_from_pool
427  * @buffer: a #GstVaapiVideoBuffer
428  * @pool: a #GstVaapiVideoPool
429  *
430  * Binds a newly allocated video object from the @pool. The @pool
431  * shall be of type #GstVaapiImagePool. Previously allocated objects
432  * are released and returned to their parent pools, if any.
433  *
434  * Return value: %TRUE on success
435  */
436 gboolean
437 gst_vaapi_video_buffer_set_image_from_pool(
438     GstVaapiVideoBuffer *buffer,
439     GstVaapiVideoPool   *pool
440 )
441 {
442     GstVaapiImage *image;
443
444     g_return_val_if_fail(GST_VAAPI_IS_VIDEO_BUFFER(buffer), FALSE);
445     g_return_val_if_fail(GST_VAAPI_IS_IMAGE_POOL(pool), FALSE);
446
447     gst_vaapi_video_buffer_destroy_image(buffer);
448
449     if (pool) {
450         image = gst_vaapi_video_pool_get_object(pool);
451         if (!image)
452             return FALSE;
453         set_image(buffer, image);
454         buffer->priv->image_pool = g_object_ref(pool);
455     }
456     return TRUE;
457 }
458
459 /**
460  * gst_vaapi_video_buffer_get_surface:
461  * @buffer: a #GstVaapiVideoBuffer
462  *
463  * Retrieves the #GstVaapiSurface bound to the @buffer. The @buffer
464  * owns the #GstVaapiSurface so the caller is responsible for calling
465  * g_object_ref() when needed.
466  *
467  * Return value: the #GstVaapiSurface bound to the @buffer, or %NULL if
468  *   there is none
469  */
470 GstVaapiSurface *
471 gst_vaapi_video_buffer_get_surface(GstVaapiVideoBuffer *buffer)
472 {
473     g_return_val_if_fail(GST_VAAPI_IS_VIDEO_BUFFER(buffer), NULL);
474
475     return buffer->priv->surface;
476 }
477
478 /**
479  * gst_vaapi_video_buffer_set_surface:
480  * @buffer: a #GstVaapiVideoBuffer
481  * @surface: a #GstVaapiSurface
482  *
483  * Binds @surface to the @buffer. If the @buffer contains another
484  * surface previously allocated from a pool, it's pushed back to its
485  * parent pool and the pool is also released.
486  */
487 void
488 gst_vaapi_video_buffer_set_surface(
489     GstVaapiVideoBuffer *buffer,
490     GstVaapiSurface     *surface
491 )
492 {
493     g_return_if_fail(GST_VAAPI_IS_VIDEO_BUFFER(buffer));
494     g_return_if_fail(GST_VAAPI_IS_SURFACE(surface));
495
496     gst_vaapi_video_buffer_destroy_surface(buffer);
497
498     if (surface)
499         set_surface(buffer, surface);
500 }
501
502 /**
503  * gst_vaapi_video_buffer_set_surface_from_pool
504  * @buffer: a #GstVaapiVideoBuffer
505  * @pool: a #GstVaapiVideoPool
506  *
507  * Binds a newly allocated video object from the @pool. The @pool
508  * shall be of type #GstVaapiSurfacePool. Previously allocated objects
509  * are released and returned to their parent pools, if any.
510  *
511  * Return value: %TRUE on success
512  */
513 gboolean
514 gst_vaapi_video_buffer_set_surface_from_pool(
515     GstVaapiVideoBuffer *buffer,
516     GstVaapiVideoPool   *pool
517 )
518 {
519     GstVaapiSurface *surface;
520
521     g_return_val_if_fail(GST_VAAPI_IS_VIDEO_BUFFER(buffer), FALSE);
522     g_return_val_if_fail(GST_VAAPI_IS_SURFACE_POOL(pool), FALSE);
523
524     gst_vaapi_video_buffer_destroy_surface(buffer);
525
526     if (pool) {
527         surface = gst_vaapi_video_pool_get_object(pool);
528         if (!surface)
529             return FALSE;
530         set_surface(buffer, surface);
531         buffer->priv->surface_pool = g_object_ref(pool);
532     }
533     return TRUE;
534 }
535
536 /**
537  * gst_vaapi_video_buffer_get_surface_proxy:
538  * @buffer: a #GstVaapiVideoBuffer
539  *
540  * Retrieves the #GstVaapiSurfaceProxy bound to the @buffer. The @buffer
541  * owns the #GstVaapiSurfaceProxy so the caller is responsible for calling
542  * g_object_ref() when needed.
543  *
544  * Return value: the #GstVaapiSurfaceProxy bound to the @buffer, or
545  *   %NULL if there is none
546  */
547 GstVaapiSurfaceProxy *
548 gst_vaapi_video_buffer_get_surface_proxy(GstVaapiVideoBuffer *buffer)
549 {
550     g_return_val_if_fail(GST_VAAPI_IS_VIDEO_BUFFER(buffer), NULL);
551
552     return buffer->priv->proxy;
553 }
554
555 /**
556  * gst_vaapi_video_buffer_set_surface_proxy:
557  * @buffer: a #GstVaapiVideoBuffer
558  * @proxy: a #GstVaapiSurfaceProxy
559  *
560  * Binds surface @proxy to the @buffer. If the @buffer contains another
561  * surface previously allocated from a pool, it's pushed back to its
562  * parent pool and the pool is also released.
563  */
564 void
565 gst_vaapi_video_buffer_set_surface_proxy(
566     GstVaapiVideoBuffer  *buffer,
567     GstVaapiSurfaceProxy *proxy
568 )
569 {
570     GstVaapiSurface *surface;
571
572     g_return_if_fail(GST_VAAPI_IS_VIDEO_BUFFER(buffer));
573     g_return_if_fail(GST_VAAPI_IS_SURFACE_PROXY(proxy));
574
575     gst_vaapi_video_buffer_destroy_surface(buffer);
576
577     if (proxy) {
578         surface = GST_VAAPI_SURFACE_PROXY_SURFACE(proxy);
579         if (!surface)
580             return;
581         set_surface(buffer, surface);
582         buffer->priv->proxy = g_object_ref(proxy);
583     }
584 }
585
586 /**
587  * gst_vaapi_video_buffer_get_render_flags:
588  * @buffer: a #GstVaapiVideoBuffer
589  *
590  * Retrieves the surface render flags bound to the @buffer.
591  *
592  * Return value: a combination for #GstVaapiSurfaceRenderFlags
593  */
594 guint
595 gst_vaapi_video_buffer_get_render_flags(GstVaapiVideoBuffer *buffer)
596 {
597     g_return_val_if_fail(GST_VAAPI_IS_VIDEO_BUFFER(buffer), 0);
598     g_return_val_if_fail(GST_VAAPI_IS_SURFACE(buffer->priv->surface), 0);
599
600     return buffer->priv->render_flags;
601 }
602
603 /**
604  * gst_vaapi_video_buffer_set_render_flags:
605  * @buffer: a #GstVaapiVideoBuffer
606  * @flags: a set of surface render flags
607  *
608  * Sets #GstVaapiSurfaceRenderFlags to the @buffer.
609  */
610 void
611 gst_vaapi_video_buffer_set_render_flags(GstVaapiVideoBuffer *buffer, guint flags)
612 {
613     g_return_if_fail(GST_VAAPI_IS_VIDEO_BUFFER(buffer));
614     g_return_if_fail(GST_VAAPI_IS_SURFACE(buffer->priv->surface));
615
616     buffer->priv->render_flags = flags;
617 }
618
619 /**
620  * gst_vaapi_video_buffer_ensure_pointer:
621  * @buffer: a #GstVaapiVideoBuffer
622  *
623  * Maps image data buffer to #GstBuffer of @buffer.
624  *
625  * Return value: %TRUE on success
626  */
627 gboolean
628 gst_vaapi_video_buffer_ensure_pointer(GstVaapiVideoBuffer *buffer)
629 {
630     GstVaapiVideoBufferPrivate * const priv = buffer->priv;
631     GstVaapiImage *image = NULL;
632     gboolean is_image_derived = FALSE;
633     gboolean ret = FALSE;
634
635     g_return_val_if_fail(GST_VAAPI_IS_VIDEO_BUFFER(buffer), FALSE);
636     g_return_val_if_fail (priv->image || priv->surface, FALSE);
637
638     if (!priv->image) {
639         image = gst_vaapi_surface_derive_image(priv->surface);
640         g_return_val_if_fail(image, FALSE);
641         is_image_derived = TRUE;
642     } else {
643         image = priv->image;
644         is_image_derived = FALSE;
645     }
646
647     if (!gst_vaapi_image_map(image))
648         goto end;
649
650     if(!gst_vaapi_image_ensure_mapped_buffer(image))
651         goto end;
652
653     GST_BUFFER_DATA(buffer) = gst_vaapi_image_get_plane(image, 0);
654     GST_BUFFER_SIZE(buffer) = gst_vaapi_image_get_data_size(image);
655
656     if (!gst_vaapi_image_unmap(image))
657         goto end;
658
659     ret = TRUE;
660
661 end:
662     if (image && is_image_derived)
663         g_object_unref(image);
664     return ret;
665 }