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_id:
310 * @surface: a #GstVaapiSurface
312 * Returns the underlying VASurfaceID of the @surface.
314 * Return value: the underlying VA surface id
317 gst_vaapi_surface_get_id(GstVaapiSurface *surface)
319 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), VA_INVALID_SURFACE);
321 return GST_VAAPI_OBJECT_ID(surface);
325 * gst_vaapi_surface_get_chroma_type:
326 * @surface: a #GstVaapiSurface
328 * Returns the #GstVaapiChromaType the @surface was created with.
330 * Return value: the #GstVaapiChromaType
333 gst_vaapi_surface_get_chroma_type(GstVaapiSurface *surface)
335 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), 0);
337 return surface->priv->chroma_type;
341 * gst_vaapi_surface_get_width:
342 * @surface: a #GstVaapiSurface
344 * Returns the @surface width.
346 * Return value: the surface width, in pixels
349 gst_vaapi_surface_get_width(GstVaapiSurface *surface)
351 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), 0);
353 return surface->priv->width;
357 * gst_vaapi_surface_get_height:
358 * @surface: a #GstVaapiSurface
360 * Returns the @surface height.
362 * Return value: the surface height, in pixels.
365 gst_vaapi_surface_get_height(GstVaapiSurface *surface)
367 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), 0);
369 return surface->priv->height;
373 * gst_vaapi_surface_get_size:
374 * @surface: a #GstVaapiSurface
375 * @pwidth: return location for the width, or %NULL
376 * @pheight: return location for the height, or %NULL
378 * Retrieves the dimensions of a #GstVaapiSurface.
381 gst_vaapi_surface_get_size(
382 GstVaapiSurface *surface,
387 g_return_if_fail(GST_VAAPI_IS_SURFACE(surface));
390 *pwidth = gst_vaapi_surface_get_width(surface);
393 *pheight = gst_vaapi_surface_get_height(surface);
397 * gst_vaapi_surface_derive_image:
398 * @surface: a #GstVaapiSurface
400 * Derives a #GstVaapiImage from the @surface. This image buffer can
401 * then be mapped/unmapped for direct CPU access. This operation is
402 * only possible if the underlying implementation supports direct
403 * rendering capabilities and internal surface formats that can be
404 * represented with a #GstVaapiImage.
406 * When the operation is not possible, the function returns %NULL and
407 * the user should then fallback to using gst_vaapi_surface_get_image()
408 * or gst_vaapi_surface_put_image() to accomplish the same task in an
409 * indirect manner (additional copy).
411 * An image created with gst_vaapi_surface_derive_image() should be
412 * unreferenced when it's no longer needed. The image and image buffer
413 * data structures will be destroyed. However, the surface contents
414 * will remain unchanged until destroyed through the last call to
417 * Return value: the newly allocated #GstVaapiImage object, or %NULL
421 gst_vaapi_surface_derive_image(GstVaapiSurface *surface)
423 GstVaapiDisplay *display;
427 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), NULL);
429 display = GST_VAAPI_OBJECT_DISPLAY(surface);
430 va_image.image_id = VA_INVALID_ID;
431 va_image.buf = VA_INVALID_ID;
433 GST_VAAPI_DISPLAY_LOCK(display);
434 status = vaDeriveImage(
435 GST_VAAPI_DISPLAY_VADISPLAY(display),
436 GST_VAAPI_OBJECT_ID(surface),
439 GST_VAAPI_DISPLAY_UNLOCK(display);
440 if (!vaapi_check_status(status, "vaDeriveImage()"))
442 if (va_image.image_id == VA_INVALID_ID || va_image.buf == VA_INVALID_ID)
445 return gst_vaapi_image_new_with_image(display, &va_image);
449 * gst_vaapi_surface_get_image
450 * @surface: a #GstVaapiSurface
451 * @image: a #GstVaapiImage
453 * Retrieves surface data into a #GstVaapiImage. The @image must have
454 * a format supported by the @surface.
456 * Return value: %TRUE on success
459 gst_vaapi_surface_get_image(GstVaapiSurface *surface, GstVaapiImage *image)
461 GstVaapiDisplay *display;
466 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
467 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
469 display = GST_VAAPI_OBJECT_DISPLAY(surface);
473 gst_vaapi_image_get_size(image, &width, &height);
474 if (width != surface->priv->width || height != surface->priv->height)
477 image_id = GST_VAAPI_OBJECT_ID(image);
478 if (image_id == VA_INVALID_ID)
481 GST_VAAPI_DISPLAY_LOCK(display);
483 GST_VAAPI_DISPLAY_VADISPLAY(display),
484 GST_VAAPI_OBJECT_ID(surface),
488 GST_VAAPI_DISPLAY_UNLOCK(display);
489 if (!vaapi_check_status(status, "vaGetImage()"))
496 * gst_vaapi_surface_put_image:
497 * @surface: a #GstVaapiSurface
498 * @image: a #GstVaapiImage
500 * Copies data from a #GstVaapiImage into a @surface. The @image must
501 * have a format supported by the @surface.
503 * Return value: %TRUE on success
506 gst_vaapi_surface_put_image(GstVaapiSurface *surface, GstVaapiImage *image)
508 GstVaapiDisplay *display;
513 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
514 g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
516 display = GST_VAAPI_OBJECT_DISPLAY(surface);
520 gst_vaapi_image_get_size(image, &width, &height);
521 if (width != surface->priv->width || height != surface->priv->height)
524 image_id = GST_VAAPI_OBJECT_ID(image);
525 if (image_id == VA_INVALID_ID)
528 GST_VAAPI_DISPLAY_LOCK(display);
530 GST_VAAPI_DISPLAY_VADISPLAY(display),
531 GST_VAAPI_OBJECT_ID(surface),
536 GST_VAAPI_DISPLAY_UNLOCK(display);
537 if (!vaapi_check_status(status, "vaPutImage()"))
544 * gst_vaapi_surface_associate_subpicture:
545 * @surface: a #GstVaapiSurface
546 * @subpicture: a #GstVaapiSubpicture
547 * @src_rect: the sub-rectangle of the source subpicture
548 * image to extract and process. If %NULL, the entire image will be used.
549 * @dst_rect: the sub-rectangle of the destination
550 * surface into which the image is rendered. If %NULL, the entire
551 * surface will be used.
553 * Associates the @subpicture with the @surface. The @src_rect
554 * coordinates and size are relative to the source image bound to
555 * @subpicture. The @dst_rect coordinates and size are relative to the
556 * target @surface. Note that the @surface holds an additional
557 * reference to the @subpicture.
559 * Return value: %TRUE on success
562 gst_vaapi_surface_associate_subpicture(
563 GstVaapiSurface *surface,
564 GstVaapiSubpicture *subpicture,
565 const GstVaapiRectangle *src_rect,
566 const GstVaapiRectangle *dst_rect
571 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
572 g_return_val_if_fail(GST_VAAPI_IS_SUBPICTURE(subpicture), FALSE);
574 if (!gst_vaapi_surface_deassociate_subpicture(surface, subpicture))
577 if (!surface->priv->subpictures) {
578 surface->priv->subpictures = g_ptr_array_new();
579 if (!surface->priv->subpictures)
583 success = _gst_vaapi_surface_associate_subpicture(
592 g_ptr_array_add(surface->priv->subpictures, g_object_ref(subpicture));
597 _gst_vaapi_surface_associate_subpicture(
598 GstVaapiSurface *surface,
599 GstVaapiSubpicture *subpicture,
600 const GstVaapiRectangle *src_rect,
601 const GstVaapiRectangle *dst_rect
604 GstVaapiDisplay *display;
605 GstVaapiRectangle src_rect_default, dst_rect_default;
606 GstVaapiImage *image;
607 VASurfaceID surface_id;
610 display = GST_VAAPI_OBJECT_DISPLAY(surface);
614 surface_id = GST_VAAPI_OBJECT_ID(surface);
615 if (surface_id == VA_INVALID_SURFACE)
619 image = gst_vaapi_subpicture_get_image(subpicture);
622 src_rect = &src_rect_default;
623 src_rect_default.x = 0;
624 src_rect_default.y = 0;
625 gst_vaapi_image_get_size(
627 &src_rect_default.width,
628 &src_rect_default.height
633 dst_rect = &dst_rect_default;
634 dst_rect_default.x = 0;
635 dst_rect_default.y = 0;
636 dst_rect_default.width = surface->priv->width;
637 dst_rect_default.height = surface->priv->height;
640 GST_VAAPI_DISPLAY_LOCK(display);
641 status = vaAssociateSubpicture(
642 GST_VAAPI_DISPLAY_VADISPLAY(display),
643 GST_VAAPI_OBJECT_ID(subpicture),
645 src_rect->x, src_rect->y, src_rect->width, src_rect->height,
646 dst_rect->x, dst_rect->y, dst_rect->width, dst_rect->height,
649 GST_VAAPI_DISPLAY_UNLOCK(display);
650 if (!vaapi_check_status(status, "vaAssociateSubpicture()"))
657 * gst_vaapi_surface_deassociate_subpicture:
658 * @surface: a #GstVaapiSurface
659 * @subpicture: a #GstVaapiSubpicture
661 * Deassociates @subpicture from @surface. Other associations are kept.
663 * Return value: %TRUE on success
666 gst_vaapi_surface_deassociate_subpicture(
667 GstVaapiSurface *surface,
668 GstVaapiSubpicture *subpicture
673 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
674 g_return_val_if_fail(GST_VAAPI_IS_SUBPICTURE(subpicture), FALSE);
676 if (!surface->priv->subpictures)
679 /* First, check subpicture was really associated with this surface */
680 if (!g_ptr_array_remove_fast(surface->priv->subpictures, subpicture)) {
681 GST_DEBUG("subpicture %" GST_VAAPI_ID_FORMAT "was not bound to "
682 "surface %" GST_VAAPI_ID_FORMAT,
683 GST_VAAPI_ID_ARGS(GST_VAAPI_OBJECT_ID(subpicture)),
684 GST_VAAPI_ID_ARGS(GST_VAAPI_OBJECT_ID(surface)));
688 success = _gst_vaapi_surface_deassociate_subpicture(surface, subpicture);
689 g_object_unref(subpicture);
694 _gst_vaapi_surface_deassociate_subpicture(
695 GstVaapiSurface *surface,
696 GstVaapiSubpicture *subpicture
699 GstVaapiDisplay *display;
700 VASurfaceID surface_id;
703 display = GST_VAAPI_OBJECT_DISPLAY(surface);
707 surface_id = GST_VAAPI_OBJECT_ID(surface);
708 if (surface_id == VA_INVALID_SURFACE)
711 GST_VAAPI_DISPLAY_LOCK(display);
712 status = vaDeassociateSubpicture(
713 GST_VAAPI_DISPLAY_VADISPLAY(display),
714 GST_VAAPI_OBJECT_ID(subpicture),
717 GST_VAAPI_DISPLAY_UNLOCK(display);
718 if (!vaapi_check_status(status, "vaDeassociateSubpicture()"))
725 * gst_vaapi_surface_sync:
726 * @surface: a #GstVaapiSurface
728 * Blocks until all pending operations on the @surface have been
731 * Return value: %TRUE on success
734 gst_vaapi_surface_sync(GstVaapiSurface *surface)
736 GstVaapiDisplay *display;
739 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
741 display = GST_VAAPI_OBJECT_DISPLAY(surface);
745 GST_VAAPI_DISPLAY_LOCK(display);
746 status = vaSyncSurface(
747 GST_VAAPI_DISPLAY_VADISPLAY(display),
748 GST_VAAPI_OBJECT_ID(surface)
750 GST_VAAPI_DISPLAY_UNLOCK(display);
751 if (!vaapi_check_status(status, "vaSyncSurface()"))