diff --git a/NEWS b/NEWS index 64b58ffe3c..621c5500d8 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ Copyright (C) 2011 Collabora Version 0.5.0 - DD.Dec.2012 * Require glib >= 2.31.2 +* Add support for raw YUV buffers in vaapisink (+Halley Zhao) * Fix memory leak in GstVaapiVideoBuffer for images and surfaces (Feng Yuan) Version 0.4.1 - 20.Nov.2012 diff --git a/gst/vaapi/Makefile.am b/gst/vaapi/Makefile.am index 0c1097ca31..4da267e31e 100644 --- a/gst/vaapi/Makefile.am +++ b/gst/vaapi/Makefile.am @@ -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) libgstvaapi_la_CFLAGS = \ diff --git a/gst/vaapi/gstvaapisink.c b/gst/vaapi/gstvaapisink.c index 72513981b8..916cd8e176 100644 --- a/gst/vaapi/gstvaapisink.c +++ b/gst/vaapi/gstvaapisink.c @@ -72,12 +72,18 @@ static const GstElementDetails gst_vaapisink_details = "Gwenole Beauchesne "); /* 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); @@ -228,6 +234,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); } @@ -561,7 +568,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 @@ -572,6 +585,7 @@ gst_vaapisink_stop(GstBaseSink *base_sink) gst_buffer_replace(&sink->video_buffer, NULL); g_clear_object(&sink->window); g_clear_object(&sink->display); + g_clear_object(&sink->uploader); return TRUE; } @@ -598,6 +612,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; @@ -808,26 +825,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))); @@ -865,11 +901,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; } @@ -974,6 +1049,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, diff --git a/gst/vaapi/gstvaapisink.h b/gst/vaapi/gstvaapisink.h index a2e8bff66d..b8b082a960 100644 --- a/gst/vaapi/gstvaapisink.h +++ b/gst/vaapi/gstvaapisink.h @@ -30,6 +30,7 @@ #include #endif #include "gstvaapipluginutil.h" +#include "gstvaapiuploader.h" G_BEGIN_DECLS @@ -67,6 +68,7 @@ struct _GstVaapiSink { /*< private >*/ GstVideoSink parent_instance; + GstVaapiUploader *uploader; GstCaps *caps; GstVaapiDisplay *display; GstVaapiDisplayType display_type; @@ -88,6 +90,7 @@ struct _GstVaapiSink { guint use_reflection : 1; guint use_overlay : 1; guint use_rotation : 1; + guint use_video_raw : 1; }; struct _GstVaapiSinkClass { diff --git a/gst/vaapi/gstvaapiuploader.c b/gst/vaapi/gstvaapiuploader.c new file mode 100644 index 0000000000..d7ba1f979e --- /dev/null +++ b/gst/vaapi/gstvaapiuploader.c @@ -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 +#include +#include +#include +#include + +#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 index 0000000000..06f62d3957 --- /dev/null +++ b/gst/vaapi/gstvaapiuploader.h @@ -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 + +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 */