Split map/unmap functions into internal functions that don't check preconditions.
[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               is_constructed  : 1;
47     guint               is_linear       : 1;
48 };
49
50 enum {
51     PROP_0,
52
53     PROP_DISPLAY,
54     PROP_IMAGE_ID,
55     PROP_FORMAT,
56     PROP_WIDTH,
57     PROP_HEIGHT
58 };
59
60 #define SWAP_UINT(a, b) do { \
61         guint v = a;         \
62         a = b;               \
63         b = v;               \
64     } while (0)
65
66 static gboolean
67 _gst_vaapi_image_map(GstVaapiImage *image);
68
69 static gboolean
70 _gst_vaapi_image_unmap(GstVaapiImage *image);
71
72 static void
73 gst_vaapi_image_destroy(GstVaapiImage *image)
74 {
75     GstVaapiImagePrivate * const priv = image->priv;
76     VAStatus status;
77
78     _gst_vaapi_image_unmap(image);
79
80     if (priv->internal_image.image_id != VA_INVALID_ID) {
81         GST_VAAPI_DISPLAY_LOCK(priv->display);
82         status = vaDestroyImage(
83             GST_VAAPI_DISPLAY_VADISPLAY(priv->display),
84             priv->internal_image.image_id
85         );
86         GST_VAAPI_DISPLAY_UNLOCK(priv->display);
87         if (!vaapi_check_status(status, "vaDestroyImage()"))
88             g_warning("failed to destroy image 0x%08x\n",
89                       priv->internal_image.image_id);
90         priv->internal_image.image_id = VA_INVALID_ID;
91     }
92
93     if (priv->display) {
94         g_object_unref(priv->display);
95         priv->display = NULL;
96     }
97 }
98
99 static gboolean
100 _gst_vaapi_image_create(GstVaapiImage *image, GstVaapiImageFormat format)
101 {
102     GstVaapiImagePrivate * const priv = image->priv;
103     const VAImageFormat *va_format;
104     VAStatus status;
105
106     if (!gst_vaapi_display_has_image_format(priv->display, format))
107         return FALSE;
108
109     va_format = gst_vaapi_image_format_get_va_format(format);
110     if (!va_format)
111         return FALSE;
112
113     GST_VAAPI_DISPLAY_LOCK(priv->display);
114     status = vaCreateImage(
115         GST_VAAPI_DISPLAY_VADISPLAY(priv->display),
116         (VAImageFormat *)va_format,
117         priv->width,
118         priv->height,
119         &priv->internal_image
120     );
121     GST_VAAPI_DISPLAY_UNLOCK(priv->display);
122     if (status != VA_STATUS_SUCCESS ||
123         priv->internal_image.format.fourcc != va_format->fourcc)
124         return FALSE;
125
126     priv->internal_format = format;
127     return TRUE;
128 }
129
130 static gboolean
131 _gst_vaapi_image_is_linear(GstVaapiImage *image)
132 {
133     GstVaapiImagePrivate * const priv = image->priv;
134     guint i, width, height, width2, height2, data_size;
135
136     for (i = 1; i < priv->image.num_planes; i++)
137         if (priv->image.offsets[i] < priv->image.offsets[i - 1])
138             return FALSE;
139
140     width   = priv->width;
141     height  = priv->height;
142     width2  = (width  + 1) / 2;
143     height2 = (height + 1) / 2;
144
145     switch (priv->internal_format) {
146     case GST_VAAPI_IMAGE_NV12:
147     case GST_VAAPI_IMAGE_YV12:
148     case GST_VAAPI_IMAGE_I420:
149         data_size = width * height + 2 * width2 * height2;
150         break;
151     case GST_VAAPI_IMAGE_ARGB:
152     case GST_VAAPI_IMAGE_RGBA:
153     case GST_VAAPI_IMAGE_ABGR:
154     case GST_VAAPI_IMAGE_BGRA:
155         data_size = 4 * width * height;
156         break;
157     default:
158         g_error("FIXME: incomplete formats");
159         break;
160     }
161     return priv->image.data_size == data_size;
162 }
163
164 static gboolean
165 gst_vaapi_image_create(GstVaapiImage *image)
166 {
167     GstVaapiImagePrivate * const priv = image->priv;
168     GstVaapiImageFormat format = priv->format;
169     const VAImageFormat *va_format;
170
171     if (!_gst_vaapi_image_create(image, format)) {
172         switch (format) {
173         case GST_VAAPI_IMAGE_I420:
174             format = GST_VAAPI_IMAGE_YV12;
175             break;
176         case GST_VAAPI_IMAGE_YV12:
177             format = GST_VAAPI_IMAGE_I420;
178             break;
179         default:
180             format = 0;
181             break;
182         }
183         if (!format || !_gst_vaapi_image_create(image, format))
184             return FALSE;
185     }
186     priv->image = priv->internal_image;
187
188     if (priv->format != priv->internal_format) {
189         switch (priv->format) {
190         case GST_VAAPI_IMAGE_YV12:
191         case GST_VAAPI_IMAGE_I420:
192             va_format = gst_vaapi_image_format_get_va_format(priv->format);
193             if (!va_format)
194                 return FALSE;
195             priv->image.format = *va_format;
196             SWAP_UINT(priv->image.offsets[1], priv->image.offsets[2]);
197             SWAP_UINT(priv->image.pitches[1], priv->image.pitches[2]);
198             break;
199         default:
200             break;
201         }
202     }
203
204     GST_DEBUG("image 0x%08x", priv->image.image_id);
205     priv->is_linear = _gst_vaapi_image_is_linear(image);
206     return TRUE;
207 }
208
209 static void
210 gst_vaapi_image_finalize(GObject *object)
211 {
212     gst_vaapi_image_destroy(GST_VAAPI_IMAGE(object));
213
214     G_OBJECT_CLASS(gst_vaapi_image_parent_class)->finalize(object);
215 }
216
217 static void
218 gst_vaapi_image_set_property(
219     GObject      *object,
220     guint         prop_id,
221     const GValue *value,
222     GParamSpec   *pspec
223 )
224 {
225     GstVaapiImage        * const image = GST_VAAPI_IMAGE(object);
226     GstVaapiImagePrivate * const priv  = image->priv;
227
228     switch (prop_id) {
229     case PROP_DISPLAY:
230         priv->display = g_object_ref(g_value_get_object(value));
231         break;
232     case PROP_FORMAT:
233         priv->format = g_value_get_uint(value);
234         break;
235     case PROP_WIDTH:
236         priv->width = g_value_get_uint(value);
237         break;
238     case PROP_HEIGHT:
239         priv->height = g_value_get_uint(value);
240         break;
241     default:
242         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
243         break;
244     }
245 }
246
247 static void
248 gst_vaapi_image_get_property(
249     GObject    *object,
250     guint       prop_id,
251     GValue     *value,
252     GParamSpec *pspec
253 )
254 {
255     GstVaapiImage * const image = GST_VAAPI_IMAGE(object);
256
257     switch (prop_id) {
258     case PROP_DISPLAY:
259         g_value_set_pointer(value, gst_vaapi_image_get_display(image));
260         break;
261     case PROP_IMAGE_ID:
262         g_value_set_uint(value, gst_vaapi_image_get_id(image));
263         break;
264     case PROP_FORMAT:
265         g_value_set_uint(value, gst_vaapi_image_get_format(image));
266         break;
267     case PROP_WIDTH:
268         g_value_set_uint(value, gst_vaapi_image_get_width(image));
269         break;
270     case PROP_HEIGHT:
271         g_value_set_uint(value, gst_vaapi_image_get_height(image));
272         break;
273     default:
274         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
275         break;
276     }
277 }
278
279 static void
280 gst_vaapi_image_constructed(GObject *object)
281 {
282     GstVaapiImage * const image = GST_VAAPI_IMAGE(object);
283     GObjectClass *parent_class;
284
285     image->priv->is_constructed = gst_vaapi_image_create(image);
286
287     parent_class = G_OBJECT_CLASS(gst_vaapi_image_parent_class);
288     if (parent_class->constructed)
289         parent_class->constructed(object);
290 }
291
292 static void
293 gst_vaapi_image_class_init(GstVaapiImageClass *klass)
294 {
295     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
296
297     g_type_class_add_private(klass, sizeof(GstVaapiImagePrivate));
298
299     object_class->finalize     = gst_vaapi_image_finalize;
300     object_class->set_property = gst_vaapi_image_set_property;
301     object_class->get_property = gst_vaapi_image_get_property;
302     object_class->constructed  = gst_vaapi_image_constructed;
303
304     g_object_class_install_property
305         (object_class,
306          PROP_DISPLAY,
307          g_param_spec_object("display",
308                              "display",
309                              "GStreamer Va display",
310                              GST_VAAPI_TYPE_DISPLAY,
311                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
312
313     g_object_class_install_property
314         (object_class,
315          PROP_IMAGE_ID,
316          g_param_spec_uint("id",
317                            "VA image id",
318                            "VA image id",
319                            0, G_MAXUINT32, VA_INVALID_ID,
320                            G_PARAM_READABLE));
321
322     g_object_class_install_property
323         (object_class,
324          PROP_WIDTH,
325          g_param_spec_uint("width",
326                            "width",
327                            "Image width",
328                            0, G_MAXUINT32, 0,
329                            G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
330
331     g_object_class_install_property
332         (object_class,
333          PROP_HEIGHT,
334          g_param_spec_uint("height",
335                            "height",
336                            "Image height",
337                            0, G_MAXUINT32, 0,
338                            G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
339
340     g_object_class_install_property
341         (object_class,
342          PROP_FORMAT,
343          g_param_spec_uint("format",
344                            "format",
345                            "Image format",
346                            0, G_MAXUINT32, 0,
347                            G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
348 }
349
350 static void
351 gst_vaapi_image_init(GstVaapiImage *image)
352 {
353     GstVaapiImagePrivate *priv = GST_VAAPI_IMAGE_GET_PRIVATE(image);
354
355     image->priv                   = priv;
356     priv->display                 = NULL;
357     priv->image_data              = NULL;
358     priv->width                   = 0;
359     priv->height                  = 0;
360     priv->internal_format         = 0;
361     priv->format                  = 0;
362     priv->is_constructed          = FALSE;
363     priv->is_linear               = FALSE;
364
365     memset(&priv->internal_image, 0, sizeof(priv->internal_image));
366     priv->internal_image.image_id = VA_INVALID_ID;
367     priv->internal_image.buf      = VA_INVALID_ID;
368
369     memset(&priv->image, 0, sizeof(priv->image));
370     priv->image.image_id          = VA_INVALID_ID;
371     priv->image.buf               = VA_INVALID_ID;
372 }
373
374 GstVaapiImage *
375 gst_vaapi_image_new(
376     GstVaapiDisplay    *display,
377     GstVaapiImageFormat format,
378     guint               width,
379     guint               height
380 )
381 {
382     GstVaapiImage *image;
383
384     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
385     g_return_val_if_fail(width > 0, NULL);
386     g_return_val_if_fail(height > 0, NULL);
387
388     GST_DEBUG("format %" GST_FOURCC_FORMAT ", size %ux%u",
389               GST_FOURCC_ARGS(format), width, height);
390
391     image = g_object_new(
392         GST_VAAPI_TYPE_IMAGE,
393         "display", display,
394         "format",  format,
395         "width",   width,
396         "height",  height,
397         NULL
398     );
399     if (!image)
400         return NULL;
401
402     if (!image->priv->is_constructed) {
403         g_object_unref(image);
404         return NULL;
405     }
406     return image;
407 }
408
409 VAImageID
410 gst_vaapi_image_get_id(GstVaapiImage *image)
411 {
412     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), VA_INVALID_ID);
413     g_return_val_if_fail(image->priv->is_constructed, VA_INVALID_ID);
414
415     return image->priv->image.image_id;
416 }
417
418 gboolean
419 gst_vaapi_image_get_image(GstVaapiImage *image, VAImage *va_image)
420 {
421     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
422     g_return_val_if_fail(image->priv->is_constructed, FALSE);
423
424     if (va_image)
425         *va_image = image->priv->image;
426
427     return TRUE;
428 }
429
430 GstVaapiDisplay *
431 gst_vaapi_image_get_display(GstVaapiImage *image)
432 {
433     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), NULL);
434     g_return_val_if_fail(image->priv->is_constructed, FALSE);
435
436     return image->priv->display;
437 }
438
439 GstVaapiImageFormat
440 gst_vaapi_image_get_format(GstVaapiImage *image)
441 {
442     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
443     g_return_val_if_fail(image->priv->is_constructed, FALSE);
444
445     return image->priv->format;
446 }
447
448 guint
449 gst_vaapi_image_get_width(GstVaapiImage *image)
450 {
451     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
452     g_return_val_if_fail(image->priv->is_constructed, FALSE);
453
454     return image->priv->width;
455 }
456
457 guint
458 gst_vaapi_image_get_height(GstVaapiImage *image)
459 {
460     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
461     g_return_val_if_fail(image->priv->is_constructed, FALSE);
462
463     return image->priv->height;
464 }
465
466 void
467 gst_vaapi_image_get_size(GstVaapiImage *image, guint *pwidth, guint *pheight)
468 {
469     g_return_if_fail(GST_VAAPI_IS_IMAGE(image));
470     g_return_if_fail(image->priv->is_constructed);
471
472     if (pwidth)
473         *pwidth = image->priv->width;
474
475     if (pheight)
476         *pheight = image->priv->height;
477 }
478
479 gboolean
480 gst_vaapi_image_is_linear(GstVaapiImage *image)
481 {
482     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
483     g_return_val_if_fail(image->priv->is_constructed, FALSE);
484
485     return image->priv->is_linear;
486 }
487
488 static inline gboolean
489 _gst_vaapi_image_is_mapped(GstVaapiImage *image)
490 {
491     return image->priv->image_data != NULL;
492 }
493
494 gboolean
495 gst_vaapi_image_is_mapped(GstVaapiImage *image)
496 {
497     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
498     g_return_val_if_fail(image->priv->is_constructed, FALSE);
499
500     return _gst_vaapi_image_is_mapped(image);
501 }
502
503 gboolean
504 gst_vaapi_image_map(GstVaapiImage *image)
505 {
506     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
507     g_return_val_if_fail(image->priv->is_constructed, FALSE);
508
509     return _gst_vaapi_image_map(image);
510 }
511
512 gboolean
513 _gst_vaapi_image_map(GstVaapiImage *image)
514 {
515     void *image_data;
516     VAStatus status;
517
518     if (_gst_vaapi_image_is_mapped(image))
519         return TRUE;
520
521     GST_VAAPI_DISPLAY_LOCK(image->priv->display);
522     status = vaMapBuffer(
523         GST_VAAPI_DISPLAY_VADISPLAY(image->priv->display),
524         image->priv->image.buf,
525         &image_data
526     );
527     GST_VAAPI_DISPLAY_UNLOCK(image->priv->display);
528     if (!vaapi_check_status(status, "vaMapBuffer()"))
529         return FALSE;
530
531     image->priv->image_data = image_data;
532     return TRUE;
533 }
534
535 gboolean
536 gst_vaapi_image_unmap(GstVaapiImage *image)
537 {
538     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
539     g_return_val_if_fail(image->priv->is_constructed, FALSE);
540
541     return _gst_vaapi_image_unmap(image);
542 }
543
544 gboolean
545 _gst_vaapi_image_unmap(GstVaapiImage *image)
546 {
547     VAStatus status;
548
549     if (!_gst_vaapi_image_is_mapped(image))
550         return FALSE;
551
552     GST_VAAPI_DISPLAY_LOCK(image->priv->display);
553     status = vaUnmapBuffer(
554         GST_VAAPI_DISPLAY_VADISPLAY(image->priv->display),
555         image->priv->image.buf
556     );
557     GST_VAAPI_DISPLAY_UNLOCK(image->priv->display);
558     if (!vaapi_check_status(status, "vaUnmapBuffer()"))
559         return FALSE;
560
561     image->priv->image_data = NULL;
562     return TRUE;
563 }
564
565 guint
566 gst_vaapi_image_get_plane_count(GstVaapiImage *image)
567 {
568     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
569     g_return_val_if_fail(image->priv->is_constructed, FALSE);
570     g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), 0);
571
572     return image->priv->image.num_planes;
573 }
574
575 guchar *
576 gst_vaapi_image_get_plane(GstVaapiImage *image, guint plane)
577 {
578     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), NULL);
579     g_return_val_if_fail(image->priv->is_constructed, FALSE);
580     g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), NULL);
581     g_return_val_if_fail(plane < image->priv->image.num_planes, NULL);
582
583     return image->priv->image_data + image->priv->image.offsets[plane];
584 }
585
586 guint
587 gst_vaapi_image_get_pitch(GstVaapiImage *image, guint plane)
588 {
589     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
590     g_return_val_if_fail(image->priv->is_constructed, FALSE);
591     g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), 0);
592     g_return_val_if_fail(plane < image->priv->image.num_planes, 0);
593
594     return image->priv->image.pitches[plane];
595 }
596
597 guint
598 gst_vaapi_image_get_data_size(GstVaapiImage *image)
599 {
600     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
601     g_return_val_if_fail(image->priv->is_constructed, FALSE);
602
603     return image->priv->image.data_size;
604 }
605
606 gboolean
607 gst_vaapi_image_update_from_buffer(GstVaapiImage *image, GstBuffer *buffer)
608 {
609     GstVaapiImagePrivate *priv;
610     GstStructure *structure;
611     GstCaps *caps;
612     GstVaapiImageFormat format;
613     gint width, height;
614     guint offsets[3], pitches[3], widths[3], heights[3];
615     guint i, j;
616     guchar *data;
617     guint32 data_size;
618
619     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
620     g_return_val_if_fail(image->priv->is_constructed, FALSE);
621     g_return_val_if_fail(GST_IS_BUFFER(buffer), FALSE);
622
623     priv      = image->priv;
624     data      = GST_BUFFER_DATA(buffer);
625     data_size = GST_BUFFER_SIZE(buffer);
626     caps      = GST_BUFFER_CAPS(buffer);
627
628     if (!caps)
629         return FALSE;
630
631     format = gst_vaapi_image_format_from_caps(caps);
632     if (format != priv->format)
633         return FALSE;
634
635     structure = gst_caps_get_structure(caps, 0);
636     gst_structure_get_int(structure, "width",  &width);
637     gst_structure_get_int(structure, "height", &height);
638     if (width != priv->width || height != priv->height)
639         return FALSE;
640
641     if (!gst_vaapi_image_map(image))
642         return FALSE;
643
644     if (priv->is_linear && data_size == priv->image.data_size)
645         memcpy(priv->image_data, data, data_size);
646     else {
647         /* XXX: copied from gst_video_format_get_row_stride() -- no NV12? */
648         const guint width2  = (width  + 1) / 2;
649         const guint height2 = (height + 1) / 2;
650         guint size2;
651         switch (format) {
652         case GST_VAAPI_IMAGE_NV12:
653             offsets[0] = 0;
654             pitches[0] = GST_ROUND_UP_4(width);
655             widths [0] = width;
656             heights[0] = height;
657             offsets[1] = offsets[0] + height * pitches[0];
658             pitches[1] = pitches[0];
659             widths [1] = width2 * 2;
660             heights[1] = height2;
661             size2      = offsets[1] + height2 * pitches[1];
662             break;
663         case GST_VAAPI_IMAGE_YV12:
664         case GST_VAAPI_IMAGE_I420:
665             offsets[0] = 0;
666             pitches[0] = GST_ROUND_UP_4(width);
667             widths [0] = width;
668             heights[0] = height;
669             offsets[1] = offsets[0] + height * pitches[0];
670             pitches[1] = GST_ROUND_UP_4(GST_ROUND_UP_2(width) / 2);
671             widths [1] = width2;
672             heights[1] = height2;
673             offsets[2] = offsets[1] + height2 * pitches[1];
674             pitches[2] = pitches[1];
675             widths [2] = width2;
676             heights[2] = height2;
677             size2      = offsets[2] + height2 * pitches[2];
678             break;
679         case GST_VAAPI_IMAGE_ARGB:
680         case GST_VAAPI_IMAGE_RGBA:
681         case GST_VAAPI_IMAGE_ABGR:
682         case GST_VAAPI_IMAGE_BGRA:
683             offsets[0] = 0;
684             pitches[0] = width * 4;
685             widths [0] = width * 4;
686             heights[0] = height;
687             size2      = offsets[0] + height * pitches[0];
688             break;
689         default:
690             g_error("could not compute row-stride for %" GST_FOURCC_FORMAT,
691                     GST_FOURCC_ARGS(format));
692             break;
693         }
694         if (size2 != data_size)
695             g_error("data_size mismatch %d / %u", size2, data_size);
696         for (i = 0; i < priv->image.num_planes; i++) {
697             guchar *src = data + offsets[i];
698             guchar *dst = priv->image_data + priv->image.offsets[i];
699             for (j = 0; j < heights[i]; j++) {
700                 memcpy(dst, src, widths[i]);
701                 src += pitches[i];
702                 dst += priv->image.pitches[i];
703             }
704         }
705     }
706
707     if (!gst_vaapi_image_unmap(image))
708         return FALSE;
709
710     return TRUE;
711 }