2 * gstvaapiimage.c - VA image abstraction
4 * Copyright (C) 2010-2011 Splitted-Desktop Systems
5 * Copyright (C) 2011-2012 Intel Corporation
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public License
9 * as published by the Free Software Foundation; either version 2.1
10 * of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301 USA
24 * SECTION:gstvaapiimage
25 * @short_description: VA image abstraction
30 #include "gst/gstutils.h"
31 #include "gstvaapicompat.h"
32 #include "gstvaapiutils.h"
33 #include "gstvaapiimage.h"
34 #include "gstvaapi_priv.h"
37 #include "gstvaapidebug.h"
39 G_DEFINE_TYPE(GstVaapiImage, gst_vaapi_image, GST_VAAPI_TYPE_OBJECT)
41 #define GST_VAAPI_IMAGE_GET_PRIVATE(obj) \
42 (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
43 GST_VAAPI_TYPE_IMAGE, \
44 GstVaapiImagePrivate))
46 struct _GstVaapiImagePrivate {
47 VAImage internal_image;
50 GstVaapiImageFormat internal_format;
51 GstVaapiImageFormat format;
54 guint create_image : 1;
55 guint is_constructed : 1;
68 #define SWAP_UINT(a, b) do { \
75 _gst_vaapi_image_map(GstVaapiImage *image, GstVaapiImageRaw *raw_image);
78 _gst_vaapi_image_unmap(GstVaapiImage *image);
81 _gst_vaapi_image_set_image(GstVaapiImage *image, const VAImage *va_image);
87 #define VAAPI_TYPE_IMAGE vaapi_image_get_type()
90 vaapi_image_copy(gpointer va_image)
92 return g_slice_dup(VAImage, va_image);
96 vaapi_image_free(gpointer va_image)
98 if (G_LIKELY(va_image))
99 g_slice_free(VAImage, va_image);
103 vaapi_image_get_type(void)
105 static GType type = 0;
107 if (G_UNLIKELY(type == 0))
108 type = g_boxed_type_register_static(
117 vaapi_image_is_linear(const VAImage *va_image)
119 guint i, width, height, width2, height2, data_size;
121 for (i = 1; i < va_image->num_planes; i++)
122 if (va_image->offsets[i] < va_image->offsets[i - 1])
125 width = va_image->width;
126 height = va_image->height;
127 width2 = (width + 1) / 2;
128 height2 = (height + 1) / 2;
130 switch (va_image->format.fourcc) {
131 case VA_FOURCC('N','V','1','2'):
132 case VA_FOURCC('Y','V','1','2'):
133 case VA_FOURCC('I','4','2','0'):
134 data_size = width * height + 2 * width2 * height2;
136 case VA_FOURCC('A','Y','U','V'):
137 case VA_FOURCC('A','R','G','B'):
138 case VA_FOURCC('R','G','B','A'):
139 case VA_FOURCC('A','B','G','R'):
140 case VA_FOURCC('B','G','R','A'):
141 data_size = 4 * width * height;
144 g_error("FIXME: incomplete formats");
147 return va_image->data_size == data_size;
151 gst_vaapi_image_destroy(GstVaapiImage *image)
153 GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(image);
157 _gst_vaapi_image_unmap(image);
159 image_id = GST_VAAPI_OBJECT_ID(image);
160 GST_DEBUG("image %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(image_id));
162 if (image_id != VA_INVALID_ID) {
163 GST_VAAPI_DISPLAY_LOCK(display);
164 status = vaDestroyImage(GST_VAAPI_DISPLAY_VADISPLAY(display), image_id);
165 GST_VAAPI_DISPLAY_UNLOCK(display);
166 if (!vaapi_check_status(status, "vaDestroyImage()"))
167 g_warning("failed to destroy image %" GST_VAAPI_ID_FORMAT,
168 GST_VAAPI_ID_ARGS(image_id));
169 GST_VAAPI_OBJECT_ID(image) = VA_INVALID_ID;
174 _gst_vaapi_image_create(GstVaapiImage *image, GstVaapiImageFormat format)
176 GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(image);
177 GstVaapiImagePrivate * const priv = image->priv;
178 const VAImageFormat *va_format;
181 if (!gst_vaapi_display_has_image_format(display, format))
184 va_format = gst_vaapi_image_format_get_va_format(format);
188 GST_VAAPI_DISPLAY_LOCK(display);
189 status = vaCreateImage(
190 GST_VAAPI_DISPLAY_VADISPLAY(display),
191 (VAImageFormat *)va_format,
194 &priv->internal_image
196 GST_VAAPI_DISPLAY_UNLOCK(display);
197 if (status != VA_STATUS_SUCCESS ||
198 priv->internal_image.format.fourcc != va_format->fourcc)
201 priv->internal_format = format;
206 gst_vaapi_image_create(GstVaapiImage *image)
208 GstVaapiImagePrivate * const priv = image->priv;
209 GstVaapiImageFormat format = priv->format;
210 const VAImageFormat *va_format;
213 if (!priv->create_image)
214 return (priv->image.image_id != VA_INVALID_ID &&
215 priv->image.buf != VA_INVALID_ID);
217 if (!_gst_vaapi_image_create(image, format)) {
219 case GST_VAAPI_IMAGE_I420:
220 format = GST_VAAPI_IMAGE_YV12;
222 case GST_VAAPI_IMAGE_YV12:
223 format = GST_VAAPI_IMAGE_I420;
229 if (!format || !_gst_vaapi_image_create(image, format))
232 priv->image = priv->internal_image;
233 image_id = priv->image.image_id;
235 if (priv->format != priv->internal_format) {
236 switch (priv->format) {
237 case GST_VAAPI_IMAGE_YV12:
238 case GST_VAAPI_IMAGE_I420:
239 va_format = gst_vaapi_image_format_get_va_format(priv->format);
242 priv->image.format = *va_format;
243 SWAP_UINT(priv->image.offsets[1], priv->image.offsets[2]);
244 SWAP_UINT(priv->image.pitches[1], priv->image.pitches[2]);
250 priv->is_linear = vaapi_image_is_linear(&priv->image);
252 GST_DEBUG("image %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(image_id));
253 GST_VAAPI_OBJECT_ID(image) = image_id;
258 gst_vaapi_image_finalize(GObject *object)
260 gst_vaapi_image_destroy(GST_VAAPI_IMAGE(object));
262 G_OBJECT_CLASS(gst_vaapi_image_parent_class)->finalize(object);
266 gst_vaapi_image_set_property(
273 GstVaapiImage * const image = GST_VAAPI_IMAGE(object);
274 GstVaapiImagePrivate * const priv = image->priv;
278 const VAImage * const va_image = g_value_get_boxed(value);
280 _gst_vaapi_image_set_image(image, va_image);
284 if (priv->create_image)
285 priv->format = g_value_get_uint(value);
288 if (priv->create_image)
289 priv->width = g_value_get_uint(value);
292 if (priv->create_image)
293 priv->height = g_value_get_uint(value);
296 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
302 gst_vaapi_image_get_property(
309 GstVaapiImage * const image = GST_VAAPI_IMAGE(object);
313 g_value_set_boxed(value, &image->priv->image);
316 g_value_set_uint(value, gst_vaapi_image_get_format(image));
319 g_value_set_uint(value, gst_vaapi_image_get_width(image));
322 g_value_set_uint(value, gst_vaapi_image_get_height(image));
325 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
331 gst_vaapi_image_constructed(GObject *object)
333 GstVaapiImage * const image = GST_VAAPI_IMAGE(object);
334 GObjectClass *parent_class;
336 image->priv->is_constructed = gst_vaapi_image_create(image);
338 parent_class = G_OBJECT_CLASS(gst_vaapi_image_parent_class);
339 if (parent_class->constructed)
340 parent_class->constructed(object);
344 gst_vaapi_image_class_init(GstVaapiImageClass *klass)
346 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
348 g_type_class_add_private(klass, sizeof(GstVaapiImagePrivate));
350 object_class->finalize = gst_vaapi_image_finalize;
351 object_class->set_property = gst_vaapi_image_set_property;
352 object_class->get_property = gst_vaapi_image_get_property;
353 object_class->constructed = gst_vaapi_image_constructed;
355 g_object_class_install_property
358 g_param_spec_boxed("image",
360 "The underlying VA image",
362 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
364 g_object_class_install_property
367 g_param_spec_uint("width",
371 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
373 g_object_class_install_property
376 g_param_spec_uint("height",
380 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
383 * GstVaapiImage:format:
385 * The #GstVaapiImageFormat of the image
387 g_object_class_install_property
390 g_param_spec_uint("format",
392 "The underlying image format",
394 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
398 gst_vaapi_image_init(GstVaapiImage *image)
400 GstVaapiImagePrivate *priv = GST_VAAPI_IMAGE_GET_PRIVATE(image);
403 priv->image_data = NULL;
406 priv->internal_format = 0;
408 priv->create_image = TRUE;
409 priv->is_constructed = FALSE;
410 priv->is_linear = FALSE;
412 memset(&priv->internal_image, 0, sizeof(priv->internal_image));
413 priv->internal_image.image_id = VA_INVALID_ID;
414 priv->internal_image.buf = VA_INVALID_ID;
416 memset(&priv->image, 0, sizeof(priv->image));
417 priv->image.image_id = VA_INVALID_ID;
418 priv->image.buf = VA_INVALID_ID;
422 * gst_vaapi_image_new:
423 * @display: a #GstVaapiDisplay
424 * @format: a #GstVaapiImageFormat
425 * @width: the requested image width
426 * @height: the requested image height
428 * Creates a new #GstVaapiImage with the specified format and
431 * Return value: the newly allocated #GstVaapiImage object
435 GstVaapiDisplay *display,
436 GstVaapiImageFormat format,
441 GstVaapiImage *image;
443 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
444 g_return_val_if_fail(width > 0, NULL);
445 g_return_val_if_fail(height > 0, NULL);
447 GST_DEBUG("format %" GST_FOURCC_FORMAT ", size %ux%u",
448 GST_FOURCC_ARGS(format), width, height);
450 image = g_object_new(
451 GST_VAAPI_TYPE_IMAGE,
453 "id", GST_VAAPI_ID(VA_INVALID_ID),
462 if (!image->priv->is_constructed) {
463 g_object_unref(image);
470 * gst_vaapi_image_new_with_image:
471 * @display: a #GstVaapiDisplay
472 * @va_image: a VA image
474 * Creates a new #GstVaapiImage from a foreign VA image. The image
475 * format and dimensions will be extracted from @va_image. This
476 * function is mainly used by gst_vaapi_surface_derive_image() to bind
477 * a VA image to a #GstVaapiImage object.
479 * Return value: the newly allocated #GstVaapiImage object
482 gst_vaapi_image_new_with_image(GstVaapiDisplay *display, VAImage *va_image)
484 GstVaapiImage *image;
486 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
487 g_return_val_if_fail(va_image, NULL);
488 g_return_val_if_fail(va_image->image_id != VA_INVALID_ID, NULL);
489 g_return_val_if_fail(va_image->buf != VA_INVALID_ID, NULL);
491 GST_DEBUG("VA image 0x%08x, format %" GST_FOURCC_FORMAT ", size %ux%u",
493 GST_FOURCC_ARGS(va_image->format.fourcc),
494 va_image->width, va_image->height);
496 image = g_object_new(
497 GST_VAAPI_TYPE_IMAGE,
499 "id", GST_VAAPI_ID(va_image->image_id),
506 if (!image->priv->is_constructed) {
507 g_object_unref(image);
514 * gst_vaapi_image_get_id:
515 * @image: a #GstVaapiImage
517 * Returns the underlying VAImageID of the @image.
519 * Return value: the underlying VA image id
522 gst_vaapi_image_get_id(GstVaapiImage *image)
524 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), VA_INVALID_ID);
525 g_return_val_if_fail(image->priv->is_constructed, VA_INVALID_ID);
527 return GST_VAAPI_OBJECT_ID(image);
531 * gst_vaapi_image_get_image:
532 * @image: a #GstVaapiImage
533 * @va_image: a VA image
535 * Fills @va_image with the VA image used internally.
537 * Return value: %TRUE on success
540 gst_vaapi_image_get_image(GstVaapiImage *image, VAImage *va_image)
542 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
543 g_return_val_if_fail(image->priv->is_constructed, FALSE);
546 *va_image = image->priv->image;
552 * _gst_vaapi_image_set_image:
553 * @image: a #GstVaapiImage
554 * @va_image: a VA image
556 * Initializes #GstVaapiImage with a foreign VA image. This function
557 * will try to "linearize" the VA image. i.e. making sure that the VA
558 * image offsets into the data buffer are in increasing order with the
559 * number of planes available in the image.
561 * This is an internal function used by gst_vaapi_image_new_with_image().
563 * Return value: %TRUE on success
566 _gst_vaapi_image_set_image(GstVaapiImage *image, const VAImage *va_image)
568 GstVaapiImagePrivate * const priv = image->priv;
569 GstVaapiImageFormat format;
570 VAImage alt_va_image;
571 const VAImageFormat *alt_va_format;
576 format = gst_vaapi_image_format(&va_image->format);
580 priv->create_image = FALSE;
581 priv->internal_image = *va_image;
582 priv->internal_format = format;
583 priv->is_linear = vaapi_image_is_linear(va_image);
584 priv->image = *va_image;
585 priv->format = format;
586 priv->width = va_image->width;
587 priv->height = va_image->height;
589 /* Try to linearize image */
590 if (!priv->is_linear) {
592 case GST_VAAPI_IMAGE_I420:
593 format = GST_VAAPI_IMAGE_YV12;
595 case GST_VAAPI_IMAGE_YV12:
596 format = GST_VAAPI_IMAGE_I420;
603 (alt_va_format = gst_vaapi_image_format_get_va_format(format))) {
604 alt_va_image = *va_image;
605 alt_va_image.format = *alt_va_format;
606 SWAP_UINT(alt_va_image.offsets[1], alt_va_image.offsets[2]);
607 SWAP_UINT(alt_va_image.pitches[1], alt_va_image.pitches[2]);
608 if (vaapi_image_is_linear(&alt_va_image)) {
609 priv->image = alt_va_image;
610 priv->format = format;
611 priv->is_linear = TRUE;
612 GST_DEBUG("linearized image to %" GST_FOURCC_FORMAT " format",
613 GST_FOURCC_ARGS(format));
621 * gst_vaapi_image_get_format:
622 * @image: a #GstVaapiImage
624 * Returns the #GstVaapiImageFormat the @image was created with.
626 * Return value: the #GstVaapiImageFormat
629 gst_vaapi_image_get_format(GstVaapiImage *image)
631 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
632 g_return_val_if_fail(image->priv->is_constructed, 0);
634 return image->priv->format;
638 * gst_vaapi_image_get_width:
639 * @image: a #GstVaapiImage
641 * Returns the @image width.
643 * Return value: the image width, in pixels
646 gst_vaapi_image_get_width(GstVaapiImage *image)
648 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
649 g_return_val_if_fail(image->priv->is_constructed, 0);
651 return image->priv->width;
655 * gst_vaapi_image_get_height:
656 * @image: a #GstVaapiImage
658 * Returns the @image height.
660 * Return value: the image height, in pixels.
663 gst_vaapi_image_get_height(GstVaapiImage *image)
665 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
666 g_return_val_if_fail(image->priv->is_constructed, 0);
668 return image->priv->height;
672 * gst_vaapi_image_get_size:
673 * @image: a #GstVaapiImage
674 * @pwidth: return location for the width, or %NULL
675 * @pheight: return location for the height, or %NULL
677 * Retrieves the dimensions of a #GstVaapiImage.
680 gst_vaapi_image_get_size(GstVaapiImage *image, guint *pwidth, guint *pheight)
682 g_return_if_fail(GST_VAAPI_IS_IMAGE(image));
683 g_return_if_fail(image->priv->is_constructed);
686 *pwidth = image->priv->width;
689 *pheight = image->priv->height;
693 * gst_vaapi_image_is_linear:
694 * @image: a #GstVaapiImage
696 * Checks whether the @image has data planes allocated from a single
697 * buffer and offsets into that buffer are in increasing order with
698 * the number of planes.
700 * Return value: %TRUE if image data planes are allocated from a single buffer
703 gst_vaapi_image_is_linear(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 image->priv->is_linear;
712 * gst_vaapi_image_is_mapped:
713 * @image: a #GstVaapiImage
715 * Checks whether the @image is currently mapped or not.
717 * Return value: %TRUE if the @image is mapped
719 static inline gboolean
720 _gst_vaapi_image_is_mapped(GstVaapiImage *image)
722 return image->priv->image_data != NULL;
726 gst_vaapi_image_is_mapped(GstVaapiImage *image)
728 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
729 g_return_val_if_fail(image->priv->is_constructed, FALSE);
731 return _gst_vaapi_image_is_mapped(image);
735 * gst_vaapi_image_map:
736 * @image: a #GstVaapiImage
738 * Maps the image data buffer. The actual pixels are returned by the
739 * gst_vaapi_image_get_plane() function.
741 * Return value: %TRUE on success
744 gst_vaapi_image_map(GstVaapiImage *image)
746 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
747 g_return_val_if_fail(image->priv->is_constructed, FALSE);
749 return _gst_vaapi_image_map(image, NULL);
753 _gst_vaapi_image_map(GstVaapiImage *image, GstVaapiImageRaw *raw_image)
755 GstVaapiImagePrivate * const priv = image->priv;
756 GstVaapiDisplay *display;
760 if (_gst_vaapi_image_is_mapped(image))
763 display = GST_VAAPI_OBJECT_DISPLAY(image);
767 GST_VAAPI_DISPLAY_LOCK(display);
768 status = vaMapBuffer(
769 GST_VAAPI_DISPLAY_VADISPLAY(display),
771 (void **)&priv->image_data
773 GST_VAAPI_DISPLAY_UNLOCK(display);
774 if (!vaapi_check_status(status, "vaMapBuffer()"))
779 const VAImage * const va_image = &priv->image;
780 raw_image->format = priv->format;
781 raw_image->width = va_image->width;
782 raw_image->height = va_image->height;
783 raw_image->num_planes = va_image->num_planes;
784 for (i = 0; i < raw_image->num_planes; i++) {
785 raw_image->pixels[i] = (guchar *)priv->image_data +
786 va_image->offsets[i];
787 raw_image->stride[i] = va_image->pitches[i];
794 * gst_vaapi_image_unmap:
795 * @image: a #GstVaapiImage
797 * Unmaps the image data buffer. Pointers to pixels returned by
798 * gst_vaapi_image_get_plane() are then no longer valid.
800 * Return value: %TRUE on success
803 gst_vaapi_image_unmap(GstVaapiImage *image)
805 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
806 g_return_val_if_fail(image->priv->is_constructed, FALSE);
808 return _gst_vaapi_image_unmap(image);
812 _gst_vaapi_image_unmap(GstVaapiImage *image)
814 GstVaapiDisplay *display;
817 if (!_gst_vaapi_image_is_mapped(image))
820 display = GST_VAAPI_OBJECT_DISPLAY(image);
824 GST_VAAPI_DISPLAY_LOCK(display);
825 status = vaUnmapBuffer(
826 GST_VAAPI_DISPLAY_VADISPLAY(display),
827 image->priv->image.buf
829 GST_VAAPI_DISPLAY_UNLOCK(display);
830 if (!vaapi_check_status(status, "vaUnmapBuffer()"))
833 image->priv->image_data = NULL;
838 * gst_vaapi_image_get_plane_count:
839 * @image: a #GstVaapiImage
841 * Retrieves the number of planes available in the @image. The @image
842 * must be mapped for this function to work properly.
844 * Return value: the number of planes available in the @image
847 gst_vaapi_image_get_plane_count(GstVaapiImage *image)
849 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
850 g_return_val_if_fail(image->priv->is_constructed, FALSE);
851 g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), 0);
853 return image->priv->image.num_planes;
857 * gst_vaapi_image_get_plane:
858 * @image: a #GstVaapiImage
859 * @plane: the requested plane number
861 * Retrieves the pixels data to the specified @plane. The @image must
862 * be mapped for this function to work properly.
864 * Return value: the pixels data of the specified @plane
867 gst_vaapi_image_get_plane(GstVaapiImage *image, guint plane)
869 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), NULL);
870 g_return_val_if_fail(image->priv->is_constructed, FALSE);
871 g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), NULL);
872 g_return_val_if_fail(plane < image->priv->image.num_planes, NULL);
874 return image->priv->image_data + image->priv->image.offsets[plane];
878 * gst_vaapi_image_get_pitch:
879 * @image: a #GstVaapiImage
880 * @plane: the requested plane number
882 * Retrieves the line size (stride) of the specified @plane. The
883 * @image must be mapped for this function to work properly.
885 * Return value: the line size (stride) of the specified plane
888 gst_vaapi_image_get_pitch(GstVaapiImage *image, guint plane)
890 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
891 g_return_val_if_fail(image->priv->is_constructed, FALSE);
892 g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), 0);
893 g_return_val_if_fail(plane < image->priv->image.num_planes, 0);
895 return image->priv->image.pitches[plane];
899 * gst_vaapi_image_get_data_size:
900 * @image: a #GstVaapiImage
902 * Retrieves the underlying image data size. This function could be
903 * used to determine whether the image has a compatible layout with
904 * another image structure.
906 * Return value: the whole image data size of the @image
909 gst_vaapi_image_get_data_size(GstVaapiImage *image)
911 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
912 g_return_val_if_fail(image->priv->is_constructed, FALSE);
914 return image->priv->image.data_size;
918 init_image_from_buffer(GstVaapiImageRaw *raw_image, GstBuffer *buffer)
920 GstStructure *structure;
922 GstVaapiImageFormat format;
923 guint width2, height2, size2;
928 data = GST_BUFFER_DATA(buffer);
929 data_size = GST_BUFFER_SIZE(buffer);
930 caps = GST_BUFFER_CAPS(buffer);
935 format = gst_vaapi_image_format_from_caps(caps);
937 structure = gst_caps_get_structure(caps, 0);
938 gst_structure_get_int(structure, "width", &width);
939 gst_structure_get_int(structure, "height", &height);
941 /* XXX: copied from gst_video_format_get_row_stride() -- no NV12? */
942 raw_image->format = format;
943 raw_image->width = width;
944 raw_image->height = height;
945 width2 = (width + 1) / 2;
946 height2 = (height + 1) / 2;
949 case GST_VAAPI_IMAGE_NV12:
950 raw_image->num_planes = 2;
951 raw_image->pixels[0] = data;
952 raw_image->stride[0] = GST_ROUND_UP_4(width);
953 size2 += height * raw_image->stride[0];
954 raw_image->pixels[1] = data + size2;
955 raw_image->stride[1] = raw_image->stride[0];
956 size2 += height2 * raw_image->stride[1];
958 case GST_VAAPI_IMAGE_YV12:
959 case GST_VAAPI_IMAGE_I420:
960 raw_image->num_planes = 3;
961 raw_image->pixels[0] = data;
962 raw_image->stride[0] = GST_ROUND_UP_4(width);
963 size2 += height * raw_image->stride[0];
964 raw_image->pixels[1] = data + size2;
965 raw_image->stride[1] = GST_ROUND_UP_4(width2);
966 size2 += height2 * raw_image->stride[1];
967 raw_image->pixels[2] = data + size2;
968 raw_image->stride[2] = raw_image->stride[1];
969 size2 += height2 * raw_image->stride[2];
971 case GST_VAAPI_IMAGE_ARGB:
972 case GST_VAAPI_IMAGE_RGBA:
973 case GST_VAAPI_IMAGE_ABGR:
974 case GST_VAAPI_IMAGE_BGRA:
975 raw_image->num_planes = 1;
976 raw_image->pixels[0] = data;
977 raw_image->stride[0] = width * 4;
978 size2 += height * raw_image->stride[0];
981 g_error("could not compute row-stride for %" GST_FOURCC_FORMAT,
982 GST_FOURCC_ARGS(format));
986 if (size2 != data_size) {
987 g_error("data_size mismatch %d / %u", size2, data_size);
988 if (size2 > data_size)
994 /* Copy N lines of an image */
1007 for (i = 0; i < height; i++) {
1008 memcpy(dst, src, len);
1014 /* Copy NV12 images */
1017 GstVaapiImageRaw *dst_image,
1018 GstVaapiImageRaw *src_image,
1019 const GstVaapiRectangle *rect
1023 guint dst_stride, src_stride;
1026 dst_stride = dst_image->stride[0];
1027 dst = dst_image->pixels[0] + rect->y * dst_stride + rect->x;
1028 src_stride = src_image->stride[0];
1029 src = src_image->pixels[0] + rect->y * src_stride + rect->x;
1030 memcpy_pic(dst, dst_stride, src, src_stride, rect->width, rect->height);
1033 dst_stride = dst_image->stride[1];
1034 dst = dst_image->pixels[1] + (rect->y / 2) * dst_stride + (rect->x & -2);
1035 src_stride = src_image->stride[1];
1036 src = src_image->pixels[1] + (rect->y / 2) * src_stride + (rect->x & -2);
1037 memcpy_pic(dst, dst_stride, src, src_stride, rect->width, rect->height / 2);
1040 /* Copy YV12 images */
1043 GstVaapiImageRaw *dst_image,
1044 GstVaapiImageRaw *src_image,
1045 const GstVaapiRectangle *rect
1049 guint dst_stride, src_stride;
1050 guint i, x, y, w, h;
1053 dst_stride = dst_image->stride[0];
1054 dst = dst_image->pixels[0] + rect->y * dst_stride + rect->x;
1055 src_stride = src_image->stride[0];
1056 src = src_image->pixels[0] + rect->y * src_stride + rect->x;
1057 memcpy_pic(dst, dst_stride, src, src_stride, rect->width, rect->height);
1062 w = rect->width / 2;
1063 h = rect->height / 2;
1064 for (i = 1; i < dst_image->num_planes; i++) {
1065 dst_stride = dst_image->stride[i];
1066 dst = dst_image->pixels[i] + y * dst_stride + x;
1067 src_stride = src_image->stride[i];
1068 src = src_image->pixels[i] + y * src_stride + x;
1069 memcpy_pic(dst, dst_stride, src, src_stride, w, h);
1073 /* Copy RGBA images */
1076 GstVaapiImageRaw *dst_image,
1077 GstVaapiImageRaw *src_image,
1078 const GstVaapiRectangle *rect
1082 guint dst_stride, src_stride;
1084 dst_stride = dst_image->stride[0];
1085 dst = dst_image->pixels[0] + rect->y * dst_stride + rect->x;
1086 src_stride = src_image->stride[0];
1087 src = src_image->pixels[0] + rect->y * src_stride + rect->x;
1088 memcpy_pic(dst, dst_stride, src, src_stride, 4 * rect->width, rect->height);
1093 GstVaapiImageRaw *dst_image,
1094 GstVaapiImageRaw *src_image,
1095 const GstVaapiRectangle *rect
1098 GstVaapiRectangle default_rect;
1100 if (dst_image->format != src_image->format ||
1101 dst_image->width != src_image->width ||
1102 dst_image->height != src_image->height)
1106 if (rect->x >= src_image->width ||
1107 rect->x + src_image->width > src_image->width ||
1108 rect->y >= src_image->height ||
1109 rect->y + src_image->height > src_image->height)
1115 default_rect.width = src_image->width;
1116 default_rect.height = src_image->height;
1117 rect = &default_rect;
1120 switch (dst_image->format) {
1121 case GST_VAAPI_IMAGE_NV12:
1122 copy_image_NV12(dst_image, src_image, rect);
1124 case GST_VAAPI_IMAGE_YV12:
1125 case GST_VAAPI_IMAGE_I420:
1126 copy_image_YV12(dst_image, src_image, rect);
1128 case GST_VAAPI_IMAGE_ARGB:
1129 case GST_VAAPI_IMAGE_RGBA:
1130 case GST_VAAPI_IMAGE_ABGR:
1131 case GST_VAAPI_IMAGE_BGRA:
1132 copy_image_RGBA(dst_image, src_image, rect);
1135 GST_ERROR("unsupported image format for copy");
1142 * gst_vaapi_image_get_buffer:
1143 * @image: a #GstVaapiImage
1144 * @buffer: a #GstBuffer
1145 * @rect: a #GstVaapiRectangle expressing a region, or %NULL for the
1148 * Transfers pixels data contained in the @image into the #GstBuffer.
1149 * Both image structures shall have the same format.
1151 * Return value: %TRUE on success
1154 gst_vaapi_image_get_buffer(
1155 GstVaapiImage *image,
1157 GstVaapiRectangle *rect
1160 GstVaapiImagePrivate *priv;
1161 GstVaapiImageRaw dst_image, src_image;
1164 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
1165 g_return_val_if_fail(image->priv->is_constructed, FALSE);
1166 g_return_val_if_fail(GST_IS_BUFFER(buffer), FALSE);
1170 if (!init_image_from_buffer(&dst_image, buffer))
1172 if (dst_image.format != priv->format)
1174 if (dst_image.width != priv->width || dst_image.height != priv->height)
1177 if (!_gst_vaapi_image_map(image, &src_image))
1180 success = copy_image(&dst_image, &src_image, rect);
1182 if (!_gst_vaapi_image_unmap(image))
1189 * gst_vaapi_image_get_raw:
1190 * @image: a #GstVaapiImage
1191 * @dst_image: a #GstVaapiImageRaw
1192 * @rect: a #GstVaapiRectangle expressing a region, or %NULL for the
1195 * Transfers pixels data contained in the @image into the #GstVaapiImageRaw.
1196 * Both image structures shall have the same format.
1198 * Return value: %TRUE on success
1201 gst_vaapi_image_get_raw(
1202 GstVaapiImage *image,
1203 GstVaapiImageRaw *dst_image,
1204 GstVaapiRectangle *rect
1207 GstVaapiImageRaw src_image;
1210 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
1211 g_return_val_if_fail(image->priv->is_constructed, FALSE);
1213 if (!_gst_vaapi_image_map(image, &src_image))
1216 success = copy_image(dst_image, &src_image, rect);
1218 if (!_gst_vaapi_image_unmap(image))
1225 * gst_vaapi_image_update_from_buffer:
1226 * @image: a #GstVaapiImage
1227 * @buffer: a #GstBuffer
1228 * @rect: a #GstVaapiRectangle expressing a region, or %NULL for the
1231 * Transfers pixels data contained in the #GstBuffer into the
1232 * @image. Both image structures shall have the same format.
1234 * Return value: %TRUE on success
1237 gst_vaapi_image_update_from_buffer(
1238 GstVaapiImage *image,
1240 GstVaapiRectangle *rect
1243 GstVaapiImagePrivate *priv;
1244 GstVaapiImageRaw dst_image, src_image;
1247 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
1248 g_return_val_if_fail(image->priv->is_constructed, FALSE);
1249 g_return_val_if_fail(GST_IS_BUFFER(buffer), FALSE);
1253 if (!init_image_from_buffer(&src_image, buffer))
1255 if (src_image.format != priv->format)
1257 if (src_image.width != priv->width || src_image.height != priv->height)
1260 if (!_gst_vaapi_image_map(image, &dst_image))
1263 success = copy_image(&dst_image, &src_image, rect);
1265 if (!_gst_vaapi_image_unmap(image))
1272 * gst_vaapi_image_update_from_raw:
1273 * @image: a #GstVaapiImage
1274 * @src_image: a #GstVaapiImageRaw
1275 * @buffer: a #GstBuffer
1276 * @rect: a #GstVaapiRectangle expressing a region, or %NULL for the
1279 * Transfers pixels data contained in the #GstVaapiImageRaw into the
1280 * @image. Both image structures shall have the same format.
1282 * Return value: %TRUE on success
1285 gst_vaapi_image_update_from_raw(
1286 GstVaapiImage *image,
1287 GstVaapiImageRaw *src_image,
1288 GstVaapiRectangle *rect
1291 GstVaapiImageRaw dst_image;
1294 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
1295 g_return_val_if_fail(image->priv->is_constructed, FALSE);
1297 if (!_gst_vaapi_image_map(image, &dst_image))
1300 success = copy_image(&dst_image, src_image, rect);
1302 if (!_gst_vaapi_image_unmap(image))
1310 const guint8 *y_src,
1311 guint32 y_src_stride,
1312 const guint8 *u_src,
1313 guint32 u_src_stride,
1314 const guint8 *v_src,
1315 guint32 v_src_stride,
1317 guint32 y_dest_stride,
1319 guint32 uv_dest_stride,
1324 guint32 row, column;
1327 memcpy_pic(y_dest, y_dest_stride, y_src, y_src_stride, width, height);
1328 uv_height = GST_ROUND_UP_2(height)/2;
1329 for (row = 0; row < uv_height; row++) {
1330 for (column = 0; column < width/2; column++) {
1331 uv_dest[column*2] = u_src[column];
1332 uv_dest[column*2+1] = v_src[column];
1334 u_src += u_src_stride;
1335 v_src += v_src_stride;
1336 uv_dest += uv_dest_stride;
1342 const guint8 *y_src,
1343 guint32 y_src_stride,
1344 const guint8 *uv_src,
1345 guint32 uv_src_stride,
1347 guint32 y_dest_stride,
1349 guint32 u_dest_stride,
1351 guint32 v_dest_stride,
1356 guint32 row, column;
1359 memcpy_pic(y_dest, y_dest_stride, y_src, y_src_stride, width, height);
1360 uv_height = GST_ROUND_UP_2(height)/2;
1361 for (row = 0; row < uv_height; row++) {
1362 for (column = 0; column < width/2; column++) {
1363 u_dest[column] = uv_src[column*2];
1364 v_dest[column] = uv_src[column*2+1];
1366 uv_src += uv_src_stride;
1367 u_dest += u_dest_stride;
1368 v_dest += v_dest_stride;
1374 const guint8 *yuv_src,
1375 guint32 yuv_src_stride,
1377 guint32 y_dest_stride,
1379 guint32 u_dest_stride,
1381 guint32 v_dest_stride,
1382 gboolean uv_interlaced,
1387 guint32 row, column;
1388 const guint8 *yuv_next_src;
1389 guint8 *y_next_dest;
1392 interval = uv_interlaced ? 2 : 1;
1393 for (row = 0; row < height/2; row++) {
1394 yuv_next_src = yuv_src + yuv_src_stride;
1395 y_next_dest = y_dest + y_dest_stride;
1396 for (column = 0; column < width/2; column++) {
1397 y_dest[column*2] = yuv_src[column*4];
1398 y_dest[column*2+1] = yuv_src[column*4+2];
1399 y_next_dest[column*2] = yuv_next_src[column*4];
1400 y_next_dest[column*2+1] = yuv_next_src[column*4+2];
1401 u_dest[column*interval] = ((yuv_src[column*4+1] + yuv_next_src[column*4+1])>>1);
1402 v_dest[column*interval] = ((yuv_src[column*4+3] + yuv_next_src[column*4+3])>>1);
1404 yuv_src = yuv_next_src + yuv_src_stride;
1405 y_dest = y_next_dest + y_dest_stride;
1406 u_dest += u_dest_stride;
1407 v_dest += v_dest_stride;
1412 for (column = 0; column < width/2; column++) {
1413 y_dest[column*2] = yuv_src[column*4];
1414 y_dest[column*2+1] = yuv_src[column*4+2];
1415 u_dest[column*interval] = yuv_src[column*4+1];
1416 v_dest[column*interval] = yuv_src[column*4+3];
1423 _image_convert_to_nv12(
1429 guint32 y_dest_stride,
1431 guint32 uv_dest_stride
1434 const guint8 *y_src, *u_src, *v_src, *uv_src;
1435 guint32 ystride, ustride, vstride, uv_stride;
1437 switch (src_format) {
1438 case GST_MAKE_FOURCC('N','V','1','2'): {
1440 ystride = GST_ROUND_UP_4(width);
1441 uv_src = src + ystride*GST_ROUND_UP_2(height);
1442 uv_stride = ystride;
1443 memcpy_pic(y_dest, y_dest_stride, y_src, ystride, width, height);
1444 memcpy_pic(uv_dest, uv_dest_stride, uv_src, uv_stride,
1445 width, GST_ROUND_UP_2(height)/2);
1449 case GST_MAKE_FOURCC('I','4','2','0'): {
1451 ystride = GST_ROUND_UP_4(width);
1452 u_src = src + ystride*GST_ROUND_UP_2(height);
1453 ustride = GST_ROUND_UP_8(ystride)/2;
1454 v_src = u_src + ustride*GST_ROUND_UP_2(height)/2;
1455 vstride = GST_ROUND_UP_8(ystride)/2;
1457 _yuv411_to_nv12(y_src, ystride, u_src, ustride, v_src, vstride,
1458 y_dest, y_dest_stride,
1459 uv_dest, uv_dest_stride,
1464 case GST_MAKE_FOURCC('Y','V','1','2'):{
1466 ystride = GST_ROUND_UP_4(width);
1467 v_src = src + ystride*GST_ROUND_UP_2(height);
1468 vstride = GST_ROUND_UP_8(ystride)/2;
1469 u_src = v_src + vstride*GST_ROUND_UP_2(height)/2;
1470 ustride = GST_ROUND_UP_8(ystride)/2;
1472 _yuv411_to_nv12(y_src, ystride, u_src, ustride, v_src, vstride,
1473 y_dest, y_dest_stride, uv_dest, uv_dest_stride,
1478 case GST_MAKE_FOURCC('Y', 'U', 'Y', '2'): {
1480 ystride = GST_ROUND_UP_2(width)*2;
1481 _yuy2_to_yuv411(y_src, ystride,
1482 y_dest, y_dest_stride,
1483 uv_dest, uv_dest_stride,
1484 uv_dest+1, uv_dest_stride,
1497 _image_convert_to_yuv411(
1503 guint32 y_dest_stride,
1505 guint32 u_dest_stride,
1507 guint32 v_dest_stride
1510 const guint8 *y_src, *u_src, *v_src, *uv_src;
1511 guint32 ystride, ustride, vstride, uv_stride;
1513 switch (src_format) {
1514 case GST_MAKE_FOURCC('N','V','1','2'): {
1516 ystride = GST_ROUND_UP_4(width);
1517 uv_src = src + ystride*GST_ROUND_UP_2(height);
1518 uv_stride = ystride;
1519 _nv12_to_yuv411(y_src, ystride, uv_src, uv_stride,
1520 y_dest, y_dest_stride,
1521 u_dest, u_dest_stride,
1522 v_dest, v_dest_stride,
1527 case GST_MAKE_FOURCC('I','4','2','0'):
1528 case GST_MAKE_FOURCC('Y','V','1','2'):{
1530 ystride = GST_ROUND_UP_4(width);
1531 if (GST_MAKE_FOURCC('I','4','2','0') == src_format) {
1532 u_src = src + ystride*GST_ROUND_UP_2(height);
1533 ustride = GST_ROUND_UP_8(ystride)/2;
1534 v_src = u_src + ustride*GST_ROUND_UP_2(height)/2;
1535 vstride = GST_ROUND_UP_8(ystride)/2;
1537 v_src = src + ystride*GST_ROUND_UP_2(height);
1538 vstride = GST_ROUND_UP_8(ystride)/2;
1539 u_src = v_src + vstride*GST_ROUND_UP_2(height)/2;
1540 ustride = GST_ROUND_UP_8(ystride)/2;
1543 memcpy_pic(y_dest, y_dest_stride, y_src, ystride, width, height);
1544 memcpy_pic(u_dest, u_dest_stride, u_src, ustride, width/2, GST_ROUND_UP_2(height)/2);
1545 memcpy_pic(v_dest, v_dest_stride, v_src, vstride, width/2, GST_ROUND_UP_2(height)/2);
1549 case GST_MAKE_FOURCC('Y', 'U', 'Y', '2'): {
1551 ystride = GST_ROUND_UP_2(width)*2;
1552 _yuy2_to_yuv411(y_src, ystride,
1553 y_dest, y_dest_stride,
1554 u_dest, u_dest_stride,
1555 v_dest, v_dest_stride,
1569 gst_vaapi_convert_buffer_to_image(
1570 GstVaapiImage *image,
1574 GstVaapiImagePrivate *priv;
1575 guint width, height;
1576 GstVaapiImageFormat image_format;
1577 gboolean success = TRUE;
1578 GstCaps *buffer_caps;
1579 GstStructure *structure;
1580 guint32 in_format = 0;
1583 gst_vaapi_image_get_size(image, &width, &height);
1584 image_format = gst_vaapi_image_get_format(image);
1586 /* get buffer format */
1587 buffer_caps = GST_BUFFER_CAPS(inbuf);
1590 structure = gst_caps_get_structure(buffer_caps, 0);
1593 if (!gst_structure_get_fourcc(structure, "format", &in_format))
1596 /* currently only support YUV convert */
1597 if ( (in_format != GST_MAKE_FOURCC('N','V','1','2')
1598 && in_format != GST_MAKE_FOURCC('Y','V','1','2')
1599 && in_format != GST_MAKE_FOURCC('I','4','2','0')
1600 && in_format != GST_MAKE_FOURCC('Y', 'U', 'Y', '2'))
1601 || (image_format != GST_VAAPI_IMAGE_NV12
1602 && image_format != GST_VAAPI_IMAGE_YV12
1603 && image_format != GST_VAAPI_IMAGE_I420)
1610 gst_vaapi_image_map(image);
1611 switch (image_format) {
1612 case GST_VAAPI_IMAGE_NV12: {
1613 g_assert(priv->image.num_planes == 2);
1614 success = _image_convert_to_nv12(GST_BUFFER_DATA(inbuf),
1615 width, height, in_format,
1616 priv->image_data+priv->image.offsets[0],
1617 priv->image.pitches[0],
1618 priv->image_data+priv->image.offsets[1],
1619 priv->image.pitches[1]);
1623 case GST_VAAPI_IMAGE_I420: {
1624 g_assert(priv->image.num_planes == 3);
1625 success = _image_convert_to_yuv411(GST_BUFFER_DATA(inbuf),
1626 width, height, in_format,
1627 priv->image_data+priv->image.offsets[0],
1628 priv->image.pitches[0],
1629 priv->image_data+priv->image.offsets[1],
1630 priv->image.pitches[1],
1631 priv->image_data+priv->image.offsets[2],
1632 priv->image.pitches[2]);
1635 case GST_VAAPI_IMAGE_YV12:{
1636 g_assert(priv->image.num_planes == 3);
1637 success = _image_convert_to_yuv411(GST_BUFFER_DATA(inbuf),
1638 width, height, in_format,
1639 priv->image_data+priv->image.offsets[0],
1640 priv->image.pitches[0],
1641 priv->image_data+priv->image.offsets[2],
1642 priv->image.pitches[2],
1643 priv->image_data+priv->image.offsets[1],
1644 priv->image.pitches[1]);
1652 gst_vaapi_image_unmap(image);