2 * gstvaapitexture.c - VA texture abstraction
4 * Copyright (C) 2010-2011 Splitted-Desktop Systems
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either version 2.1
9 * of the License, or (at your option) any later version.
11 * This library 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 GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free
18 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
23 * SECTION:gstvaapitexture
24 * @short_description: VA/GLX texture abstraction
28 #include "gstvaapitexture.h"
29 #include "gstvaapicompat.h"
30 #include "gstvaapiutils.h"
31 #include "gstvaapiutils_glx.h"
32 #include "gstvaapidisplay_glx.h"
33 #include "gstvaapi_priv.h"
34 #include "gstvaapidisplay_x11_priv.h"
37 #include "gstvaapidebug.h"
39 G_DEFINE_TYPE(GstVaapiTexture, gst_vaapi_texture, GST_VAAPI_TYPE_OBJECT);
41 #define GST_VAAPI_TEXTURE_GET_PRIVATE(obj) \
42 (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
43 GST_VAAPI_TYPE_TEXTURE, \
44 GstVaapiTexturePrivate))
46 struct _GstVaapiTexturePrivate {
51 GLContextState *gl_context;
54 GLFramebufferObject *fbo;
55 guint foreign_texture : 1;
56 guint is_constructed : 1;
69 _gst_vaapi_texture_destroy_objects(GstVaapiTexture *texture)
71 GstVaapiTexturePrivate * const priv = texture->priv;
74 GST_VAAPI_OBJECT_LOCK_DISPLAY(texture);
75 if (priv->gl_surface) {
77 GST_VAAPI_OBJECT_VADISPLAY(texture),
80 priv->gl_surface = NULL;
82 GST_VAAPI_OBJECT_UNLOCK_DISPLAY(texture);
84 GLContextState old_cs;
86 GST_VAAPI_OBJECT_LOCK_DISPLAY(texture);
88 gl_set_current_context(priv->gl_context, &old_cs);
91 gl_destroy_framebuffer_object(priv->fbo);
96 gl_destroy_pixmap_object(priv->pixo);
100 if (priv->gl_context) {
101 gl_set_current_context(&old_cs, NULL);
102 gl_destroy_context(priv->gl_context);
103 priv->gl_context = NULL;
105 GST_VAAPI_OBJECT_UNLOCK_DISPLAY(texture);
110 gst_vaapi_texture_destroy(GstVaapiTexture *texture)
112 GstVaapiTexturePrivate * const priv = texture->priv;
113 const GLuint texture_id = GST_VAAPI_OBJECT_ID(texture);
115 _gst_vaapi_texture_destroy_objects(texture);
118 if (!priv->foreign_texture)
119 glDeleteTextures(1, &texture_id);
120 GST_VAAPI_OBJECT_ID(texture) = 0;
125 _gst_vaapi_texture_create_objects(GstVaapiTexture *texture, GLuint texture_id)
127 GstVaapiTexturePrivate * const priv = texture->priv;
128 gboolean success = FALSE;
133 GST_VAAPI_OBJECT_LOCK_DISPLAY(texture);
134 status = vaCreateSurfaceGLX(
135 GST_VAAPI_OBJECT_VADISPLAY(texture),
140 GST_VAAPI_OBJECT_UNLOCK_DISPLAY(texture);
141 success = vaapi_check_status(status, "vaCreateSurfaceGLX()");
143 GLContextState old_cs;
145 GST_VAAPI_OBJECT_LOCK_DISPLAY(texture);
146 gl_get_current_context(&old_cs);
147 priv->gl_context = gl_create_context(
148 GST_VAAPI_OBJECT_XDISPLAY(texture),
149 GST_VAAPI_OBJECT_XSCREEN(texture),
152 if (!priv->gl_context || !gl_set_current_context(priv->gl_context, NULL))
155 priv->pixo = gl_create_pixmap_object(
156 GST_VAAPI_OBJECT_XDISPLAY(texture),
163 priv->fbo = gl_create_framebuffer_object(
172 gl_set_current_context(&old_cs, NULL);
173 GST_VAAPI_OBJECT_UNLOCK_DISPLAY(texture);
179 gst_vaapi_texture_create(GstVaapiTexture *texture)
181 GstVaapiTexturePrivate * const priv = texture->priv;
184 if (priv->foreign_texture)
185 texture_id = GST_VAAPI_OBJECT_ID(texture);
187 GST_VAAPI_OBJECT_LOCK_DISPLAY(texture);
188 texture_id = gl_create_texture(
194 GST_VAAPI_OBJECT_UNLOCK_DISPLAY(texture);
197 GST_VAAPI_OBJECT_ID(texture) = texture_id;
200 return _gst_vaapi_texture_create_objects(texture, texture_id);
204 gst_vaapi_texture_finalize(GObject *object)
206 gst_vaapi_texture_destroy(GST_VAAPI_TEXTURE(object));
208 G_OBJECT_CLASS(gst_vaapi_texture_parent_class)->finalize(object);
212 gst_vaapi_texture_constructed(GObject *object)
214 GstVaapiTexture * const texture = GST_VAAPI_TEXTURE(object);
215 GObjectClass *parent_class;
217 texture->priv->foreign_texture = GST_VAAPI_OBJECT_ID(texture) != 0;
218 texture->priv->is_constructed = gst_vaapi_texture_create(texture);
220 parent_class = G_OBJECT_CLASS(gst_vaapi_texture_parent_class);
221 if (parent_class->constructed)
222 parent_class->constructed(object);
226 gst_vaapi_texture_set_property(
233 GstVaapiTexture * const texture = GST_VAAPI_TEXTURE(object);
237 texture->priv->target = g_value_get_uint(value);
240 texture->priv->format = g_value_get_uint(value);
243 texture->priv->width = g_value_get_uint(value);
246 texture->priv->height = g_value_get_uint(value);
249 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
255 gst_vaapi_texture_get_property(
262 GstVaapiTexture * const texture = GST_VAAPI_TEXTURE(object);
266 g_value_set_uint(value, gst_vaapi_texture_get_target(texture));
269 g_value_set_uint(value, gst_vaapi_texture_get_format(texture));
272 g_value_set_uint(value, gst_vaapi_texture_get_width(texture));
275 g_value_set_uint(value, gst_vaapi_texture_get_height(texture));
278 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
284 gst_vaapi_texture_class_init(GstVaapiTextureClass *klass)
286 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
288 g_type_class_add_private(klass, sizeof(GstVaapiTexturePrivate));
290 object_class->finalize = gst_vaapi_texture_finalize;
291 object_class->set_property = gst_vaapi_texture_set_property;
292 object_class->get_property = gst_vaapi_texture_get_property;
293 object_class->constructed = gst_vaapi_texture_constructed;
295 g_object_class_install_property
298 g_param_spec_uint("target",
300 "The texture target",
302 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
304 g_object_class_install_property
307 g_param_spec_uint("format",
309 "The texture format",
311 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
313 g_object_class_install_property
316 g_param_spec_uint("width",
320 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
322 g_object_class_install_property
325 g_param_spec_uint("height",
327 "The texture height",
329 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
333 gst_vaapi_texture_init(GstVaapiTexture *texture)
335 GstVaapiTexturePrivate *priv = GST_VAAPI_TEXTURE_GET_PRIVATE(texture);
337 texture->priv = priv;
338 priv->target = GL_NONE;
339 priv->format = GL_NONE;
342 priv->gl_context = NULL;
343 priv->gl_surface = NULL;
346 priv->foreign_texture = FALSE;
347 priv->is_constructed = FALSE;
351 * gst_vaapi_texture_new:
352 * @display: a #GstVaapiDisplay
353 * @target: the target to which the texture is bound
354 * @format: the format of the pixel data
355 * @width: the requested width, in pixels
356 * @height: the requested height, in pixels
358 * Creates a texture with the specified dimensions, @target and
359 * @format. Note that only GL_TEXTURE_2D @target and GL_RGBA or
360 * GL_BGRA formats are supported at this time.
362 * The application shall maintain the live GL context itself. That is,
363 * gst_vaapi_window_glx_make_current() must be called beforehand, or
364 * any other function like glXMakeCurrent() if the context is managed
365 * outside of this library.
367 * Return value: the newly created #GstVaapiTexture object
370 gst_vaapi_texture_new(
371 GstVaapiDisplay *display,
378 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
380 return g_object_new(GST_VAAPI_TYPE_TEXTURE,
382 "id", GST_VAAPI_ID(0),
391 * gst_vaapi_texture_new_with_texture:
392 * @display: a #GstVaapiDisplay
393 * @texture: the foreign GL texture name to use
394 * @target: the target to which the texture is bound
395 * @format: the format of the pixel data
397 * Creates a texture from an existing GL texture, with the specified
398 * @target and @format. Note that only GL_TEXTURE_2D @target and
399 * GL_RGBA or GL_BGRA formats are supported at this time. The
400 * dimensions will be retrieved from the @texture.
402 * The application shall maintain the live GL context itself. That is,
403 * gst_vaapi_window_glx_make_current() must be called beforehand, or
404 * any other function like glXMakeCurrent() if the context is managed
405 * outside of this library.
407 * Return value: the newly created #GstVaapiTexture object
410 gst_vaapi_texture_new_with_texture(
411 GstVaapiDisplay *display,
417 guint width, height, border_width;
421 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
423 /* Check texture dimensions */
424 GST_VAAPI_DISPLAY_LOCK(display);
425 success = gl_bind_texture(&ts, target, texture);
427 if (!gl_get_texture_param(target, GL_TEXTURE_WIDTH, &width) ||
428 !gl_get_texture_param(target, GL_TEXTURE_HEIGHT, &height) ||
429 !gl_get_texture_param(target, GL_TEXTURE_BORDER, &border_width))
431 gl_unbind_texture(&ts);
433 GST_VAAPI_DISPLAY_UNLOCK(display);
437 width -= 2 * border_width;
438 height -= 2 * border_width;
439 if (width == 0 || height == 0)
442 return g_object_new(GST_VAAPI_TYPE_TEXTURE,
444 "id", GST_VAAPI_ID(texture),
453 * gst_vaapi_texture_get_id:
454 * @texture: a #GstVaapiTexture
456 * Returns the underlying texture id of the @texture.
458 * Return value: the underlying texture id of the @texture
461 gst_vaapi_texture_get_id(GstVaapiTexture *texture)
463 g_return_val_if_fail(GST_VAAPI_IS_TEXTURE(texture), 0);
465 return GST_VAAPI_OBJECT_ID(texture);
469 * gst_vaapi_texture_get_target:
470 * @texture: a #GstVaapiTexture
472 * Returns the @texture target type
474 * Return value: the texture target
477 gst_vaapi_texture_get_target(GstVaapiTexture *texture)
479 g_return_val_if_fail(GST_VAAPI_IS_TEXTURE(texture), GL_NONE);
480 g_return_val_if_fail(texture->priv->is_constructed, GL_NONE);
482 return texture->priv->target;
486 * gst_vaapi_texture_get_format
487 * @texture: a #GstVaapiTexture
489 * Returns the @texture format
491 * Return value: the texture format
494 gst_vaapi_texture_get_format(GstVaapiTexture *texture)
496 g_return_val_if_fail(GST_VAAPI_IS_TEXTURE(texture), GL_NONE);
497 g_return_val_if_fail(texture->priv->is_constructed, GL_NONE);
499 return texture->priv->format;
503 * gst_vaapi_texture_get_width:
504 * @texture: a #GstVaapiTexture
506 * Returns the @texture width.
508 * Return value: the texture width, in pixels
511 gst_vaapi_texture_get_width(GstVaapiTexture *texture)
513 g_return_val_if_fail(GST_VAAPI_IS_TEXTURE(texture), 0);
514 g_return_val_if_fail(texture->priv->is_constructed, 0);
516 return texture->priv->width;
520 * gst_vaapi_texture_get_height:
521 * @texture: a #GstVaapiTexture
523 * Returns the @texture height.
525 * Return value: the texture height, in pixels.
528 gst_vaapi_texture_get_height(GstVaapiTexture *texture)
530 g_return_val_if_fail(GST_VAAPI_IS_TEXTURE(texture), 0);
531 g_return_val_if_fail(texture->priv->is_constructed, 0);
533 return texture->priv->height;
537 * gst_vaapi_texture_get_size:
538 * @texture: a #GstVaapiTexture
539 * @pwidth: return location for the width, or %NULL
540 * @pheight: return location for the height, or %NULL
542 * Retrieves the dimensions of a #GstVaapiTexture.
545 gst_vaapi_texture_get_size(
546 GstVaapiTexture *texture,
551 g_return_if_fail(GST_VAAPI_IS_TEXTURE(texture));
552 g_return_if_fail(texture->priv->is_constructed);
555 *pwidth = texture->priv->width;
558 *pheight = texture->priv->height;
562 * gst_vaapi_texture_put_surface:
563 * @texture: a #GstVaapiTexture
564 * @surface: a #GstVaapiSurface
565 * @flags: postprocessing flags. See #GstVaapiTextureRenderFlags
567 * Renders the @surface into the àtexture. The @flags specify how
568 * de-interlacing (if needed), color space conversion, scaling and
569 * other postprocessing transformations are performed.
571 * Return value: %TRUE on success
574 _gst_vaapi_texture_put_surface(
575 GstVaapiTexture *texture,
576 GstVaapiSurface *surface,
580 GstVaapiTexturePrivate * const priv = texture->priv;
584 GST_VAAPI_OBJECT_LOCK_DISPLAY(texture);
585 status = vaCopySurfaceGLX(
586 GST_VAAPI_OBJECT_VADISPLAY(texture),
588 GST_VAAPI_OBJECT_ID(surface),
589 from_GstVaapiSurfaceRenderFlags(flags)
591 GST_VAAPI_OBJECT_UNLOCK_DISPLAY(texture);
592 if (!vaapi_check_status(status, "vaCopySurfaceGLX()"))
595 guint surface_width, surface_height;
596 GLContextState old_cs;
597 gboolean success = FALSE;
599 gst_vaapi_surface_get_size(surface, &surface_width, &surface_height);
601 GST_VAAPI_OBJECT_LOCK_DISPLAY(texture);
602 status = vaPutSurface(
603 GST_VAAPI_OBJECT_VADISPLAY(texture),
604 GST_VAAPI_OBJECT_ID(surface),
606 0, 0, surface_width, surface_height,
607 0, 0, priv->width, priv->height,
609 from_GstVaapiSurfaceRenderFlags(flags)
611 GST_VAAPI_OBJECT_UNLOCK_DISPLAY(texture);
612 if (!vaapi_check_status(status, "vaPutSurface() [TFP]"))
615 GST_VAAPI_OBJECT_LOCK_DISPLAY(texture);
616 if (priv->gl_context) {
617 success = gl_set_current_context(priv->gl_context, &old_cs);
622 success = gl_bind_framebuffer_object(priv->fbo);
624 GST_DEBUG("could not bind FBO");
625 goto out_reset_context;
628 GST_VAAPI_OBJECT_UNLOCK_DISPLAY(texture);
629 success = gst_vaapi_surface_sync(surface);
630 GST_VAAPI_OBJECT_LOCK_DISPLAY(texture);
632 GST_DEBUG("could not render surface to pixmap");
636 success = gl_bind_pixmap_object(priv->pixo);
638 GST_DEBUG("could not bind GLX pixmap");
642 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
645 glTexCoord2f(0.0f, 0.0f); glVertex2i(0, 0 );
646 glTexCoord2f(0.0f, 1.0f); glVertex2i(0, priv->height);
647 glTexCoord2f(1.0f, 1.0f); glVertex2i(priv->width, priv->height);
648 glTexCoord2f(1.0f, 0.0f); glVertex2i(priv->width, 0 );
652 success = gl_unbind_pixmap_object(priv->pixo);
654 GST_DEBUG("could not release GLX pixmap");
659 if (!gl_unbind_framebuffer_object(priv->fbo))
662 if (priv->gl_context && !gl_set_current_context(&old_cs, NULL))
665 GST_VAAPI_OBJECT_UNLOCK_DISPLAY(texture);
672 gst_vaapi_texture_put_surface(
673 GstVaapiTexture *texture,
674 GstVaapiSurface *surface,
678 g_return_val_if_fail(GST_VAAPI_IS_TEXTURE(texture), FALSE);
679 g_return_val_if_fail(texture->priv->is_constructed, FALSE);
680 g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
682 return _gst_vaapi_texture_put_surface(texture, surface, flags);