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 "vaapi_utils.h"
24 #include "gstvaapiimage.h"
25 #include <va/va_backend.h>
28 #include "vaapi_debug.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 format;
58 gst_vaapi_image_destroy(GstVaapiImage *image)
60 GstVaapiImagePrivate * const priv = image->priv;
61 VADisplay dpy = gst_vaapi_display_get_display(priv->display);
64 gst_vaapi_image_unmap(image);
66 if (priv->image.image_id != VA_INVALID_ID) {
67 status = vaDestroyImage(dpy, priv->image.image_id);
68 if (!vaapi_check_status(status, "vaDestroyImage()"))
69 g_warning("failed to destroy image 0x%08x\n", priv->image.image_id);
70 priv->image.image_id = VA_INVALID_ID;
74 g_object_unref(priv->display);
80 gst_vaapi_image_create(GstVaapiImage *image)
82 GstVaapiImagePrivate * const priv = image->priv;
83 const VAImageFormat *format;
86 if (!gst_vaapi_display_has_image_format(priv->display, priv->format))
89 format = gst_vaapi_image_format_get_va_format(priv->format);
91 g_return_val_if_fail(format, FALSE);
93 status = vaCreateImage(
94 gst_vaapi_display_get_display(priv->display),
95 (VAImageFormat *)format,
100 if (!vaapi_check_status(status, "vaCreateImage()"))
107 gst_vaapi_image_finalize(GObject *object)
109 gst_vaapi_image_destroy(GST_VAAPI_IMAGE(object));
111 G_OBJECT_CLASS(gst_vaapi_image_parent_class)->finalize(object);
115 gst_vaapi_image_set_property(
122 GstVaapiImage * const image = GST_VAAPI_IMAGE(object);
123 GstVaapiImagePrivate * const priv = image->priv;
127 priv->display = g_object_ref(g_value_get_object(value));
130 priv->format = g_value_get_uint(value);
133 priv->width = g_value_get_uint(value);
136 priv->height = g_value_get_uint(value);
139 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
145 gst_vaapi_image_get_property(
152 GstVaapiImage * const image = GST_VAAPI_IMAGE(object);
156 g_value_set_pointer(value, gst_vaapi_image_get_display(image));
159 g_value_set_uint(value, gst_vaapi_image_get_id(image));
162 g_value_set_uint(value, gst_vaapi_image_get_format(image));
165 g_value_set_uint(value, gst_vaapi_image_get_width(image));
168 g_value_set_uint(value, gst_vaapi_image_get_height(image));
171 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
177 gst_vaapi_image_constructed(GObject *object)
179 GstVaapiImage * const image = GST_VAAPI_IMAGE(object);
180 GObjectClass *parent_class;
182 image->priv->is_constructed = gst_vaapi_image_create(image);
184 parent_class = G_OBJECT_CLASS(gst_vaapi_image_parent_class);
185 if (parent_class->constructed)
186 parent_class->constructed(object);
190 gst_vaapi_image_class_init(GstVaapiImageClass *klass)
192 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
194 g_type_class_add_private(klass, sizeof(GstVaapiImagePrivate));
196 object_class->finalize = gst_vaapi_image_finalize;
197 object_class->set_property = gst_vaapi_image_set_property;
198 object_class->get_property = gst_vaapi_image_get_property;
199 object_class->constructed = gst_vaapi_image_constructed;
201 g_object_class_install_property
204 g_param_spec_object("display",
206 "GStreamer Va display",
207 GST_VAAPI_TYPE_DISPLAY,
208 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
210 g_object_class_install_property
213 g_param_spec_uint("id",
216 0, G_MAXUINT32, VA_INVALID_ID,
219 g_object_class_install_property
222 g_param_spec_uint("width",
226 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
228 g_object_class_install_property
231 g_param_spec_uint("height",
235 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
237 g_object_class_install_property
240 g_param_spec_uint("format",
244 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
248 gst_vaapi_image_init(GstVaapiImage *image)
250 GstVaapiImagePrivate *priv = GST_VAAPI_IMAGE_GET_PRIVATE(image);
253 priv->display = NULL;
254 priv->image_data = NULL;
259 memset(&priv->image, 0, sizeof(priv->image));
260 priv->image.image_id = VA_INVALID_ID;
261 priv->image.buf = VA_INVALID_ID;
266 GstVaapiDisplay *display,
267 GstVaapiImageFormat format,
272 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
273 g_return_val_if_fail(width > 0, NULL);
274 g_return_val_if_fail(height > 0, NULL);
276 GST_DEBUG("format %" GST_FOURCC_FORMAT ", size %ux%u",
277 GST_FOURCC_ARGS(format), width, height);
279 return g_object_new(GST_VAAPI_TYPE_IMAGE,
288 gst_vaapi_image_get_id(GstVaapiImage *image)
290 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), VA_INVALID_ID);
291 g_return_val_if_fail(image->priv->is_constructed, FALSE);
293 return image->priv->image.image_id;
297 gst_vaapi_image_get_display(GstVaapiImage *image)
299 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), NULL);
300 g_return_val_if_fail(image->priv->is_constructed, FALSE);
302 return image->priv->display;
306 gst_vaapi_image_get_format(GstVaapiImage *image)
308 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
309 g_return_val_if_fail(image->priv->is_constructed, FALSE);
311 return image->priv->format;
315 gst_vaapi_image_get_width(GstVaapiImage *image)
317 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
318 g_return_val_if_fail(image->priv->is_constructed, FALSE);
320 return image->priv->width;
324 gst_vaapi_image_get_height(GstVaapiImage *image)
326 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
327 g_return_val_if_fail(image->priv->is_constructed, FALSE);
329 return image->priv->height;
333 gst_vaapi_image_get_size(GstVaapiImage *image, guint *pwidth, guint *pheight)
335 g_return_if_fail(GST_VAAPI_IS_IMAGE(image));
336 g_return_if_fail(image->priv->is_constructed);
339 *pwidth = image->priv->width;
342 *pheight = image->priv->height;
345 static inline gboolean
346 _gst_vaapi_image_is_mapped(GstVaapiImage *image)
348 return image->priv->image_data != NULL;
352 gst_vaapi_image_is_mapped(GstVaapiImage *image)
354 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
355 g_return_val_if_fail(image->priv->is_constructed, FALSE);
357 return _gst_vaapi_image_is_mapped(image);
361 gst_vaapi_image_map(GstVaapiImage *image)
366 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
367 g_return_val_if_fail(image->priv->is_constructed, FALSE);
369 if (_gst_vaapi_image_is_mapped(image))
372 status = vaMapBuffer(
373 gst_vaapi_display_get_display(image->priv->display),
374 image->priv->image.buf,
377 if (!vaapi_check_status(status, "vaMapBuffer()"))
380 image->priv->image_data = image_data;
385 gst_vaapi_image_unmap(GstVaapiImage *image)
389 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
390 g_return_val_if_fail(image->priv->is_constructed, FALSE);
392 if (!_gst_vaapi_image_is_mapped(image))
395 status = vaUnmapBuffer(
396 gst_vaapi_display_get_display(image->priv->display),
397 image->priv->image.buf
399 if (!vaapi_check_status(status, "vaUnmapBuffer()"))
402 image->priv->image_data = NULL;
407 gst_vaapi_image_get_plane_count(GstVaapiImage *image)
409 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
410 g_return_val_if_fail(image->priv->is_constructed, FALSE);
411 g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), 0);
413 return image->priv->image.num_planes;
417 gst_vaapi_image_get_plane(GstVaapiImage *image, guint plane)
419 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), NULL);
420 g_return_val_if_fail(image->priv->is_constructed, FALSE);
421 g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), NULL);
422 g_return_val_if_fail(plane < image->priv->image.num_planes, NULL);
424 return image->priv->image_data + image->priv->image.offsets[plane];
428 gst_vaapi_image_get_pitch(GstVaapiImage *image, guint plane)
430 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
431 g_return_val_if_fail(image->priv->is_constructed, FALSE);
432 g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), 0);
433 g_return_val_if_fail(plane < image->priv->image.num_planes, 0);
435 return image->priv->image.pitches[plane];
439 gst_vaapi_image_update_from_buffer(GstVaapiImage *image, GstBuffer *buffer)
441 GstVaapiImagePrivate *priv;
442 GstStructure *structure;
444 GstVaapiImageFormat format;
446 guint offsets[3], pitches[3], widths[3], heights[3];
452 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
453 g_return_val_if_fail(image->priv->is_constructed, FALSE);
454 g_return_val_if_fail(GST_IS_BUFFER(buffer), FALSE);
457 data = GST_BUFFER_DATA(buffer);
458 data_size = GST_BUFFER_SIZE(buffer);
459 caps = GST_BUFFER_CAPS(buffer);
464 format = gst_vaapi_image_format_from_caps(caps);
465 swap_YUV = ((format == GST_VAAPI_IMAGE_I420 &&
466 priv->format == GST_VAAPI_IMAGE_YV12) ||
467 (format == GST_VAAPI_IMAGE_YV12 &&
468 priv->format == GST_VAAPI_IMAGE_I420));
469 if (format != priv->format && !swap_YUV)
472 structure = gst_caps_get_structure(caps, 0);
473 gst_structure_get_int(structure, "width", &width);
474 gst_structure_get_int(structure, "height", &height);
475 if (width != priv->width || height != priv->height)
478 if (!gst_vaapi_image_map(image))
481 if (format == priv->format && data_size == priv->image.data_size)
482 memcpy(priv->image_data, data, data_size);
484 /* XXX: copied from gst_video_format_get_row_stride() -- no NV12? */
485 const guint width2 = (width + 1) / 2;
486 const guint height2 = (height + 1) / 2;
489 case GST_VAAPI_IMAGE_NV12:
491 pitches[0] = GST_ROUND_UP_4(width);
494 offsets[1] = offsets[0] + height * pitches[0];
495 pitches[1] = pitches[0];
496 widths [1] = width2 * 2;
497 heights[1] = height2;
498 size2 = offsets[1] + height2 * pitches[1];
500 case GST_VAAPI_IMAGE_YV12:
501 case GST_VAAPI_IMAGE_I420:
503 pitches[0] = GST_ROUND_UP_4(width);
506 offsets[1] = offsets[0] + height * pitches[0];
507 pitches[1] = GST_ROUND_UP_4(GST_ROUND_UP_2(width) / 2);
509 heights[1] = height2;
510 offsets[2] = offsets[1] + height2 * pitches[1];
511 pitches[2] = pitches[1];
513 heights[2] = height2;
514 size2 = offsets[2] + height2 * pitches[2];
516 case GST_VAAPI_IMAGE_ARGB:
517 case GST_VAAPI_IMAGE_RGBA:
518 case GST_VAAPI_IMAGE_ABGR:
519 case GST_VAAPI_IMAGE_BGRA:
521 pitches[0] = width * 4;
522 widths [0] = width * 4;
524 size2 = offsets[0] + height * pitches[0];
527 g_error("could not compute row-stride for %" GST_FOURCC_FORMAT,
528 GST_FOURCC_ARGS(format));
531 if (size2 != data_size)
532 g_error("data_size mismatch %d / %u", size2, data_size);
534 guint offset = offsets[1];
535 guint stride = pitches[1];
536 guint width = widths [1];
537 guint height = heights[1];
538 offsets[1] = offsets[2];
539 pitches[1] = pitches[2];
540 widths [1] = widths [2];
541 heights[1] = heights[2];
547 for (i = 0; i < priv->image.num_planes; i++) {
548 guchar *src = data + offsets[i];
549 guchar *dst = priv->image_data + priv->image.offsets[i];
550 for (j = 0; j < heights[i]; j++) {
551 memcpy(dst, src, widths[i]);
553 dst += priv->image.pitches[i];
558 if (!gst_vaapi_image_unmap(image))