2 * gstvaapisurface.c - VA surface 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
22 * SECTION:gst-vaapi-surface
27 #include "gstvaapiutils.h"
28 #include "gstvaapisurface.h"
29 #include "gstvaapiimage.h"
30 #include <va/va_backend.h>
33 #include "gstvaapidebug.h"
35 G_DEFINE_TYPE(GstVaapiSurface, gst_vaapi_surface, G_TYPE_OBJECT);
37 #define GST_VAAPI_SURFACE_GET_PRIVATE(obj) \
38 (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
39 GST_VAAPI_TYPE_SURFACE, \
40 GstVaapiSurfacePrivate))
42 struct _GstVaapiSurfacePrivate {
43 GstVaapiDisplay *display;
44 VASurfaceID surface_id;
47 GstVaapiChromaType chroma_type;
48 GPtrArray *subpictures;
62 destroy_subpicture_cb(gpointer subpicture, gpointer user_data)
64 g_object_unref(subpicture);
68 gst_vaapi_surface_destroy(GstVaapiSurface *surface)
70 GstVaapiSurfacePrivate * const priv = surface->priv;
73 GST_DEBUG("surface 0x%08x", priv->surface_id);
75 if (priv->surface_id != VA_INVALID_SURFACE) {
76 GST_VAAPI_DISPLAY_LOCK(priv->display);
77 status = vaDestroySurfaces(
78 GST_VAAPI_DISPLAY_VADISPLAY(priv->display),
81 GST_VAAPI_DISPLAY_UNLOCK(priv->display);
82 if (!vaapi_check_status(status, "vaDestroySurfaces()"))
83 g_warning("failed to destroy surface 0x%08x\n", priv->surface_id);
84 priv->surface_id = VA_INVALID_SURFACE;
87 if (priv->subpictures) {
88 g_ptr_array_foreach(priv->subpictures, destroy_subpicture_cb, NULL);
89 g_ptr_array_free(priv->subpictures, TRUE);
90 priv->subpictures = NULL;
94 g_object_unref(priv->display);
100 gst_vaapi_surface_create(GstVaapiSurface *surface)
102 GstVaapiSurfacePrivate * const priv = surface->priv;
103 VASurfaceID surface_id;
107 switch (priv->chroma_type) {
108 case GST_VAAPI_CHROMA_TYPE_YUV420:
109 format = VA_RT_FORMAT_YUV420;
111 case GST_VAAPI_CHROMA_TYPE_YUV422:
112 format = VA_RT_FORMAT_YUV422;
114 case GST_VAAPI_CHROMA_TYPE_YUV444:
115 format = VA_RT_FORMAT_YUV444;
118 GST_DEBUG("unsupported chroma-type %u\n", priv->chroma_type);
122 GST_VAAPI_DISPLAY_LOCK(priv->display);
123 status = vaCreateSurfaces(
124 GST_VAAPI_DISPLAY_VADISPLAY(priv->display),
130 GST_VAAPI_DISPLAY_UNLOCK(priv->display);
131 if (!vaapi_check_status(status, "vaCreateSurfaces()"))
134 GST_DEBUG("surface 0x%08x", surface_id);
135 priv->surface_id = surface_id;
140 gst_vaapi_surface_finalize(GObject *object)
142 gst_vaapi_surface_destroy(GST_VAAPI_SURFACE(object));
144 G_OBJECT_CLASS(gst_vaapi_surface_parent_class)->finalize(object);
148 gst_vaapi_surface_set_property(
155 GstVaapiSurface * const surface = GST_VAAPI_SURFACE(object);
156 GstVaapiSurfacePrivate * const priv = surface->priv;
160 priv->display = g_object_ref(g_value_get_object(value));
163 priv->width = g_value_get_uint(value);
166 priv->height = g_value_get_uint(value);
168 case PROP_CHROMA_TYPE:
169 priv->chroma_type = g_value_get_uint(value);
172 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
178 gst_vaapi_surface_get_property(
185 GstVaapiSurface * const surface = GST_VAAPI_SURFACE(object);
189 g_value_set_object(value, gst_vaapi_surface_get_display(surface));
191 case PROP_SURFACE_ID:
192 g_value_set_uint(value, gst_vaapi_surface_get_id(surface));
195 g_value_set_uint(value, gst_vaapi_surface_get_width(surface));
198 g_value_set_uint(value, gst_vaapi_surface_get_height(surface));
200 case PROP_CHROMA_TYPE:
201 g_value_set_uint(value, gst_vaapi_surface_get_chroma_type(surface));
204 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
210 gst_vaapi_surface_constructed(GObject *object)
212 GstVaapiSurface * const surface = GST_VAAPI_SURFACE(object);
213 GObjectClass *parent_class;
215 gst_vaapi_surface_create(surface);
217 parent_class = G_OBJECT_CLASS(gst_vaapi_surface_parent_class);
218 if (parent_class->constructed)
219 parent_class->constructed(object);
223 gst_vaapi_surface_class_init(GstVaapiSurfaceClass *klass)
225 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
227 g_type_class_add_private(klass, sizeof(GstVaapiSurfacePrivate));
229 object_class->finalize = gst_vaapi_surface_finalize;
230 object_class->set_property = gst_vaapi_surface_set_property;
231 object_class->get_property = gst_vaapi_surface_get_property;
232 object_class->constructed = gst_vaapi_surface_constructed;
235 * GstVaapiSurface:display:
237 * The #GstVaapiDisplay this surface is bound to.
239 g_object_class_install_property
242 g_param_spec_object("display",
244 "The GstVaapiDisplay this surface is bound to",
245 GST_VAAPI_TYPE_DISPLAY,
246 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
249 * GstVaapiSurface:id:
251 * The underlying #VASurfaceID of the surface.
253 g_object_class_install_property
256 g_param_spec_uint("id",
258 "The underlying VA surface id",
259 0, G_MAXUINT32, VA_INVALID_SURFACE,
262 g_object_class_install_property
265 g_param_spec_uint("width",
267 "The width of the surface",
269 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
271 g_object_class_install_property
274 g_param_spec_uint("height",
276 "The height of the surface",
278 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
280 g_object_class_install_property
283 g_param_spec_uint("chroma-type",
285 "The chroma type of the surface",
287 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
291 gst_vaapi_surface_init(GstVaapiSurface *surface)
293 GstVaapiSurfacePrivate *priv = GST_VAAPI_SURFACE_GET_PRIVATE(surface);
295 surface->priv = priv;
296 priv->display = NULL;
297 priv->surface_id = VA_INVALID_SURFACE;
300 priv->chroma_type = 0;
301 priv->subpictures = NULL;
305 * gst_vaapi_surface_new:
306 * @display: a #GstVaapiDisplay
307 * @chroma_type: the surface chroma format
308 * @width: the requested surface width
309 * @height: the requested surface height
311 * Creates a new #GstVaapiSurface with the specified chroma format and
314 * Return value: the newly allocated #GstVaapiSurface object
317 gst_vaapi_surface_new(
318 GstVaapiDisplay *display,
319 GstVaapiChromaType chroma_type,
324 GST_DEBUG("size %ux%u, chroma type 0x%x", width, height, chroma_type);
326 return g_object_new(GST_VAAPI_TYPE_SURFACE,
330 "chroma-type", chroma_type,
335 * gst_vaapi_surface_get_id:
336 * @surface: a #GstVaapiSurface
338 * Returns the underlying VASurfaceID of the @surface.
340 * Return value: the underlying VA surface id
343 gst_vaapi_surface_get_id(GstVaapiSurface *surface)
345 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), VA_INVALID_SURFACE);
347 return surface->priv->surface_id;
351 * gst_vaapi_surface_get_display:
352 * @surface: a #GstVaapiSurface
354 * Returns the #GstVaapiDisplay this @surface is bound to.
356 * Return value: the parent #GstVaapiDisplay object
359 gst_vaapi_surface_get_display(GstVaapiSurface *surface)
361 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), NULL);
363 return surface->priv->display;
367 * gst_vaapi_surface_get_chroma_type:
368 * @surface: a #GstVaapiSurface
370 * Returns the #GstVaapiChromaType the @surface was created with.
372 * Return value: the #GstVaapiChromaType
375 gst_vaapi_surface_get_chroma_type(GstVaapiSurface *surface)
377 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), 0);
379 return surface->priv->chroma_type;
383 * gst_vaapi_surface_get_width:
384 * @surface: a #GstVaapiSurface
386 * Returns the @surface width.
388 * Return value: the surface width, in pixels
391 gst_vaapi_surface_get_width(GstVaapiSurface *surface)
393 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), 0);
395 return surface->priv->width;
399 * gst_vaapi_surface_get_height:
400 * @surface: a #GstVaapiSurface
402 * Returns the @surface height.
404 * Return value: the surface height, in pixels.
407 gst_vaapi_surface_get_height(GstVaapiSurface *surface)
409 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), 0);
411 return surface->priv->height;
415 * gst_vaapi_surface_get_size:
416 * @surface: a #GstVaapiSurface
417 * @pwidth: return location for the width, or %NULL
418 * @pheight: return location for the height, or %NULL
420 * Retrieves the dimensions of a #GstVaapiSurface.
423 gst_vaapi_surface_get_size(
424 GstVaapiSurface *surface,
429 g_return_if_fail(GST_VAAPI_IS_SURFACE(surface));
432 *pwidth = gst_vaapi_surface_get_width(surface);
435 *pheight = gst_vaapi_surface_get_height(surface);
439 * gst_vaapi_surface_derive_image:
440 * @surface: a #GstVaapiSurface
442 * Derives a #GstVaapiImage from the @surface. This image buffer can
443 * then be mapped/unmapped for direct CPU access. This operation is
444 * only possible if the underlying implementation supports direct
445 * rendering capabilities and internal surface formats that can be
446 * represented with a #GstVaapiImage.
448 * When the operation is not possible, the function returns %NULL and
449 * the user should then fallback to using gst_vaapi_surface_get_image()
450 * or gst_vaapi_surface_put_image() to accomplish the same task in an
451 * indirect manner (additional copy).
453 * An image created with gst_vaapi_surface_derive_image() should be
454 * unreferenced when it's no longer needed. The image and image buffer
455 * data structures will be destroyed. However, the surface contents
456 * will remain unchanged until destroyed through the last call to
459 * Return value: the newly allocated #GstVaapiImage object, or %NULL
463 gst_vaapi_surface_derive_image(GstVaapiSurface *surface)
468 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), NULL);
470 va_image.image_id = VA_INVALID_ID;
471 va_image.buf = VA_INVALID_ID;
473 GST_VAAPI_DISPLAY_LOCK(surface->priv->display);
474 status = vaDeriveImage(
475 GST_VAAPI_DISPLAY_VADISPLAY(surface->priv->display),
476 surface->priv->surface_id,
479 GST_VAAPI_DISPLAY_UNLOCK(surface->priv->display);
480 if (!vaapi_check_status(status, "vaDeriveImage()"))
482 if (va_image.image_id == VA_INVALID_ID || va_image.buf == VA_INVALID_ID)
485 return gst_vaapi_image_new_with_image(surface->priv->display, &va_image);
489 * gst_vaapi_surface_get_image
490 * @surface: a #GstVaapiSurface
491 * @image: a #GstVaapiImage
493 * Retrieves surface data into a #GstVaapiImage. The @image must have
494 * a format supported by the @surface.
496 * Return value: %TRUE on success
499 gst_vaapi_surface_get_image(GstVaapiSurface *surface, GstVaapiImage *image)
505 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
506 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
508 gst_vaapi_image_get_size(image, &width, &height);
509 if (width != surface->priv->width || height != surface->priv->height)
512 image_id = gst_vaapi_image_get_id(image);
513 if (image_id == VA_INVALID_ID)
516 GST_VAAPI_DISPLAY_LOCK(surface->priv->display);
518 GST_VAAPI_DISPLAY_VADISPLAY(surface->priv->display),
519 surface->priv->surface_id,
523 GST_VAAPI_DISPLAY_UNLOCK(surface->priv->display);
524 if (!vaapi_check_status(status, "vaGetImage()"))
531 * gst_vaapi_surface_put_image:
532 * @surface: a #GstVaapiSurface
533 * @image: a #GstVaapiImage
535 * Copies data from a #GstVaapiImage into a @surface. The @image must
536 * have a format supported by the @surface.
538 * Return value: %TRUE on success
541 gst_vaapi_surface_put_image(GstVaapiSurface *surface, GstVaapiImage *image)
547 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
548 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
550 gst_vaapi_image_get_size(image, &width, &height);
551 if (width != surface->priv->width || height != surface->priv->height)
554 image_id = gst_vaapi_image_get_id(image);
555 if (image_id == VA_INVALID_ID)
558 GST_VAAPI_DISPLAY_LOCK(surface->priv->display);
560 GST_VAAPI_DISPLAY_VADISPLAY(surface->priv->display),
561 surface->priv->surface_id,
566 GST_VAAPI_DISPLAY_UNLOCK(surface->priv->display);
567 if (!vaapi_check_status(status, "vaPutImage()"))
574 * gst_vaapi_surface_associate_subpicture:
575 * @surface: a #GstVaapiSurface
576 * @subpicture: a #GstVaapiSubpicture
577 * @src_rect: the sub-rectangle of the source subpicture
578 * image to extract and process. If %NULL, the entire image will be used.
579 * @dst_rect: the sub-rectangle of the destination
580 * surface into which the image is rendered. If %NULL, the entire
581 * surface will be used.
583 * Associates the @subpicture with the @surface. The @src_rect
584 * coordinates and size are relative to the source image bound to
585 * @subpicture. The @dst_rect coordinates and size are relative to the
586 * target @surface. Note that the @surface holds an additional
587 * reference to the @subpicture.
589 * Return value: %TRUE on success
592 gst_vaapi_surface_associate_subpicture(
593 GstVaapiSurface *surface,
594 GstVaapiSubpicture *subpicture,
595 const GstVaapiRectangle *src_rect,
596 const GstVaapiRectangle *dst_rect
599 GstVaapiRectangle src_rect_default, dst_rect_default;
600 GstVaapiImage *image;
603 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
604 g_return_val_if_fail(GST_VAAPI_IS_SUBPICTURE(subpicture), FALSE);
606 if (!gst_vaapi_surface_deassociate_subpicture(surface, subpicture))
609 if (!surface->priv->subpictures) {
610 surface->priv->subpictures = g_ptr_array_new();
611 if (!surface->priv->subpictures)
616 image = gst_vaapi_subpicture_get_image(subpicture);
619 src_rect = &src_rect_default;
620 src_rect_default.x = 0;
621 src_rect_default.y = 0;
622 gst_vaapi_image_get_size(
624 &src_rect_default.width,
625 &src_rect_default.height
630 dst_rect = &dst_rect_default;
631 dst_rect_default.x = 0;
632 dst_rect_default.y = 0;
633 dst_rect_default.width = surface->priv->width;
634 dst_rect_default.height = surface->priv->height;
637 GST_VAAPI_DISPLAY_LOCK(surface->priv->display);
638 status = vaAssociateSubpicture(
639 GST_VAAPI_DISPLAY_VADISPLAY(surface->priv->display),
640 gst_vaapi_subpicture_get_id(subpicture),
641 &surface->priv->surface_id, 1,
642 src_rect->x, src_rect->y, src_rect->width, src_rect->height,
643 dst_rect->x, dst_rect->y, dst_rect->width, dst_rect->height,
646 GST_VAAPI_DISPLAY_UNLOCK(surface->priv->display);
647 if (!vaapi_check_status(status, "vaAssociateSubpicture()"))
650 g_ptr_array_add(surface->priv->subpictures, g_object_ref(subpicture));
655 * gst_vaapi_surface_deassociate_subpicture:
656 * @surface: a #GstVaapiSurface
657 * @subpicture: a #GstVaapiSubpicture
659 * Deassociates @subpicture from @surface. Other associations are kept.
661 * Return value: %TRUE on success
664 gst_vaapi_surface_deassociate_subpicture(
665 GstVaapiSurface *surface,
666 GstVaapiSubpicture *subpicture
671 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
672 g_return_val_if_fail(GST_VAAPI_IS_SUBPICTURE(subpicture), FALSE);
674 if (!surface->priv->subpictures)
677 /* First, check subpicture was really associated with this surface */
678 if (!g_ptr_array_remove_fast(surface->priv->subpictures, subpicture)) {
679 GST_DEBUG("subpicture 0x%08x was not bound to surface 0x%08x",
680 gst_vaapi_subpicture_get_id(subpicture),
681 surface->priv->surface_id);
685 GST_VAAPI_DISPLAY_LOCK(surface->priv->display);
686 status = vaDeassociateSubpicture(
687 GST_VAAPI_DISPLAY_VADISPLAY(surface->priv->display),
688 gst_vaapi_subpicture_get_id(subpicture),
689 &surface->priv->surface_id, 1
691 GST_VAAPI_DISPLAY_UNLOCK(surface->priv->display);
692 g_object_unref(subpicture);
693 if (!vaapi_check_status(status, "vaDeassociateSubpicture()"))
699 * gst_vaapi_surface_sync:
700 * @surface: a #GstVaapiSurface
702 * Blocks until all pending operations on the @surface have been
705 * Return value: %TRUE on success
708 gst_vaapi_surface_sync(GstVaapiSurface *surface)
712 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
714 GST_VAAPI_DISPLAY_LOCK(surface->priv->display);
715 status = vaSyncSurface(
716 GST_VAAPI_DISPLAY_VADISPLAY(surface->priv->display),
717 surface->priv->surface_id
719 GST_VAAPI_DISPLAY_UNLOCK(surface->priv->display);
720 if (!vaapi_check_status(status, "vaSyncSurface()"))