decoder: propagate MVC metadata ("view-id", head of multiview set).
[platform/upstream/gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapisurfaceproxy.c
index c67e8cb..ab8f508 100644 (file)
@@ -2,6 +2,9 @@
  *  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));
 }
 
 /**
@@ -243,9 +207,26 @@ gst_vaapi_surface_proxy_set_context(
 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);
 }
 
 /**
@@ -259,75 +240,117 @@ gst_vaapi_surface_proxy_get_surface(GstVaapiSurfaceProxy *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;
 }