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_id:
509 * @image: a #GstVaapiImage
511 * Returns the underlying VAImageID of the @image.
513 * Return value: the underlying VA image id
516 gst_vaapi_image_get_id(GstVaapiImage *image)
518 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), VA_INVALID_ID);
519 g_return_val_if_fail(image->priv->is_constructed, VA_INVALID_ID);
521 return GST_VAAPI_OBJECT_ID(image);
525 * gst_vaapi_image_get_image:
526 * @image: a #GstVaapiImage
527 * @va_image: a VA image
529 * Fills @va_image with the VA image used internally.
531 * Return value: %TRUE on success
534 gst_vaapi_image_get_image(GstVaapiImage *image, VAImage *va_image)
536 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
537 g_return_val_if_fail(image->priv->is_constructed, FALSE);
540 *va_image = image->priv->image;
546 * _gst_vaapi_image_set_image:
547 * @image: a #GstVaapiImage
548 * @va_image: a VA image
550 * Initializes #GstVaapiImage with a foreign VA image. This function
551 * will try to "linearize" the VA image. i.e. making sure that the VA
552 * image offsets into the data buffer are in increasing order with the
553 * number of planes available in the image.
555 * This is an internal function used by gst_vaapi_image_new_with_image().
557 * Return value: %TRUE on success
560 _gst_vaapi_image_set_image(GstVaapiImage *image, const VAImage *va_image)
562 GstVaapiImagePrivate * const priv = image->priv;
563 GstVaapiImageFormat format;
564 VAImage alt_va_image;
565 const VAImageFormat *alt_va_format;
570 format = gst_vaapi_image_format(&va_image->format);
574 priv->create_image = FALSE;
575 priv->internal_image = *va_image;
576 priv->internal_format = format;
577 priv->is_linear = vaapi_image_is_linear(va_image);
578 priv->image = *va_image;
579 priv->format = format;
580 priv->width = va_image->width;
581 priv->height = va_image->height;
583 /* Try to linearize image */
584 if (!priv->is_linear) {
586 case GST_VAAPI_IMAGE_I420:
587 format = GST_VAAPI_IMAGE_YV12;
589 case GST_VAAPI_IMAGE_YV12:
590 format = GST_VAAPI_IMAGE_I420;
597 (alt_va_format = gst_vaapi_image_format_get_va_format(format))) {
598 alt_va_image = *va_image;
599 alt_va_image.format = *alt_va_format;
600 SWAP_UINT(alt_va_image.offsets[1], alt_va_image.offsets[2]);
601 SWAP_UINT(alt_va_image.pitches[1], alt_va_image.pitches[2]);
602 if (vaapi_image_is_linear(&alt_va_image)) {
603 priv->image = alt_va_image;
604 priv->format = format;
605 priv->is_linear = TRUE;
606 GST_DEBUG("linearized image to %" GST_FOURCC_FORMAT " format",
607 GST_FOURCC_ARGS(format));
615 * gst_vaapi_image_get_format:
616 * @image: a #GstVaapiImage
618 * Returns the #GstVaapiImageFormat the @image was created with.
620 * Return value: the #GstVaapiImageFormat
623 gst_vaapi_image_get_format(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->format;
632 * gst_vaapi_image_get_width:
633 * @image: a #GstVaapiImage
635 * Returns the @image width.
637 * Return value: the image width, in pixels
640 gst_vaapi_image_get_width(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->width;
649 * gst_vaapi_image_get_height:
650 * @image: a #GstVaapiImage
652 * Returns the @image height.
654 * Return value: the image height, in pixels.
657 gst_vaapi_image_get_height(GstVaapiImage *image)
659 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
660 g_return_val_if_fail(image->priv->is_constructed, FALSE);
662 return image->priv->height;
666 * gst_vaapi_image_get_size:
667 * @image: a #GstVaapiImage
668 * @pwidth: return location for the width, or %NULL
669 * @pheight: return location for the height, or %NULL
671 * Retrieves the dimensions of a #GstVaapiImage.
674 gst_vaapi_image_get_size(GstVaapiImage *image, guint *pwidth, guint *pheight)
676 g_return_if_fail(GST_VAAPI_IS_IMAGE(image));
677 g_return_if_fail(image->priv->is_constructed);
680 *pwidth = image->priv->width;
683 *pheight = image->priv->height;
687 * gst_vaapi_image_is_linear:
688 * @image: a #GstVaapiImage
690 * Checks whether the @image has data planes allocated from a single
691 * buffer and offsets into that buffer are in increasing order with
692 * the number of planes.
694 * Return value: %TRUE if image data planes are allocated from a single buffer
697 gst_vaapi_image_is_linear(GstVaapiImage *image)
699 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
700 g_return_val_if_fail(image->priv->is_constructed, FALSE);
702 return image->priv->is_linear;
706 * gst_vaapi_image_is_mapped:
707 * @image: a #GstVaapiImage
709 * Checks whether the @image is currently mapped or not.
711 * Return value: %TRUE if the @image is mapped
713 static inline gboolean
714 _gst_vaapi_image_is_mapped(GstVaapiImage *image)
716 return image->priv->image_data != NULL;
720 gst_vaapi_image_is_mapped(GstVaapiImage *image)
722 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
723 g_return_val_if_fail(image->priv->is_constructed, FALSE);
725 return _gst_vaapi_image_is_mapped(image);
729 * gst_vaapi_image_map:
730 * @image: a #GstVaapiImage
732 * Maps the image data buffer. The actual pixels are returned by the
733 * gst_vaapi_image_get_plane() function.
735 * Return value: %TRUE on success
738 gst_vaapi_image_map(GstVaapiImage *image)
740 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
741 g_return_val_if_fail(image->priv->is_constructed, FALSE);
743 return _gst_vaapi_image_map(image);
747 _gst_vaapi_image_map(GstVaapiImage *image)
749 GstVaapiDisplay *display;
753 if (_gst_vaapi_image_is_mapped(image))
756 display = GST_VAAPI_OBJECT_DISPLAY(image);
760 GST_VAAPI_DISPLAY_LOCK(display);
761 status = vaMapBuffer(
762 GST_VAAPI_DISPLAY_VADISPLAY(display),
763 image->priv->image.buf,
766 GST_VAAPI_DISPLAY_UNLOCK(display);
767 if (!vaapi_check_status(status, "vaMapBuffer()"))
770 image->priv->image_data = image_data;
775 * gst_vaapi_image_unmap:
776 * @image: a #GstVaapiImage
778 * Unmaps the image data buffer. Pointers to pixels returned by
779 * gst_vaapi_image_get_plane() are then no longer valid.
781 * Return value: %TRUE on success
784 gst_vaapi_image_unmap(GstVaapiImage *image)
786 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
787 g_return_val_if_fail(image->priv->is_constructed, FALSE);
789 return _gst_vaapi_image_unmap(image);
793 _gst_vaapi_image_unmap(GstVaapiImage *image)
795 GstVaapiDisplay *display;
798 if (!_gst_vaapi_image_is_mapped(image))
801 display = GST_VAAPI_OBJECT_DISPLAY(image);
805 GST_VAAPI_DISPLAY_LOCK(display);
806 status = vaUnmapBuffer(
807 GST_VAAPI_DISPLAY_VADISPLAY(display),
808 image->priv->image.buf
810 GST_VAAPI_DISPLAY_UNLOCK(display);
811 if (!vaapi_check_status(status, "vaUnmapBuffer()"))
814 image->priv->image_data = NULL;
819 * gst_vaapi_image_get_plane_count:
820 * @image: a #GstVaapiImage
822 * Retrieves the number of planes available in the @image. The @image
823 * must be mapped for this function to work properly.
825 * Return value: the number of planes available in the @image
828 gst_vaapi_image_get_plane_count(GstVaapiImage *image)
830 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
831 g_return_val_if_fail(image->priv->is_constructed, FALSE);
832 g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), 0);
834 return image->priv->image.num_planes;
838 * gst_vaapi_image_get_plane:
839 * @image: a #GstVaapiImage
840 * @plane: the requested plane number
842 * Retrieves the pixels data to the specified @plane. The @image must
843 * be mapped for this function to work properly.
845 * Return value: the pixels data of the specified @plane
848 gst_vaapi_image_get_plane(GstVaapiImage *image, guint plane)
850 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), NULL);
851 g_return_val_if_fail(image->priv->is_constructed, FALSE);
852 g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), NULL);
853 g_return_val_if_fail(plane < image->priv->image.num_planes, NULL);
855 return image->priv->image_data + image->priv->image.offsets[plane];
859 * gst_vaapi_image_get_pitch:
860 * @image: a #GstVaapiImage
861 * @plane: the requested plane number
863 * Retrieves the line size (stride) of the specified @plane. The
864 * @image must be mapped for this function to work properly.
866 * Return value: the line size (stride) of the specified plane
869 gst_vaapi_image_get_pitch(GstVaapiImage *image, guint plane)
871 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
872 g_return_val_if_fail(image->priv->is_constructed, FALSE);
873 g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), 0);
874 g_return_val_if_fail(plane < image->priv->image.num_planes, 0);
876 return image->priv->image.pitches[plane];
880 * gst_vaapi_image_get_data_size:
881 * @image: a #GstVaapiImage
883 * Retrieves the underlying image data size. This function could be
884 * used to determine whether the image has a compatible layout with
885 * another image structure.
887 * Return value: the whole image data size of the @image
890 gst_vaapi_image_get_data_size(GstVaapiImage *image)
892 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
893 g_return_val_if_fail(image->priv->is_constructed, FALSE);
895 return image->priv->image.data_size;
899 * gst_vaapi_image_update_from_buffer:
900 * @image: a #GstVaapiImage
901 * @buffer: a #GstBuffer
903 * Transfers pixels data contained in the #GstBuffer into the
904 * @image. Both image structures shall have the same format.
906 * Return value: %TRUE on success
909 gst_vaapi_image_update_from_buffer(GstVaapiImage *image, GstBuffer *buffer)
911 GstVaapiImagePrivate *priv;
912 GstStructure *structure;
914 GstVaapiImageFormat format;
916 guint offsets[3], pitches[3], widths[3], heights[3];
921 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
922 g_return_val_if_fail(image->priv->is_constructed, FALSE);
923 g_return_val_if_fail(GST_IS_BUFFER(buffer), FALSE);
926 data = GST_BUFFER_DATA(buffer);
927 data_size = GST_BUFFER_SIZE(buffer);
928 caps = GST_BUFFER_CAPS(buffer);
933 format = gst_vaapi_image_format_from_caps(caps);
934 if (format != priv->format)
937 structure = gst_caps_get_structure(caps, 0);
938 gst_structure_get_int(structure, "width", &width);
939 gst_structure_get_int(structure, "height", &height);
940 if (width != priv->width || height != priv->height)
943 if (!gst_vaapi_image_map(image))
946 if (priv->is_linear && data_size == priv->image.data_size)
947 memcpy(priv->image_data, data, data_size);
949 /* XXX: copied from gst_video_format_get_row_stride() -- no NV12? */
950 const guint width2 = (width + 1) / 2;
951 const guint height2 = (height + 1) / 2;
954 case GST_VAAPI_IMAGE_NV12:
956 pitches[0] = GST_ROUND_UP_4(width);
959 offsets[1] = offsets[0] + height * pitches[0];
960 pitches[1] = pitches[0];
961 widths [1] = width2 * 2;
962 heights[1] = height2;
963 size2 = offsets[1] + height2 * pitches[1];
965 case GST_VAAPI_IMAGE_YV12:
966 case GST_VAAPI_IMAGE_I420:
968 pitches[0] = GST_ROUND_UP_4(width);
971 offsets[1] = offsets[0] + height * pitches[0];
972 pitches[1] = GST_ROUND_UP_4(GST_ROUND_UP_2(width) / 2);
974 heights[1] = height2;
975 offsets[2] = offsets[1] + height2 * pitches[1];
976 pitches[2] = pitches[1];
978 heights[2] = height2;
979 size2 = offsets[2] + height2 * pitches[2];
981 case GST_VAAPI_IMAGE_ARGB:
982 case GST_VAAPI_IMAGE_RGBA:
983 case GST_VAAPI_IMAGE_ABGR:
984 case GST_VAAPI_IMAGE_BGRA:
986 pitches[0] = width * 4;
987 widths [0] = width * 4;
989 size2 = offsets[0] + height * pitches[0];
992 g_error("could not compute row-stride for %" GST_FOURCC_FORMAT,
993 GST_FOURCC_ARGS(format));
996 if (size2 != data_size)
997 g_error("data_size mismatch %d / %u", size2, data_size);
998 for (i = 0; i < priv->image.num_planes; i++) {
999 guchar *src = data + offsets[i];
1000 guchar *dst = priv->image_data + priv->image.offsets[i];
1001 for (j = 0; j < heights[i]; j++) {
1002 memcpy(dst, src, widths[i]);
1004 dst += priv->image.pitches[i];
1009 if (!gst_vaapi_image_unmap(image))