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;
59 gst_vaapi_image_destroy(GstVaapiImage *image)
61 GstVaapiImagePrivate * const priv = image->priv;
62 VADisplay dpy = gst_vaapi_display_get_display(priv->display);
65 gst_vaapi_image_unmap(image);
67 if (priv->image.image_id != VA_INVALID_ID) {
68 status = vaDestroyImage(dpy, priv->image.image_id);
69 if (!vaapi_check_status(status, "vaDestroyImage()"))
70 g_warning("failed to destroy image 0x%08x\n", priv->image.image_id);
71 priv->image.image_id = VA_INVALID_ID;
75 g_object_unref(priv->display);
81 _gst_vaapi_image_create(GstVaapiImage *image, GstVaapiImageFormat format)
83 GstVaapiImagePrivate * const priv = image->priv;
84 const VAImageFormat *va_format;
87 if (!gst_vaapi_display_has_image_format(priv->display, format))
90 va_format = gst_vaapi_image_format_get_va_format(format);
94 status = vaCreateImage(
95 gst_vaapi_display_get_display(priv->display),
96 (VAImageFormat *)va_format,
101 return (status == VA_STATUS_SUCCESS &&
102 priv->image.format.fourcc == va_format->fourcc);
106 gst_vaapi_image_create(GstVaapiImage *image)
108 GstVaapiImagePrivate * const priv = image->priv;
110 if (_gst_vaapi_image_create(image, priv->format)) {
111 priv->internal_format = priv->format;
115 switch (priv->format) {
116 case GST_VAAPI_IMAGE_I420:
117 priv->internal_format = GST_VAAPI_IMAGE_YV12;
119 case GST_VAAPI_IMAGE_YV12:
120 priv->internal_format = GST_VAAPI_IMAGE_I420;
123 priv->internal_format = 0;
126 if (!priv->internal_format)
128 if (!_gst_vaapi_image_create(image, priv->internal_format))
131 GST_DEBUG("image 0x%08x", priv->image.image_id);
136 gst_vaapi_image_finalize(GObject *object)
138 gst_vaapi_image_destroy(GST_VAAPI_IMAGE(object));
140 G_OBJECT_CLASS(gst_vaapi_image_parent_class)->finalize(object);
144 gst_vaapi_image_set_property(
151 GstVaapiImage * const image = GST_VAAPI_IMAGE(object);
152 GstVaapiImagePrivate * const priv = image->priv;
156 priv->display = g_object_ref(g_value_get_object(value));
159 priv->format = g_value_get_uint(value);
162 priv->width = g_value_get_uint(value);
165 priv->height = g_value_get_uint(value);
168 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
174 gst_vaapi_image_get_property(
181 GstVaapiImage * const image = GST_VAAPI_IMAGE(object);
185 g_value_set_pointer(value, gst_vaapi_image_get_display(image));
188 g_value_set_uint(value, gst_vaapi_image_get_id(image));
191 g_value_set_uint(value, gst_vaapi_image_get_format(image));
194 g_value_set_uint(value, gst_vaapi_image_get_width(image));
197 g_value_set_uint(value, gst_vaapi_image_get_height(image));
200 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
206 gst_vaapi_image_constructed(GObject *object)
208 GstVaapiImage * const image = GST_VAAPI_IMAGE(object);
209 GObjectClass *parent_class;
211 image->priv->is_constructed = gst_vaapi_image_create(image);
213 parent_class = G_OBJECT_CLASS(gst_vaapi_image_parent_class);
214 if (parent_class->constructed)
215 parent_class->constructed(object);
219 gst_vaapi_image_class_init(GstVaapiImageClass *klass)
221 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
223 g_type_class_add_private(klass, sizeof(GstVaapiImagePrivate));
225 object_class->finalize = gst_vaapi_image_finalize;
226 object_class->set_property = gst_vaapi_image_set_property;
227 object_class->get_property = gst_vaapi_image_get_property;
228 object_class->constructed = gst_vaapi_image_constructed;
230 g_object_class_install_property
233 g_param_spec_object("display",
235 "GStreamer Va display",
236 GST_VAAPI_TYPE_DISPLAY,
237 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
239 g_object_class_install_property
242 g_param_spec_uint("id",
245 0, G_MAXUINT32, VA_INVALID_ID,
248 g_object_class_install_property
251 g_param_spec_uint("width",
255 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
257 g_object_class_install_property
260 g_param_spec_uint("height",
264 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
266 g_object_class_install_property
269 g_param_spec_uint("format",
273 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
277 gst_vaapi_image_init(GstVaapiImage *image)
279 GstVaapiImagePrivate *priv = GST_VAAPI_IMAGE_GET_PRIVATE(image);
282 priv->display = NULL;
283 priv->image_data = NULL;
288 memset(&priv->image, 0, sizeof(priv->image));
289 priv->image.image_id = VA_INVALID_ID;
290 priv->image.buf = VA_INVALID_ID;
295 GstVaapiDisplay *display,
296 GstVaapiImageFormat format,
301 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
302 g_return_val_if_fail(width > 0, NULL);
303 g_return_val_if_fail(height > 0, NULL);
305 GST_DEBUG("format %" GST_FOURCC_FORMAT ", size %ux%u",
306 GST_FOURCC_ARGS(format), width, height);
308 return g_object_new(GST_VAAPI_TYPE_IMAGE,
317 gst_vaapi_image_get_id(GstVaapiImage *image)
319 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), VA_INVALID_ID);
320 g_return_val_if_fail(image->priv->is_constructed, FALSE);
322 return image->priv->image.image_id;
326 gst_vaapi_image_get_display(GstVaapiImage *image)
328 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), NULL);
329 g_return_val_if_fail(image->priv->is_constructed, FALSE);
331 return image->priv->display;
335 gst_vaapi_image_get_format(GstVaapiImage *image)
337 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
338 g_return_val_if_fail(image->priv->is_constructed, FALSE);
340 return image->priv->format;
344 gst_vaapi_image_get_width(GstVaapiImage *image)
346 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
347 g_return_val_if_fail(image->priv->is_constructed, FALSE);
349 return image->priv->width;
353 gst_vaapi_image_get_height(GstVaapiImage *image)
355 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
356 g_return_val_if_fail(image->priv->is_constructed, FALSE);
358 return image->priv->height;
362 gst_vaapi_image_get_size(GstVaapiImage *image, guint *pwidth, guint *pheight)
364 g_return_if_fail(GST_VAAPI_IS_IMAGE(image));
365 g_return_if_fail(image->priv->is_constructed);
368 *pwidth = image->priv->width;
371 *pheight = image->priv->height;
374 static inline gboolean
375 _gst_vaapi_image_is_mapped(GstVaapiImage *image)
377 return image->priv->image_data != NULL;
381 gst_vaapi_image_is_mapped(GstVaapiImage *image)
383 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
384 g_return_val_if_fail(image->priv->is_constructed, FALSE);
386 return _gst_vaapi_image_is_mapped(image);
390 gst_vaapi_image_map(GstVaapiImage *image)
395 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
396 g_return_val_if_fail(image->priv->is_constructed, FALSE);
398 if (_gst_vaapi_image_is_mapped(image))
401 status = vaMapBuffer(
402 gst_vaapi_display_get_display(image->priv->display),
403 image->priv->image.buf,
406 if (!vaapi_check_status(status, "vaMapBuffer()"))
409 image->priv->image_data = image_data;
414 gst_vaapi_image_unmap(GstVaapiImage *image)
418 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
419 g_return_val_if_fail(image->priv->is_constructed, FALSE);
421 if (!_gst_vaapi_image_is_mapped(image))
424 status = vaUnmapBuffer(
425 gst_vaapi_display_get_display(image->priv->display),
426 image->priv->image.buf
428 if (!vaapi_check_status(status, "vaUnmapBuffer()"))
431 image->priv->image_data = NULL;
436 gst_vaapi_image_get_plane_count(GstVaapiImage *image)
438 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
439 g_return_val_if_fail(image->priv->is_constructed, FALSE);
440 g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), 0);
442 return image->priv->image.num_planes;
446 gst_vaapi_image_get_plane(GstVaapiImage *image, guint plane)
448 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), NULL);
449 g_return_val_if_fail(image->priv->is_constructed, FALSE);
450 g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), NULL);
451 g_return_val_if_fail(plane < image->priv->image.num_planes, NULL);
453 return image->priv->image_data + image->priv->image.offsets[plane];
457 gst_vaapi_image_get_pitch(GstVaapiImage *image, guint plane)
459 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
460 g_return_val_if_fail(image->priv->is_constructed, FALSE);
461 g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), 0);
462 g_return_val_if_fail(plane < image->priv->image.num_planes, 0);
464 return image->priv->image.pitches[plane];
468 gst_vaapi_image_update_from_buffer(GstVaapiImage *image, GstBuffer *buffer)
470 GstVaapiImagePrivate *priv;
471 GstStructure *structure;
473 GstVaapiImageFormat format;
475 guint offsets[3], pitches[3], widths[3], heights[3];
481 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
482 g_return_val_if_fail(image->priv->is_constructed, FALSE);
483 g_return_val_if_fail(GST_IS_BUFFER(buffer), FALSE);
486 data = GST_BUFFER_DATA(buffer);
487 data_size = GST_BUFFER_SIZE(buffer);
488 caps = GST_BUFFER_CAPS(buffer);
493 format = gst_vaapi_image_format_from_caps(caps);
494 if (format != priv->format)
497 swap_YUV = (priv->format != priv->internal_format &&
498 ((priv->format == GST_VAAPI_IMAGE_I420 &&
499 priv->internal_format == GST_VAAPI_IMAGE_YV12) ||
500 (priv->format == GST_VAAPI_IMAGE_YV12 &&
501 priv->internal_format == GST_VAAPI_IMAGE_I420)));
503 structure = gst_caps_get_structure(caps, 0);
504 gst_structure_get_int(structure, "width", &width);
505 gst_structure_get_int(structure, "height", &height);
506 if (width != priv->width || height != priv->height)
509 if (!gst_vaapi_image_map(image))
512 if (format == priv->internal_format && data_size == priv->image.data_size)
513 memcpy(priv->image_data, data, data_size);
515 /* XXX: copied from gst_video_format_get_row_stride() -- no NV12? */
516 const guint width2 = (width + 1) / 2;
517 const guint height2 = (height + 1) / 2;
520 case GST_VAAPI_IMAGE_NV12:
522 pitches[0] = GST_ROUND_UP_4(width);
525 offsets[1] = offsets[0] + height * pitches[0];
526 pitches[1] = pitches[0];
527 widths [1] = width2 * 2;
528 heights[1] = height2;
529 size2 = offsets[1] + height2 * pitches[1];
531 case GST_VAAPI_IMAGE_YV12:
532 case GST_VAAPI_IMAGE_I420:
534 pitches[0] = GST_ROUND_UP_4(width);
537 offsets[1] = offsets[0] + height * pitches[0];
538 pitches[1] = GST_ROUND_UP_4(GST_ROUND_UP_2(width) / 2);
540 heights[1] = height2;
541 offsets[2] = offsets[1] + height2 * pitches[1];
542 pitches[2] = pitches[1];
544 heights[2] = height2;
545 size2 = offsets[2] + height2 * pitches[2];
547 case GST_VAAPI_IMAGE_ARGB:
548 case GST_VAAPI_IMAGE_RGBA:
549 case GST_VAAPI_IMAGE_ABGR:
550 case GST_VAAPI_IMAGE_BGRA:
552 pitches[0] = width * 4;
553 widths [0] = width * 4;
555 size2 = offsets[0] + height * pitches[0];
558 g_error("could not compute row-stride for %" GST_FOURCC_FORMAT,
559 GST_FOURCC_ARGS(format));
562 if (size2 != data_size)
563 g_error("data_size mismatch %d / %u", size2, data_size);
565 guint offset = offsets[1];
566 guint stride = pitches[1];
567 guint width = widths [1];
568 guint height = heights[1];
569 offsets[1] = offsets[2];
570 pitches[1] = pitches[2];
571 widths [1] = widths [2];
572 heights[1] = heights[2];
578 for (i = 0; i < priv->image.num_planes; i++) {
579 guchar *src = data + offsets[i];
580 guchar *dst = priv->image_data + priv->image.offsets[i];
581 for (j = 0; j < heights[i]; j++) {
582 memcpy(dst, src, widths[i]);
584 dst += priv->image.pitches[i];
589 if (!gst_vaapi_image_unmap(image))