* gstvaapisurfaceproxy.c - VA surface proxy
*
* Copyright (C) 2010-2011 Splitted-Desktop Systems
+ * Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ * Copyright (C) 2011-2014 Intel Corporation
+ * Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* @short_description: VA surface proxy
*/
-#include "config.h"
+#include "sysdeps.h"
#include "gstvaapisurfaceproxy.h"
-#include "gstvaapiobject_priv.h"
+#include "gstvaapisurfaceproxy_priv.h"
+#include "gstvaapivideopool_priv.h"
#define DEBUG 1
#include "gstvaapidebug.h"
-G_DEFINE_TYPE(GstVaapiSurfaceProxy, gst_vaapi_surface_proxy, G_TYPE_OBJECT);
-
-#define GST_VAAPI_SURFACE_PROXY_GET_PRIVATE(obj) \
- (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
- GST_VAAPI_TYPE_SURFACE_PROXY, \
- GstVaapiSurfaceProxyPrivate))
-
-struct _GstVaapiSurfaceProxyPrivate {
- GstVaapiContext *context;
- GstVaapiSurface *surface;
- GstClockTime timestamp;
-};
-
-enum {
- PROP_0,
-
- PROP_CONTEXT,
- PROP_SURFACE,
- PROP_TIMESTAMP
-};
-
static void
-gst_vaapi_surface_proxy_finalize(GObject *object)
+gst_vaapi_surface_proxy_finalize(GstVaapiSurfaceProxy *proxy)
{
- GstVaapiSurfaceProxy * const proxy = GST_VAAPI_SURFACE_PROXY(object);
-
- gst_vaapi_surface_proxy_set_surface(proxy, NULL);
- gst_vaapi_surface_proxy_set_context(proxy, NULL);
-
- G_OBJECT_CLASS(gst_vaapi_surface_proxy_parent_class)->finalize(object);
-}
-
-static void
-gst_vaapi_surface_proxy_set_property(
- GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec
-)
-{
- GstVaapiSurfaceProxy * const proxy = GST_VAAPI_SURFACE_PROXY(object);
-
- switch (prop_id) {
- case PROP_CONTEXT:
- gst_vaapi_surface_proxy_set_context(proxy, g_value_get_pointer(value));
- break;
- case PROP_SURFACE:
- gst_vaapi_surface_proxy_set_surface(proxy, g_value_get_pointer(value));
- break;
- case PROP_TIMESTAMP:
- gst_vaapi_surface_proxy_set_timestamp(proxy, g_value_get_uint64(value));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
- break;
+ if (proxy->surface) {
+ if (proxy->pool && !proxy->parent)
+ gst_vaapi_video_pool_put_object(proxy->pool, proxy->surface);
+ gst_vaapi_object_unref(proxy->surface);
+ proxy->surface = NULL;
}
+ gst_vaapi_video_pool_replace(&proxy->pool, NULL);
+ gst_vaapi_surface_proxy_replace(&proxy->parent, NULL);
+
+ /* Notify the user function that the object is now destroyed */
+ if (proxy->destroy_func)
+ proxy->destroy_func(proxy->destroy_data);
}
-static void
-gst_vaapi_surface_proxy_get_property(
- GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec
-)
+static inline const GstVaapiMiniObjectClass *
+gst_vaapi_surface_proxy_class(void)
{
- GstVaapiSurfaceProxy * const proxy = GST_VAAPI_SURFACE_PROXY(object);
-
- switch (prop_id) {
- case PROP_CONTEXT:
- g_value_set_pointer(value, gst_vaapi_surface_proxy_get_context(proxy));
- break;
- case PROP_SURFACE:
- g_value_set_pointer(value, gst_vaapi_surface_proxy_get_surface(proxy));
- break;
- case PROP_TIMESTAMP:
- g_value_set_uint64(value, gst_vaapi_surface_proxy_get_timestamp(proxy));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
- break;
- }
+ static const GstVaapiMiniObjectClass GstVaapiSurfaceProxyClass = {
+ sizeof(GstVaapiSurfaceProxy),
+ (GDestroyNotify)gst_vaapi_surface_proxy_finalize
+ };
+ return &GstVaapiSurfaceProxyClass;
}
-static void
-gst_vaapi_surface_proxy_class_init(GstVaapiSurfaceProxyClass *klass)
+/**
+ * gst_vaapi_surface_proxy_new_from_pool:
+ * @pool: a #GstVaapiSurfacePool
+ *
+ * Allocates a new surface from the supplied surface @pool and creates
+ * the wrapped surface proxy object from it. When the last reference
+ * to the proxy object is released, then the underlying VA surface is
+ * pushed back to its parent pool.
+ *
+ * Returns: The same newly allocated @proxy object, or %NULL on error
+ */
+GstVaapiSurfaceProxy *
+gst_vaapi_surface_proxy_new_from_pool(GstVaapiSurfacePool *pool)
{
- GObjectClass * const object_class = G_OBJECT_CLASS(klass);
-
- g_type_class_add_private(klass, sizeof(GstVaapiSurfaceProxyPrivate));
-
- object_class->finalize = gst_vaapi_surface_proxy_finalize;
- object_class->set_property = gst_vaapi_surface_proxy_set_property;
- object_class->get_property = gst_vaapi_surface_proxy_get_property;
-
- g_object_class_install_property
- (object_class,
- PROP_CONTEXT,
- g_param_spec_pointer("context",
- "Context",
- "The context stored in the proxy",
- G_PARAM_READWRITE));
-
- g_object_class_install_property
- (object_class,
- PROP_SURFACE,
- g_param_spec_pointer("surface",
- "Surface",
- "The surface stored in the proxy",
- G_PARAM_READWRITE));
-
- g_object_class_install_property
- (object_class,
- PROP_TIMESTAMP,
- g_param_spec_uint64("timestamp",
- "Timestamp",
- "The presentation time of the surface",
- 0, G_MAXUINT64, GST_CLOCK_TIME_NONE,
- G_PARAM_READWRITE));
+ GstVaapiSurfaceProxy *proxy;
+
+ g_return_val_if_fail(pool != NULL, NULL);
+
+ proxy = (GstVaapiSurfaceProxy *)
+ gst_vaapi_mini_object_new(gst_vaapi_surface_proxy_class());
+ if (!proxy)
+ return NULL;
+
+ proxy->parent = NULL;
+ proxy->destroy_func = NULL;
+ proxy->pool = gst_vaapi_video_pool_ref(pool);
+ proxy->surface = gst_vaapi_video_pool_get_object(proxy->pool);
+ if (!proxy->surface)
+ goto error;
+ proxy->view_id = 0;
+ proxy->timestamp = GST_CLOCK_TIME_NONE;
+ proxy->duration = GST_CLOCK_TIME_NONE;
+ proxy->has_crop_rect = FALSE;
+ gst_vaapi_object_ref(proxy->surface);
+ return proxy;
+
+error:
+ gst_vaapi_surface_proxy_unref(proxy);
+ return NULL;
}
-static void
-gst_vaapi_surface_proxy_init(GstVaapiSurfaceProxy *proxy)
-{
- GstVaapiSurfaceProxyPrivate *priv;
-
- priv = GST_VAAPI_SURFACE_PROXY_GET_PRIVATE(proxy);
- proxy->priv = priv;
- priv->context = NULL;
- priv->surface = NULL;
- priv->timestamp = GST_CLOCK_TIME_NONE;
-}
/**
- * gst_vaapi_surface_proxy_new:
- * @context: a #GstVaapiContext
- * @surface: a #GstVaapiSurface
+ * gst_vaapi_surface_proxy_copy:
+ * @proxy: the parent #GstVaapiSurfaceProxy
*
- * Creates a new #GstVaapiSurfaceProxy with the specified context and
- * surface.
+ * Creates are new VA surface proxy object from the supplied parent
+ * @proxy object with the same initial information, e.g. timestamp,
+ * duration.
*
- * Return value: the newly allocated #GstVaapiSurfaceProxy object
+ * Note: the destroy notify function is not copied into the new
+ * surface proxy object.
+ *
+ * Returns: The same newly allocated @proxy object, or %NULL on error
*/
GstVaapiSurfaceProxy *
-gst_vaapi_surface_proxy_new(GstVaapiContext *context, GstVaapiSurface *surface)
+gst_vaapi_surface_proxy_copy(GstVaapiSurfaceProxy *proxy)
{
- g_return_val_if_fail(GST_VAAPI_IS_CONTEXT(context), NULL);
- g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), NULL);
-
- return g_object_new(GST_VAAPI_TYPE_SURFACE_PROXY,
- "context", context,
- "surface", surface,
- NULL);
+ GstVaapiSurfaceProxy *copy;
+
+ g_return_val_if_fail(proxy != NULL, NULL);
+
+ copy = (GstVaapiSurfaceProxy *)
+ gst_vaapi_mini_object_new(gst_vaapi_surface_proxy_class());
+ if (!copy)
+ return NULL;
+
+ GST_VAAPI_SURFACE_PROXY_FLAGS(copy) =
+ GST_VAAPI_SURFACE_PROXY_FLAGS(proxy);
+
+ copy->parent = gst_vaapi_surface_proxy_ref(proxy->parent ?
+ proxy->parent : proxy);
+ copy->pool = gst_vaapi_video_pool_ref(proxy->pool);
+ copy->surface = gst_vaapi_object_ref(proxy->surface);
+ copy->timestamp = proxy->timestamp;
+ copy->duration = proxy->duration;
+ copy->destroy_func = NULL;
+ copy->has_crop_rect = proxy->has_crop_rect;
+ if (copy->has_crop_rect)
+ copy->crop_rect = proxy->crop_rect;
+ return copy;
}
/**
- * gst_vaapi_surface_proxy_get_context:
+ * gst_vaapi_surface_proxy_ref:
* @proxy: a #GstVaapiSurfaceProxy
*
- * Returns the #GstVaapiContext stored in the @proxy.
+ * Atomically increases the reference count of the given @proxy by one.
*
- * Return value: the #GstVaapiContext
+ * Returns: The same @proxy argument
*/
-GstVaapiContext *
-gst_vaapi_surface_proxy_get_context(GstVaapiSurfaceProxy *proxy)
+GstVaapiSurfaceProxy *
+gst_vaapi_surface_proxy_ref(GstVaapiSurfaceProxy *proxy)
{
- g_return_val_if_fail(GST_VAAPI_IS_SURFACE_PROXY(proxy), NULL);
+ g_return_val_if_fail(proxy != NULL, NULL);
- return proxy->priv->context;
+ return GST_VAAPI_SURFACE_PROXY(gst_vaapi_mini_object_ref(
+ GST_VAAPI_MINI_OBJECT(proxy)));
}
/**
- * gst_vaapi_surface_proxy_set_context:
+ * gst_vaapi_surface_proxy_unref:
* @proxy: a #GstVaapiSurfaceProxy
- * @context: the new #GstVaapiContext to be stored in @proxy
*
- * Stores a new @context into the @proxy. The proxy releases the
- * previous reference, if any, and then holds a reference to the new
- * @context.
+ * Atomically decreases the reference count of the @proxy by one. If
+ * the reference count reaches zero, the object will be free'd.
*/
void
-gst_vaapi_surface_proxy_set_context(
- GstVaapiSurfaceProxy *proxy,
- GstVaapiContext *context
-)
+gst_vaapi_surface_proxy_unref(GstVaapiSurfaceProxy *proxy)
{
- GstVaapiSurfaceProxyPrivate *priv;
-
- g_return_if_fail(GST_VAAPI_IS_SURFACE_PROXY(proxy));
+ g_return_if_fail(proxy != NULL);
- priv = proxy->priv;
+ gst_vaapi_mini_object_unref(GST_VAAPI_MINI_OBJECT(proxy));
+}
- if (priv->context) {
- g_object_unref(priv->context);
- priv->context = NULL;
- }
+/**
+ * gst_vaapi_surface_proxy_replace:
+ * @old_proxy_ptr: a pointer to a #GstVaapiSurfaceProxy
+ * @new_proxy: a #GstVaapiSurfaceProxy
+ *
+ * Atomically replaces the proxy object held in @old_proxy_ptr with
+ * @new_proxy. This means that @old_proxy_ptr shall reference a valid
+ * object. However, @new_proxy can be NULL.
+ */
+void
+gst_vaapi_surface_proxy_replace(GstVaapiSurfaceProxy **old_proxy_ptr,
+ GstVaapiSurfaceProxy *new_proxy)
+{
+ g_return_if_fail(old_proxy_ptr != NULL);
- if (context)
- priv->context = g_object_ref(context);
+ gst_vaapi_mini_object_replace((GstVaapiMiniObject **)old_proxy_ptr,
+ GST_VAAPI_MINI_OBJECT(new_proxy));
}
/**
GstVaapiSurface *
gst_vaapi_surface_proxy_get_surface(GstVaapiSurfaceProxy *proxy)
{
- g_return_val_if_fail(GST_VAAPI_IS_SURFACE_PROXY(proxy), NULL);
+ g_return_val_if_fail(proxy != NULL, NULL);
- return proxy->priv->surface;
+ return GST_VAAPI_SURFACE_PROXY_SURFACE(proxy);
+}
+
+/**
+ * gst_vaapi_surface_proxy_get_flags:
+ * @proxy: a #GstVaapiSurfaceProxy
+ *
+ * Returns the #GstVaapiSurfaceProxyFlags associated with this surface
+ * @proxy.
+ *
+ * Return value: the set of #GstVaapiSurfaceProxyFlags
+ */
+guint
+gst_vaapi_surface_proxy_get_flags(GstVaapiSurfaceProxy *proxy)
+{
+ g_return_val_if_fail(proxy != NULL, 0);
+
+ return GST_VAAPI_SURFACE_PROXY_FLAGS(proxy);
}
/**
GstVaapiID
gst_vaapi_surface_proxy_get_surface_id(GstVaapiSurfaceProxy *proxy)
{
- g_return_val_if_fail(GST_VAAPI_IS_SURFACE_PROXY(proxy), GST_VAAPI_ID_NONE);
- g_return_val_if_fail(proxy->priv->surface != NULL, GST_VAAPI_ID_NONE);
+ g_return_val_if_fail(proxy != NULL, VA_INVALID_ID);
+ g_return_val_if_fail(proxy->surface != NULL, VA_INVALID_ID);
- return GST_VAAPI_OBJECT_ID(proxy->priv->surface);
+ return GST_VAAPI_SURFACE_PROXY_SURFACE_ID(proxy);
}
/**
- * gst_vaapi_surface_proxy_set_surface:
+ * gst_vaapi_surface_proxy_get_view_id:
* @proxy: a #GstVaapiSurfaceProxy
- * @surface: the new #GstVaapiSurface to be stored in @proxy
*
- * Stores a new @surface into the @proxy. The proxy releases the
- * previous reference, if any, and then holds a reference to the new
- * @surface.
+ * Returns the decoded view-id stored in the @proxy.
+ *
+ * Return value: the #GstVaapiID
*/
-void
-gst_vaapi_surface_proxy_set_surface(
- GstVaapiSurfaceProxy *proxy,
- GstVaapiSurface *surface
-)
+guintptr
+gst_vaapi_surface_proxy_get_view_id(GstVaapiSurfaceProxy *proxy)
{
- GstVaapiSurfaceProxyPrivate *priv;
-
- g_return_if_fail(GST_VAAPI_IS_SURFACE_PROXY(proxy));
-
- priv = proxy->priv;
+ g_return_val_if_fail(proxy != NULL, 0);
- if (priv->surface) {
- if (priv->context)
- gst_vaapi_context_put_surface(priv->context, priv->surface);
- g_object_unref(priv->surface);
- priv->surface = NULL;
- }
-
- if (surface)
- priv->surface = g_object_ref(surface);
+ return GST_VAAPI_SURFACE_PROXY_VIEW_ID(proxy);
}
/**
* gst_vaapi_surface_proxy_get_timestamp:
* @proxy: a #GstVaapiSurfaceProxy
*
- * Returns the presentation timestamp of the #GstVaapiSurface held by @proxy.
+ * Returns the presentation timestamp for this surface @proxy.
*
- * Return value: the presentation timestamp of the surface, or
- * %GST_CLOCK_TIME_NONE is none was set
+ * Return value: the presentation timestamp
*/
GstClockTime
gst_vaapi_surface_proxy_get_timestamp(GstVaapiSurfaceProxy *proxy)
{
- g_return_val_if_fail(GST_VAAPI_IS_SURFACE_PROXY(proxy), GST_CLOCK_TIME_NONE);
+ g_return_val_if_fail(proxy != NULL, 0);
+
+ return GST_VAAPI_SURFACE_PROXY_TIMESTAMP(proxy);
+}
+
+/**
+ * gst_vaapi_surface_proxy_get_duration:
+ * @proxy: a #GstVaapiSurfaceProxy
+ *
+ * Returns the presentation duration for this surface @proxy.
+ *
+ * Return value: the presentation duration
+ */
+GstClockTime
+gst_vaapi_surface_proxy_get_duration(GstVaapiSurfaceProxy *proxy)
+{
+ g_return_val_if_fail(proxy != NULL, 0);
+
+ return GST_VAAPI_SURFACE_PROXY_DURATION(proxy);
+}
+
+/**
+ * gst_vaapi_surface_proxy_set_destroy_notify:
+ * @proxy: a @GstVaapiSurfaceProxy
+ * @destroy_func: a #GDestroyNotify function
+ * @user_data: some extra data to pass to the @destroy_func function
+ *
+ * Sets @destroy_func as the function to call when the surface @proxy
+ * was released. At this point, the proxy object is considered
+ * released, i.e. the underlying data storage is no longer valid and
+ * the callback function shall not expect anything from that.
+ */
+void
+gst_vaapi_surface_proxy_set_destroy_notify(GstVaapiSurfaceProxy *proxy,
+ GDestroyNotify destroy_func, gpointer user_data)
+{
+ g_return_if_fail(proxy != NULL);
- return proxy->priv->timestamp;
+ proxy->destroy_func = destroy_func;
+ proxy->destroy_data = user_data;
}
/**
- * gst_vaapi_surface_proxy_set_timestamp:
+ * gst_vaapi_surface_proxy_get_crop_rect:
* @proxy: a #GstVaapiSurfaceProxy
- * @timestamp: the new presentation timestamp as a #GstClockTime
*
- * Sets the presentation timestamp of the @proxy surface to @timestamp.
+ * Returns the #GstVaapiRectangle stored in the @proxy and that
+ * represents the cropping rectangle for the underlying surface to be
+ * used for rendering.
+ *
+ * If no cropping rectangle was associated with the @proxy, then this
+ * function returns %NULL.
+ *
+ * Return value: the #GstVaapiRectangle, or %NULL if none was
+ * associated with the surface proxy
+ */
+const GstVaapiRectangle *
+gst_vaapi_surface_proxy_get_crop_rect(GstVaapiSurfaceProxy *proxy)
+{
+ g_return_val_if_fail(proxy != NULL, NULL);
+
+ return GST_VAAPI_SURFACE_PROXY_CROP_RECT(proxy);
+}
+
+/**
+ * gst_vaapi_surface_proxy_set_crop_rect:
+ * @proxy: #GstVaapiSurfaceProxy
+ * @crop_rect: the #GstVaapiRectangle to be stored in @proxy
+ *
+ * Associates the @crop_rect with the @proxy
*/
void
-gst_vaapi_surface_proxy_set_timestamp(
- GstVaapiSurfaceProxy *proxy,
- GstClockTime timestamp
-)
+gst_vaapi_surface_proxy_set_crop_rect(GstVaapiSurfaceProxy *proxy,
+ const GstVaapiRectangle *crop_rect)
{
- g_return_if_fail(GST_VAAPI_IS_SURFACE_PROXY(proxy));
+ g_return_if_fail(proxy != NULL);
- proxy->priv->timestamp = timestamp;
+ proxy->has_crop_rect = crop_rect != NULL;
+ if (proxy->has_crop_rect)
+ proxy->crop_rect = *crop_rect;
}