2 * gstvaapiimage.c - VA image abstraction
4 * gstreamer-vaapi (C) 2010 Splitted-Desktop Systems
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.
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.
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
22 * SECTION:gstvaapiimage
23 * @short_description: VA image abstraction
28 #include "gstvaapicompat.h"
29 #include "gstvaapiutils.h"
30 #include "gstvaapiimage.h"
31 #include "gstvaapiobject_priv.h"
34 #include "gstvaapidebug.h"
36 G_DEFINE_TYPE(GstVaapiImage, gst_vaapi_image, GST_VAAPI_TYPE_OBJECT);
38 #define GST_VAAPI_IMAGE_GET_PRIVATE(obj) \
39 (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
40 GST_VAAPI_TYPE_IMAGE, \
41 GstVaapiImagePrivate))
43 struct _GstVaapiImagePrivate {
44 VAImage internal_image;
47 GstVaapiImageFormat internal_format;
48 GstVaapiImageFormat format;
51 guint create_image : 1;
52 guint is_constructed : 1;
65 #define SWAP_UINT(a, b) do { \
72 _gst_vaapi_image_map(GstVaapiImage *image);
75 _gst_vaapi_image_unmap(GstVaapiImage *image);
78 _gst_vaapi_image_set_image(GstVaapiImage *image, const VAImage *va_image);
84 #define VAAPI_TYPE_IMAGE vaapi_image_get_type()
87 vaapi_image_copy(gpointer va_image)
89 return g_slice_dup(VAImage, va_image);
93 vaapi_image_free(gpointer va_image)
95 if (G_LIKELY(va_image))
96 g_slice_free(VAImage, va_image);
100 vaapi_image_get_type(void)
102 static GType type = 0;
104 if (G_UNLIKELY(type == 0))
105 type = g_boxed_type_register_static(
114 vaapi_image_is_linear(const VAImage *va_image)
116 guint i, width, height, width2, height2, data_size;
118 for (i = 1; i < va_image->num_planes; i++)
119 if (va_image->offsets[i] < va_image->offsets[i - 1])
122 width = va_image->width;
123 height = va_image->height;
124 width2 = (width + 1) / 2;
125 height2 = (height + 1) / 2;
127 switch (va_image->format.fourcc) {
128 case VA_FOURCC('N','V','1','2'):
129 case VA_FOURCC('Y','V','1','2'):
130 case VA_FOURCC('I','4','2','0'):
131 data_size = width * height + 2 * width2 * height2;
133 case VA_FOURCC('A','Y','U','V'):
134 case VA_FOURCC('A','R','G','B'):
135 case VA_FOURCC('R','G','B','A'):
136 case VA_FOURCC('A','B','G','R'):
137 case VA_FOURCC('B','G','R','A'):
138 data_size = 4 * width * height;
141 g_error("FIXME: incomplete formats");
144 return va_image->data_size == data_size;
148 gst_vaapi_image_destroy(GstVaapiImage *image)
150 GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(image);
154 _gst_vaapi_image_unmap(image);
156 image_id = GST_VAAPI_OBJECT_ID(image);
157 GST_DEBUG("image %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(image_id));
159 if (image_id != VA_INVALID_ID) {
160 GST_VAAPI_DISPLAY_LOCK(display);
161 status = vaDestroyImage(GST_VAAPI_DISPLAY_VADISPLAY(display), image_id);
162 GST_VAAPI_DISPLAY_UNLOCK(display);
163 if (!vaapi_check_status(status, "vaDestroyImage()"))
164 g_warning("failed to destroy image %" GST_VAAPI_ID_FORMAT,
165 GST_VAAPI_ID_ARGS(image_id));
166 GST_VAAPI_OBJECT_ID(image) = VA_INVALID_ID;
171 _gst_vaapi_image_create(GstVaapiImage *image, GstVaapiImageFormat format)
173 GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(image);
174 GstVaapiImagePrivate * const priv = image->priv;
175 const VAImageFormat *va_format;
178 if (!gst_vaapi_display_has_image_format(display, format))
181 va_format = gst_vaapi_image_format_get_va_format(format);
185 GST_VAAPI_DISPLAY_LOCK(display);
186 status = vaCreateImage(
187 GST_VAAPI_DISPLAY_VADISPLAY(display),
188 (VAImageFormat *)va_format,
191 &priv->internal_image
193 GST_VAAPI_DISPLAY_UNLOCK(display);
194 if (status != VA_STATUS_SUCCESS ||
195 priv->internal_image.format.fourcc != va_format->fourcc)
198 priv->internal_format = format;
203 gst_vaapi_image_create(GstVaapiImage *image)
205 GstVaapiImagePrivate * const priv = image->priv;
206 GstVaapiImageFormat format = priv->format;
207 const VAImageFormat *va_format;
210 if (!priv->create_image)
211 return (priv->image.image_id != VA_INVALID_ID &&
212 priv->image.buf != VA_INVALID_ID);
214 if (!_gst_vaapi_image_create(image, format)) {
216 case GST_VAAPI_IMAGE_I420:
217 format = GST_VAAPI_IMAGE_YV12;
219 case GST_VAAPI_IMAGE_YV12:
220 format = GST_VAAPI_IMAGE_I420;
226 if (!format || !_gst_vaapi_image_create(image, format))
229 priv->image = priv->internal_image;
230 image_id = priv->image.image_id;
232 if (priv->format != priv->internal_format) {
233 switch (priv->format) {
234 case GST_VAAPI_IMAGE_YV12:
235 case GST_VAAPI_IMAGE_I420:
236 va_format = gst_vaapi_image_format_get_va_format(priv->format);
239 priv->image.format = *va_format;
240 SWAP_UINT(priv->image.offsets[1], priv->image.offsets[2]);
241 SWAP_UINT(priv->image.pitches[1], priv->image.pitches[2]);
247 priv->is_linear = vaapi_image_is_linear(&priv->image);
249 GST_DEBUG("image %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(image_id));
250 GST_VAAPI_OBJECT_ID(image) = image_id;
255 gst_vaapi_image_finalize(GObject *object)
257 gst_vaapi_image_destroy(GST_VAAPI_IMAGE(object));
259 G_OBJECT_CLASS(gst_vaapi_image_parent_class)->finalize(object);
263 gst_vaapi_image_set_property(
270 GstVaapiImage * const image = GST_VAAPI_IMAGE(object);
271 GstVaapiImagePrivate * const priv = image->priv;
275 const VAImage * const va_image = g_value_get_boxed(value);
277 _gst_vaapi_image_set_image(image, va_image);
281 priv->format = g_value_get_uint(value);
284 priv->width = g_value_get_uint(value);
287 priv->height = g_value_get_uint(value);
290 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
296 gst_vaapi_image_get_property(
303 GstVaapiImage * const image = GST_VAAPI_IMAGE(object);
307 g_value_set_boxed(value, &image->priv->image);
310 g_value_set_uint(value, gst_vaapi_image_get_format(image));
313 g_value_set_uint(value, gst_vaapi_image_get_width(image));
316 g_value_set_uint(value, gst_vaapi_image_get_height(image));
319 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
325 gst_vaapi_image_constructed(GObject *object)
327 GstVaapiImage * const image = GST_VAAPI_IMAGE(object);
328 GObjectClass *parent_class;
330 image->priv->is_constructed = gst_vaapi_image_create(image);
332 parent_class = G_OBJECT_CLASS(gst_vaapi_image_parent_class);
333 if (parent_class->constructed)
334 parent_class->constructed(object);
338 gst_vaapi_image_class_init(GstVaapiImageClass *klass)
340 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
342 g_type_class_add_private(klass, sizeof(GstVaapiImagePrivate));
344 object_class->finalize = gst_vaapi_image_finalize;
345 object_class->set_property = gst_vaapi_image_set_property;
346 object_class->get_property = gst_vaapi_image_get_property;
347 object_class->constructed = gst_vaapi_image_constructed;
349 g_object_class_install_property
352 g_param_spec_boxed("image",
354 "The underlying VA image",
356 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
358 g_object_class_install_property
361 g_param_spec_uint("width",
365 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
367 g_object_class_install_property
370 g_param_spec_uint("height",
374 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
377 * GstVaapiImage:format:
379 * The #GstVaapiImageFormat of the image
381 g_object_class_install_property
384 g_param_spec_uint("format",
386 "The underlying image format",
388 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
392 gst_vaapi_image_init(GstVaapiImage *image)
394 GstVaapiImagePrivate *priv = GST_VAAPI_IMAGE_GET_PRIVATE(image);
397 priv->image_data = NULL;
400 priv->internal_format = 0;
402 priv->create_image = TRUE;
403 priv->is_constructed = FALSE;
404 priv->is_linear = FALSE;
406 memset(&priv->internal_image, 0, sizeof(priv->internal_image));
407 priv->internal_image.image_id = VA_INVALID_ID;
408 priv->internal_image.buf = VA_INVALID_ID;
410 memset(&priv->image, 0, sizeof(priv->image));
411 priv->image.image_id = VA_INVALID_ID;
412 priv->image.buf = VA_INVALID_ID;
416 * gst_vaapi_image_new:
417 * @display: a #GstVaapiDisplay
418 * @format: a #GstVaapiImageFormat
419 * @width: the requested image width
420 * @height: the requested image height
422 * Creates a new #GstVaapiImage with the specified format and
425 * Return value: the newly allocated #GstVaapiImage object
429 GstVaapiDisplay *display,
430 GstVaapiImageFormat format,
435 GstVaapiImage *image;
437 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
438 g_return_val_if_fail(width > 0, NULL);
439 g_return_val_if_fail(height > 0, NULL);
441 GST_DEBUG("format %" GST_FOURCC_FORMAT ", size %ux%u",
442 GST_FOURCC_ARGS(format), width, height);
444 image = g_object_new(
445 GST_VAAPI_TYPE_IMAGE,
447 "id", GST_VAAPI_ID(VA_INVALID_ID),
456 if (!image->priv->is_constructed) {
457 g_object_unref(image);
464 * gst_vaapi_image_new_with_image:
465 * @display: a #GstVaapiDisplay
466 * @va_image: a VA image
468 * Creates a new #GstVaapiImage from a foreign VA image. The image
469 * format and dimensions will be extracted from @va_image. This
470 * function is mainly used by gst_vaapi_surface_derive_image() to bind
471 * a VA image to a #GstVaapiImage object.
473 * Return value: the newly allocated #GstVaapiImage object
476 gst_vaapi_image_new_with_image(GstVaapiDisplay *display, VAImage *va_image)
478 GstVaapiImage *image;
480 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
481 g_return_val_if_fail(va_image, NULL);
482 g_return_val_if_fail(va_image->image_id != VA_INVALID_ID, NULL);
483 g_return_val_if_fail(va_image->buf != VA_INVALID_ID, NULL);
485 GST_DEBUG("VA image 0x%08x, format %" GST_FOURCC_FORMAT ", size %ux%u",
487 GST_FOURCC_ARGS(va_image->format.fourcc),
488 va_image->width, va_image->height);
490 image = g_object_new(
491 GST_VAAPI_TYPE_IMAGE,
493 "id", GST_VAAPI_ID(va_image->image_id),
500 if (!image->priv->is_constructed) {
501 g_object_unref(image);
508 * gst_vaapi_image_get_image:
509 * @image: a #GstVaapiImage
510 * @va_image: a VA image
512 * Fills @va_image with the VA image used internally.
514 * Return value: %TRUE on success
517 gst_vaapi_image_get_image(GstVaapiImage *image, VAImage *va_image)
519 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
520 g_return_val_if_fail(image->priv->is_constructed, FALSE);
523 *va_image = image->priv->image;
529 * _gst_vaapi_image_set_image:
530 * @image: a #GstVaapiImage
531 * @va_image: a VA image
533 * Initializes #GstVaapiImage with a foreign VA image. This function
534 * will try to "linearize" the VA image. i.e. making sure that the VA
535 * image offsets into the data buffer are in increasing order with the
536 * number of planes available in the image.
538 * This is an internal function used by gst_vaapi_image_new_with_image().
540 * Return value: %TRUE on success
543 _gst_vaapi_image_set_image(GstVaapiImage *image, const VAImage *va_image)
545 GstVaapiImagePrivate * const priv = image->priv;
546 GstVaapiImageFormat format;
547 VAImage alt_va_image;
548 const VAImageFormat *alt_va_format;
553 format = gst_vaapi_image_format(&va_image->format);
557 priv->create_image = FALSE;
558 priv->internal_image = *va_image;
559 priv->internal_format = format;
560 priv->is_linear = vaapi_image_is_linear(va_image);
561 priv->image = *va_image;
562 priv->format = format;
563 priv->width = va_image->width;
564 priv->height = va_image->height;
566 /* Try to linearize image */
567 if (!priv->is_linear) {
569 case GST_VAAPI_IMAGE_I420:
570 format = GST_VAAPI_IMAGE_YV12;
572 case GST_VAAPI_IMAGE_YV12:
573 format = GST_VAAPI_IMAGE_I420;
580 (alt_va_format = gst_vaapi_image_format_get_va_format(format))) {
581 alt_va_image = *va_image;
582 alt_va_image.format = *alt_va_format;
583 SWAP_UINT(alt_va_image.offsets[1], alt_va_image.offsets[2]);
584 SWAP_UINT(alt_va_image.pitches[1], alt_va_image.pitches[2]);
585 if (vaapi_image_is_linear(&alt_va_image)) {
586 priv->image = alt_va_image;
587 priv->format = format;
588 priv->is_linear = TRUE;
589 GST_DEBUG("linearized image to %" GST_FOURCC_FORMAT " format",
590 GST_FOURCC_ARGS(format));
598 * gst_vaapi_image_get_format:
599 * @image: a #GstVaapiImage
601 * Returns the #GstVaapiImageFormat the @image was created with.
603 * Return value: the #GstVaapiImageFormat
606 gst_vaapi_image_get_format(GstVaapiImage *image)
608 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
609 g_return_val_if_fail(image->priv->is_constructed, FALSE);
611 return image->priv->format;
615 * gst_vaapi_image_get_width:
616 * @image: a #GstVaapiImage
618 * Returns the @image width.
620 * Return value: the image width, in pixels
623 gst_vaapi_image_get_width(GstVaapiImage *image)
625 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
626 g_return_val_if_fail(image->priv->is_constructed, FALSE);
628 return image->priv->width;
632 * gst_vaapi_image_get_height:
633 * @image: a #GstVaapiImage
635 * Returns the @image height.
637 * Return value: the image height, in pixels.
640 gst_vaapi_image_get_height(GstVaapiImage *image)
642 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
643 g_return_val_if_fail(image->priv->is_constructed, FALSE);
645 return image->priv->height;
649 * gst_vaapi_image_get_size:
650 * @image: a #GstVaapiImage
651 * @pwidth: return location for the width, or %NULL
652 * @pheight: return location for the height, or %NULL
654 * Retrieves the dimensions of a #GstVaapiImage.
657 gst_vaapi_image_get_size(GstVaapiImage *image, guint *pwidth, guint *pheight)
659 g_return_if_fail(GST_VAAPI_IS_IMAGE(image));
660 g_return_if_fail(image->priv->is_constructed);
663 *pwidth = image->priv->width;
666 *pheight = image->priv->height;
670 * gst_vaapi_image_is_linear:
671 * @image: a #GstVaapiImage
673 * Checks whether the @image has data planes allocated from a single
674 * buffer and offsets into that buffer are in increasing order with
675 * the number of planes.
677 * Return value: %TRUE if image data planes are allocated from a single buffer
680 gst_vaapi_image_is_linear(GstVaapiImage *image)
682 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
683 g_return_val_if_fail(image->priv->is_constructed, FALSE);
685 return image->priv->is_linear;
689 * gst_vaapi_image_is_mapped:
690 * @image: a #GstVaapiImage
692 * Checks whether the @image is currently mapped or not.
694 * Return value: %TRUE if the @image is mapped
696 static inline gboolean
697 _gst_vaapi_image_is_mapped(GstVaapiImage *image)
699 return image->priv->image_data != NULL;
703 gst_vaapi_image_is_mapped(GstVaapiImage *image)
705 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
706 g_return_val_if_fail(image->priv->is_constructed, FALSE);
708 return _gst_vaapi_image_is_mapped(image);
712 * gst_vaapi_image_map:
713 * @image: a #GstVaapiImage
715 * Maps the image data buffer. The actual pixels are returned by the
716 * gst_vaapi_image_get_plane() function.
718 * Return value: %TRUE on success
721 gst_vaapi_image_map(GstVaapiImage *image)
723 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
724 g_return_val_if_fail(image->priv->is_constructed, FALSE);
726 return _gst_vaapi_image_map(image);
730 _gst_vaapi_image_map(GstVaapiImage *image)
732 GstVaapiDisplay *display;
736 if (_gst_vaapi_image_is_mapped(image))
739 display = GST_VAAPI_OBJECT_DISPLAY(image);
743 GST_VAAPI_DISPLAY_LOCK(display);
744 status = vaMapBuffer(
745 GST_VAAPI_DISPLAY_VADISPLAY(display),
746 image->priv->image.buf,
749 GST_VAAPI_DISPLAY_UNLOCK(display);
750 if (!vaapi_check_status(status, "vaMapBuffer()"))
753 image->priv->image_data = image_data;
758 * gst_vaapi_image_unmap:
759 * @image: a #GstVaapiImage
761 * Unmaps the image data buffer. Pointers to pixels returned by
762 * gst_vaapi_image_get_plane() are then no longer valid.
764 * Return value: %TRUE on success
767 gst_vaapi_image_unmap(GstVaapiImage *image)
769 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
770 g_return_val_if_fail(image->priv->is_constructed, FALSE);
772 return _gst_vaapi_image_unmap(image);
776 _gst_vaapi_image_unmap(GstVaapiImage *image)
778 GstVaapiDisplay *display;
781 if (!_gst_vaapi_image_is_mapped(image))
784 display = GST_VAAPI_OBJECT_DISPLAY(image);
788 GST_VAAPI_DISPLAY_LOCK(display);
789 status = vaUnmapBuffer(
790 GST_VAAPI_DISPLAY_VADISPLAY(display),
791 image->priv->image.buf
793 GST_VAAPI_DISPLAY_UNLOCK(display);
794 if (!vaapi_check_status(status, "vaUnmapBuffer()"))
797 image->priv->image_data = NULL;
802 * gst_vaapi_image_get_plane_count:
803 * @image: a #GstVaapiImage
805 * Retrieves the number of planes available in the @image. The @image
806 * must be mapped for this function to work properly.
808 * Return value: the number of planes available in the @image
811 gst_vaapi_image_get_plane_count(GstVaapiImage *image)
813 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
814 g_return_val_if_fail(image->priv->is_constructed, FALSE);
815 g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), 0);
817 return image->priv->image.num_planes;
821 * gst_vaapi_image_get_plane:
822 * @image: a #GstVaapiImage
823 * @plane: the requested plane number
825 * Retrieves the pixels data to the specified @plane. The @image must
826 * be mapped for this function to work properly.
828 * Return value: the pixels data of the specified @plane
831 gst_vaapi_image_get_plane(GstVaapiImage *image, guint plane)
833 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), NULL);
834 g_return_val_if_fail(image->priv->is_constructed, FALSE);
835 g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), NULL);
836 g_return_val_if_fail(plane < image->priv->image.num_planes, NULL);
838 return image->priv->image_data + image->priv->image.offsets[plane];
842 * gst_vaapi_image_get_pitch:
843 * @image: a #GstVaapiImage
844 * @plane: the requested plane number
846 * Retrieves the line size (stride) of the specified @plane. The
847 * @image must be mapped for this function to work properly.
849 * Return value: the line size (stride) of the specified plane
852 gst_vaapi_image_get_pitch(GstVaapiImage *image, guint plane)
854 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
855 g_return_val_if_fail(image->priv->is_constructed, FALSE);
856 g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), 0);
857 g_return_val_if_fail(plane < image->priv->image.num_planes, 0);
859 return image->priv->image.pitches[plane];
863 * gst_vaapi_image_get_data_size:
864 * @image: a #GstVaapiImage
866 * Retrieves the underlying image data size. This function could be
867 * used to determine whether the image has a compatible layout with
868 * another image structure.
870 * Return value: the whole image data size of the @image
873 gst_vaapi_image_get_data_size(GstVaapiImage *image)
875 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
876 g_return_val_if_fail(image->priv->is_constructed, FALSE);
878 return image->priv->image.data_size;
882 * gst_vaapi_image_update_from_buffer:
883 * @image: a #GstVaapiImage
884 * @buffer: a #GstBuffer
886 * Transfers pixels data contained in the #GstBuffer into the
887 * @image. Both image structures shall have the same format.
889 * Return value: %TRUE on success
892 gst_vaapi_image_update_from_buffer(GstVaapiImage *image, GstBuffer *buffer)
894 GstVaapiImagePrivate *priv;
895 GstStructure *structure;
897 GstVaapiImageFormat format;
899 guint offsets[3], pitches[3], widths[3], heights[3];
904 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
905 g_return_val_if_fail(image->priv->is_constructed, FALSE);
906 g_return_val_if_fail(GST_IS_BUFFER(buffer), FALSE);
909 data = GST_BUFFER_DATA(buffer);
910 data_size = GST_BUFFER_SIZE(buffer);
911 caps = GST_BUFFER_CAPS(buffer);
916 format = gst_vaapi_image_format_from_caps(caps);
917 if (format != priv->format)
920 structure = gst_caps_get_structure(caps, 0);
921 gst_structure_get_int(structure, "width", &width);
922 gst_structure_get_int(structure, "height", &height);
923 if (width != priv->width || height != priv->height)
926 if (!gst_vaapi_image_map(image))
929 if (priv->is_linear && data_size == priv->image.data_size)
930 memcpy(priv->image_data, data, data_size);
932 /* XXX: copied from gst_video_format_get_row_stride() -- no NV12? */
933 const guint width2 = (width + 1) / 2;
934 const guint height2 = (height + 1) / 2;
937 case GST_VAAPI_IMAGE_NV12:
939 pitches[0] = GST_ROUND_UP_4(width);
942 offsets[1] = offsets[0] + height * pitches[0];
943 pitches[1] = pitches[0];
944 widths [1] = width2 * 2;
945 heights[1] = height2;
946 size2 = offsets[1] + height2 * pitches[1];
948 case GST_VAAPI_IMAGE_YV12:
949 case GST_VAAPI_IMAGE_I420:
951 pitches[0] = GST_ROUND_UP_4(width);
954 offsets[1] = offsets[0] + height * pitches[0];
955 pitches[1] = GST_ROUND_UP_4(GST_ROUND_UP_2(width) / 2);
957 heights[1] = height2;
958 offsets[2] = offsets[1] + height2 * pitches[1];
959 pitches[2] = pitches[1];
961 heights[2] = height2;
962 size2 = offsets[2] + height2 * pitches[2];
964 case GST_VAAPI_IMAGE_ARGB:
965 case GST_VAAPI_IMAGE_RGBA:
966 case GST_VAAPI_IMAGE_ABGR:
967 case GST_VAAPI_IMAGE_BGRA:
969 pitches[0] = width * 4;
970 widths [0] = width * 4;
972 size2 = offsets[0] + height * pitches[0];
975 g_error("could not compute row-stride for %" GST_FOURCC_FORMAT,
976 GST_FOURCC_ARGS(format));
979 if (size2 != data_size)
980 g_error("data_size mismatch %d / %u", size2, data_size);
981 for (i = 0; i < priv->image.num_planes; i++) {
982 guchar *src = data + offsets[i];
983 guchar *dst = priv->image_data + priv->image.offsets[i];
984 for (j = 0; j < heights[i]; j++) {
985 memcpy(dst, src, widths[i]);
987 dst += priv->image.pitches[i];
992 if (!gst_vaapi_image_unmap(image))