Add gst_vaapi_surface_derive_image() API.
[profile/ivi/gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapiimage.c
1 /*
2  *  gstvaapiimage.c - VA image 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 #include "config.h"
22 #include <string.h>
23 #include "gstvaapiutils.h"
24 #include "gstvaapiimage.h"
25 #include <va/va_backend.h>
26
27 #define DEBUG 1
28 #include "gstvaapidebug.h"
29
30 G_DEFINE_TYPE(GstVaapiImage, gst_vaapi_image, G_TYPE_OBJECT);
31
32 #define GST_VAAPI_IMAGE_GET_PRIVATE(obj)                \
33     (G_TYPE_INSTANCE_GET_PRIVATE((obj),                 \
34                                  GST_VAAPI_TYPE_IMAGE,  \
35                                  GstVaapiImagePrivate))
36
37 struct _GstVaapiImagePrivate {
38     GstVaapiDisplay    *display;
39     VAImage             internal_image;
40     VAImage             image;
41     guchar             *image_data;
42     GstVaapiImageFormat internal_format;
43     GstVaapiImageFormat format;
44     guint               width;
45     guint               height;
46     guint               create_image    : 1;
47     guint               is_constructed  : 1;
48     guint               is_linear       : 1;
49 };
50
51 enum {
52     PROP_0,
53
54     PROP_DISPLAY,
55     PROP_IMAGE,
56     PROP_IMAGE_ID,
57     PROP_FORMAT,
58     PROP_WIDTH,
59     PROP_HEIGHT
60 };
61
62 #define SWAP_UINT(a, b) do { \
63         guint v = a;         \
64         a = b;               \
65         b = v;               \
66     } while (0)
67
68 static gboolean
69 _gst_vaapi_image_map(GstVaapiImage *image);
70
71 static gboolean
72 _gst_vaapi_image_unmap(GstVaapiImage *image);
73
74 static gboolean
75 _gst_vaapi_image_set_image(GstVaapiImage *image, const VAImage *va_image);
76
77 /*
78  * VAImage wrapper
79  */
80
81 #define VAAPI_TYPE_IMAGE vaapi_image_get_type()
82
83 static gpointer
84 vaapi_image_copy(gpointer va_image)
85 {
86     return g_slice_dup(VAImage, va_image);
87 }
88
89 static void
90 vaapi_image_free(gpointer va_image)
91 {
92     if (G_LIKELY(va_image))
93         g_slice_free(VAImage, va_image);
94 }
95
96 static GType
97 vaapi_image_get_type(void)
98 {
99     static GType type = 0;
100
101     if (G_UNLIKELY(type == 0))
102         type = g_boxed_type_register_static(
103             "VAImage",
104             vaapi_image_copy,
105             vaapi_image_free
106         );
107     return type;
108 }
109
110 static gboolean
111 vaapi_image_is_linear(const VAImage *va_image)
112 {
113     guint i, width, height, width2, height2, data_size;
114
115     for (i = 1; i < va_image->num_planes; i++)
116         if (va_image->offsets[i] < va_image->offsets[i - 1])
117             return FALSE;
118
119     width   = va_image->width;
120     height  = va_image->height;
121     width2  = (width  + 1) / 2;
122     height2 = (height + 1) / 2;
123
124     switch (va_image->format.fourcc) {
125     case VA_FOURCC('N','V','1','2'):
126     case VA_FOURCC('Y','V','1','2'):
127     case VA_FOURCC('I','4','2','0'):
128         data_size = width * height + 2 * width2 * height2;
129         break;
130     case VA_FOURCC('A','R','G','B'):
131     case VA_FOURCC('R','G','B','A'):
132     case VA_FOURCC('A','B','G','R'):
133     case VA_FOURCC('B','G','R','A'):
134         data_size = 4 * width * height;
135         break;
136     default:
137         g_error("FIXME: incomplete formats");
138         break;
139     }
140     return va_image->data_size == data_size;
141 }
142
143 static void
144 gst_vaapi_image_destroy(GstVaapiImage *image)
145 {
146     GstVaapiImagePrivate * const priv = image->priv;
147     VAStatus status;
148
149     _gst_vaapi_image_unmap(image);
150
151     if (priv->internal_image.image_id != VA_INVALID_ID) {
152         GST_VAAPI_DISPLAY_LOCK(priv->display);
153         status = vaDestroyImage(
154             GST_VAAPI_DISPLAY_VADISPLAY(priv->display),
155             priv->internal_image.image_id
156         );
157         GST_VAAPI_DISPLAY_UNLOCK(priv->display);
158         if (!vaapi_check_status(status, "vaDestroyImage()"))
159             g_warning("failed to destroy image 0x%08x\n",
160                       priv->internal_image.image_id);
161         priv->internal_image.image_id = VA_INVALID_ID;
162     }
163
164     if (priv->display) {
165         g_object_unref(priv->display);
166         priv->display = NULL;
167     }
168 }
169
170 static gboolean
171 _gst_vaapi_image_create(GstVaapiImage *image, GstVaapiImageFormat format)
172 {
173     GstVaapiImagePrivate * const priv = image->priv;
174     const VAImageFormat *va_format;
175     VAStatus status;
176
177     if (!priv->create_image)
178         return (priv->image.image_id != VA_INVALID_ID &&
179                 priv->image.buf      != VA_INVALID_ID);
180
181     if (!gst_vaapi_display_has_image_format(priv->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(priv->display);
189     status = vaCreateImage(
190         GST_VAAPI_DISPLAY_VADISPLAY(priv->display),
191         (VAImageFormat *)va_format,
192         priv->width,
193         priv->height,
194         &priv->internal_image
195     );
196     GST_VAAPI_DISPLAY_UNLOCK(priv->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
212     if (!_gst_vaapi_image_create(image, format)) {
213         switch (format) {
214         case GST_VAAPI_IMAGE_I420:
215             format = GST_VAAPI_IMAGE_YV12;
216             break;
217         case GST_VAAPI_IMAGE_YV12:
218             format = GST_VAAPI_IMAGE_I420;
219             break;
220         default:
221             format = 0;
222             break;
223         }
224         if (!format || !_gst_vaapi_image_create(image, format))
225             return FALSE;
226     }
227     priv->image = priv->internal_image;
228
229     if (priv->format != priv->internal_format) {
230         switch (priv->format) {
231         case GST_VAAPI_IMAGE_YV12:
232         case GST_VAAPI_IMAGE_I420:
233             va_format = gst_vaapi_image_format_get_va_format(priv->format);
234             if (!va_format)
235                 return FALSE;
236             priv->image.format = *va_format;
237             SWAP_UINT(priv->image.offsets[1], priv->image.offsets[2]);
238             SWAP_UINT(priv->image.pitches[1], priv->image.pitches[2]);
239             break;
240         default:
241             break;
242         }
243     }
244
245     GST_DEBUG("image 0x%08x", priv->image.image_id);
246     priv->is_linear = vaapi_image_is_linear(&priv->image);
247     return TRUE;
248 }
249
250 static void
251 gst_vaapi_image_finalize(GObject *object)
252 {
253     gst_vaapi_image_destroy(GST_VAAPI_IMAGE(object));
254
255     G_OBJECT_CLASS(gst_vaapi_image_parent_class)->finalize(object);
256 }
257
258 static void
259 gst_vaapi_image_set_property(
260     GObject      *object,
261     guint         prop_id,
262     const GValue *value,
263     GParamSpec   *pspec
264 )
265 {
266     GstVaapiImage        * const image = GST_VAAPI_IMAGE(object);
267     GstVaapiImagePrivate * const priv  = image->priv;
268
269     switch (prop_id) {
270     case PROP_DISPLAY:
271         priv->display = g_object_ref(g_value_get_object(value));
272         break;
273     case PROP_IMAGE: {
274         const VAImage * const va_image = g_value_get_boxed(value);
275         if (va_image)
276             _gst_vaapi_image_set_image(image, va_image);
277         break;
278     }
279     case PROP_FORMAT:
280         priv->format = g_value_get_uint(value);
281         break;
282     case PROP_WIDTH:
283         priv->width = g_value_get_uint(value);
284         break;
285     case PROP_HEIGHT:
286         priv->height = g_value_get_uint(value);
287         break;
288     default:
289         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
290         break;
291     }
292 }
293
294 static void
295 gst_vaapi_image_get_property(
296     GObject    *object,
297     guint       prop_id,
298     GValue     *value,
299     GParamSpec *pspec
300 )
301 {
302     GstVaapiImage * const image = GST_VAAPI_IMAGE(object);
303
304     switch (prop_id) {
305     case PROP_DISPLAY:
306         g_value_set_pointer(value, gst_vaapi_image_get_display(image));
307         break;
308     case PROP_IMAGE:
309         g_value_set_boxed(value, &image->priv->image);
310         break;
311     case PROP_IMAGE_ID:
312         g_value_set_uint(value, gst_vaapi_image_get_id(image));
313         break;
314     case PROP_FORMAT:
315         g_value_set_uint(value, gst_vaapi_image_get_format(image));
316         break;
317     case PROP_WIDTH:
318         g_value_set_uint(value, gst_vaapi_image_get_width(image));
319         break;
320     case PROP_HEIGHT:
321         g_value_set_uint(value, gst_vaapi_image_get_height(image));
322         break;
323     default:
324         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
325         break;
326     }
327 }
328
329 static void
330 gst_vaapi_image_constructed(GObject *object)
331 {
332     GstVaapiImage * const image = GST_VAAPI_IMAGE(object);
333     GObjectClass *parent_class;
334
335     image->priv->is_constructed = gst_vaapi_image_create(image);
336
337     parent_class = G_OBJECT_CLASS(gst_vaapi_image_parent_class);
338     if (parent_class->constructed)
339         parent_class->constructed(object);
340 }
341
342 static void
343 gst_vaapi_image_class_init(GstVaapiImageClass *klass)
344 {
345     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
346
347     g_type_class_add_private(klass, sizeof(GstVaapiImagePrivate));
348
349     object_class->finalize     = gst_vaapi_image_finalize;
350     object_class->set_property = gst_vaapi_image_set_property;
351     object_class->get_property = gst_vaapi_image_get_property;
352     object_class->constructed  = gst_vaapi_image_constructed;
353
354     g_object_class_install_property
355         (object_class,
356          PROP_DISPLAY,
357          g_param_spec_object("display",
358                              "display",
359                              "GStreamer Va display",
360                              GST_VAAPI_TYPE_DISPLAY,
361                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
362
363     g_object_class_install_property
364         (object_class,
365          PROP_IMAGE,
366          g_param_spec_boxed("image",
367                             "Image",
368                             "The VA image",
369                             VAAPI_TYPE_IMAGE,
370                             G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
371
372     g_object_class_install_property
373         (object_class,
374          PROP_IMAGE_ID,
375          g_param_spec_uint("id",
376                            "VA image id",
377                            "VA image id",
378                            0, G_MAXUINT32, VA_INVALID_ID,
379                            G_PARAM_READABLE));
380
381     g_object_class_install_property
382         (object_class,
383          PROP_WIDTH,
384          g_param_spec_uint("width",
385                            "width",
386                            "Image width",
387                            0, G_MAXUINT32, 0,
388                            G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
389
390     g_object_class_install_property
391         (object_class,
392          PROP_HEIGHT,
393          g_param_spec_uint("height",
394                            "height",
395                            "Image height",
396                            0, G_MAXUINT32, 0,
397                            G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
398
399     g_object_class_install_property
400         (object_class,
401          PROP_FORMAT,
402          g_param_spec_uint("format",
403                            "format",
404                            "Image format",
405                            0, G_MAXUINT32, 0,
406                            G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
407 }
408
409 static void
410 gst_vaapi_image_init(GstVaapiImage *image)
411 {
412     GstVaapiImagePrivate *priv = GST_VAAPI_IMAGE_GET_PRIVATE(image);
413
414     image->priv                   = priv;
415     priv->display                 = NULL;
416     priv->image_data              = NULL;
417     priv->width                   = 0;
418     priv->height                  = 0;
419     priv->internal_format         = 0;
420     priv->format                  = 0;
421     priv->create_image            = TRUE;
422     priv->is_constructed          = FALSE;
423     priv->is_linear               = FALSE;
424
425     memset(&priv->internal_image, 0, sizeof(priv->internal_image));
426     priv->internal_image.image_id = VA_INVALID_ID;
427     priv->internal_image.buf      = VA_INVALID_ID;
428
429     memset(&priv->image, 0, sizeof(priv->image));
430     priv->image.image_id          = VA_INVALID_ID;
431     priv->image.buf               = VA_INVALID_ID;
432 }
433
434 GstVaapiImage *
435 gst_vaapi_image_new(
436     GstVaapiDisplay    *display,
437     GstVaapiImageFormat format,
438     guint               width,
439     guint               height
440 )
441 {
442     GstVaapiImage *image;
443
444     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
445     g_return_val_if_fail(width > 0, NULL);
446     g_return_val_if_fail(height > 0, NULL);
447
448     GST_DEBUG("format %" GST_FOURCC_FORMAT ", size %ux%u",
449               GST_FOURCC_ARGS(format), width, height);
450
451     image = g_object_new(
452         GST_VAAPI_TYPE_IMAGE,
453         "display", display,
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 GstVaapiImage *
470 gst_vaapi_image_new_with_image(GstVaapiDisplay *display, VAImage *va_image)
471 {
472     GstVaapiImage *image;
473
474     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
475     g_return_val_if_fail(va_image, NULL);
476     g_return_val_if_fail(va_image->image_id != VA_INVALID_ID, NULL);
477     g_return_val_if_fail(va_image->buf != VA_INVALID_ID, NULL);
478
479     GST_DEBUG("VA image 0x%08x, format %" GST_FOURCC_FORMAT ", size %ux%u",
480               va_image->image_id,
481               GST_FOURCC_ARGS(va_image->format.fourcc),
482               va_image->width, va_image->height);
483
484     image = g_object_new(
485         GST_VAAPI_TYPE_IMAGE,
486         "display", display,
487         "image",   va_image,
488         NULL
489     );
490     if (!image)
491         return NULL;
492
493     if (!image->priv->is_constructed) {
494         g_object_unref(image);
495         return NULL;
496     }
497     return image;
498 }
499
500 VAImageID
501 gst_vaapi_image_get_id(GstVaapiImage *image)
502 {
503     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), VA_INVALID_ID);
504     g_return_val_if_fail(image->priv->is_constructed, VA_INVALID_ID);
505
506     return image->priv->image.image_id;
507 }
508
509 gboolean
510 gst_vaapi_image_get_image(GstVaapiImage *image, VAImage *va_image)
511 {
512     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
513     g_return_val_if_fail(image->priv->is_constructed, FALSE);
514
515     if (va_image)
516         *va_image = image->priv->image;
517
518     return TRUE;
519 }
520
521 gboolean
522 _gst_vaapi_image_set_image(GstVaapiImage *image, const VAImage *va_image)
523 {
524     GstVaapiImagePrivate * const priv = image->priv;
525     GstVaapiImageFormat format;
526     VAImage alt_va_image;
527     const VAImageFormat *alt_va_format;
528
529     if (!va_image)
530         return FALSE;
531
532     format = gst_vaapi_image_format(&va_image->format);
533     if (!format)
534         return FALSE;
535
536     priv->create_image    = FALSE;
537     priv->internal_image  = *va_image;
538     priv->internal_format = format;
539     priv->is_linear       = vaapi_image_is_linear(va_image);
540     priv->image           = *va_image;
541     priv->format          = format;
542     priv->width           = va_image->width;
543     priv->height          = va_image->height;
544
545     /* Try to linearize image */
546     if (!priv->is_linear) {
547         switch (format) {
548         case GST_VAAPI_IMAGE_I420:
549             format = GST_VAAPI_IMAGE_YV12;
550             break;
551         case GST_VAAPI_IMAGE_YV12:
552             format = GST_VAAPI_IMAGE_I420;
553             break;
554         default:
555             format = 0;
556             break;
557         }
558         if (format &&
559             (alt_va_format = gst_vaapi_image_format_get_va_format(format))) {
560             alt_va_image = *va_image;
561             alt_va_image.format = *alt_va_format;
562             SWAP_UINT(alt_va_image.offsets[1], alt_va_image.offsets[2]);
563             SWAP_UINT(alt_va_image.pitches[1], alt_va_image.pitches[2]);
564             if (vaapi_image_is_linear(&alt_va_image)) {
565                 priv->image     = alt_va_image;
566                 priv->format    = format;
567                 priv->is_linear = TRUE;
568                 GST_DEBUG("linearized image to %" GST_FOURCC_FORMAT " format",
569                           GST_FOURCC_ARGS(format));
570             }
571         }
572     }
573     return TRUE;
574 }
575
576 GstVaapiDisplay *
577 gst_vaapi_image_get_display(GstVaapiImage *image)
578 {
579     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), NULL);
580     g_return_val_if_fail(image->priv->is_constructed, FALSE);
581
582     return image->priv->display;
583 }
584
585 GstVaapiImageFormat
586 gst_vaapi_image_get_format(GstVaapiImage *image)
587 {
588     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
589     g_return_val_if_fail(image->priv->is_constructed, FALSE);
590
591     return image->priv->format;
592 }
593
594 guint
595 gst_vaapi_image_get_width(GstVaapiImage *image)
596 {
597     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
598     g_return_val_if_fail(image->priv->is_constructed, FALSE);
599
600     return image->priv->width;
601 }
602
603 guint
604 gst_vaapi_image_get_height(GstVaapiImage *image)
605 {
606     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
607     g_return_val_if_fail(image->priv->is_constructed, FALSE);
608
609     return image->priv->height;
610 }
611
612 void
613 gst_vaapi_image_get_size(GstVaapiImage *image, guint *pwidth, guint *pheight)
614 {
615     g_return_if_fail(GST_VAAPI_IS_IMAGE(image));
616     g_return_if_fail(image->priv->is_constructed);
617
618     if (pwidth)
619         *pwidth = image->priv->width;
620
621     if (pheight)
622         *pheight = image->priv->height;
623 }
624
625 gboolean
626 gst_vaapi_image_is_linear(GstVaapiImage *image)
627 {
628     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
629     g_return_val_if_fail(image->priv->is_constructed, FALSE);
630
631     return image->priv->is_linear;
632 }
633
634 static inline gboolean
635 _gst_vaapi_image_is_mapped(GstVaapiImage *image)
636 {
637     return image->priv->image_data != NULL;
638 }
639
640 gboolean
641 gst_vaapi_image_is_mapped(GstVaapiImage *image)
642 {
643     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
644     g_return_val_if_fail(image->priv->is_constructed, FALSE);
645
646     return _gst_vaapi_image_is_mapped(image);
647 }
648
649 gboolean
650 gst_vaapi_image_map(GstVaapiImage *image)
651 {
652     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
653     g_return_val_if_fail(image->priv->is_constructed, FALSE);
654
655     return _gst_vaapi_image_map(image);
656 }
657
658 gboolean
659 _gst_vaapi_image_map(GstVaapiImage *image)
660 {
661     void *image_data;
662     VAStatus status;
663
664     if (_gst_vaapi_image_is_mapped(image))
665         return TRUE;
666
667     GST_VAAPI_DISPLAY_LOCK(image->priv->display);
668     status = vaMapBuffer(
669         GST_VAAPI_DISPLAY_VADISPLAY(image->priv->display),
670         image->priv->image.buf,
671         &image_data
672     );
673     GST_VAAPI_DISPLAY_UNLOCK(image->priv->display);
674     if (!vaapi_check_status(status, "vaMapBuffer()"))
675         return FALSE;
676
677     image->priv->image_data = image_data;
678     return TRUE;
679 }
680
681 gboolean
682 gst_vaapi_image_unmap(GstVaapiImage *image)
683 {
684     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
685     g_return_val_if_fail(image->priv->is_constructed, FALSE);
686
687     return _gst_vaapi_image_unmap(image);
688 }
689
690 gboolean
691 _gst_vaapi_image_unmap(GstVaapiImage *image)
692 {
693     VAStatus status;
694
695     if (!_gst_vaapi_image_is_mapped(image))
696         return FALSE;
697
698     GST_VAAPI_DISPLAY_LOCK(image->priv->display);
699     status = vaUnmapBuffer(
700         GST_VAAPI_DISPLAY_VADISPLAY(image->priv->display),
701         image->priv->image.buf
702     );
703     GST_VAAPI_DISPLAY_UNLOCK(image->priv->display);
704     if (!vaapi_check_status(status, "vaUnmapBuffer()"))
705         return FALSE;
706
707     image->priv->image_data = NULL;
708     return TRUE;
709 }
710
711 guint
712 gst_vaapi_image_get_plane_count(GstVaapiImage *image)
713 {
714     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
715     g_return_val_if_fail(image->priv->is_constructed, FALSE);
716     g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), 0);
717
718     return image->priv->image.num_planes;
719 }
720
721 guchar *
722 gst_vaapi_image_get_plane(GstVaapiImage *image, guint plane)
723 {
724     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), NULL);
725     g_return_val_if_fail(image->priv->is_constructed, FALSE);
726     g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), NULL);
727     g_return_val_if_fail(plane < image->priv->image.num_planes, NULL);
728
729     return image->priv->image_data + image->priv->image.offsets[plane];
730 }
731
732 guint
733 gst_vaapi_image_get_pitch(GstVaapiImage *image, guint plane)
734 {
735     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
736     g_return_val_if_fail(image->priv->is_constructed, FALSE);
737     g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), 0);
738     g_return_val_if_fail(plane < image->priv->image.num_planes, 0);
739
740     return image->priv->image.pitches[plane];
741 }
742
743 guint
744 gst_vaapi_image_get_data_size(GstVaapiImage *image)
745 {
746     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
747     g_return_val_if_fail(image->priv->is_constructed, FALSE);
748
749     return image->priv->image.data_size;
750 }
751
752 gboolean
753 gst_vaapi_image_update_from_buffer(GstVaapiImage *image, GstBuffer *buffer)
754 {
755     GstVaapiImagePrivate *priv;
756     GstStructure *structure;
757     GstCaps *caps;
758     GstVaapiImageFormat format;
759     gint width, height;
760     guint offsets[3], pitches[3], widths[3], heights[3];
761     guint i, j;
762     guchar *data;
763     guint32 data_size;
764
765     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
766     g_return_val_if_fail(image->priv->is_constructed, FALSE);
767     g_return_val_if_fail(GST_IS_BUFFER(buffer), FALSE);
768
769     priv      = image->priv;
770     data      = GST_BUFFER_DATA(buffer);
771     data_size = GST_BUFFER_SIZE(buffer);
772     caps      = GST_BUFFER_CAPS(buffer);
773
774     if (!caps)
775         return FALSE;
776
777     format = gst_vaapi_image_format_from_caps(caps);
778     if (format != priv->format)
779         return FALSE;
780
781     structure = gst_caps_get_structure(caps, 0);
782     gst_structure_get_int(structure, "width",  &width);
783     gst_structure_get_int(structure, "height", &height);
784     if (width != priv->width || height != priv->height)
785         return FALSE;
786
787     if (!gst_vaapi_image_map(image))
788         return FALSE;
789
790     if (priv->is_linear && data_size == priv->image.data_size)
791         memcpy(priv->image_data, data, data_size);
792     else {
793         /* XXX: copied from gst_video_format_get_row_stride() -- no NV12? */
794         const guint width2  = (width  + 1) / 2;
795         const guint height2 = (height + 1) / 2;
796         guint size2;
797         switch (format) {
798         case GST_VAAPI_IMAGE_NV12:
799             offsets[0] = 0;
800             pitches[0] = GST_ROUND_UP_4(width);
801             widths [0] = width;
802             heights[0] = height;
803             offsets[1] = offsets[0] + height * pitches[0];
804             pitches[1] = pitches[0];
805             widths [1] = width2 * 2;
806             heights[1] = height2;
807             size2      = offsets[1] + height2 * pitches[1];
808             break;
809         case GST_VAAPI_IMAGE_YV12:
810         case GST_VAAPI_IMAGE_I420:
811             offsets[0] = 0;
812             pitches[0] = GST_ROUND_UP_4(width);
813             widths [0] = width;
814             heights[0] = height;
815             offsets[1] = offsets[0] + height * pitches[0];
816             pitches[1] = GST_ROUND_UP_4(GST_ROUND_UP_2(width) / 2);
817             widths [1] = width2;
818             heights[1] = height2;
819             offsets[2] = offsets[1] + height2 * pitches[1];
820             pitches[2] = pitches[1];
821             widths [2] = width2;
822             heights[2] = height2;
823             size2      = offsets[2] + height2 * pitches[2];
824             break;
825         case GST_VAAPI_IMAGE_ARGB:
826         case GST_VAAPI_IMAGE_RGBA:
827         case GST_VAAPI_IMAGE_ABGR:
828         case GST_VAAPI_IMAGE_BGRA:
829             offsets[0] = 0;
830             pitches[0] = width * 4;
831             widths [0] = width * 4;
832             heights[0] = height;
833             size2      = offsets[0] + height * pitches[0];
834             break;
835         default:
836             g_error("could not compute row-stride for %" GST_FOURCC_FORMAT,
837                     GST_FOURCC_ARGS(format));
838             break;
839         }
840         if (size2 != data_size)
841             g_error("data_size mismatch %d / %u", size2, data_size);
842         for (i = 0; i < priv->image.num_planes; i++) {
843             guchar *src = data + offsets[i];
844             guchar *dst = priv->image_data + priv->image.offsets[i];
845             for (j = 0; j < heights[i]; j++) {
846                 memcpy(dst, src, widths[i]);
847                 src += pitches[i];
848                 dst += priv->image.pitches[i];
849             }
850         }
851     }
852
853     if (!gst_vaapi_image_unmap(image))
854         return FALSE;
855
856     return TRUE;
857 }