vaapiconvert: try directly copy buffer to derived surface first
[vaapi:windyuan-gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapiimage.c
1 /*
2  *  gstvaapiimage.c - VA image abstraction
3  *
4  *  Copyright (C) 2010-2011 Splitted-Desktop Systems
5  *  Copyright (C) 2011-2012 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:gstvaapiimage
25  * @short_description: VA image abstraction
26  */
27
28 #include "sysdeps.h"
29 #include <string.h>
30 #include "gst/gstutils.h"
31 #include "gstvaapicompat.h"
32 #include "gstvaapiutils.h"
33 #include "gstvaapiimage.h"
34 #include "gstvaapi_priv.h"
35
36 #define DEBUG 1
37 #include "gstvaapidebug.h"
38
39 G_DEFINE_TYPE(GstVaapiImage, gst_vaapi_image, GST_VAAPI_TYPE_OBJECT)
40
41 #define GST_VAAPI_IMAGE_GET_PRIVATE(obj)                \
42     (G_TYPE_INSTANCE_GET_PRIVATE((obj),                 \
43                                  GST_VAAPI_TYPE_IMAGE,  \
44                                  GstVaapiImagePrivate))
45
46 struct _GstVaapiImagePrivate {
47     VAImage             internal_image;
48     VAImage             image;
49     guchar             *image_data;
50     GstVaapiImageFormat internal_format;
51     GstVaapiImageFormat format;
52     guint               width;
53     guint               height;
54     guint               create_image    : 1;
55     guint               is_constructed  : 1;
56     guint               is_linear       : 1;
57 };
58
59 enum {
60     PROP_0,
61
62     PROP_IMAGE,
63     PROP_FORMAT,
64     PROP_WIDTH,
65     PROP_HEIGHT
66 };
67
68 #define SWAP_UINT(a, b) do { \
69         guint v = a;         \
70         a = b;               \
71         b = v;               \
72     } while (0)
73
74 static gboolean
75 _gst_vaapi_image_map(GstVaapiImage *image, GstVaapiImageRaw *raw_image);
76
77 static gboolean
78 _gst_vaapi_image_unmap(GstVaapiImage *image);
79
80 static gboolean
81 _gst_vaapi_image_set_image(GstVaapiImage *image, const VAImage *va_image);
82
83 /*
84  * VAImage wrapper
85  */
86
87 #define VAAPI_TYPE_IMAGE vaapi_image_get_type()
88
89 static gpointer
90 vaapi_image_copy(gpointer va_image)
91 {
92     return g_slice_dup(VAImage, va_image);
93 }
94
95 static void
96 vaapi_image_free(gpointer va_image)
97 {
98     if (G_LIKELY(va_image))
99         g_slice_free(VAImage, va_image);
100 }
101
102 static GType
103 vaapi_image_get_type(void)
104 {
105     static GType type = 0;
106
107     if (G_UNLIKELY(type == 0))
108         type = g_boxed_type_register_static(
109             "VAImage",
110             vaapi_image_copy,
111             vaapi_image_free
112         );
113     return type;
114 }
115
116 static gboolean
117 vaapi_image_is_linear(const VAImage *va_image)
118 {
119     guint i, width, height, width2, height2, data_size;
120
121     for (i = 1; i < va_image->num_planes; i++)
122         if (va_image->offsets[i] < va_image->offsets[i - 1])
123             return FALSE;
124
125     width   = va_image->width;
126     height  = va_image->height;
127     width2  = (width  + 1) / 2;
128     height2 = (height + 1) / 2;
129
130     switch (va_image->format.fourcc) {
131     case VA_FOURCC('N','V','1','2'):
132     case VA_FOURCC('Y','V','1','2'):
133     case VA_FOURCC('I','4','2','0'):
134         data_size = width * height + 2 * width2 * height2;
135         break;
136     case VA_FOURCC('A','Y','U','V'):
137     case VA_FOURCC('A','R','G','B'):
138     case VA_FOURCC('R','G','B','A'):
139     case VA_FOURCC('A','B','G','R'):
140     case VA_FOURCC('B','G','R','A'):
141         data_size = 4 * width * height;
142         break;
143     default:
144         g_error("FIXME: incomplete formats");
145         break;
146     }
147     return va_image->data_size == data_size;
148 }
149
150 static void
151 gst_vaapi_image_destroy(GstVaapiImage *image)
152 {
153     GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(image);
154     VAImageID image_id;
155     VAStatus status;
156
157     _gst_vaapi_image_unmap(image);
158
159     image_id = GST_VAAPI_OBJECT_ID(image);
160     GST_DEBUG("image %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(image_id));
161
162     if (image_id != VA_INVALID_ID) {
163         GST_VAAPI_DISPLAY_LOCK(display);
164         status = vaDestroyImage(GST_VAAPI_DISPLAY_VADISPLAY(display), image_id);
165         GST_VAAPI_DISPLAY_UNLOCK(display);
166         if (!vaapi_check_status(status, "vaDestroyImage()"))
167             g_warning("failed to destroy image %" GST_VAAPI_ID_FORMAT,
168                       GST_VAAPI_ID_ARGS(image_id));
169         GST_VAAPI_OBJECT_ID(image) = VA_INVALID_ID;
170     }
171 }
172
173 static gboolean
174 _gst_vaapi_image_create(GstVaapiImage *image, GstVaapiImageFormat format)
175 {
176     GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(image);
177     GstVaapiImagePrivate * const priv = image->priv;
178     const VAImageFormat *va_format;
179     VAStatus status;
180
181     if (!gst_vaapi_display_has_image_format(display, format))
182         return FALSE;
183
184     va_format = gst_vaapi_image_format_get_va_format(format);
185     if (!va_format)
186         return FALSE;
187
188     GST_VAAPI_DISPLAY_LOCK(display);
189     status = vaCreateImage(
190         GST_VAAPI_DISPLAY_VADISPLAY(display),
191         (VAImageFormat *)va_format,
192         priv->width,
193         priv->height,
194         &priv->internal_image
195     );
196     GST_VAAPI_DISPLAY_UNLOCK(display);
197     if (status != VA_STATUS_SUCCESS ||
198         priv->internal_image.format.fourcc != va_format->fourcc)
199         return FALSE;
200
201     priv->internal_format = format;
202     return TRUE;
203 }
204
205 static gboolean
206 gst_vaapi_image_create(GstVaapiImage *image)
207 {
208     GstVaapiImagePrivate * const priv = image->priv;
209     GstVaapiImageFormat format = priv->format;
210     const VAImageFormat *va_format;
211     VAImageID image_id;
212
213     if (!priv->create_image)
214         return (priv->image.image_id != VA_INVALID_ID &&
215                 priv->image.buf      != VA_INVALID_ID);
216
217     if (!_gst_vaapi_image_create(image, format)) {
218         switch (format) {
219         case GST_VAAPI_IMAGE_I420:
220             format = GST_VAAPI_IMAGE_YV12;
221             break;
222         case GST_VAAPI_IMAGE_YV12:
223             format = GST_VAAPI_IMAGE_I420;
224             break;
225         default:
226             format = 0;
227             break;
228         }
229         if (!format || !_gst_vaapi_image_create(image, format))
230             return FALSE;
231     }
232     priv->image = priv->internal_image;
233     image_id    = priv->image.image_id;
234
235     if (priv->format != priv->internal_format) {
236         switch (priv->format) {
237         case GST_VAAPI_IMAGE_YV12:
238         case GST_VAAPI_IMAGE_I420:
239             va_format = gst_vaapi_image_format_get_va_format(priv->format);
240             if (!va_format)
241                 return FALSE;
242             priv->image.format = *va_format;
243             SWAP_UINT(priv->image.offsets[1], priv->image.offsets[2]);
244             SWAP_UINT(priv->image.pitches[1], priv->image.pitches[2]);
245             break;
246         default:
247             break;
248         }
249     }
250     priv->is_linear = vaapi_image_is_linear(&priv->image);
251
252     GST_DEBUG("image %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(image_id));
253     GST_VAAPI_OBJECT_ID(image) = image_id;
254     return TRUE;
255 }
256
257 static void
258 gst_vaapi_image_finalize(GObject *object)
259 {
260     gst_vaapi_image_destroy(GST_VAAPI_IMAGE(object));
261
262     G_OBJECT_CLASS(gst_vaapi_image_parent_class)->finalize(object);
263 }
264
265 static void
266 gst_vaapi_image_set_property(
267     GObject      *object,
268     guint         prop_id,
269     const GValue *value,
270     GParamSpec   *pspec
271 )
272 {
273     GstVaapiImage        * const image = GST_VAAPI_IMAGE(object);
274     GstVaapiImagePrivate * const priv  = image->priv;
275
276     switch (prop_id) {
277     case PROP_IMAGE: {
278         const VAImage * const va_image = g_value_get_boxed(value);
279         if (va_image)
280             _gst_vaapi_image_set_image(image, va_image);
281         break;
282     }
283     case PROP_FORMAT:
284         if (priv->create_image)
285             priv->format = g_value_get_uint(value);
286         break;
287     case PROP_WIDTH:
288         if (priv->create_image)
289             priv->width = g_value_get_uint(value);
290         break;
291     case PROP_HEIGHT:
292         if (priv->create_image)
293             priv->height = g_value_get_uint(value);
294         break;
295     default:
296         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
297         break;
298     }
299 }
300
301 static void
302 gst_vaapi_image_get_property(
303     GObject    *object,
304     guint       prop_id,
305     GValue     *value,
306     GParamSpec *pspec
307 )
308 {
309     GstVaapiImage * const image = GST_VAAPI_IMAGE(object);
310
311     switch (prop_id) {
312     case PROP_IMAGE:
313         g_value_set_boxed(value, &image->priv->image);
314         break;
315     case PROP_FORMAT:
316         g_value_set_uint(value, gst_vaapi_image_get_format(image));
317         break;
318     case PROP_WIDTH:
319         g_value_set_uint(value, gst_vaapi_image_get_width(image));
320         break;
321     case PROP_HEIGHT:
322         g_value_set_uint(value, gst_vaapi_image_get_height(image));
323         break;
324     default:
325         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
326         break;
327     }
328 }
329
330 static void
331 gst_vaapi_image_constructed(GObject *object)
332 {
333     GstVaapiImage * const image = GST_VAAPI_IMAGE(object);
334     GObjectClass *parent_class;
335
336     image->priv->is_constructed = gst_vaapi_image_create(image);
337
338     parent_class = G_OBJECT_CLASS(gst_vaapi_image_parent_class);
339     if (parent_class->constructed)
340         parent_class->constructed(object);
341 }
342
343 static void
344 gst_vaapi_image_class_init(GstVaapiImageClass *klass)
345 {
346     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
347
348     g_type_class_add_private(klass, sizeof(GstVaapiImagePrivate));
349
350     object_class->finalize     = gst_vaapi_image_finalize;
351     object_class->set_property = gst_vaapi_image_set_property;
352     object_class->get_property = gst_vaapi_image_get_property;
353     object_class->constructed  = gst_vaapi_image_constructed;
354
355     g_object_class_install_property
356         (object_class,
357          PROP_IMAGE,
358          g_param_spec_boxed("image",
359                             "Image",
360                             "The underlying VA image",
361                             VAAPI_TYPE_IMAGE,
362                             G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
363
364     g_object_class_install_property
365         (object_class,
366          PROP_WIDTH,
367          g_param_spec_uint("width",
368                            "width",
369                            "The image width",
370                            0, G_MAXUINT32, 0,
371                            G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
372
373     g_object_class_install_property
374         (object_class,
375          PROP_HEIGHT,
376          g_param_spec_uint("height",
377                            "heighr",
378                            "The image height",
379                            0, G_MAXUINT32, 0,
380                            G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
381
382     /**
383      * GstVaapiImage:format:
384      *
385      * The #GstVaapiImageFormat of the image
386      */
387     g_object_class_install_property
388         (object_class,
389          PROP_FORMAT,
390          g_param_spec_uint("format",
391                            "Format",
392                            "The underlying image format",
393                            0, G_MAXUINT32, 0,
394                            G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
395 }
396
397 static void
398 gst_vaapi_image_init(GstVaapiImage *image)
399 {
400     GstVaapiImagePrivate *priv = GST_VAAPI_IMAGE_GET_PRIVATE(image);
401
402     image->priv                   = priv;
403     priv->image_data              = NULL;
404     priv->width                   = 0;
405     priv->height                  = 0;
406     priv->internal_format         = 0;
407     priv->format                  = 0;
408     priv->create_image            = TRUE;
409     priv->is_constructed          = FALSE;
410     priv->is_linear               = FALSE;
411
412     memset(&priv->internal_image, 0, sizeof(priv->internal_image));
413     priv->internal_image.image_id = VA_INVALID_ID;
414     priv->internal_image.buf      = VA_INVALID_ID;
415
416     memset(&priv->image, 0, sizeof(priv->image));
417     priv->image.image_id          = VA_INVALID_ID;
418     priv->image.buf               = VA_INVALID_ID;
419 }
420
421 /**
422  * gst_vaapi_image_new:
423  * @display: a #GstVaapiDisplay
424  * @format: a #GstVaapiImageFormat
425  * @width: the requested image width
426  * @height: the requested image height
427  *
428  * Creates a new #GstVaapiImage with the specified format and
429  * dimensions.
430  *
431  * Return value: the newly allocated #GstVaapiImage object
432  */
433 GstVaapiImage *
434 gst_vaapi_image_new(
435     GstVaapiDisplay    *display,
436     GstVaapiImageFormat format,
437     guint               width,
438     guint               height
439 )
440 {
441     GstVaapiImage *image;
442
443     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
444     g_return_val_if_fail(width > 0, NULL);
445     g_return_val_if_fail(height > 0, NULL);
446
447     GST_DEBUG("format %" GST_FOURCC_FORMAT ", size %ux%u",
448               GST_FOURCC_ARGS(format), width, height);
449
450     image = g_object_new(
451         GST_VAAPI_TYPE_IMAGE,
452         "display", display,
453         "id",      GST_VAAPI_ID(VA_INVALID_ID),
454         "format",  format,
455         "width",   width,
456         "height",  height,
457         NULL
458     );
459     if (!image)
460         return NULL;
461
462     if (!image->priv->is_constructed) {
463         g_object_unref(image);
464         return NULL;
465     }
466     return image;
467 }
468
469 /**
470  * gst_vaapi_image_new_with_image:
471  * @display: a #GstVaapiDisplay
472  * @va_image: a VA image
473  *
474  * Creates a new #GstVaapiImage from a foreign VA image. The image
475  * format and dimensions will be extracted from @va_image. This
476  * function is mainly used by gst_vaapi_surface_derive_image() to bind
477  * a VA image to a #GstVaapiImage object.
478  *
479  * Return value: the newly allocated #GstVaapiImage object
480  */
481 GstVaapiImage *
482 gst_vaapi_image_new_with_image(GstVaapiDisplay *display, VAImage *va_image)
483 {
484     GstVaapiImage *image;
485
486     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
487     g_return_val_if_fail(va_image, NULL);
488     g_return_val_if_fail(va_image->image_id != VA_INVALID_ID, NULL);
489     g_return_val_if_fail(va_image->buf != VA_INVALID_ID, NULL);
490
491     GST_DEBUG("VA image 0x%08x, format %" GST_FOURCC_FORMAT ", size %ux%u",
492               va_image->image_id,
493               GST_FOURCC_ARGS(va_image->format.fourcc),
494               va_image->width, va_image->height);
495
496     image = g_object_new(
497         GST_VAAPI_TYPE_IMAGE,
498         "display", display,
499         "id",      GST_VAAPI_ID(va_image->image_id),
500         "image",   va_image,
501         NULL
502     );
503     if (!image)
504         return NULL;
505
506     if (!image->priv->is_constructed) {
507         g_object_unref(image);
508         return NULL;
509     }
510     return image;
511 }
512
513 /**
514  * gst_vaapi_image_get_id:
515  * @image: a #GstVaapiImage
516  *
517  * Returns the underlying VAImageID of the @image.
518  *
519  * Return value: the underlying VA image id
520  */
521 GstVaapiID
522 gst_vaapi_image_get_id(GstVaapiImage *image)
523 {
524     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), VA_INVALID_ID);
525     g_return_val_if_fail(image->priv->is_constructed, VA_INVALID_ID);
526
527     return GST_VAAPI_OBJECT_ID(image);
528 }
529
530 /**
531  * gst_vaapi_image_get_image:
532  * @image: a #GstVaapiImage
533  * @va_image: a VA image
534  *
535  * Fills @va_image with the VA image used internally.
536  *
537  * Return value: %TRUE on success
538  */
539 gboolean
540 gst_vaapi_image_get_image(GstVaapiImage *image, VAImage *va_image)
541 {
542     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
543     g_return_val_if_fail(image->priv->is_constructed, FALSE);
544
545     if (va_image)
546         *va_image = image->priv->image;
547
548     return TRUE;
549 }
550
551 /*
552  * _gst_vaapi_image_set_image:
553  * @image: a #GstVaapiImage
554  * @va_image: a VA image
555  *
556  * Initializes #GstVaapiImage with a foreign VA image. This function
557  * will try to "linearize" the VA image. i.e. making sure that the VA
558  * image offsets into the data buffer are in increasing order with the
559  * number of planes available in the image.
560  *
561  * This is an internal function used by gst_vaapi_image_new_with_image().
562  *
563  * Return value: %TRUE on success
564  */
565 gboolean
566 _gst_vaapi_image_set_image(GstVaapiImage *image, const VAImage *va_image)
567 {
568     GstVaapiImagePrivate * const priv = image->priv;
569     GstVaapiImageFormat format;
570     VAImage alt_va_image;
571     const VAImageFormat *alt_va_format;
572
573     if (!va_image)
574         return FALSE;
575
576     format = gst_vaapi_image_format(&va_image->format);
577     if (!format)
578         return FALSE;
579
580     priv->create_image    = FALSE;
581     priv->internal_image  = *va_image;
582     priv->internal_format = format;
583     priv->is_linear       = vaapi_image_is_linear(va_image);
584     priv->image           = *va_image;
585     priv->format          = format;
586     priv->width           = va_image->width;
587     priv->height          = va_image->height;
588
589     /* Try to linearize image */
590     if (!priv->is_linear) {
591         switch (format) {
592         case GST_VAAPI_IMAGE_I420:
593             format = GST_VAAPI_IMAGE_YV12;
594             break;
595         case GST_VAAPI_IMAGE_YV12:
596             format = GST_VAAPI_IMAGE_I420;
597             break;
598         default:
599             format = 0;
600             break;
601         }
602         if (format &&
603             (alt_va_format = gst_vaapi_image_format_get_va_format(format))) {
604             alt_va_image = *va_image;
605             alt_va_image.format = *alt_va_format;
606             SWAP_UINT(alt_va_image.offsets[1], alt_va_image.offsets[2]);
607             SWAP_UINT(alt_va_image.pitches[1], alt_va_image.pitches[2]);
608             if (vaapi_image_is_linear(&alt_va_image)) {
609                 priv->image     = alt_va_image;
610                 priv->format    = format;
611                 priv->is_linear = TRUE;
612                 GST_DEBUG("linearized image to %" GST_FOURCC_FORMAT " format",
613                           GST_FOURCC_ARGS(format));
614             }
615         }
616     }
617     return TRUE;
618 }
619
620 /**
621  * gst_vaapi_image_get_format:
622  * @image: a #GstVaapiImage
623  *
624  * Returns the #GstVaapiImageFormat the @image was created with.
625  *
626  * Return value: the #GstVaapiImageFormat
627  */
628 GstVaapiImageFormat
629 gst_vaapi_image_get_format(GstVaapiImage *image)
630 {
631     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
632     g_return_val_if_fail(image->priv->is_constructed, 0);
633
634     return image->priv->format;
635 }
636
637 /**
638  * gst_vaapi_image_get_width:
639  * @image: a #GstVaapiImage
640  *
641  * Returns the @image width.
642  *
643  * Return value: the image width, in pixels
644  */
645 guint
646 gst_vaapi_image_get_width(GstVaapiImage *image)
647 {
648     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
649     g_return_val_if_fail(image->priv->is_constructed, 0);
650
651     return image->priv->width;
652 }
653
654 /**
655  * gst_vaapi_image_get_height:
656  * @image: a #GstVaapiImage
657  *
658  * Returns the @image height.
659  *
660  * Return value: the image height, in pixels.
661  */
662 guint
663 gst_vaapi_image_get_height(GstVaapiImage *image)
664 {
665     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
666     g_return_val_if_fail(image->priv->is_constructed, 0);
667
668     return image->priv->height;
669 }
670
671 /**
672  * gst_vaapi_image_get_size:
673  * @image: a #GstVaapiImage
674  * @pwidth: return location for the width, or %NULL
675  * @pheight: return location for the height, or %NULL
676  *
677  * Retrieves the dimensions of a #GstVaapiImage.
678  */
679 void
680 gst_vaapi_image_get_size(GstVaapiImage *image, guint *pwidth, guint *pheight)
681 {
682     g_return_if_fail(GST_VAAPI_IS_IMAGE(image));
683     g_return_if_fail(image->priv->is_constructed);
684
685     if (pwidth)
686         *pwidth = image->priv->width;
687
688     if (pheight)
689         *pheight = image->priv->height;
690 }
691
692 /**
693  * gst_vaapi_image_is_linear:
694  * @image: a #GstVaapiImage
695  *
696  * Checks whether the @image has data planes allocated from a single
697  * buffer and offsets into that buffer are in increasing order with
698  * the number of planes.
699  *
700  * Return value: %TRUE if image data planes are allocated from a single buffer
701  */
702 gboolean
703 gst_vaapi_image_is_linear(GstVaapiImage *image)
704 {
705     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
706     g_return_val_if_fail(image->priv->is_constructed, FALSE);
707
708     return image->priv->is_linear;
709 }
710
711 /**
712  * gst_vaapi_image_is_mapped:
713  * @image: a #GstVaapiImage
714  *
715  * Checks whether the @image is currently mapped or not.
716  *
717  * Return value: %TRUE if the @image is mapped
718  */
719 static inline gboolean
720 _gst_vaapi_image_is_mapped(GstVaapiImage *image)
721 {
722     return image->priv->image_data != NULL;
723 }
724
725 gboolean
726 gst_vaapi_image_is_mapped(GstVaapiImage *image)
727 {
728     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
729     g_return_val_if_fail(image->priv->is_constructed, FALSE);
730
731     return _gst_vaapi_image_is_mapped(image);
732 }
733
734 /**
735  * gst_vaapi_image_map:
736  * @image: a #GstVaapiImage
737  *
738  * Maps the image data buffer. The actual pixels are returned by the
739  * gst_vaapi_image_get_plane() function.
740  *
741  * Return value: %TRUE on success
742  */
743 gboolean
744 gst_vaapi_image_map(GstVaapiImage *image)
745 {
746     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
747     g_return_val_if_fail(image->priv->is_constructed, FALSE);
748
749     return _gst_vaapi_image_map(image, NULL);
750 }
751
752 gboolean
753 _gst_vaapi_image_map(GstVaapiImage *image, GstVaapiImageRaw *raw_image)
754 {
755     GstVaapiImagePrivate * const priv = image->priv;
756     GstVaapiDisplay *display;
757     void *image_data;
758     VAStatus status;
759     guint i;
760
761     if (_gst_vaapi_image_is_mapped(image))
762         return TRUE;
763
764     display = GST_VAAPI_OBJECT_DISPLAY(image);
765     if (!display)
766         return FALSE;
767
768     GST_VAAPI_DISPLAY_LOCK(display);
769     status = vaMapBuffer(
770         GST_VAAPI_DISPLAY_VADISPLAY(display),
771         image->priv->image.buf,
772         &image_data
773     );
774     GST_VAAPI_DISPLAY_UNLOCK(display);
775     if (!vaapi_check_status(status, "vaMapBuffer()"))
776         return FALSE;
777
778     image->priv->image_data = image_data;
779
780     if (raw_image) {
781         const VAImage * const va_image = &priv->image;
782         raw_image->format     = priv->format;
783         raw_image->width      = va_image->width;
784         raw_image->height     = va_image->height;
785         raw_image->num_planes = va_image->num_planes;
786         for (i = 0; i < raw_image->num_planes; i++) {
787             raw_image->pixels[i] = (guchar *)image_data + va_image->offsets[i];
788             raw_image->stride[i] = va_image->pitches[i];
789         }
790     }
791     return TRUE;
792 }
793
794 /**
795  * gst_vaapi_image_unmap:
796  * @image: a #GstVaapiImage
797  *
798  * Unmaps the image data buffer. Pointers to pixels returned by
799  * gst_vaapi_image_get_plane() are then no longer valid.
800  *
801  * Return value: %TRUE on success
802  */
803 gboolean
804 gst_vaapi_image_unmap(GstVaapiImage *image)
805 {
806     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
807     g_return_val_if_fail(image->priv->is_constructed, FALSE);
808
809     return _gst_vaapi_image_unmap(image);
810 }
811
812 gboolean
813 _gst_vaapi_image_unmap(GstVaapiImage *image)
814 {
815     GstVaapiDisplay *display;
816     VAStatus status;
817
818     if (!_gst_vaapi_image_is_mapped(image))
819         return FALSE;
820
821     display = GST_VAAPI_OBJECT_DISPLAY(image);
822     if (!display)
823         return FALSE;
824
825     GST_VAAPI_DISPLAY_LOCK(display);
826     status = vaUnmapBuffer(
827         GST_VAAPI_DISPLAY_VADISPLAY(display),
828         image->priv->image.buf
829     );
830     GST_VAAPI_DISPLAY_UNLOCK(display);
831     if (!vaapi_check_status(status, "vaUnmapBuffer()"))
832         return FALSE;
833
834     image->priv->image_data = NULL;
835     return TRUE;
836 }
837
838 /**
839  * gst_vaapi_image_get_plane_count:
840  * @image: a #GstVaapiImage
841  *
842  * Retrieves the number of planes available in the @image. The @image
843  * must be mapped for this function to work properly.
844  *
845  * Return value: the number of planes available in the @image
846  */
847 guint
848 gst_vaapi_image_get_plane_count(GstVaapiImage *image)
849 {
850     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
851     g_return_val_if_fail(image->priv->is_constructed, FALSE);
852     g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), 0);
853
854     return image->priv->image.num_planes;
855 }
856
857 /**
858  * gst_vaapi_image_get_plane:
859  * @image: a #GstVaapiImage
860  * @plane: the requested plane number
861  *
862  * Retrieves the pixels data to the specified @plane. The @image must
863  * be mapped for this function to work properly.
864  *
865  * Return value: the pixels data of the specified @plane
866  */
867 guchar *
868 gst_vaapi_image_get_plane(GstVaapiImage *image, guint plane)
869 {
870     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), NULL);
871     g_return_val_if_fail(image->priv->is_constructed, FALSE);
872     g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), NULL);
873     g_return_val_if_fail(plane < image->priv->image.num_planes, NULL);
874
875     return image->priv->image_data + image->priv->image.offsets[plane];
876 }
877
878 /**
879  * gst_vaapi_image_get_pitch:
880  * @image: a #GstVaapiImage
881  * @plane: the requested plane number
882  *
883  * Retrieves the line size (stride) of the specified @plane. The
884  * @image must be mapped for this function to work properly.
885  *
886  * Return value: the line size (stride) of the specified plane
887  */
888 guint
889 gst_vaapi_image_get_pitch(GstVaapiImage *image, guint plane)
890 {
891     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
892     g_return_val_if_fail(image->priv->is_constructed, FALSE);
893     g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), 0);
894     g_return_val_if_fail(plane < image->priv->image.num_planes, 0);
895
896     return image->priv->image.pitches[plane];
897 }
898
899 /**
900  * gst_vaapi_image_get_data_size:
901  * @image: a #GstVaapiImage
902  *
903  * Retrieves the underlying image data size. This function could be
904  * used to determine whether the image has a compatible layout with
905  * another image structure.
906  *
907  * Return value: the whole image data size of the @image
908  */
909 guint
910 gst_vaapi_image_get_data_size(GstVaapiImage *image)
911 {
912     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
913     g_return_val_if_fail(image->priv->is_constructed, FALSE);
914
915     return image->priv->image.data_size;
916 }
917
918 static gboolean
919 init_image_from_buffer(GstVaapiImageRaw *raw_image, GstBuffer *buffer)
920 {
921     GstStructure *structure;
922     GstCaps *caps;
923     GstVaapiImageFormat format;
924     guint width2, height2, size2;
925     gint width, height;
926     guchar *data;
927     guint32 data_size;
928
929     data      = GST_BUFFER_DATA(buffer);
930     data_size = GST_BUFFER_SIZE(buffer);
931     caps      = GST_BUFFER_CAPS(buffer);
932
933     if (!caps)
934         return FALSE;
935
936     format = gst_vaapi_image_format_from_caps(caps);
937
938     structure = gst_caps_get_structure(caps, 0);
939     gst_structure_get_int(structure, "width",  &width);
940     gst_structure_get_int(structure, "height", &height);
941
942     /* XXX: copied from gst_video_format_get_row_stride() -- no NV12? */
943     raw_image->format = format;
944     raw_image->width  = width;
945     raw_image->height = height;
946     width2  = (width + 1) / 2;
947     height2 = (height + 1) / 2;
948     size2   = 0;
949     switch (format) {
950     case GST_VAAPI_IMAGE_NV12:
951         raw_image->num_planes = 2;
952         raw_image->pixels[0]  = data;
953         raw_image->stride[0]  = GST_ROUND_UP_4(width);
954         size2                += height * raw_image->stride[0];
955         raw_image->pixels[1]  = data + size2;
956         raw_image->stride[1]  = raw_image->stride[0];
957         size2                += height2 * raw_image->stride[1];
958         break;
959     case GST_VAAPI_IMAGE_YV12:
960     case GST_VAAPI_IMAGE_I420:
961         raw_image->num_planes = 3;
962         raw_image->pixels[0]  = data;
963         raw_image->stride[0]  = GST_ROUND_UP_4(width);
964         size2                += height * raw_image->stride[0];
965         raw_image->pixels[1]  = data + size2;
966         raw_image->stride[1]  = GST_ROUND_UP_4(width2);
967         size2                += height2 * raw_image->stride[1];
968         raw_image->pixels[2]  = data + size2;
969         raw_image->stride[2]  = raw_image->stride[1];
970         size2                += height2 * raw_image->stride[2];
971         break;
972     case GST_VAAPI_IMAGE_ARGB:
973     case GST_VAAPI_IMAGE_RGBA:
974     case GST_VAAPI_IMAGE_ABGR:
975     case GST_VAAPI_IMAGE_BGRA:
976         raw_image->num_planes = 1;
977         raw_image->pixels[0]  = data;
978         raw_image->stride[0]  = width * 4;
979         size2                += height * raw_image->stride[0];
980         break;
981     default:
982         g_error("could not compute row-stride for %" GST_FOURCC_FORMAT,
983                 GST_FOURCC_ARGS(format));
984         return FALSE;
985     }
986
987     if (size2 != data_size) {
988         g_error("data_size mismatch %d / %u", size2, data_size);
989         if (size2 > data_size)
990             return FALSE;
991     }
992     return TRUE;
993 }
994
995 /* Copy N lines of an image */
996 static inline void
997 memcpy_pic(
998     guchar       *dst,
999     guint         dst_stride,
1000     const guchar *src,
1001     guint         src_stride,
1002     guint         len,
1003     guint         height
1004 )
1005 {
1006     guint i;
1007
1008     for (i = 0; i < height; i++)  {
1009         memcpy(dst, src, len);
1010         dst += dst_stride;
1011         src += src_stride;
1012     }
1013 }
1014
1015 /* Copy NV12 images */
1016 static void
1017 copy_image_NV12(
1018     GstVaapiImageRaw        *dst_image,
1019     GstVaapiImageRaw        *src_image,
1020     const GstVaapiRectangle *rect
1021 )
1022 {
1023     guchar *dst, *src;
1024     guint dst_stride, src_stride;
1025
1026     /* Y plane */
1027     dst_stride = dst_image->stride[0];
1028     dst = dst_image->pixels[0] + rect->y * dst_stride + rect->x;
1029     src_stride = src_image->stride[0];
1030     src = src_image->pixels[0] + rect->y * src_stride + rect->x;
1031     memcpy_pic(dst, dst_stride, src, src_stride, rect->width, rect->height);
1032
1033     /* UV plane */
1034     dst_stride = dst_image->stride[1];
1035     dst = dst_image->pixels[1] + (rect->y / 2) * dst_stride + (rect->x & -2);
1036     src_stride = src_image->stride[1];
1037     src = src_image->pixels[1] + (rect->y / 2) * src_stride + (rect->x & -2);
1038     memcpy_pic(dst, dst_stride, src, src_stride, rect->width, rect->height / 2);
1039 }
1040
1041 /* Copy YV12 images */
1042 static void
1043 copy_image_YV12(
1044     GstVaapiImageRaw        *dst_image,
1045     GstVaapiImageRaw        *src_image,
1046     const GstVaapiRectangle *rect
1047 )
1048 {
1049     guchar *dst, *src;
1050     guint dst_stride, src_stride;
1051     guint i, x, y, w, h;
1052
1053     /* Y plane */
1054     dst_stride = dst_image->stride[0];
1055     dst = dst_image->pixels[0] + rect->y * dst_stride + rect->x;
1056     src_stride = src_image->stride[0];
1057     src = src_image->pixels[0] + rect->y * src_stride + rect->x;
1058     memcpy_pic(dst, dst_stride, src, src_stride, rect->width, rect->height);
1059
1060     /* U/V planes */
1061     x = rect->x / 2;
1062     y = rect->y / 2;
1063     w = rect->width / 2;
1064     h = rect->height / 2;
1065     for (i = 1; i < dst_image->num_planes; i++) {
1066         dst_stride = dst_image->stride[i];
1067         dst = dst_image->pixels[i] + y * dst_stride + x;
1068         src_stride = src_image->stride[i];
1069         src = src_image->pixels[i] + y * src_stride + x;
1070         memcpy_pic(dst, dst_stride, src, src_stride, w, h);
1071     }
1072 }
1073
1074 /* Copy RGBA images */
1075 static void
1076 copy_image_RGBA(
1077     GstVaapiImageRaw        *dst_image,
1078     GstVaapiImageRaw        *src_image,
1079     const GstVaapiRectangle *rect
1080 )
1081 {
1082     guchar *dst, *src;
1083     guint dst_stride, src_stride;
1084
1085     dst_stride = dst_image->stride[0];
1086     dst = dst_image->pixels[0] + rect->y * dst_stride + rect->x;
1087     src_stride = src_image->stride[0];
1088     src = src_image->pixels[0] + rect->y * src_stride + rect->x;
1089     memcpy_pic(dst, dst_stride, src, src_stride, 4 * rect->width, rect->height);
1090 }
1091
1092 static gboolean
1093 copy_image(
1094     GstVaapiImageRaw        *dst_image,
1095     GstVaapiImageRaw        *src_image,
1096     const GstVaapiRectangle *rect
1097 )
1098 {
1099     GstVaapiRectangle default_rect;
1100
1101     if (dst_image->format != src_image->format ||
1102         dst_image->width  != src_image->width  ||
1103         dst_image->height != src_image->height)
1104         return FALSE;
1105
1106     if (rect) {
1107         if (rect->x >= src_image->width ||
1108             rect->x + src_image->width > src_image->width ||
1109             rect->y >= src_image->height ||
1110             rect->y + src_image->height > src_image->height)
1111             return FALSE;
1112     }
1113     else {
1114         default_rect.x      = 0;
1115         default_rect.y      = 0;
1116         default_rect.width  = src_image->width;
1117         default_rect.height = src_image->height;
1118         rect                = &default_rect;
1119     }
1120
1121     switch (dst_image->format) {
1122     case GST_VAAPI_IMAGE_NV12:
1123         copy_image_NV12(dst_image, src_image, rect);
1124         break;
1125     case GST_VAAPI_IMAGE_YV12:
1126     case GST_VAAPI_IMAGE_I420:
1127         copy_image_YV12(dst_image, src_image, rect);
1128         break;
1129     case GST_VAAPI_IMAGE_ARGB:
1130     case GST_VAAPI_IMAGE_RGBA:
1131     case GST_VAAPI_IMAGE_ABGR:
1132     case GST_VAAPI_IMAGE_BGRA:
1133         copy_image_RGBA(dst_image, src_image, rect);
1134         break;
1135     default:
1136         GST_ERROR("unsupported image format for copy");
1137         return FALSE;
1138     }
1139     return TRUE;
1140 }
1141
1142 /**
1143  * gst_vaapi_image_get_buffer:
1144  * @image: a #GstVaapiImage
1145  * @buffer: a #GstBuffer
1146  * @rect: a #GstVaapiRectangle expressing a region, or %NULL for the
1147  *   whole image
1148  *
1149  * Transfers pixels data contained in the @image into the #GstBuffer.
1150  * Both image structures shall have the same format.
1151  *
1152  * Return value: %TRUE on success
1153  */
1154 gboolean
1155 gst_vaapi_image_get_buffer(
1156     GstVaapiImage     *image,
1157     GstBuffer         *buffer,
1158     GstVaapiRectangle *rect
1159 )
1160 {
1161     GstVaapiImagePrivate *priv;
1162     GstVaapiImageRaw dst_image, src_image;
1163     gboolean success;
1164
1165     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
1166     g_return_val_if_fail(image->priv->is_constructed, FALSE);
1167     g_return_val_if_fail(GST_IS_BUFFER(buffer), FALSE);
1168
1169     priv = image->priv;
1170
1171     if (!init_image_from_buffer(&dst_image, buffer))
1172         return FALSE;
1173     if (dst_image.format != priv->format)
1174         return FALSE;
1175     if (dst_image.width != priv->width || dst_image.height != priv->height)
1176         return FALSE;
1177
1178     if (!_gst_vaapi_image_map(image, &src_image))
1179         return FALSE;
1180
1181     success = copy_image(&dst_image, &src_image, rect);
1182
1183     if (!_gst_vaapi_image_unmap(image))
1184         return FALSE;
1185
1186     return success;
1187 }
1188
1189 /**
1190  * gst_vaapi_image_get_raw:
1191  * @image: a #GstVaapiImage
1192  * @dst_image: a #GstVaapiImageRaw
1193  * @rect: a #GstVaapiRectangle expressing a region, or %NULL for the
1194  *   whole image
1195  *
1196  * Transfers pixels data contained in the @image into the #GstVaapiImageRaw.
1197  * Both image structures shall have the same format.
1198  *
1199  * Return value: %TRUE on success
1200  */
1201 gboolean
1202 gst_vaapi_image_get_raw(
1203     GstVaapiImage     *image,
1204     GstVaapiImageRaw  *dst_image,
1205     GstVaapiRectangle *rect
1206 )
1207 {
1208     GstVaapiImageRaw src_image;
1209     gboolean success;
1210
1211     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
1212     g_return_val_if_fail(image->priv->is_constructed, FALSE);
1213
1214     if (!_gst_vaapi_image_map(image, &src_image))
1215         return FALSE;
1216
1217     success = copy_image(dst_image, &src_image, rect);
1218
1219     if (!_gst_vaapi_image_unmap(image))
1220         return FALSE;
1221
1222     return success;
1223 }
1224
1225 /**
1226  * gst_vaapi_image_update_from_buffer:
1227  * @image: a #GstVaapiImage
1228  * @buffer: a #GstBuffer
1229  * @rect: a #GstVaapiRectangle expressing a region, or %NULL for the
1230  *   whole image
1231  *
1232  * Transfers pixels data contained in the #GstBuffer into the
1233  * @image. Both image structures shall have the same format.
1234  *
1235  * Return value: %TRUE on success
1236  */
1237 gboolean
1238 gst_vaapi_image_update_from_buffer(
1239     GstVaapiImage     *image,
1240     GstBuffer         *buffer,
1241     GstVaapiRectangle *rect
1242 )
1243 {
1244     GstVaapiImagePrivate *priv;
1245     GstVaapiImageRaw dst_image, src_image;
1246     gboolean success;
1247
1248     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
1249     g_return_val_if_fail(image->priv->is_constructed, FALSE);
1250     g_return_val_if_fail(GST_IS_BUFFER(buffer), FALSE);
1251
1252     priv = image->priv;
1253
1254     if (!init_image_from_buffer(&src_image, buffer))
1255         return FALSE;
1256     if (src_image.format != priv->format)
1257         return FALSE;
1258     if (src_image.width != priv->width || src_image.height != priv->height)
1259         return FALSE;
1260
1261     if (!_gst_vaapi_image_map(image, &dst_image))
1262         return FALSE;
1263
1264     success = copy_image(&dst_image, &src_image, rect);
1265
1266     if (!_gst_vaapi_image_unmap(image))
1267         return FALSE;
1268
1269     return success;
1270 }
1271
1272 /**
1273  * gst_vaapi_image_update_from_raw:
1274  * @image: a #GstVaapiImage
1275  * @src_image: a #GstVaapiImageRaw
1276  * @buffer: a #GstBuffer
1277  * @rect: a #GstVaapiRectangle expressing a region, or %NULL for the
1278  *   whole image
1279  *
1280  * Transfers pixels data contained in the #GstVaapiImageRaw into the
1281  * @image. Both image structures shall have the same format.
1282  *
1283  * Return value: %TRUE on success
1284  */
1285 gboolean
1286 gst_vaapi_image_update_from_raw(
1287     GstVaapiImage     *image,
1288     GstVaapiImageRaw  *src_image,
1289     GstVaapiRectangle *rect
1290 )
1291 {
1292     GstVaapiImageRaw dst_image;
1293     gboolean success;
1294
1295     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
1296     g_return_val_if_fail(image->priv->is_constructed, FALSE);
1297
1298     if (!_gst_vaapi_image_map(image, &dst_image))
1299         return FALSE;
1300
1301     success = copy_image(&dst_image, src_image, rect);
1302
1303     if (!_gst_vaapi_image_unmap(image))
1304         return FALSE;
1305
1306     return success;
1307 }
1308
1309 static gboolean
1310 _image_convert_to_nv12(
1311   guint8 *src,
1312   guint32 width,
1313   guint32 height,
1314   GstVaapiImageFormat src_format,
1315   guint8 *dest,
1316   VAImage *va_image)
1317 {
1318   guint8 *y_src, *u_src, *v_src, *uv_src;
1319   guint8 *y_dest, *uv_dest;
1320   guint32 ystride, ustride, vstride, uv_stride;
1321   guint row, column;
1322
1323   y_src = src;
1324   ystride = GST_ROUND_UP_4(width);
1325
1326   y_dest = dest + va_image->offsets[0];
1327   uv_dest = dest + va_image->offsets[1];
1328   g_assert(va_image->num_planes == 2);
1329
1330   /* copy Y first */
1331   for (row = 0; row < height; row++) {
1332     memcpy(y_dest, y_src, width);
1333     y_src += ystride;
1334     y_dest += va_image->pitches[0];
1335   }
1336
1337   switch (src_format) {
1338     case GST_VAAPI_IMAGE_NV12: {
1339       uv_src = src + ystride*GST_ROUND_UP_2(height);
1340       uv_stride = ystride;
1341       for (row = 0; row < GST_ROUND_UP_2(height)/2; row++) {
1342         memcpy(uv_dest, uv_src, width);
1343         uv_src += uv_stride;
1344         uv_dest += va_image->pitches[1];
1345       }
1346     }
1347     break;
1348
1349     case GST_VAAPI_IMAGE_I420: {
1350       u_src = src + ystride*GST_ROUND_UP_2(height);
1351       ustride = GST_ROUND_UP_8(ystride)/2;
1352       v_src = u_src + ustride*GST_ROUND_UP_2(height)/2;
1353       vstride = GST_ROUND_UP_8(ystride)/2;
1354
1355       for (row = 0; row < GST_ROUND_UP_2(height)/2; row++) {
1356         for (column = 0; column < width/2; column++) {
1357           uv_dest[column*2] = u_src[column];
1358           uv_dest[column*2+1] = v_src[column];
1359         }
1360         u_src += ustride;
1361         v_src += vstride;
1362         uv_dest += va_image->pitches[1];
1363       }
1364     }
1365     break;
1366
1367     case GST_VAAPI_IMAGE_YV12:{
1368       v_src = src + ystride*GST_ROUND_UP_2(height);
1369       vstride = GST_ROUND_UP_8(ystride)/2;
1370       u_src = v_src + vstride*GST_ROUND_UP_2(height)/2;
1371       ustride = GST_ROUND_UP_8(ystride)/2;
1372
1373       for (row = 0; row < GST_ROUND_UP_2(height)/2; row++) {
1374         for (column = 0; column < width/2; column++) {
1375           uv_dest[column*2] = u_src[column];
1376           uv_dest[column*2+1] = v_src[column];
1377         }
1378         u_src += ustride;
1379         v_src += vstride;
1380         uv_dest += va_image->pitches[1];
1381       }
1382     }
1383     break;
1384
1385     default:
1386       return FALSE;
1387   }
1388   return TRUE;
1389 }
1390
1391
1392 gboolean
1393 gst_vaapi_convert_buffer_to_image(
1394     GstVaapiImage *image,
1395     GstBuffer *inbuf, // inbuf : I420
1396     GstVaapiImageFormat in_format)
1397 {
1398   GstVaapiImagePrivate *priv;
1399   guint width, height;
1400   GstVaapiImageFormat image_format;
1401   gboolean success = TRUE;
1402
1403   priv = image->priv;
1404   gst_vaapi_image_get_size(image, &width, &height);
1405   image_format = gst_vaapi_image_get_format(image);
1406
1407   /* currently only support YUV convert */
1408   if ( (in_format != GST_VAAPI_IMAGE_NV12
1409         && in_format != GST_VAAPI_IMAGE_YV12
1410         && in_format != GST_VAAPI_IMAGE_I420)
1411       || (image_format != GST_VAAPI_IMAGE_NV12
1412         && image_format != GST_VAAPI_IMAGE_YV12
1413         && image_format != GST_VAAPI_IMAGE_I420)
1414       )
1415   {
1416       return FALSE;
1417   }
1418
1419
1420   gst_vaapi_image_map(image);
1421   switch (image_format) {
1422     case GST_VAAPI_IMAGE_NV12:
1423       success = _image_convert_to_nv12(GST_BUFFER_DATA(inbuf),
1424                                        width, height, in_format,
1425                                        priv->image_data,
1426                                        &priv->image);
1427     break;
1428
1429     case GST_VAAPI_IMAGE_I420:
1430     case GST_VAAPI_IMAGE_YV12:
1431       success = FALSE;
1432       break;
1433
1434     default:
1435       success = FALSE;
1436       break;
1437   }
1438   gst_vaapi_image_unmap(image);
1439
1440   return success;
1441 }
1442