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:gstvaapisurface
23 * @short_description: VA surface abstraction
27 #include "gstvaapicompat.h"
28 #include "gstvaapiutils.h"
29 #include "gstvaapisurface.h"
30 #include "gstvaapiimage.h"
31 #include "gstvaapiobject_priv.h"
34 #include "gstvaapidebug.h"
36 G_DEFINE_TYPE(GstVaapiSurface, gst_vaapi_surface, GST_VAAPI_TYPE_OBJECT);
38 #define GST_VAAPI_SURFACE_GET_PRIVATE(obj) \
39 (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
40 GST_VAAPI_TYPE_SURFACE, \
41 GstVaapiSurfacePrivate))
43 struct _GstVaapiSurfacePrivate {
46 GstVaapiChromaType chroma_type;
47 GPtrArray *subpictures;
59 _gst_vaapi_surface_associate_subpicture(
60 GstVaapiSurface *surface,
61 GstVaapiSubpicture *subpicture,
62 const GstVaapiRectangle *src_rect,
63 const GstVaapiRectangle *dst_rect
67 _gst_vaapi_surface_deassociate_subpicture(
68 GstVaapiSurface *surface,
69 GstVaapiSubpicture *subpicture
73 destroy_subpicture_cb(gpointer subpicture, gpointer surface)
75 _gst_vaapi_surface_deassociate_subpicture(surface, subpicture);
76 g_object_unref(subpicture);
80 gst_vaapi_surface_destroy(GstVaapiSurface *surface)
82 GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(surface);
83 GstVaapiSurfacePrivate * const priv = surface->priv;
84 VASurfaceID surface_id;
87 surface_id = GST_VAAPI_OBJECT_ID(surface);
88 GST_DEBUG("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(surface_id));
90 if (priv->subpictures) {
91 g_ptr_array_foreach(priv->subpictures, destroy_subpicture_cb, surface);
92 g_ptr_array_free(priv->subpictures, TRUE);
93 priv->subpictures = NULL;
96 if (surface_id != VA_INVALID_SURFACE) {
97 GST_VAAPI_DISPLAY_LOCK(display);
98 status = vaDestroySurfaces(
99 GST_VAAPI_DISPLAY_VADISPLAY(display),
102 GST_VAAPI_DISPLAY_UNLOCK(display);
103 if (!vaapi_check_status(status, "vaDestroySurfaces()"))
104 g_warning("failed to destroy surface %" GST_VAAPI_ID_FORMAT,
105 GST_VAAPI_ID_ARGS(surface_id));
106 GST_VAAPI_OBJECT_ID(surface) = VA_INVALID_SURFACE;
111 gst_vaapi_surface_create(GstVaapiSurface *surface)
113 GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(surface);
114 GstVaapiSurfacePrivate * const priv = surface->priv;
115 VASurfaceID surface_id;
119 switch (priv->chroma_type) {
120 case GST_VAAPI_CHROMA_TYPE_YUV420:
121 format = VA_RT_FORMAT_YUV420;
123 case GST_VAAPI_CHROMA_TYPE_YUV422:
124 format = VA_RT_FORMAT_YUV422;
126 case GST_VAAPI_CHROMA_TYPE_YUV444:
127 format = VA_RT_FORMAT_YUV444;
130 GST_DEBUG("unsupported chroma-type %u\n", priv->chroma_type);
134 GST_VAAPI_DISPLAY_LOCK(display);
135 status = vaCreateSurfaces(
136 GST_VAAPI_DISPLAY_VADISPLAY(display),
142 GST_VAAPI_DISPLAY_UNLOCK(display);
143 if (!vaapi_check_status(status, "vaCreateSurfaces()"))
146 GST_DEBUG("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(surface_id));
147 GST_VAAPI_OBJECT_ID(surface) = surface_id;
152 gst_vaapi_surface_finalize(GObject *object)
154 gst_vaapi_surface_destroy(GST_VAAPI_SURFACE(object));
156 G_OBJECT_CLASS(gst_vaapi_surface_parent_class)->finalize(object);
160 gst_vaapi_surface_set_property(
167 GstVaapiSurface * const surface = GST_VAAPI_SURFACE(object);
168 GstVaapiSurfacePrivate * const priv = surface->priv;
172 priv->width = g_value_get_uint(value);
175 priv->height = g_value_get_uint(value);
177 case PROP_CHROMA_TYPE:
178 priv->chroma_type = g_value_get_uint(value);
181 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
187 gst_vaapi_surface_get_property(
194 GstVaapiSurface * const surface = GST_VAAPI_SURFACE(object);
198 g_value_set_uint(value, gst_vaapi_surface_get_width(surface));
201 g_value_set_uint(value, gst_vaapi_surface_get_height(surface));
203 case PROP_CHROMA_TYPE:
204 g_value_set_uint(value, gst_vaapi_surface_get_chroma_type(surface));
207 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
213 gst_vaapi_surface_constructed(GObject *object)
215 GstVaapiSurface * const surface = GST_VAAPI_SURFACE(object);
216 GObjectClass *parent_class;
218 gst_vaapi_surface_create(surface);
220 parent_class = G_OBJECT_CLASS(gst_vaapi_surface_parent_class);
221 if (parent_class->constructed)
222 parent_class->constructed(object);
226 gst_vaapi_surface_class_init(GstVaapiSurfaceClass *klass)
228 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
230 g_type_class_add_private(klass, sizeof(GstVaapiSurfacePrivate));
232 object_class->finalize = gst_vaapi_surface_finalize;
233 object_class->set_property = gst_vaapi_surface_set_property;
234 object_class->get_property = gst_vaapi_surface_get_property;
235 object_class->constructed = gst_vaapi_surface_constructed;
237 g_object_class_install_property
240 g_param_spec_uint("width",
242 "The width of the surface",
244 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
246 g_object_class_install_property
249 g_param_spec_uint("height",
251 "The height of the surface",
253 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
255 g_object_class_install_property
258 g_param_spec_uint("chroma-type",
260 "The chroma type of the surface",
262 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
266 gst_vaapi_surface_init(GstVaapiSurface *surface)
268 GstVaapiSurfacePrivate *priv = GST_VAAPI_SURFACE_GET_PRIVATE(surface);
270 surface->priv = priv;
273 priv->chroma_type = 0;
274 priv->subpictures = NULL;
278 * gst_vaapi_surface_new:
279 * @display: a #GstVaapiDisplay
280 * @chroma_type: the surface chroma format
281 * @width: the requested surface width
282 * @height: the requested surface height
284 * Creates a new #GstVaapiSurface with the specified chroma format and
287 * Return value: the newly allocated #GstVaapiSurface object
290 gst_vaapi_surface_new(
291 GstVaapiDisplay *display,
292 GstVaapiChromaType chroma_type,
297 GST_DEBUG("size %ux%u, chroma type 0x%x", width, height, chroma_type);
299 return g_object_new(GST_VAAPI_TYPE_SURFACE,
301 "id", GST_VAAPI_ID(VA_INVALID_ID),
304 "chroma-type", chroma_type,
309 * gst_vaapi_surface_get_chroma_type:
310 * @surface: a #GstVaapiSurface
312 * Returns the #GstVaapiChromaType the @surface was created with.
314 * Return value: the #GstVaapiChromaType
317 gst_vaapi_surface_get_chroma_type(GstVaapiSurface *surface)
319 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), 0);
321 return surface->priv->chroma_type;
325 * gst_vaapi_surface_get_width:
326 * @surface: a #GstVaapiSurface
328 * Returns the @surface width.
330 * Return value: the surface width, in pixels
333 gst_vaapi_surface_get_width(GstVaapiSurface *surface)
335 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), 0);
337 return surface->priv->width;
341 * gst_vaapi_surface_get_height:
342 * @surface: a #GstVaapiSurface
344 * Returns the @surface height.
346 * Return value: the surface height, in pixels.
349 gst_vaapi_surface_get_height(GstVaapiSurface *surface)
351 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), 0);
353 return surface->priv->height;
357 * gst_vaapi_surface_get_size:
358 * @surface: a #GstVaapiSurface
359 * @pwidth: return location for the width, or %NULL
360 * @pheight: return location for the height, or %NULL
362 * Retrieves the dimensions of a #GstVaapiSurface.
365 gst_vaapi_surface_get_size(
366 GstVaapiSurface *surface,
371 g_return_if_fail(GST_VAAPI_IS_SURFACE(surface));
374 *pwidth = gst_vaapi_surface_get_width(surface);
377 *pheight = gst_vaapi_surface_get_height(surface);
381 * gst_vaapi_surface_derive_image:
382 * @surface: a #GstVaapiSurface
384 * Derives a #GstVaapiImage from the @surface. This image buffer can
385 * then be mapped/unmapped for direct CPU access. This operation is
386 * only possible if the underlying implementation supports direct
387 * rendering capabilities and internal surface formats that can be
388 * represented with a #GstVaapiImage.
390 * When the operation is not possible, the function returns %NULL and
391 * the user should then fallback to using gst_vaapi_surface_get_image()
392 * or gst_vaapi_surface_put_image() to accomplish the same task in an
393 * indirect manner (additional copy).
395 * An image created with gst_vaapi_surface_derive_image() should be
396 * unreferenced when it's no longer needed. The image and image buffer
397 * data structures will be destroyed. However, the surface contents
398 * will remain unchanged until destroyed through the last call to
401 * Return value: the newly allocated #GstVaapiImage object, or %NULL
405 gst_vaapi_surface_derive_image(GstVaapiSurface *surface)
407 GstVaapiDisplay *display;
411 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), NULL);
413 display = GST_VAAPI_OBJECT_DISPLAY(surface);
414 va_image.image_id = VA_INVALID_ID;
415 va_image.buf = VA_INVALID_ID;
417 GST_VAAPI_DISPLAY_LOCK(display);
418 status = vaDeriveImage(
419 GST_VAAPI_DISPLAY_VADISPLAY(display),
420 GST_VAAPI_OBJECT_ID(surface),
423 GST_VAAPI_DISPLAY_UNLOCK(display);
424 if (!vaapi_check_status(status, "vaDeriveImage()"))
426 if (va_image.image_id == VA_INVALID_ID || va_image.buf == VA_INVALID_ID)
429 return gst_vaapi_image_new_with_image(display, &va_image);
433 * gst_vaapi_surface_get_image
434 * @surface: a #GstVaapiSurface
435 * @image: a #GstVaapiImage
437 * Retrieves surface data into a #GstVaapiImage. The @image must have
438 * a format supported by the @surface.
440 * Return value: %TRUE on success
443 gst_vaapi_surface_get_image(GstVaapiSurface *surface, GstVaapiImage *image)
445 GstVaapiDisplay *display;
450 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
451 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
453 display = GST_VAAPI_OBJECT_DISPLAY(surface);
457 gst_vaapi_image_get_size(image, &width, &height);
458 if (width != surface->priv->width || height != surface->priv->height)
461 image_id = GST_VAAPI_OBJECT_ID(image);
462 if (image_id == VA_INVALID_ID)
465 GST_VAAPI_DISPLAY_LOCK(display);
467 GST_VAAPI_DISPLAY_VADISPLAY(display),
468 GST_VAAPI_OBJECT_ID(surface),
472 GST_VAAPI_DISPLAY_UNLOCK(display);
473 if (!vaapi_check_status(status, "vaGetImage()"))
480 * gst_vaapi_surface_put_image:
481 * @surface: a #GstVaapiSurface
482 * @image: a #GstVaapiImage
484 * Copies data from a #GstVaapiImage into a @surface. The @image must
485 * have a format supported by the @surface.
487 * Return value: %TRUE on success
490 gst_vaapi_surface_put_image(GstVaapiSurface *surface, GstVaapiImage *image)
492 GstVaapiDisplay *display;
497 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
498 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
500 display = GST_VAAPI_OBJECT_DISPLAY(surface);
504 gst_vaapi_image_get_size(image, &width, &height);
505 if (width != surface->priv->width || height != surface->priv->height)
508 image_id = GST_VAAPI_OBJECT_ID(image);
509 if (image_id == VA_INVALID_ID)
512 GST_VAAPI_DISPLAY_LOCK(display);
514 GST_VAAPI_DISPLAY_VADISPLAY(display),
515 GST_VAAPI_OBJECT_ID(surface),
520 GST_VAAPI_DISPLAY_UNLOCK(display);
521 if (!vaapi_check_status(status, "vaPutImage()"))
528 * gst_vaapi_surface_associate_subpicture:
529 * @surface: a #GstVaapiSurface
530 * @subpicture: a #GstVaapiSubpicture
531 * @src_rect: the sub-rectangle of the source subpicture
532 * image to extract and process. If %NULL, the entire image will be used.
533 * @dst_rect: the sub-rectangle of the destination
534 * surface into which the image is rendered. If %NULL, the entire
535 * surface will be used.
537 * Associates the @subpicture with the @surface. The @src_rect
538 * coordinates and size are relative to the source image bound to
539 * @subpicture. The @dst_rect coordinates and size are relative to the
540 * target @surface. Note that the @surface holds an additional
541 * reference to the @subpicture.
543 * Return value: %TRUE on success
546 gst_vaapi_surface_associate_subpicture(
547 GstVaapiSurface *surface,
548 GstVaapiSubpicture *subpicture,
549 const GstVaapiRectangle *src_rect,
550 const GstVaapiRectangle *dst_rect
555 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
556 g_return_val_if_fail(GST_VAAPI_IS_SUBPICTURE(subpicture), FALSE);
558 if (!gst_vaapi_surface_deassociate_subpicture(surface, subpicture))
561 if (!surface->priv->subpictures) {
562 surface->priv->subpictures = g_ptr_array_new();
563 if (!surface->priv->subpictures)
567 success = _gst_vaapi_surface_associate_subpicture(
576 g_ptr_array_add(surface->priv->subpictures, g_object_ref(subpicture));
581 _gst_vaapi_surface_associate_subpicture(
582 GstVaapiSurface *surface,
583 GstVaapiSubpicture *subpicture,
584 const GstVaapiRectangle *src_rect,
585 const GstVaapiRectangle *dst_rect
588 GstVaapiDisplay *display;
589 GstVaapiRectangle src_rect_default, dst_rect_default;
590 GstVaapiImage *image;
591 VASurfaceID surface_id;
594 display = GST_VAAPI_OBJECT_DISPLAY(surface);
598 surface_id = GST_VAAPI_OBJECT_ID(surface);
599 if (surface_id == VA_INVALID_SURFACE)
603 image = gst_vaapi_subpicture_get_image(subpicture);
606 src_rect = &src_rect_default;
607 src_rect_default.x = 0;
608 src_rect_default.y = 0;
609 gst_vaapi_image_get_size(
611 &src_rect_default.width,
612 &src_rect_default.height
617 dst_rect = &dst_rect_default;
618 dst_rect_default.x = 0;
619 dst_rect_default.y = 0;
620 dst_rect_default.width = surface->priv->width;
621 dst_rect_default.height = surface->priv->height;
624 GST_VAAPI_DISPLAY_LOCK(display);
625 status = vaAssociateSubpicture(
626 GST_VAAPI_DISPLAY_VADISPLAY(display),
627 GST_VAAPI_OBJECT_ID(subpicture),
629 src_rect->x, src_rect->y, src_rect->width, src_rect->height,
630 dst_rect->x, dst_rect->y, dst_rect->width, dst_rect->height,
633 GST_VAAPI_DISPLAY_UNLOCK(display);
634 if (!vaapi_check_status(status, "vaAssociateSubpicture()"))
641 * gst_vaapi_surface_deassociate_subpicture:
642 * @surface: a #GstVaapiSurface
643 * @subpicture: a #GstVaapiSubpicture
645 * Deassociates @subpicture from @surface. Other associations are kept.
647 * Return value: %TRUE on success
650 gst_vaapi_surface_deassociate_subpicture(
651 GstVaapiSurface *surface,
652 GstVaapiSubpicture *subpicture
657 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
658 g_return_val_if_fail(GST_VAAPI_IS_SUBPICTURE(subpicture), FALSE);
660 if (!surface->priv->subpictures)
663 /* First, check subpicture was really associated with this surface */
664 if (!g_ptr_array_remove_fast(surface->priv->subpictures, subpicture)) {
665 GST_DEBUG("subpicture %" GST_VAAPI_ID_FORMAT "was not bound to "
666 "surface %" GST_VAAPI_ID_FORMAT,
667 GST_VAAPI_ID_ARGS(GST_VAAPI_OBJECT_ID(subpicture)),
668 GST_VAAPI_ID_ARGS(GST_VAAPI_OBJECT_ID(surface)));
672 success = _gst_vaapi_surface_deassociate_subpicture(surface, subpicture);
673 g_object_unref(subpicture);
678 _gst_vaapi_surface_deassociate_subpicture(
679 GstVaapiSurface *surface,
680 GstVaapiSubpicture *subpicture
683 GstVaapiDisplay *display;
684 VASurfaceID surface_id;
687 display = GST_VAAPI_OBJECT_DISPLAY(surface);
691 surface_id = GST_VAAPI_OBJECT_ID(surface);
692 if (surface_id == VA_INVALID_SURFACE)
695 GST_VAAPI_DISPLAY_LOCK(display);
696 status = vaDeassociateSubpicture(
697 GST_VAAPI_DISPLAY_VADISPLAY(display),
698 GST_VAAPI_OBJECT_ID(subpicture),
701 GST_VAAPI_DISPLAY_UNLOCK(display);
702 if (!vaapi_check_status(status, "vaDeassociateSubpicture()"))
709 * gst_vaapi_surface_sync:
710 * @surface: a #GstVaapiSurface
712 * Blocks until all pending operations on the @surface have been
715 * Return value: %TRUE on success
718 gst_vaapi_surface_sync(GstVaapiSurface *surface)
720 GstVaapiDisplay *display;
723 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
725 display = GST_VAAPI_OBJECT_DISPLAY(surface);
729 GST_VAAPI_DISPLAY_LOCK(display);
730 status = vaSyncSurface(
731 GST_VAAPI_DISPLAY_VADISPLAY(display),
732 GST_VAAPI_OBJECT_ID(surface)
734 GST_VAAPI_DISPLAY_UNLOCK(display);
735 if (!vaapi_check_status(status, "vaSyncSurface()"))