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
23 #include "gstvaapiutils.h"
24 #include "gstvaapiimage.h"
25 #include <va/va_backend.h>
28 #include "gstvaapidebug.h"
30 G_DEFINE_TYPE(GstVaapiImage, gst_vaapi_image, G_TYPE_OBJECT);
32 #define GST_VAAPI_IMAGE_GET_PRIVATE(obj) \
33 (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
34 GST_VAAPI_TYPE_IMAGE, \
35 GstVaapiImagePrivate))
37 struct _GstVaapiImagePrivate {
38 GstVaapiDisplay *display;
39 VAImage internal_image;
42 GstVaapiImageFormat internal_format;
43 GstVaapiImageFormat format;
46 guint is_constructed : 1;
60 #define SWAP_UINT(a, b) do { \
67 _gst_vaapi_image_map(GstVaapiImage *image);
70 _gst_vaapi_image_unmap(GstVaapiImage *image);
73 gst_vaapi_image_destroy(GstVaapiImage *image)
75 GstVaapiImagePrivate * const priv = image->priv;
78 _gst_vaapi_image_unmap(image);
80 if (priv->internal_image.image_id != VA_INVALID_ID) {
81 GST_VAAPI_DISPLAY_LOCK(priv->display);
82 status = vaDestroyImage(
83 GST_VAAPI_DISPLAY_VADISPLAY(priv->display),
84 priv->internal_image.image_id
86 GST_VAAPI_DISPLAY_UNLOCK(priv->display);
87 if (!vaapi_check_status(status, "vaDestroyImage()"))
88 g_warning("failed to destroy image 0x%08x\n",
89 priv->internal_image.image_id);
90 priv->internal_image.image_id = VA_INVALID_ID;
94 g_object_unref(priv->display);
100 _gst_vaapi_image_create(GstVaapiImage *image, GstVaapiImageFormat format)
102 GstVaapiImagePrivate * const priv = image->priv;
103 const VAImageFormat *va_format;
106 if (!gst_vaapi_display_has_image_format(priv->display, format))
109 va_format = gst_vaapi_image_format_get_va_format(format);
113 GST_VAAPI_DISPLAY_LOCK(priv->display);
114 status = vaCreateImage(
115 GST_VAAPI_DISPLAY_VADISPLAY(priv->display),
116 (VAImageFormat *)va_format,
119 &priv->internal_image
121 GST_VAAPI_DISPLAY_UNLOCK(priv->display);
122 if (status != VA_STATUS_SUCCESS ||
123 priv->internal_image.format.fourcc != va_format->fourcc)
126 priv->internal_format = format;
131 _gst_vaapi_image_is_linear(GstVaapiImage *image)
133 GstVaapiImagePrivate * const priv = image->priv;
134 guint i, width, height, width2, height2, data_size;
136 for (i = 1; i < priv->image.num_planes; i++)
137 if (priv->image.offsets[i] < priv->image.offsets[i - 1])
141 height = priv->height;
142 width2 = (width + 1) / 2;
143 height2 = (height + 1) / 2;
145 switch (priv->internal_format) {
146 case GST_VAAPI_IMAGE_NV12:
147 case GST_VAAPI_IMAGE_YV12:
148 case GST_VAAPI_IMAGE_I420:
149 data_size = width * height + 2 * width2 * height2;
151 case GST_VAAPI_IMAGE_ARGB:
152 case GST_VAAPI_IMAGE_RGBA:
153 case GST_VAAPI_IMAGE_ABGR:
154 case GST_VAAPI_IMAGE_BGRA:
155 data_size = 4 * width * height;
158 g_error("FIXME: incomplete formats");
161 return priv->image.data_size == data_size;
165 gst_vaapi_image_create(GstVaapiImage *image)
167 GstVaapiImagePrivate * const priv = image->priv;
168 GstVaapiImageFormat format = priv->format;
169 const VAImageFormat *va_format;
171 if (!_gst_vaapi_image_create(image, format)) {
173 case GST_VAAPI_IMAGE_I420:
174 format = GST_VAAPI_IMAGE_YV12;
176 case GST_VAAPI_IMAGE_YV12:
177 format = GST_VAAPI_IMAGE_I420;
183 if (!format || !_gst_vaapi_image_create(image, format))
186 priv->image = priv->internal_image;
188 if (priv->format != priv->internal_format) {
189 switch (priv->format) {
190 case GST_VAAPI_IMAGE_YV12:
191 case GST_VAAPI_IMAGE_I420:
192 va_format = gst_vaapi_image_format_get_va_format(priv->format);
195 priv->image.format = *va_format;
196 SWAP_UINT(priv->image.offsets[1], priv->image.offsets[2]);
197 SWAP_UINT(priv->image.pitches[1], priv->image.pitches[2]);
204 GST_DEBUG("image 0x%08x", priv->image.image_id);
205 priv->is_linear = _gst_vaapi_image_is_linear(image);
210 gst_vaapi_image_finalize(GObject *object)
212 gst_vaapi_image_destroy(GST_VAAPI_IMAGE(object));
214 G_OBJECT_CLASS(gst_vaapi_image_parent_class)->finalize(object);
218 gst_vaapi_image_set_property(
225 GstVaapiImage * const image = GST_VAAPI_IMAGE(object);
226 GstVaapiImagePrivate * const priv = image->priv;
230 priv->display = g_object_ref(g_value_get_object(value));
233 priv->format = g_value_get_uint(value);
236 priv->width = g_value_get_uint(value);
239 priv->height = g_value_get_uint(value);
242 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
248 gst_vaapi_image_get_property(
255 GstVaapiImage * const image = GST_VAAPI_IMAGE(object);
259 g_value_set_pointer(value, gst_vaapi_image_get_display(image));
262 g_value_set_uint(value, gst_vaapi_image_get_id(image));
265 g_value_set_uint(value, gst_vaapi_image_get_format(image));
268 g_value_set_uint(value, gst_vaapi_image_get_width(image));
271 g_value_set_uint(value, gst_vaapi_image_get_height(image));
274 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
280 gst_vaapi_image_constructed(GObject *object)
282 GstVaapiImage * const image = GST_VAAPI_IMAGE(object);
283 GObjectClass *parent_class;
285 image->priv->is_constructed = gst_vaapi_image_create(image);
287 parent_class = G_OBJECT_CLASS(gst_vaapi_image_parent_class);
288 if (parent_class->constructed)
289 parent_class->constructed(object);
293 gst_vaapi_image_class_init(GstVaapiImageClass *klass)
295 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
297 g_type_class_add_private(klass, sizeof(GstVaapiImagePrivate));
299 object_class->finalize = gst_vaapi_image_finalize;
300 object_class->set_property = gst_vaapi_image_set_property;
301 object_class->get_property = gst_vaapi_image_get_property;
302 object_class->constructed = gst_vaapi_image_constructed;
304 g_object_class_install_property
307 g_param_spec_object("display",
309 "GStreamer Va display",
310 GST_VAAPI_TYPE_DISPLAY,
311 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
313 g_object_class_install_property
316 g_param_spec_uint("id",
319 0, G_MAXUINT32, VA_INVALID_ID,
322 g_object_class_install_property
325 g_param_spec_uint("width",
329 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
331 g_object_class_install_property
334 g_param_spec_uint("height",
338 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
340 g_object_class_install_property
343 g_param_spec_uint("format",
347 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
351 gst_vaapi_image_init(GstVaapiImage *image)
353 GstVaapiImagePrivate *priv = GST_VAAPI_IMAGE_GET_PRIVATE(image);
356 priv->display = NULL;
357 priv->image_data = NULL;
360 priv->internal_format = 0;
362 priv->is_constructed = FALSE;
363 priv->is_linear = FALSE;
365 memset(&priv->internal_image, 0, sizeof(priv->internal_image));
366 priv->internal_image.image_id = VA_INVALID_ID;
367 priv->internal_image.buf = VA_INVALID_ID;
369 memset(&priv->image, 0, sizeof(priv->image));
370 priv->image.image_id = VA_INVALID_ID;
371 priv->image.buf = VA_INVALID_ID;
376 GstVaapiDisplay *display,
377 GstVaapiImageFormat format,
382 GstVaapiImage *image;
384 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
385 g_return_val_if_fail(width > 0, NULL);
386 g_return_val_if_fail(height > 0, NULL);
388 GST_DEBUG("format %" GST_FOURCC_FORMAT ", size %ux%u",
389 GST_FOURCC_ARGS(format), width, height);
391 image = g_object_new(
392 GST_VAAPI_TYPE_IMAGE,
402 if (!image->priv->is_constructed) {
403 g_object_unref(image);
410 gst_vaapi_image_get_id(GstVaapiImage *image)
412 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), VA_INVALID_ID);
413 g_return_val_if_fail(image->priv->is_constructed, VA_INVALID_ID);
415 return image->priv->image.image_id;
419 gst_vaapi_image_get_image(GstVaapiImage *image, VAImage *va_image)
421 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
422 g_return_val_if_fail(image->priv->is_constructed, FALSE);
425 *va_image = image->priv->image;
431 gst_vaapi_image_get_display(GstVaapiImage *image)
433 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), NULL);
434 g_return_val_if_fail(image->priv->is_constructed, FALSE);
436 return image->priv->display;
440 gst_vaapi_image_get_format(GstVaapiImage *image)
442 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
443 g_return_val_if_fail(image->priv->is_constructed, FALSE);
445 return image->priv->format;
449 gst_vaapi_image_get_width(GstVaapiImage *image)
451 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
452 g_return_val_if_fail(image->priv->is_constructed, FALSE);
454 return image->priv->width;
458 gst_vaapi_image_get_height(GstVaapiImage *image)
460 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
461 g_return_val_if_fail(image->priv->is_constructed, FALSE);
463 return image->priv->height;
467 gst_vaapi_image_get_size(GstVaapiImage *image, guint *pwidth, guint *pheight)
469 g_return_if_fail(GST_VAAPI_IS_IMAGE(image));
470 g_return_if_fail(image->priv->is_constructed);
473 *pwidth = image->priv->width;
476 *pheight = image->priv->height;
480 gst_vaapi_image_is_linear(GstVaapiImage *image)
482 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
483 g_return_val_if_fail(image->priv->is_constructed, FALSE);
485 return image->priv->is_linear;
488 static inline gboolean
489 _gst_vaapi_image_is_mapped(GstVaapiImage *image)
491 return image->priv->image_data != NULL;
495 gst_vaapi_image_is_mapped(GstVaapiImage *image)
497 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
498 g_return_val_if_fail(image->priv->is_constructed, FALSE);
500 return _gst_vaapi_image_is_mapped(image);
504 gst_vaapi_image_map(GstVaapiImage *image)
506 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
507 g_return_val_if_fail(image->priv->is_constructed, FALSE);
509 return _gst_vaapi_image_map(image);
513 _gst_vaapi_image_map(GstVaapiImage *image)
518 if (_gst_vaapi_image_is_mapped(image))
521 GST_VAAPI_DISPLAY_LOCK(image->priv->display);
522 status = vaMapBuffer(
523 GST_VAAPI_DISPLAY_VADISPLAY(image->priv->display),
524 image->priv->image.buf,
527 GST_VAAPI_DISPLAY_UNLOCK(image->priv->display);
528 if (!vaapi_check_status(status, "vaMapBuffer()"))
531 image->priv->image_data = image_data;
536 gst_vaapi_image_unmap(GstVaapiImage *image)
538 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
539 g_return_val_if_fail(image->priv->is_constructed, FALSE);
541 return _gst_vaapi_image_unmap(image);
545 _gst_vaapi_image_unmap(GstVaapiImage *image)
549 if (!_gst_vaapi_image_is_mapped(image))
552 GST_VAAPI_DISPLAY_LOCK(image->priv->display);
553 status = vaUnmapBuffer(
554 GST_VAAPI_DISPLAY_VADISPLAY(image->priv->display),
555 image->priv->image.buf
557 GST_VAAPI_DISPLAY_UNLOCK(image->priv->display);
558 if (!vaapi_check_status(status, "vaUnmapBuffer()"))
561 image->priv->image_data = NULL;
566 gst_vaapi_image_get_plane_count(GstVaapiImage *image)
568 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
569 g_return_val_if_fail(image->priv->is_constructed, FALSE);
570 g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), 0);
572 return image->priv->image.num_planes;
576 gst_vaapi_image_get_plane(GstVaapiImage *image, guint plane)
578 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), NULL);
579 g_return_val_if_fail(image->priv->is_constructed, FALSE);
580 g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), NULL);
581 g_return_val_if_fail(plane < image->priv->image.num_planes, NULL);
583 return image->priv->image_data + image->priv->image.offsets[plane];
587 gst_vaapi_image_get_pitch(GstVaapiImage *image, guint plane)
589 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
590 g_return_val_if_fail(image->priv->is_constructed, FALSE);
591 g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), 0);
592 g_return_val_if_fail(plane < image->priv->image.num_planes, 0);
594 return image->priv->image.pitches[plane];
598 gst_vaapi_image_get_data_size(GstVaapiImage *image)
600 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
601 g_return_val_if_fail(image->priv->is_constructed, FALSE);
603 return image->priv->image.data_size;
607 gst_vaapi_image_update_from_buffer(GstVaapiImage *image, GstBuffer *buffer)
609 GstVaapiImagePrivate *priv;
610 GstStructure *structure;
612 GstVaapiImageFormat format;
614 guint offsets[3], pitches[3], widths[3], heights[3];
619 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
620 g_return_val_if_fail(image->priv->is_constructed, FALSE);
621 g_return_val_if_fail(GST_IS_BUFFER(buffer), FALSE);
624 data = GST_BUFFER_DATA(buffer);
625 data_size = GST_BUFFER_SIZE(buffer);
626 caps = GST_BUFFER_CAPS(buffer);
631 format = gst_vaapi_image_format_from_caps(caps);
632 if (format != priv->format)
635 structure = gst_caps_get_structure(caps, 0);
636 gst_structure_get_int(structure, "width", &width);
637 gst_structure_get_int(structure, "height", &height);
638 if (width != priv->width || height != priv->height)
641 if (!gst_vaapi_image_map(image))
644 if (priv->is_linear && data_size == priv->image.data_size)
645 memcpy(priv->image_data, data, data_size);
647 /* XXX: copied from gst_video_format_get_row_stride() -- no NV12? */
648 const guint width2 = (width + 1) / 2;
649 const guint height2 = (height + 1) / 2;
652 case GST_VAAPI_IMAGE_NV12:
654 pitches[0] = GST_ROUND_UP_4(width);
657 offsets[1] = offsets[0] + height * pitches[0];
658 pitches[1] = pitches[0];
659 widths [1] = width2 * 2;
660 heights[1] = height2;
661 size2 = offsets[1] + height2 * pitches[1];
663 case GST_VAAPI_IMAGE_YV12:
664 case GST_VAAPI_IMAGE_I420:
666 pitches[0] = GST_ROUND_UP_4(width);
669 offsets[1] = offsets[0] + height * pitches[0];
670 pitches[1] = GST_ROUND_UP_4(GST_ROUND_UP_2(width) / 2);
672 heights[1] = height2;
673 offsets[2] = offsets[1] + height2 * pitches[1];
674 pitches[2] = pitches[1];
676 heights[2] = height2;
677 size2 = offsets[2] + height2 * pitches[2];
679 case GST_VAAPI_IMAGE_ARGB:
680 case GST_VAAPI_IMAGE_RGBA:
681 case GST_VAAPI_IMAGE_ABGR:
682 case GST_VAAPI_IMAGE_BGRA:
684 pitches[0] = width * 4;
685 widths [0] = width * 4;
687 size2 = offsets[0] + height * pitches[0];
690 g_error("could not compute row-stride for %" GST_FOURCC_FORMAT,
691 GST_FOURCC_ARGS(format));
694 if (size2 != data_size)
695 g_error("data_size mismatch %d / %u", size2, data_size);
696 for (i = 0; i < priv->image.num_planes; i++) {
697 guchar *src = data + offsets[i];
698 guchar *dst = priv->image_data + priv->image.offsets[i];
699 for (j = 0; j < heights[i]; j++) {
700 memcpy(dst, src, widths[i]);
702 dst += priv->image.pitches[i];
707 if (!gst_vaapi_image_unmap(image))