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 gboolean is_constructed;
42 GstVaapiImageFormat internal_format;
43 GstVaapiImageFormat format;
58 #define SWAP_UINT(a, b) do { \
65 gst_vaapi_image_destroy(GstVaapiImage *image)
67 GstVaapiImagePrivate * const priv = image->priv;
70 gst_vaapi_image_unmap(image);
72 if (priv->image.image_id != VA_INVALID_ID) {
73 GST_VAAPI_DISPLAY_LOCK(priv->display);
74 status = vaDestroyImage(
75 GST_VAAPI_DISPLAY_VADISPLAY(priv->display),
78 GST_VAAPI_DISPLAY_UNLOCK(priv->display);
79 if (!vaapi_check_status(status, "vaDestroyImage()"))
80 g_warning("failed to destroy image 0x%08x\n", priv->image.image_id);
81 priv->image.image_id = VA_INVALID_ID;
85 g_object_unref(priv->display);
91 _gst_vaapi_image_create(GstVaapiImage *image, GstVaapiImageFormat format)
93 GstVaapiImagePrivate * const priv = image->priv;
94 const VAImageFormat *va_format;
97 if (!gst_vaapi_display_has_image_format(priv->display, format))
100 va_format = gst_vaapi_image_format_get_va_format(format);
104 GST_VAAPI_DISPLAY_LOCK(priv->display);
105 status = vaCreateImage(
106 GST_VAAPI_DISPLAY_VADISPLAY(priv->display),
107 (VAImageFormat *)va_format,
112 GST_VAAPI_DISPLAY_UNLOCK(priv->display);
113 return (status == VA_STATUS_SUCCESS &&
114 priv->image.format.fourcc == va_format->fourcc);
118 gst_vaapi_image_create(GstVaapiImage *image)
120 GstVaapiImagePrivate * const priv = image->priv;
122 if (_gst_vaapi_image_create(image, priv->format)) {
123 priv->internal_format = priv->format;
127 switch (priv->format) {
128 case GST_VAAPI_IMAGE_I420:
129 priv->internal_format = GST_VAAPI_IMAGE_YV12;
131 case GST_VAAPI_IMAGE_YV12:
132 priv->internal_format = GST_VAAPI_IMAGE_I420;
135 priv->internal_format = 0;
138 if (!priv->internal_format)
140 if (!_gst_vaapi_image_create(image, priv->internal_format))
143 GST_DEBUG("image 0x%08x", priv->image.image_id);
148 gst_vaapi_image_finalize(GObject *object)
150 gst_vaapi_image_destroy(GST_VAAPI_IMAGE(object));
152 G_OBJECT_CLASS(gst_vaapi_image_parent_class)->finalize(object);
156 gst_vaapi_image_set_property(
163 GstVaapiImage * const image = GST_VAAPI_IMAGE(object);
164 GstVaapiImagePrivate * const priv = image->priv;
168 priv->display = g_object_ref(g_value_get_object(value));
171 priv->format = g_value_get_uint(value);
174 priv->width = g_value_get_uint(value);
177 priv->height = g_value_get_uint(value);
180 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
186 gst_vaapi_image_get_property(
193 GstVaapiImage * const image = GST_VAAPI_IMAGE(object);
197 g_value_set_pointer(value, gst_vaapi_image_get_display(image));
200 g_value_set_uint(value, gst_vaapi_image_get_id(image));
203 g_value_set_uint(value, gst_vaapi_image_get_format(image));
206 g_value_set_uint(value, gst_vaapi_image_get_width(image));
209 g_value_set_uint(value, gst_vaapi_image_get_height(image));
212 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
218 gst_vaapi_image_constructed(GObject *object)
220 GstVaapiImage * const image = GST_VAAPI_IMAGE(object);
221 GObjectClass *parent_class;
223 image->priv->is_constructed = gst_vaapi_image_create(image);
225 parent_class = G_OBJECT_CLASS(gst_vaapi_image_parent_class);
226 if (parent_class->constructed)
227 parent_class->constructed(object);
231 gst_vaapi_image_class_init(GstVaapiImageClass *klass)
233 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
235 g_type_class_add_private(klass, sizeof(GstVaapiImagePrivate));
237 object_class->finalize = gst_vaapi_image_finalize;
238 object_class->set_property = gst_vaapi_image_set_property;
239 object_class->get_property = gst_vaapi_image_get_property;
240 object_class->constructed = gst_vaapi_image_constructed;
242 g_object_class_install_property
245 g_param_spec_object("display",
247 "GStreamer Va display",
248 GST_VAAPI_TYPE_DISPLAY,
249 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
251 g_object_class_install_property
254 g_param_spec_uint("id",
257 0, G_MAXUINT32, VA_INVALID_ID,
260 g_object_class_install_property
263 g_param_spec_uint("width",
267 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
269 g_object_class_install_property
272 g_param_spec_uint("height",
276 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
278 g_object_class_install_property
281 g_param_spec_uint("format",
285 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
289 gst_vaapi_image_init(GstVaapiImage *image)
291 GstVaapiImagePrivate *priv = GST_VAAPI_IMAGE_GET_PRIVATE(image);
294 priv->display = NULL;
295 priv->image_data = NULL;
300 memset(&priv->image, 0, sizeof(priv->image));
301 priv->image.image_id = VA_INVALID_ID;
302 priv->image.buf = VA_INVALID_ID;
307 GstVaapiDisplay *display,
308 GstVaapiImageFormat format,
313 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
314 g_return_val_if_fail(width > 0, NULL);
315 g_return_val_if_fail(height > 0, NULL);
317 GST_DEBUG("format %" GST_FOURCC_FORMAT ", size %ux%u",
318 GST_FOURCC_ARGS(format), width, height);
320 return g_object_new(GST_VAAPI_TYPE_IMAGE,
329 gst_vaapi_image_get_id(GstVaapiImage *image)
331 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), VA_INVALID_ID);
332 g_return_val_if_fail(image->priv->is_constructed, VA_INVALID_ID);
334 return image->priv->image.image_id;
338 gst_vaapi_image_get_image(GstVaapiImage *image, VAImage *va_image)
340 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
341 g_return_val_if_fail(image->priv->is_constructed, FALSE);
346 *va_image = image->priv->image;
348 if (image->priv->format != image->priv->internal_format) {
349 if (!(image->priv->format == GST_VAAPI_IMAGE_I420 &&
350 image->priv->internal_format == GST_VAAPI_IMAGE_YV12) &&
351 !(image->priv->format == GST_VAAPI_IMAGE_YV12 &&
352 image->priv->internal_format == GST_VAAPI_IMAGE_I420))
354 SWAP_UINT(va_image->offsets[1], va_image->offsets[2]);
355 SWAP_UINT(va_image->pitches[1], va_image->pitches[2]);
361 gst_vaapi_image_get_display(GstVaapiImage *image)
363 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), NULL);
364 g_return_val_if_fail(image->priv->is_constructed, FALSE);
366 return image->priv->display;
370 gst_vaapi_image_get_format(GstVaapiImage *image)
372 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
373 g_return_val_if_fail(image->priv->is_constructed, FALSE);
375 return image->priv->format;
379 gst_vaapi_image_get_width(GstVaapiImage *image)
381 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
382 g_return_val_if_fail(image->priv->is_constructed, FALSE);
384 return image->priv->width;
388 gst_vaapi_image_get_height(GstVaapiImage *image)
390 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
391 g_return_val_if_fail(image->priv->is_constructed, FALSE);
393 return image->priv->height;
397 gst_vaapi_image_get_size(GstVaapiImage *image, guint *pwidth, guint *pheight)
399 g_return_if_fail(GST_VAAPI_IS_IMAGE(image));
400 g_return_if_fail(image->priv->is_constructed);
403 *pwidth = image->priv->width;
406 *pheight = image->priv->height;
410 gst_vaapi_image_is_linear(GstVaapiImage *image)
413 guint i, width, height, width2, height2, data_size;
415 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
416 g_return_val_if_fail(image->priv->is_constructed, FALSE);
418 if (!gst_vaapi_image_get_image(image, &va_image))
421 for (i = 1; i < va_image.num_planes; i++)
422 if (va_image.offsets[i] < va_image.offsets[i - 1])
425 width = image->priv->width;
426 height = image->priv->height;
427 width2 = (width + 1) / 2;
428 height2 = (height + 1) / 2;
430 switch (image->priv->internal_format) {
431 case GST_VAAPI_IMAGE_NV12:
432 case GST_VAAPI_IMAGE_YV12:
433 case GST_VAAPI_IMAGE_I420:
434 data_size = width * height + 2 * width2 * height2;
436 case GST_VAAPI_IMAGE_ARGB:
437 case GST_VAAPI_IMAGE_RGBA:
438 case GST_VAAPI_IMAGE_ABGR:
439 case GST_VAAPI_IMAGE_BGRA:
440 data_size = 4 * width * height;
443 g_error("FIXME: incomplete formats");
446 return va_image.data_size == data_size;
449 static inline gboolean
450 _gst_vaapi_image_is_mapped(GstVaapiImage *image)
452 return image->priv->image_data != NULL;
456 gst_vaapi_image_is_mapped(GstVaapiImage *image)
458 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
459 g_return_val_if_fail(image->priv->is_constructed, FALSE);
461 return _gst_vaapi_image_is_mapped(image);
465 gst_vaapi_image_map(GstVaapiImage *image)
470 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
471 g_return_val_if_fail(image->priv->is_constructed, FALSE);
473 if (_gst_vaapi_image_is_mapped(image))
476 GST_VAAPI_DISPLAY_LOCK(image->priv->display);
477 status = vaMapBuffer(
478 GST_VAAPI_DISPLAY_VADISPLAY(image->priv->display),
479 image->priv->image.buf,
482 GST_VAAPI_DISPLAY_UNLOCK(image->priv->display);
483 if (!vaapi_check_status(status, "vaMapBuffer()"))
486 image->priv->image_data = image_data;
491 gst_vaapi_image_unmap(GstVaapiImage *image)
495 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
496 g_return_val_if_fail(image->priv->is_constructed, FALSE);
498 if (!_gst_vaapi_image_is_mapped(image))
501 GST_VAAPI_DISPLAY_LOCK(image->priv->display);
502 status = vaUnmapBuffer(
503 GST_VAAPI_DISPLAY_VADISPLAY(image->priv->display),
504 image->priv->image.buf
506 GST_VAAPI_DISPLAY_UNLOCK(image->priv->display);
507 if (!vaapi_check_status(status, "vaUnmapBuffer()"))
510 image->priv->image_data = NULL;
515 gst_vaapi_image_get_plane_count(GstVaapiImage *image)
517 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
518 g_return_val_if_fail(image->priv->is_constructed, FALSE);
519 g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), 0);
521 return image->priv->image.num_planes;
525 gst_vaapi_image_get_plane(GstVaapiImage *image, guint plane)
527 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), NULL);
528 g_return_val_if_fail(image->priv->is_constructed, FALSE);
529 g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), NULL);
530 g_return_val_if_fail(plane < image->priv->image.num_planes, NULL);
532 return image->priv->image_data + image->priv->image.offsets[plane];
536 gst_vaapi_image_get_pitch(GstVaapiImage *image, guint plane)
538 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
539 g_return_val_if_fail(image->priv->is_constructed, FALSE);
540 g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), 0);
541 g_return_val_if_fail(plane < image->priv->image.num_planes, 0);
543 return image->priv->image.pitches[plane];
547 gst_vaapi_image_get_data_size(GstVaapiImage *image)
549 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
550 g_return_val_if_fail(image->priv->is_constructed, FALSE);
552 return image->priv->image.data_size;
556 gst_vaapi_image_update_from_buffer(GstVaapiImage *image, GstBuffer *buffer)
558 GstVaapiImagePrivate *priv;
559 GstStructure *structure;
561 GstVaapiImageFormat format;
563 guint offsets[3], pitches[3], widths[3], heights[3];
569 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
570 g_return_val_if_fail(image->priv->is_constructed, FALSE);
571 g_return_val_if_fail(GST_IS_BUFFER(buffer), FALSE);
574 data = GST_BUFFER_DATA(buffer);
575 data_size = GST_BUFFER_SIZE(buffer);
576 caps = GST_BUFFER_CAPS(buffer);
581 format = gst_vaapi_image_format_from_caps(caps);
582 if (format != priv->format)
585 swap_YUV = (priv->format != priv->internal_format &&
586 ((priv->format == GST_VAAPI_IMAGE_I420 &&
587 priv->internal_format == GST_VAAPI_IMAGE_YV12) ||
588 (priv->format == GST_VAAPI_IMAGE_YV12 &&
589 priv->internal_format == GST_VAAPI_IMAGE_I420)));
591 structure = gst_caps_get_structure(caps, 0);
592 gst_structure_get_int(structure, "width", &width);
593 gst_structure_get_int(structure, "height", &height);
594 if (width != priv->width || height != priv->height)
597 if (!gst_vaapi_image_map(image))
600 if (format == priv->internal_format && data_size == priv->image.data_size)
601 memcpy(priv->image_data, data, data_size);
603 /* XXX: copied from gst_video_format_get_row_stride() -- no NV12? */
604 const guint width2 = (width + 1) / 2;
605 const guint height2 = (height + 1) / 2;
608 case GST_VAAPI_IMAGE_NV12:
610 pitches[0] = GST_ROUND_UP_4(width);
613 offsets[1] = offsets[0] + height * pitches[0];
614 pitches[1] = pitches[0];
615 widths [1] = width2 * 2;
616 heights[1] = height2;
617 size2 = offsets[1] + height2 * pitches[1];
619 case GST_VAAPI_IMAGE_YV12:
620 case GST_VAAPI_IMAGE_I420:
622 pitches[0] = GST_ROUND_UP_4(width);
625 offsets[1] = offsets[0] + height * pitches[0];
626 pitches[1] = GST_ROUND_UP_4(GST_ROUND_UP_2(width) / 2);
628 heights[1] = height2;
629 offsets[2] = offsets[1] + height2 * pitches[1];
630 pitches[2] = pitches[1];
632 heights[2] = height2;
633 size2 = offsets[2] + height2 * pitches[2];
635 case GST_VAAPI_IMAGE_ARGB:
636 case GST_VAAPI_IMAGE_RGBA:
637 case GST_VAAPI_IMAGE_ABGR:
638 case GST_VAAPI_IMAGE_BGRA:
640 pitches[0] = width * 4;
641 widths [0] = width * 4;
643 size2 = offsets[0] + height * pitches[0];
646 g_error("could not compute row-stride for %" GST_FOURCC_FORMAT,
647 GST_FOURCC_ARGS(format));
650 if (size2 != data_size)
651 g_error("data_size mismatch %d / %u", size2, data_size);
653 guint offset = offsets[1];
654 guint stride = pitches[1];
655 guint width = widths [1];
656 guint height = heights[1];
657 offsets[1] = offsets[2];
658 pitches[1] = pitches[2];
659 widths [1] = widths [2];
660 heights[1] = heights[2];
666 for (i = 0; i < priv->image.num_planes; i++) {
667 guchar *src = data + offsets[i];
668 guchar *dst = priv->image_data + priv->image.offsets[i];
669 for (j = 0; j < heights[i]; j++) {
670 memcpy(dst, src, widths[i]);
672 dst += priv->image.pitches[i];
677 if (!gst_vaapi_image_unmap(image))