vaapisink: add support for raw YUV buffers.
authorGwenole Beauchesne <gwenole.beauchesne@intel.com>
Tue, 20 Nov 2012 13:28:55 +0000 (14:28 +0100)
committerWei,changzhi <changzhix.wei@intel.com>
Wed, 17 Apr 2013 08:14:39 +0000 (16:14 +0800)
Add new GstVaapiUploader helper to upload raw YUV buffers to VA surfaces.
It is up to the caller to negotiate source caps (for images) and output
caps (for surfaces). gst_vaapi_uploader_has_direct_rendering() is available
to help decide between the creation of a GstVaapiVideoBuffer or a regular
GstBuffer on sink pads.

Signed-off-by: Zhao Halley <halley.zhao@intel.com>
Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
NEWS
gst/vaapi/Makefile.am
gst/vaapi/gstvaapisink.c
gst/vaapi/gstvaapisink.h
gst/vaapi/gstvaapiuploader.c [new file with mode: 0644]
gst/vaapi/gstvaapiuploader.h [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 6acabbe..8e00bc2 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,7 @@ Version 0.4.2 - 18.Dec.2012
 * Fix memory leak in GstVaapiVideoBuffer for images and surfaces (Feng Yuan)
 * Fix symbols collision between built-in codecparsers/ and system library
 * Use GST_PLUGIN_PATH, if set, to install plugin elements (Halley Zhao)
+* Add support for raw YUV buffers in vaapisink (+Halley Zhao)
 
 Version 0.4.1 - 27.Nov.2012
 * Add support for H.264 interlaced streams
index ebe46bb..b473907 100644 (file)
@@ -38,6 +38,7 @@ libgstvaapi_la_SOURCES =      \
        gstvaapipostproc.c      \
        gstvaapisink.c          \
        gstvaapiupload.c        \
+       gstvaapiuploader.c      \
        $(NULL)
 
 noinst_HEADERS =               \
@@ -48,6 +49,7 @@ noinst_HEADERS =              \
        gstvaapipostproc.h      \
        gstvaapisink.h          \
        gstvaapiupload.h        \
+       gstvaapiuploader.h      \
        $(NULL)
 
 if USE_ENCODERS
index 46246db..e4f4a05 100755 (executable)
@@ -72,12 +72,18 @@ static const GstElementDetails gst_vaapisink_details =
         "Gwenole Beauchesne <gwenole.beauchesne@intel.com>");
 
 /* Default template */
+static const char gst_vaapisink_sink_caps_str[] =
+    "video/x-raw-yuv, "
+    "width  = (int) [ 1, MAX ], "
+    "height = (int) [ 1, MAX ]; "
+    GST_VAAPI_SURFACE_CAPS;
+
 static GstStaticPadTemplate gst_vaapisink_sink_factory =
     GST_STATIC_PAD_TEMPLATE(
         "sink",
         GST_PAD_SINK,
         GST_PAD_ALWAYS,
-        GST_STATIC_CAPS(GST_VAAPI_SURFACE_CAPS));
+        GST_STATIC_CAPS(gst_vaapisink_sink_caps_str));
 
 static void
 gst_vaapisink_implements_iface_init(GstImplementsInterfaceClass *iface);
@@ -268,6 +274,7 @@ gst_vaapisink_destroy(GstVaapiSink *sink)
     gst_buffer_replace(&sink->video_buffer, NULL);
     g_clear_object(&sink->texture);
     g_clear_object(&sink->display);
+    g_clear_object(&sink->uploader);
 
     gst_caps_replace(&sink->caps, NULL);
 }
@@ -628,7 +635,13 @@ gst_vaapisink_start(GstBaseSink *base_sink)
 {
     GstVaapiSink * const sink = GST_VAAPISINK(base_sink);
 
-    return gst_vaapisink_ensure_display(sink);
+    if (!gst_vaapisink_ensure_display(sink))
+        return FALSE;
+
+    sink->uploader = gst_vaapi_uploader_new(sink->display);
+    if (!sink->uploader)
+        return FALSE;
+    return TRUE;
 }
 
 static gboolean
@@ -650,6 +663,7 @@ gst_vaapisink_stop(GstBaseSink *base_sink)
     sink->window = NULL;
     
     g_clear_object(&sink->display);
+    g_clear_object(&sink->uploader);
 
     return TRUE;
 }
@@ -676,6 +690,9 @@ gst_vaapisink_set_caps(GstBaseSink *base_sink, GstCaps *caps)
     sink->video_width  = video_width;
     sink->video_height = video_height;
 
+    if (gst_structure_has_name(structure, "video/x-raw-yuv"))
+        sink->use_video_raw = TRUE;
+
     gst_video_parse_caps_pixel_aspect_ratio(caps, &video_par_n, &video_par_d);
     sink->video_par_n  = video_par_n;
     sink->video_par_d  = video_par_d;
@@ -888,26 +905,45 @@ static GstFlowReturn
 gst_vaapisink_show_frame(GstBaseSink *base_sink, GstBuffer *buffer)
 {
     GstVaapiSink * const sink = GST_VAAPISINK(base_sink);
-    GstVaapiVideoBuffer * const vbuffer = GST_VAAPI_VIDEO_BUFFER(buffer);
+    GstVaapiVideoBuffer *vbuffer;
     GstVaapiSurface *surface;
     guint flags;
     gboolean success;
     GstVideoOverlayComposition * const composition =
         gst_video_buffer_get_overlay_composition(buffer);
 
+    if (!sink->use_video_raw)
+        buffer = gst_buffer_ref(buffer);
+    else {
+        GstBuffer * const src_buffer = buffer;
+        if (GST_VAAPI_IS_VIDEO_BUFFER(buffer))
+            buffer = gst_buffer_ref(src_buffer);
+        else if (GST_VAAPI_IS_VIDEO_BUFFER(buffer->parent))
+            buffer = gst_buffer_ref(src_buffer->parent);
+        else {
+            buffer = gst_vaapi_uploader_get_buffer(sink->uploader);
+            if (!buffer)
+                return GST_FLOW_UNEXPECTED;
+        }
+        if (!gst_vaapi_uploader_process(sink->uploader, src_buffer, buffer))
+            goto error;
+    }
+    vbuffer = GST_VAAPI_VIDEO_BUFFER(buffer);
+    g_return_val_if_fail(vbuffer != NULL, GST_FLOW_UNEXPECTED);
+
     if (sink->display != gst_vaapi_video_buffer_get_display (vbuffer)) {
       g_clear_object(&sink->display);
       sink->display = g_object_ref (gst_vaapi_video_buffer_get_display (vbuffer));
     }
 
     if (!sink->window)
-        return GST_FLOW_UNEXPECTED;
+        goto error;
 
     gst_vaapisink_ensure_rotation(sink, TRUE);
 
     surface = gst_vaapi_video_buffer_get_surface(vbuffer);
     if (!surface)
-        return GST_FLOW_UNEXPECTED;
+        goto error;
 
     GST_DEBUG("render surface %" GST_VAAPI_ID_FORMAT,
               GST_VAAPI_ID_ARGS(gst_vaapi_surface_get_id(surface)));
@@ -945,11 +981,50 @@ gst_vaapisink_show_frame(GstBaseSink *base_sink, GstBuffer *buffer)
         break;
     }
     if (!success)
-        return GST_FLOW_UNEXPECTED;
+        goto error;
 
     /* Retain VA surface until the next one is displayed */
     if (sink->use_overlay)
         gst_buffer_replace(&sink->video_buffer, buffer);
+    gst_buffer_unref(buffer);
+    return GST_FLOW_OK;
+
+error:
+    gst_buffer_unref(buffer);
+    return GST_FLOW_UNEXPECTED;
+}
+
+static GstFlowReturn
+gst_vaapisink_buffer_alloc(
+    GstBaseSink        *base_sink,
+    guint64             offset,
+    guint               size,
+    GstCaps            *caps,
+    GstBuffer         **pbuf
+)
+{
+    GstVaapiSink * const sink = GST_VAAPISINK(base_sink);
+    GstStructure *structure;
+    GstBuffer *buf;
+
+    *pbuf = NULL;
+
+    structure = gst_caps_get_structure(caps, 0);
+    if (!gst_structure_has_name(structure, "video/x-raw-yuv"))
+        return GST_FLOW_OK;
+
+    if (!gst_vaapi_uploader_ensure_display(sink->uploader, sink->display))
+        return GST_FLOW_NOT_SUPPORTED;
+    if (!gst_vaapi_uploader_ensure_caps(sink->uploader, caps, NULL))
+        return GST_FLOW_NOT_SUPPORTED;
+
+    buf = gst_vaapi_uploader_get_buffer(sink->uploader);
+    if (!buf) {
+        GST_WARNING("failed to allocate resources for raw YUV buffer");
+        return GST_FLOW_NOT_SUPPORTED;
+    }
+
+    *pbuf = buf;
     return GST_FLOW_OK;
 }
 
@@ -1060,6 +1135,7 @@ gst_vaapisink_class_init(GstVaapiSinkClass *klass)
     basesink_class->preroll      = gst_vaapisink_show_frame;
     basesink_class->render       = gst_vaapisink_show_frame;
     basesink_class->query        = gst_vaapisink_query;
+    basesink_class->buffer_alloc = gst_vaapisink_buffer_alloc;
 
     gst_element_class_set_details_simple(
         element_class,
index 774bb40..66b30e0 100755 (executable)
@@ -30,6 +30,7 @@
 #include <gst/vaapi/gstvaapitexture.h>
 #endif
 #include "gstvaapipluginutil.h"
+#include "gstvaapiuploader.h"
 
 G_BEGIN_DECLS
 
@@ -69,6 +70,7 @@ struct _GstVaapiSink {
     /*< private >*/
     GstVideoSink parent_instance;
 
+    GstVaapiUploader   *uploader;
     GstCaps            *caps;
     GstVaapiDisplay    *display;
     GstVaapiDisplayType display_type;
@@ -90,6 +92,7 @@ struct _GstVaapiSink {
     guint               use_reflection  : 1;
     guint               use_overlay     : 1;
     guint               use_rotation    : 1;
+    guint               use_video_raw   : 1;
     guint               is_pixmap       : 1;
     GstVaapiWindow     *pixmap_pool[MAX_PIXMAP_COUNT];
 };
diff --git a/gst/vaapi/gstvaapiuploader.c b/gst/vaapi/gstvaapiuploader.c
new file mode 100644 (file)
index 0000000..d7ba1f9
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ *  gstvaapiuploader.c - VA-API video upload helper
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *  Copyright (C) 2011-2012 Intel Corporation
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "gst/vaapi/sysdeps.h"
+#include <gst/video/video.h>
+#include <gst/vaapi/gstvaapisurface.h>
+#include <gst/vaapi/gstvaapiimagepool.h>
+#include <gst/vaapi/gstvaapisurfacepool.h>
+#include <gst/vaapi/gstvaapivideobuffer.h>
+
+#include "gstvaapiuploader.h"
+#include "gstvaapipluginbuffer.h"
+
+#define GST_HELPER_NAME "vaapiupload"
+#define GST_HELPER_DESC "VA-API video uploader"
+
+GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapi_uploader);
+#define GST_CAT_DEFAULT gst_debug_vaapi_uploader
+
+G_DEFINE_TYPE(GstVaapiUploader, gst_vaapi_uploader, G_TYPE_OBJECT)
+
+#define GST_VAAPI_UPLOADER_CAST(obj) \
+    ((GstVaapiUploader *)(obj))
+
+#define GST_VAAPI_UPLOADER_GET_PRIVATE(obj)                     \
+    (G_TYPE_INSTANCE_GET_PRIVATE((obj),                         \
+                                 GST_VAAPI_TYPE_UPLOADER,      \
+                                 GstVaapiUploaderPrivate))
+
+struct _GstVaapiUploaderPrivate {
+    GstVaapiDisplay    *display;
+    GstVaapiVideoPool  *images;
+    GstCaps            *image_caps;
+    guint               image_width;
+    guint               image_height;
+    GstVaapiVideoPool  *surfaces;
+    guint               surface_width;
+    guint               surface_height;
+    guint               direct_rendering;
+};
+
+enum {
+    PROP_0,
+
+    PROP_DISPLAY,
+};
+
+static void
+gst_vaapi_uploader_destroy(GstVaapiUploader *uploader)
+{
+    GstVaapiUploaderPrivate * const priv = uploader->priv;
+
+    gst_caps_replace(&priv->image_caps, NULL);
+    g_clear_object(&priv->images);
+    g_clear_object(&priv->surfaces);
+    g_clear_object(&priv->display);
+}
+
+static gboolean
+ensure_display(GstVaapiUploader *uploader, GstVaapiDisplay *display)
+{
+    GstVaapiUploaderPrivate * const priv = uploader->priv;
+
+    if (priv->display == display)
+        return TRUE;
+
+    g_clear_object(&priv->display);
+    if (display)
+        priv->display = g_object_ref(display);
+    return TRUE;
+}
+
+static gboolean
+ensure_image_pool(GstVaapiUploader *uploader, GstCaps *caps)
+{
+    GstVaapiUploaderPrivate * const priv = uploader->priv;
+    GstStructure * const structure = gst_caps_get_structure(caps, 0);
+    gint width, height;
+
+    gst_structure_get_int(structure, "width",  &width);
+    gst_structure_get_int(structure, "height", &height);
+
+    if (width != priv->image_width || height != priv->image_height) {
+        priv->image_width  = width;
+        priv->image_height = height;
+        g_clear_object(&priv->images);
+        priv->images = gst_vaapi_image_pool_new(priv->display, caps);
+        if (!priv->images)
+            return FALSE;
+        gst_caps_replace(&priv->image_caps, caps);
+    }
+    return TRUE;
+}
+
+static gboolean
+ensure_surface_pool(GstVaapiUploader *uploader, GstCaps *caps)
+{
+    GstVaapiUploaderPrivate * const priv = uploader->priv;
+    GstStructure * const structure = gst_caps_get_structure(caps, 0);
+    gint width, height;
+
+    gst_structure_get_int(structure, "width",  &width);
+    gst_structure_get_int(structure, "height", &height);
+
+    if (width != priv->surface_width || height != priv->surface_height) {
+        priv->surface_width  = width;
+        priv->surface_height = height;
+        g_clear_object(&priv->surfaces);
+        priv->surfaces = gst_vaapi_surface_pool_new(priv->display, caps);
+        if (!priv->surfaces)
+            return FALSE;
+    }
+    return TRUE;
+}
+
+static void
+gst_vaapi_uploader_finalize(GObject *object)
+{
+    gst_vaapi_uploader_destroy(GST_VAAPI_UPLOADER_CAST(object));
+
+    G_OBJECT_CLASS(gst_vaapi_uploader_parent_class)->finalize(object);
+}
+
+static void
+gst_vaapi_uploader_set_property(GObject *object, guint prop_id,
+    const GValue *value, GParamSpec *pspec)
+{
+    GstVaapiUploader * const uploader = GST_VAAPI_UPLOADER_CAST(object);
+
+    switch (prop_id) {
+    case PROP_DISPLAY:
+        ensure_display(uploader, g_value_get_object(value));
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+gst_vaapi_uploader_get_property(GObject *object, guint prop_id,
+    GValue *value, GParamSpec *pspec)
+{
+    GstVaapiUploader * const uploader = GST_VAAPI_UPLOADER_CAST(object);
+
+    switch (prop_id) {
+    case PROP_DISPLAY:
+        g_value_set_object(value, uploader->priv->display);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+gst_vaapi_uploader_class_init(GstVaapiUploaderClass *klass)
+{
+    GObjectClass * const object_class = G_OBJECT_CLASS(klass);
+
+    GST_DEBUG_CATEGORY_INIT(gst_debug_vaapi_uploader,
+        GST_HELPER_NAME, 0, GST_HELPER_DESC);
+
+    g_type_class_add_private(klass, sizeof(GstVaapiUploaderPrivate));
+
+    object_class->finalize      = gst_vaapi_uploader_finalize;
+    object_class->set_property = gst_vaapi_uploader_set_property;
+    object_class->get_property = gst_vaapi_uploader_get_property;
+
+    g_object_class_install_property(
+        object_class,
+        PROP_DISPLAY,
+        g_param_spec_object(
+            "display",
+            "Display",
+            "The GstVaapiDisplay this object is bound to",
+            GST_VAAPI_TYPE_DISPLAY,
+            G_PARAM_READWRITE));
+}
+
+static void
+gst_vaapi_uploader_init(GstVaapiUploader *uploader)
+{
+    GstVaapiUploaderPrivate *priv;
+
+    priv                = GST_VAAPI_UPLOADER_GET_PRIVATE(uploader);
+    uploader->priv      = priv;
+}
+
+GstVaapiUploader *
+gst_vaapi_uploader_new(GstVaapiDisplay *display)
+{
+    return g_object_new(GST_VAAPI_TYPE_UPLOADER, "display", display, NULL);
+}
+
+gboolean
+gst_vaapi_uploader_ensure_display(
+    GstVaapiUploader *uploader,
+    GstVaapiDisplay  *display
+)
+{
+    g_return_val_if_fail(GST_VAAPI_IS_UPLOADER(uploader), FALSE);
+    g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), FALSE);
+
+    return ensure_display(uploader,display);
+}
+
+gboolean
+gst_vaapi_uploader_ensure_caps(
+    GstVaapiUploader *uploader,
+    GstCaps          *src_caps,
+    GstCaps          *out_caps
+)
+{
+    GstVaapiUploaderPrivate *priv;
+    GstVaapiImage *image;
+    GstVaapiImageFormat vaformat;
+    GstVideoFormat vformat;
+    GstStructure *structure;
+    gint width, height;
+
+    g_return_val_if_fail(GST_VAAPI_IS_UPLOADER(uploader), FALSE);
+    g_return_val_if_fail(src_caps != NULL, FALSE);
+
+    if (!ensure_image_pool(uploader, src_caps))
+        return FALSE;
+    if (!ensure_surface_pool(uploader, out_caps ? out_caps : src_caps))
+        return FALSE;
+
+    priv = uploader->priv;
+
+    structure = gst_caps_get_structure(src_caps, 0);
+    if (!structure)
+        return FALSE;
+    gst_structure_get_int(structure, "width",  &width);
+    gst_structure_get_int(structure, "height", &height);
+
+    /* Translate from Gst video format to VA image format */
+    if (!gst_video_format_parse_caps(src_caps, &vformat, NULL, NULL))
+        return FALSE;
+    if (!gst_video_format_is_yuv(vformat))
+        return FALSE;
+    vaformat = gst_vaapi_image_format_from_video(vformat);
+    if (!vaformat)
+        return FALSE;
+
+    /* Check if we can alias source and output buffers (same data_size) */
+    image = gst_vaapi_video_pool_get_object(priv->images);
+    if (image) {
+        if (gst_vaapi_image_get_format(image) == vaformat &&
+            gst_vaapi_image_is_linear(image) &&
+            (gst_vaapi_image_get_data_size(image) ==
+             gst_video_format_get_size(vformat, width, height)))
+            priv->direct_rendering = 1;
+        gst_vaapi_video_pool_put_object(priv->images, image);
+    }
+    return TRUE;
+}
+
+gboolean
+gst_vaapi_uploader_process(
+    GstVaapiUploader *uploader,
+    GstBuffer        *src_buffer,
+    GstBuffer        *out_buffer
+)
+{
+    GstVaapiVideoBuffer *out_vbuffer;
+    GstVaapiSurface *surface;
+    GstVaapiImage *image;
+
+    g_return_val_if_fail(GST_VAAPI_IS_UPLOADER(uploader), FALSE);
+
+    if (GST_VAAPI_IS_VIDEO_BUFFER(out_buffer))
+        out_vbuffer = GST_VAAPI_VIDEO_BUFFER(out_buffer);
+    else if (GST_VAAPI_IS_VIDEO_BUFFER(out_buffer->parent))
+        out_vbuffer = GST_VAAPI_VIDEO_BUFFER(out_buffer->parent);
+    else {
+        GST_WARNING("expected an output video buffer");
+        return FALSE;
+    }
+
+    surface = gst_vaapi_video_buffer_get_surface(out_vbuffer);
+    g_return_val_if_fail(surface != NULL, FALSE);
+
+    if (GST_VAAPI_IS_VIDEO_BUFFER(src_buffer)) {
+        /* GstVaapiVideoBuffer with mapped VA image */
+        image = gst_vaapi_video_buffer_get_image(
+            GST_VAAPI_VIDEO_BUFFER(src_buffer));
+        if (!image || !gst_vaapi_image_unmap(image))
+            return FALSE;
+    }
+    else if (GST_VAAPI_IS_VIDEO_BUFFER(src_buffer->parent)) {
+        /* Sub-buffer from GstVaapiVideoBuffer with mapped VA image */
+        image = gst_vaapi_video_buffer_get_image(
+            GST_VAAPI_VIDEO_BUFFER(src_buffer->parent));
+        if (!image || !gst_vaapi_image_unmap(image))
+            return FALSE;
+    }
+    else {
+        /* Regular GstBuffer that needs to be uploaded to a VA image */
+        image = gst_vaapi_video_buffer_get_image(out_vbuffer);
+        if (!image) {
+            image = gst_vaapi_video_pool_get_object(uploader->priv->images);
+            if (!image)
+                return FALSE;
+            gst_vaapi_video_buffer_set_image(out_vbuffer, image);
+        }
+        if (!gst_vaapi_image_update_from_buffer(image, src_buffer, NULL))
+            return FALSE;
+    }
+    g_return_val_if_fail(image != NULL, FALSE);
+
+    if (!gst_vaapi_surface_put_image(surface, image)) {
+        GST_WARNING("failed to upload YUV buffer to VA surface");
+        return FALSE;
+    }
+
+    /* Map again for next uploads */
+    if (!gst_vaapi_image_map(image))
+        return FALSE;
+    return TRUE;
+}
+
+GstBuffer *
+gst_vaapi_uploader_get_buffer(GstVaapiUploader *uploader)
+{
+    GstVaapiUploaderPrivate *priv;
+    GstVaapiSurface *surface;
+    GstVaapiImage *image;
+    GstVaapiVideoBuffer *vbuffer;
+    GstBuffer *buffer = NULL;
+
+    g_return_val_if_fail(GST_VAAPI_IS_UPLOADER(uploader), NULL);
+
+    priv = uploader->priv;
+
+    buffer = gst_vaapi_video_buffer_new_from_pool(priv->images);
+    if (!buffer) {
+        GST_WARNING("failed to allocate video buffer");
+        goto error;
+    }
+    vbuffer = GST_VAAPI_VIDEO_BUFFER(buffer);
+
+    surface = gst_vaapi_video_pool_get_object(priv->surfaces);
+    if (!surface) {
+        GST_WARNING("failed to allocate VA surface");
+        goto error;
+    }
+
+    gst_vaapi_video_buffer_set_surface(vbuffer, surface);
+
+    image = gst_vaapi_video_buffer_get_image(vbuffer);
+    if (!gst_vaapi_image_map(image)) {
+        GST_WARNING("failed to map VA image");
+        goto error;
+    }
+
+    GST_BUFFER_DATA(buffer) = gst_vaapi_image_get_plane(image, 0);
+    GST_BUFFER_SIZE(buffer) = gst_vaapi_image_get_data_size(image);
+
+    gst_buffer_set_caps(buffer, priv->image_caps);
+    return buffer;
+
+error:
+    gst_buffer_unref(buffer);
+    return buffer;
+}
+
+gboolean
+gst_vaapi_uploader_has_direct_rendering(GstVaapiUploader *uploader)
+{
+    g_return_val_if_fail(GST_VAAPI_IS_UPLOADER(uploader), FALSE);
+
+    return uploader->priv->direct_rendering;
+}
diff --git a/gst/vaapi/gstvaapiuploader.h b/gst/vaapi/gstvaapiuploader.h
new file mode 100644 (file)
index 0000000..06f62d3
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ *  gstvaapiuploader.h - VA-API video upload helper
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *  Copyright (C) 2011-2012 Intel Corporation
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+*/
+
+#ifndef GST_VAAPIUPLOADER_H
+#define GST_VAAPIUPLOADER_H
+
+#include <gst/vaapi/gstvaapidisplay.h>
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_TYPE_UPLOADER \
+    (gst_vaapi_uploader_get_type())
+
+#define GST_VAAPI_UPLOADER(obj)                                 \
+    (G_TYPE_CHECK_INSTANCE_CAST((obj),                          \
+                                GST_VAAPI_TYPE_UPLOADER,        \
+                                GstVaapiUploader))
+
+#define GST_VAAPI_UPLOADER_CLASS(klass)                         \
+    (G_TYPE_CHECK_CLASS_CAST((klass),                           \
+                             GST_VAAPI_TYPE_UPLOADER,           \
+                             GstVaapiUploaderClass))
+
+#define GST_VAAPI_IS_UPLOADER(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_UPLOADER))
+
+#define GST_VAAPI_IS_UPLOADER_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_UPLOADER))
+
+#define GST_VAAPI_UPLOADER_GET_CLASS(obj)                       \
+    (G_TYPE_INSTANCE_GET_CLASS((obj),                           \
+                               GST_VAAPI_TYPE_UPLOADER,         \
+                               GstVaapiUploaderClass))
+
+typedef struct _GstVaapiUploader                GstVaapiUploader;
+typedef struct _GstVaapiUploaderPrivate         GstVaapiUploaderPrivate;
+typedef struct _GstVaapiUploaderClass           GstVaapiUploaderClass;
+
+struct _GstVaapiUploader {
+    /*< private >*/
+    GObject             parent_instance;
+
+    GstVaapiUploaderPrivate *priv;
+};
+
+struct _GstVaapiUploaderClass {
+    /*< private >*/
+    GObjectClass        parent_class;
+};
+
+G_GNUC_INTERNAL
+GType
+gst_vaapi_uploader_get_type(void) G_GNUC_CONST;
+
+G_GNUC_INTERNAL
+GstVaapiUploader *
+gst_vaapi_uploader_new(GstVaapiDisplay *display);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_uploader_ensure_display(
+    GstVaapiUploader *uploader,
+    GstVaapiDisplay  *display
+);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_uploader_ensure_caps(
+    GstVaapiUploader *uploader,
+    GstCaps          *src_caps,
+    GstCaps          *out_caps
+);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_uploader_process(
+    GstVaapiUploader *uploader,
+    GstBuffer        *src_buffer,
+    GstBuffer        *out_buffer
+);
+
+G_GNUC_INTERNAL
+GstBuffer *
+gst_vaapi_uploader_get_buffer(GstVaapiUploader *uploader);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_uploader_has_direct_rendering(GstVaapiUploader *uploader);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_UPLOADER_H */