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;
761 if (_gst_vaapi_image_is_mapped(image))
764 display = GST_VAAPI_OBJECT_DISPLAY(image);
768 GST_VAAPI_DISPLAY_LOCK(display);
769 status = vaMapBuffer(
770 GST_VAAPI_DISPLAY_VADISPLAY(display),
771 image->priv->image.buf,
774 GST_VAAPI_DISPLAY_UNLOCK(display);
775 if (!vaapi_check_status(status, "vaMapBuffer()"))
778 image->priv->image_data = image_data;
781 const VAImage * const va_image = &priv->image;
782 raw_image->format = priv->format;
783 raw_image->width = va_image->width;
784 raw_image->height = va_image->height;
785 raw_image->num_planes = va_image->num_planes;
786 for (i = 0; i < raw_image->num_planes; i++) {
787 raw_image->pixels[i] = image_data + va_image->offsets[i];
788 raw_image->stride[i] = va_image->pitches[i];
795 * gst_vaapi_image_unmap:
796 * @image: a #GstVaapiImage
798 * Unmaps the image data buffer. Pointers to pixels returned by
799 * gst_vaapi_image_get_plane() are then no longer valid.
801 * Return value: %TRUE on success
804 gst_vaapi_image_unmap(GstVaapiImage *image)
806 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
807 g_return_val_if_fail(image->priv->is_constructed, FALSE);
809 return _gst_vaapi_image_unmap(image);
813 _gst_vaapi_image_unmap(GstVaapiImage *image)
815 GstVaapiDisplay *display;
818 if (!_gst_vaapi_image_is_mapped(image))
821 display = GST_VAAPI_OBJECT_DISPLAY(image);
825 GST_VAAPI_DISPLAY_LOCK(display);
826 status = vaUnmapBuffer(
827 GST_VAAPI_DISPLAY_VADISPLAY(display),
828 image->priv->image.buf
830 GST_VAAPI_DISPLAY_UNLOCK(display);
831 if (!vaapi_check_status(status, "vaUnmapBuffer()"))
834 image->priv->image_data = NULL;
839 * gst_vaapi_image_ensure_mapped_buffer:
840 * @image: a #GstVaapiImage
842 * initialize mapped image buffer in case of optimizition on
843 * nothing did between map and unmap operations.
845 * Return value: %TRUE on success
849 gst_vaapi_image_ensure_mapped_buffer(GstVaapiImage *image)
851 GstVaapiImagePrivate * const priv = image->priv;
856 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
857 g_return_val_if_fail(priv->is_constructed, FALSE);
859 if (!_gst_vaapi_image_is_mapped(image) || !priv->image_data)
862 #undef GST_VAAPI_IMAGE_PAGE_SIZE
863 #define GST_VAAPI_IMAGE_PAGE_SIZE 4096
865 /* read each page make sure virtual buffer mapped*/
866 user_ptr = priv->image_data;
868 index < priv->image.data_size;
869 index += GST_VAAPI_IMAGE_PAGE_SIZE) {
870 tmp = *(user_ptr + index);
871 /*prevent from compiling optimization*/
873 *(user_ptr + index) = 0;
880 * gst_vaapi_image_get_plane_count:
881 * @image: a #GstVaapiImage
883 * Retrieves the number of planes available in the @image. The @image
884 * must be mapped for this function to work properly.
886 * Return value: the number of planes available in the @image
889 gst_vaapi_image_get_plane_count(GstVaapiImage *image)
891 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
892 g_return_val_if_fail(image->priv->is_constructed, FALSE);
893 g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), 0);
895 return image->priv->image.num_planes;
899 * gst_vaapi_image_get_plane:
900 * @image: a #GstVaapiImage
901 * @plane: the requested plane number
903 * Retrieves the pixels data to the specified @plane. The @image must
904 * be mapped for this function to work properly.
906 * Return value: the pixels data of the specified @plane
909 gst_vaapi_image_get_plane(GstVaapiImage *image, guint plane)
911 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), NULL);
912 g_return_val_if_fail(image->priv->is_constructed, FALSE);
913 g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), NULL);
914 g_return_val_if_fail(plane < image->priv->image.num_planes, NULL);
916 return image->priv->image_data + image->priv->image.offsets[plane];
920 * gst_vaapi_image_get_pitch:
921 * @image: a #GstVaapiImage
922 * @plane: the requested plane number
924 * Retrieves the line size (stride) of the specified @plane. The
925 * @image must be mapped for this function to work properly.
927 * Return value: the line size (stride) of the specified plane
930 gst_vaapi_image_get_pitch(GstVaapiImage *image, guint plane)
932 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
933 g_return_val_if_fail(image->priv->is_constructed, FALSE);
934 g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), 0);
935 g_return_val_if_fail(plane < image->priv->image.num_planes, 0);
937 return image->priv->image.pitches[plane];
941 * gst_vaapi_image_get_data_size:
942 * @image: a #GstVaapiImage
944 * Retrieves the underlying image data size. This function could be
945 * used to determine whether the image has a compatible layout with
946 * another image structure.
948 * Return value: the whole image data size of the @image
951 gst_vaapi_image_get_data_size(GstVaapiImage *image)
953 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
954 g_return_val_if_fail(image->priv->is_constructed, FALSE);
956 return image->priv->image.data_size;
960 init_image_from_buffer(GstVaapiImageRaw *raw_image, GstBuffer *buffer)
962 GstStructure *structure;
964 GstVaapiImageFormat format;
965 guint width2, height2, size2;
970 data = GST_BUFFER_DATA(buffer);
971 data_size = GST_BUFFER_SIZE(buffer);
972 caps = GST_BUFFER_CAPS(buffer);
977 format = gst_vaapi_image_format_from_caps(caps);
979 structure = gst_caps_get_structure(caps, 0);
980 gst_structure_get_int(structure, "width", &width);
981 gst_structure_get_int(structure, "height", &height);
983 /* XXX: copied from gst_video_format_get_row_stride() -- no NV12? */
984 raw_image->format = format;
985 raw_image->width = width;
986 raw_image->height = height;
987 width2 = (width + 1) / 2;
988 height2 = (height + 1) / 2;
991 case GST_VAAPI_IMAGE_NV12:
992 raw_image->num_planes = 2;
993 raw_image->pixels[0] = data;
994 raw_image->stride[0] = GST_ROUND_UP_4(width);
995 size2 += height * raw_image->stride[0];
996 raw_image->pixels[1] = data + size2;
997 raw_image->stride[1] = raw_image->stride[0];
998 size2 += height2 * raw_image->stride[1];
1000 case GST_VAAPI_IMAGE_YV12:
1001 case GST_VAAPI_IMAGE_I420:
1002 raw_image->num_planes = 3;
1003 raw_image->pixels[0] = data;
1004 raw_image->stride[0] = GST_ROUND_UP_4(width);
1005 size2 += height * raw_image->stride[0];
1006 raw_image->pixels[1] = data + size2;
1007 raw_image->stride[1] = GST_ROUND_UP_4(width2);
1008 size2 += height2 * raw_image->stride[1];
1009 raw_image->pixels[2] = data + size2;
1010 raw_image->stride[2] = raw_image->stride[1];
1011 size2 += height2 * raw_image->stride[2];
1013 case GST_VAAPI_IMAGE_ARGB:
1014 case GST_VAAPI_IMAGE_RGBA:
1015 case GST_VAAPI_IMAGE_ABGR:
1016 case GST_VAAPI_IMAGE_BGRA:
1017 raw_image->num_planes = 1;
1018 raw_image->pixels[0] = data;
1019 raw_image->stride[0] = width * 4;
1020 size2 += height * raw_image->stride[0];
1023 g_error("could not compute row-stride for %" GST_FOURCC_FORMAT,
1024 GST_FOURCC_ARGS(format));
1028 if (size2 != data_size) {
1029 g_error("data_size mismatch %d / %u", size2, data_size);
1030 if (size2 > data_size)
1036 /* Copy N lines of an image */
1049 for (i = 0; i < height; i++) {
1050 memcpy(dst, src, len);
1056 /* Copy NV12 images */
1059 GstVaapiImageRaw *dst_image,
1060 GstVaapiImageRaw *src_image,
1061 const GstVaapiRectangle *rect
1065 guint dst_stride, src_stride;
1068 dst_stride = dst_image->stride[0];
1069 dst = dst_image->pixels[0] + rect->y * dst_stride + rect->x;
1070 src_stride = src_image->stride[0];
1071 src = src_image->pixels[0] + rect->y * src_stride + rect->x;
1072 memcpy_pic(dst, dst_stride, src, src_stride, rect->width, rect->height);
1075 dst_stride = dst_image->stride[1];
1076 dst = dst_image->pixels[1] + (rect->y / 2) * dst_stride + (rect->x & -2);
1077 src_stride = src_image->stride[1];
1078 src = src_image->pixels[1] + (rect->y / 2) * src_stride + (rect->x & -2);
1079 memcpy_pic(dst, dst_stride, src, src_stride, rect->width, rect->height / 2);
1082 /* Copy YV12 images */
1085 GstVaapiImageRaw *dst_image,
1086 GstVaapiImageRaw *src_image,
1087 const GstVaapiRectangle *rect
1091 guint dst_stride, src_stride;
1092 guint i, x, y, w, h;
1095 dst_stride = dst_image->stride[0];
1096 dst = dst_image->pixels[0] + rect->y * dst_stride + rect->x;
1097 src_stride = src_image->stride[0];
1098 src = src_image->pixels[0] + rect->y * src_stride + rect->x;
1099 memcpy_pic(dst, dst_stride, src, src_stride, rect->width, rect->height);
1104 w = rect->width / 2;
1105 h = rect->height / 2;
1106 for (i = 1; i < dst_image->num_planes; i++) {
1107 dst_stride = dst_image->stride[i];
1108 dst = dst_image->pixels[i] + y * dst_stride + x;
1109 src_stride = src_image->stride[i];
1110 src = src_image->pixels[i] + y * src_stride + x;
1111 memcpy_pic(dst, dst_stride, src, src_stride, w, h);
1115 /* Copy RGBA images */
1118 GstVaapiImageRaw *dst_image,
1119 GstVaapiImageRaw *src_image,
1120 const GstVaapiRectangle *rect
1124 guint dst_stride, src_stride;
1126 dst_stride = dst_image->stride[0];
1127 dst = dst_image->pixels[0] + rect->y * dst_stride + rect->x;
1128 src_stride = src_image->stride[0];
1129 src = src_image->pixels[0] + rect->y * src_stride + rect->x;
1130 memcpy_pic(dst, dst_stride, src, src_stride, 4 * rect->width, rect->height);
1135 GstVaapiImageRaw *dst_image,
1136 GstVaapiImageRaw *src_image,
1137 const GstVaapiRectangle *rect
1140 GstVaapiRectangle default_rect;
1142 if (dst_image->format != src_image->format ||
1143 dst_image->width != src_image->width ||
1144 dst_image->height < src_image->height)
1148 if (rect->x >= src_image->width ||
1149 rect->x + src_image->width > src_image->width ||
1150 rect->y >= src_image->height ||
1151 rect->y + src_image->height > src_image->height)
1157 default_rect.width = src_image->width;
1158 default_rect.height = src_image->height;
1159 rect = &default_rect;
1162 switch (dst_image->format) {
1163 case GST_VAAPI_IMAGE_NV12:
1164 copy_image_NV12(dst_image, src_image, rect);
1166 case GST_VAAPI_IMAGE_YV12:
1167 case GST_VAAPI_IMAGE_I420:
1168 copy_image_YV12(dst_image, src_image, rect);
1170 case GST_VAAPI_IMAGE_ARGB:
1171 case GST_VAAPI_IMAGE_RGBA:
1172 case GST_VAAPI_IMAGE_ABGR:
1173 case GST_VAAPI_IMAGE_BGRA:
1174 copy_image_RGBA(dst_image, src_image, rect);
1177 GST_ERROR("unsupported image format for copy");
1184 * gst_vaapi_image_get_buffer:
1185 * @image: a #GstVaapiImage
1186 * @buffer: a #GstBuffer
1187 * @rect: a #GstVaapiRectangle expressing a region, or %NULL for the
1190 * Transfers pixels data contained in the @image into the #GstBuffer.
1191 * Both image structures shall have the same format.
1193 * Return value: %TRUE on success
1196 gst_vaapi_image_get_buffer(
1197 GstVaapiImage *image,
1199 GstVaapiRectangle *rect
1202 GstVaapiImagePrivate *priv;
1203 GstVaapiImageRaw dst_image, src_image;
1206 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
1207 g_return_val_if_fail(image->priv->is_constructed, FALSE);
1208 g_return_val_if_fail(GST_IS_BUFFER(buffer), FALSE);
1212 if (!init_image_from_buffer(&dst_image, buffer))
1214 if (dst_image.format != priv->format)
1216 if (dst_image.width != priv->width || dst_image.height != priv->height)
1219 if (!_gst_vaapi_image_map(image, &src_image))
1222 success = copy_image(&dst_image, &src_image, rect);
1224 if (!_gst_vaapi_image_unmap(image))
1231 * gst_vaapi_image_get_raw:
1232 * @image: a #GstVaapiImage
1233 * @dst_image: a #GstVaapiImageRaw
1234 * @rect: a #GstVaapiRectangle expressing a region, or %NULL for the
1237 * Transfers pixels data contained in the @image into the #GstVaapiImageRaw.
1238 * Both image structures shall have the same format.
1240 * Return value: %TRUE on success
1243 gst_vaapi_image_get_raw(
1244 GstVaapiImage *image,
1245 GstVaapiImageRaw *dst_image,
1246 GstVaapiRectangle *rect
1249 GstVaapiImageRaw src_image;
1252 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
1253 g_return_val_if_fail(image->priv->is_constructed, FALSE);
1255 if (!_gst_vaapi_image_map(image, &src_image))
1258 success = copy_image(dst_image, &src_image, rect);
1260 if (!_gst_vaapi_image_unmap(image))
1267 * gst_vaapi_image_update_from_buffer:
1268 * @image: a #GstVaapiImage
1269 * @buffer: a #GstBuffer
1270 * @rect: a #GstVaapiRectangle expressing a region, or %NULL for the
1273 * Transfers pixels data contained in the #GstBuffer into the
1274 * @image. Both image structures shall have the same format.
1276 * Return value: %TRUE on success
1279 gst_vaapi_image_update_from_buffer(
1280 GstVaapiImage *image,
1282 GstVaapiRectangle *rect
1285 GstVaapiImagePrivate *priv;
1286 GstVaapiImageRaw dst_image, src_image;
1289 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
1290 g_return_val_if_fail(image->priv->is_constructed, FALSE);
1291 g_return_val_if_fail(GST_IS_BUFFER(buffer), FALSE);
1295 if (!init_image_from_buffer(&src_image, buffer))
1297 if (src_image.format != priv->format)
1299 if (src_image.width != priv->width || src_image.height > priv->height)
1302 if (!_gst_vaapi_image_map(image, &dst_image))
1305 success = copy_image(&dst_image, &src_image, rect);
1307 if (!_gst_vaapi_image_unmap(image))
1314 * gst_vaapi_image_update_from_raw:
1315 * @image: a #GstVaapiImage
1316 * @src_image: a #GstVaapiImageRaw
1317 * @buffer: a #GstBuffer
1318 * @rect: a #GstVaapiRectangle expressing a region, or %NULL for the
1321 * Transfers pixels data contained in the #GstVaapiImageRaw into the
1322 * @image. Both image structures shall have the same format.
1324 * Return value: %TRUE on success
1327 gst_vaapi_image_update_from_raw(
1328 GstVaapiImage *image,
1329 GstVaapiImageRaw *src_image,
1330 GstVaapiRectangle *rect
1333 GstVaapiImageRaw dst_image;
1336 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
1337 g_return_val_if_fail(image->priv->is_constructed, FALSE);
1339 if (!_gst_vaapi_image_map(image, &dst_image))
1342 success = copy_image(&dst_image, src_image, rect);
1344 if (!_gst_vaapi_image_unmap(image))
1352 const guint8 *y_src,
1353 guint32 y_src_stride,
1354 const guint8 *u_src,
1355 guint32 u_src_stride,
1356 const guint8 *v_src,
1357 guint32 v_src_stride,
1359 guint32 y_dest_stride,
1361 guint32 uv_dest_stride,
1366 guint32 row, column;
1369 memcpy_pic(y_dest, y_dest_stride, y_src, y_src_stride, width, height);
1370 uv_height = GST_ROUND_UP_2(height)/2;
1371 for (row = 0; row < uv_height; row++) {
1372 for (column = 0; column < width/2; column++) {
1373 uv_dest[column*2] = u_src[column];
1374 uv_dest[column*2+1] = v_src[column];
1376 u_src += u_src_stride;
1377 v_src += v_src_stride;
1378 uv_dest += uv_dest_stride;
1384 const guint8 *y_src,
1385 guint32 y_src_stride,
1386 const guint8 *uv_src,
1387 guint32 uv_src_stride,
1389 guint32 y_dest_stride,
1391 guint32 u_dest_stride,
1393 guint32 v_dest_stride,
1398 guint32 row, column;
1401 memcpy_pic(y_dest, y_dest_stride, y_src, y_src_stride, width, height);
1402 uv_height = GST_ROUND_UP_2(height)/2;
1403 for (row = 0; row < uv_height; row++) {
1404 for (column = 0; column < width/2; column++) {
1405 u_dest[column] = uv_src[column*2];
1406 v_dest[column] = uv_src[column*2+1];
1408 uv_src += uv_src_stride;
1409 u_dest += u_dest_stride;
1410 v_dest += v_dest_stride;
1416 const guint8 *yuv_src,
1417 guint32 yuv_src_stride,
1419 guint32 y_dest_stride,
1421 guint32 u_dest_stride,
1423 guint32 v_dest_stride,
1424 gboolean uv_interlaced,
1429 guint32 row, column;
1430 const guint8 *yuv_next_src;
1431 guint8 *y_next_dest;
1434 interval = uv_interlaced ? 2 : 1;
1435 for (row = 0; row < height/2; row++) {
1436 yuv_next_src = yuv_src + yuv_src_stride;
1437 y_next_dest = y_dest + y_dest_stride;
1438 for (column = 0; column < width/2; column++) {
1439 y_dest[column*2] = yuv_src[column*4];
1440 y_dest[column*2+1] = yuv_src[column*4+2];
1441 y_next_dest[column*2] = yuv_next_src[column*4];
1442 y_next_dest[column*2+1] = yuv_next_src[column*4+2];
1443 u_dest[column*interval] = ((yuv_src[column*4+1] + yuv_next_src[column*4+1])>>1);
1444 v_dest[column*interval] = ((yuv_src[column*4+3] + yuv_next_src[column*4+3])>>1);
1446 yuv_src = yuv_next_src + yuv_src_stride;
1447 y_dest = y_next_dest + y_dest_stride;
1448 u_dest += u_dest_stride;
1449 v_dest += v_dest_stride;
1454 for (column = 0; column < width/2; column++) {
1455 y_dest[column*2] = yuv_src[column*4];
1456 y_dest[column*2+1] = yuv_src[column*4+2];
1457 u_dest[column*interval] = yuv_src[column*4+1];
1458 v_dest[column*interval] = yuv_src[column*4+3];
1465 _image_convert_to_nv12(
1471 guint32 y_dest_stride,
1473 guint32 uv_dest_stride
1476 const guint8 *y_src, *u_src, *v_src, *uv_src;
1477 guint32 ystride, ustride, vstride, uv_stride;
1479 switch (src_format) {
1480 case GST_MAKE_FOURCC('N','V','1','2'): {
1482 ystride = GST_ROUND_UP_4(width);
1483 uv_src = src + ystride*GST_ROUND_UP_2(height);
1484 uv_stride = ystride;
1485 memcpy_pic(y_dest, y_dest_stride, y_src, ystride, width, height);
1486 memcpy_pic(uv_dest, uv_dest_stride, uv_src, uv_stride,
1487 width, GST_ROUND_UP_2(height)/2);
1491 case GST_MAKE_FOURCC('I','4','2','0'): {
1493 ystride = GST_ROUND_UP_4(width);
1494 u_src = src + ystride*GST_ROUND_UP_2(height);
1495 ustride = GST_ROUND_UP_8(ystride)/2;
1496 v_src = u_src + ustride*GST_ROUND_UP_2(height)/2;
1497 vstride = GST_ROUND_UP_8(ystride)/2;
1499 _yuv411_to_nv12(y_src, ystride, u_src, ustride, v_src, vstride,
1500 y_dest, y_dest_stride,
1501 uv_dest, uv_dest_stride,
1506 case GST_MAKE_FOURCC('Y','V','1','2'):{
1508 ystride = GST_ROUND_UP_4(width);
1509 v_src = src + ystride*GST_ROUND_UP_2(height);
1510 vstride = GST_ROUND_UP_8(ystride)/2;
1511 u_src = v_src + vstride*GST_ROUND_UP_2(height)/2;
1512 ustride = GST_ROUND_UP_8(ystride)/2;
1514 _yuv411_to_nv12(y_src, ystride, u_src, ustride, v_src, vstride,
1515 y_dest, y_dest_stride, uv_dest, uv_dest_stride,
1520 case GST_MAKE_FOURCC('Y', 'U', 'Y', '2'): {
1522 ystride = GST_ROUND_UP_2(width)*2;
1523 _yuy2_to_yuv411(y_src, ystride,
1524 y_dest, y_dest_stride,
1525 uv_dest, uv_dest_stride,
1526 uv_dest+1, uv_dest_stride,
1539 _image_convert_to_yuv411(
1545 guint32 y_dest_stride,
1547 guint32 u_dest_stride,
1549 guint32 v_dest_stride
1552 const guint8 *y_src, *u_src, *v_src, *uv_src;
1553 guint32 ystride, ustride, vstride, uv_stride;
1555 switch (src_format) {
1556 case GST_MAKE_FOURCC('N','V','1','2'): {
1558 ystride = GST_ROUND_UP_4(width);
1559 uv_src = src + ystride*GST_ROUND_UP_2(height);
1560 uv_stride = ystride;
1561 _nv12_to_yuv411(y_src, ystride, uv_src, uv_stride,
1562 y_dest, y_dest_stride,
1563 u_dest, u_dest_stride,
1564 v_dest, v_dest_stride,
1569 case GST_MAKE_FOURCC('I','4','2','0'):
1570 case GST_MAKE_FOURCC('Y','V','1','2'):{
1572 ystride = GST_ROUND_UP_4(width);
1573 if (GST_MAKE_FOURCC('I','4','2','0') == src_format) {
1574 u_src = src + ystride*GST_ROUND_UP_2(height);
1575 ustride = GST_ROUND_UP_8(ystride)/2;
1576 v_src = u_src + ustride*GST_ROUND_UP_2(height)/2;
1577 vstride = GST_ROUND_UP_8(ystride)/2;
1579 v_src = src + ystride*GST_ROUND_UP_2(height);
1580 vstride = GST_ROUND_UP_8(ystride)/2;
1581 u_src = v_src + vstride*GST_ROUND_UP_2(height)/2;
1582 ustride = GST_ROUND_UP_8(ystride)/2;
1585 memcpy_pic(y_dest, y_dest_stride, y_src, ystride, width, height);
1586 memcpy_pic(u_dest, u_dest_stride, u_src, ustride, width/2, GST_ROUND_UP_2(height)/2);
1587 memcpy_pic(v_dest, v_dest_stride, v_src, vstride, width/2, GST_ROUND_UP_2(height)/2);
1591 case GST_MAKE_FOURCC('Y', 'U', 'Y', '2'): {
1593 ystride = GST_ROUND_UP_2(width)*2;
1594 _yuy2_to_yuv411(y_src, ystride,
1595 y_dest, y_dest_stride,
1596 u_dest, u_dest_stride,
1597 v_dest, v_dest_stride,
1611 gst_vaapi_convert_buffer_to_image(
1612 GstVaapiImage *image,
1616 GstVaapiImagePrivate *priv;
1617 guint width, height;
1618 GstVaapiImageFormat image_format;
1619 gboolean success = TRUE;
1620 GstCaps *buffer_caps;
1621 GstStructure *structure;
1622 guint32 in_format = 0;
1625 gst_vaapi_image_get_size(image, &width, &height);
1626 image_format = gst_vaapi_image_get_format(image);
1628 /* get buffer format */
1629 buffer_caps = GST_BUFFER_CAPS(inbuf);
1632 structure = gst_caps_get_structure(buffer_caps, 0);
1635 if (!gst_structure_get_fourcc(structure, "format", &in_format))
1638 /* currently only support YUV convert */
1639 if ( (in_format != GST_MAKE_FOURCC('N','V','1','2')
1640 && in_format != GST_MAKE_FOURCC('Y','V','1','2')
1641 && in_format != GST_MAKE_FOURCC('I','4','2','0')
1642 && in_format != GST_MAKE_FOURCC('Y', 'U', 'Y', '2'))
1643 || (image_format != GST_VAAPI_IMAGE_NV12
1644 && image_format != GST_VAAPI_IMAGE_YV12
1645 && image_format != GST_VAAPI_IMAGE_I420)
1652 gst_vaapi_image_map(image);
1653 switch (image_format) {
1654 case GST_VAAPI_IMAGE_NV12: {
1655 g_assert(priv->image.num_planes == 2);
1656 success = _image_convert_to_nv12(GST_BUFFER_DATA(inbuf),
1657 width, height, in_format,
1658 priv->image_data+priv->image.offsets[0],
1659 priv->image.pitches[0],
1660 priv->image_data+priv->image.offsets[1],
1661 priv->image.pitches[1]);
1665 case GST_VAAPI_IMAGE_I420: {
1666 g_assert(priv->image.num_planes == 3);
1667 success = _image_convert_to_yuv411(GST_BUFFER_DATA(inbuf),
1668 width, height, in_format,
1669 priv->image_data+priv->image.offsets[0],
1670 priv->image.pitches[0],
1671 priv->image_data+priv->image.offsets[1],
1672 priv->image.pitches[1],
1673 priv->image_data+priv->image.offsets[2],
1674 priv->image.pitches[2]);
1677 case GST_VAAPI_IMAGE_YV12:{
1678 g_assert(priv->image.num_planes == 3);
1679 success = _image_convert_to_yuv411(GST_BUFFER_DATA(inbuf),
1680 width, height, in_format,
1681 priv->image_data+priv->image.offsets[0],
1682 priv->image.pitches[0],
1683 priv->image_data+priv->image.offsets[2],
1684 priv->image.pitches[2],
1685 priv->image_data+priv->image.offsets[1],
1686 priv->image.pitches[1]);
1694 gst_vaapi_image_unmap(image);