vaapipostproc: add new element for video postprocessing.

Add vaapipostproc element for video postprocessing. So far, only basic
bob deinterlacing is implemented. Interlaced mode is automatically
detected based on sink caps ("interlaced" field).
This commit is contained in:
Gwenole Beauchesne 2012-03-26 14:37:24 +02:00
parent a5144358d1
commit 894d65b81a
6 changed files with 848 additions and 1 deletions

5
README
View file

@ -26,9 +26,12 @@ GStreamer and helper libraries.
* `vaapiupload' is used to convert from video/x-raw-yuv pixels to
video/x-vaapi-surface surfaces.
* `vaapidownload' is used to convert from video-x-vaapi-surface
* `vaapidownload' is used to convert from video/x-vaapi-surface
surfaces to video/x-raw-yuv pixels.
* `vaapipostproc' is used to postprocess video/x-vaapi-surface
surfaces, for e.g. deinterlacing.
* `vaapisink' is used to display video/x-vaapi-surface surfaces to
screen.

View file

@ -21,6 +21,7 @@ Description: VA-API plugins for GStreamer
- `vaapidecode': decode bitstreams using VA-API
- `vaapiupload': converts from YUV pixels to VA surfaces
- `vaapidownload': convert from VA surfaces to YUV pixels
- `vaapipostproc': postprocess VA surfaces, e.g. deinterlacing
- `vaapisink': a VA-API based video sink
Package: gstreamer@GST_MAJORMINOR@-vaapi-doc

View file

@ -20,6 +20,7 @@ libgstvaapi_la_SOURCES = \
gstvaapidecode.c \
gstvaapidownload.c \
gstvaapipluginutil.c \
gstvaapipostproc.c \
gstvaapisink.c \
gstvaapiupload.c \
$(NULL)
@ -28,6 +29,7 @@ noinst_HEADERS = \
gstvaapidecode.h \
gstvaapidownload.h \
gstvaapipluginutil.h \
gstvaapipostproc.h \
gstvaapisink.h \
gstvaapiupload.h \
$(NULL)

View file

@ -30,6 +30,7 @@
#include "gstvaapidownload.h"
#include "gstvaapiupload.h"
#include "gstvaapidecode.h"
#include "gstvaapipostproc.h"
#include "gstvaapisink.h"
static gboolean
@ -44,6 +45,9 @@ plugin_init (GstPlugin *plugin)
gst_element_register(plugin, "vaapidecode",
GST_RANK_PRIMARY,
GST_TYPE_VAAPIDECODE);
gst_element_register(plugin, "vaapipostproc",
GST_RANK_PRIMARY,
GST_TYPE_VAAPIPOSTPROC);
gst_element_register(plugin, "vaapisink",
GST_RANK_PRIMARY,
GST_TYPE_VAAPISINK);

View file

@ -0,0 +1,714 @@
/*
* gstvaapipostproc.c - VA-API video postprocessing
*
* Copyright (C) 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
*/
/**
* SECTION:gstvaapipostproc
* @short_description: A video postprocessing filter
*
* vaapipostproc consists in various postprocessing algorithms to be
* applied to VA surfaces. So far, only basic bob deinterlacing is
* implemented.
*/
#include "config.h"
#include <gst/video/video.h>
#include <gst/video/videocontext.h>
#include <gst/vaapi/gstvaapivideosink.h>
#include <gst/vaapi/gstvaapivideobuffer.h>
#include "gstvaapipluginutil.h"
#include "gstvaapipostproc.h"
#define GST_PLUGIN_NAME "vaapipostproc"
#define GST_PLUGIN_DESC "A video postprocessing filter"
GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapipostproc);
#define GST_CAT_DEFAULT gst_debug_vaapipostproc
/* ElementFactory information */
static const GstElementDetails gst_vaapipostproc_details =
GST_ELEMENT_DETAILS(
"VA-API video postprocessing",
"Filter/Converter/Video",
GST_PLUGIN_DESC,
"Gwenole Beauchesne <gwenole.beauchesne@intel.com>");
/* Default templates */
static const char gst_vaapipostproc_sink_caps_str[] =
GST_VAAPI_SURFACE_CAPS ", "
"interlaced = (boolean) { true, false }";
static const char gst_vaapipostproc_src_caps_str[] =
GST_VAAPI_SURFACE_CAPS ", "
"interlaced = (boolean) false";
static GstStaticPadTemplate gst_vaapipostproc_sink_factory =
GST_STATIC_PAD_TEMPLATE(
"sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS(gst_vaapipostproc_sink_caps_str));
static GstStaticPadTemplate gst_vaapipostproc_src_factory =
GST_STATIC_PAD_TEMPLATE(
"src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS(gst_vaapipostproc_src_caps_str));
#define GstVideoContextClass GstVideoContextInterface
GST_BOILERPLATE_WITH_INTERFACE(
GstVaapiPostproc,
gst_vaapipostproc,
GstElement,
GST_TYPE_ELEMENT,
GstVideoContext,
GST_TYPE_VIDEO_CONTEXT,
gst_video_context);
enum {
PROP_0,
PROP_DEINTERLACE_MODE,
PROP_DEINTERLACE_METHOD,
};
#define DEFAULT_DEINTERLACE_MODE GST_VAAPI_DEINTERLACE_MODE_AUTO
#define DEFAULT_DEINTERLACE_METHOD GST_VAAPI_DEINTERLACE_METHOD_BOB
#define GST_TYPE_VAAPI_DEINTERLACE_MODES \
gst_vaapi_deinterlace_modes_get_type()
static GType
gst_vaapi_deinterlace_modes_get_type(void)
{
static GType deinterlace_modes_type = 0;
static const GEnumValue modes_types[] = {
{ GST_VAAPI_DEINTERLACE_MODE_AUTO,
"Auto detection", "auto" },
{ GST_VAAPI_DEINTERLACE_MODE_INTERLACED,
"Force deinterlacing", "interlaced" },
{ GST_VAAPI_DEINTERLACE_MODE_DISABLED,
"Never deinterlace", "disabled" },
{ 0, NULL, NULL },
};
if (!deinterlace_modes_type) {
deinterlace_modes_type =
g_enum_register_static("GstVaapiDeinterlaceModes", modes_types);
}
return deinterlace_modes_type;
}
#define GST_TYPE_VAAPI_DEINTERLACE_METHODS \
gst_vaapi_deinterlace_methods_get_type()
static GType
gst_vaapi_deinterlace_methods_get_type(void)
{
static GType deinterlace_methods_type = 0;
static const GEnumValue methods_types[] = {
{ GST_VAAPI_DEINTERLACE_METHOD_BOB,
"Bob deinterlacing", "bob" },
#if 0
/* VA/VPP */
{ GST_VAAPI_DEINTERLACE_METHOD_WEAVE,
"Weave deinterlacing", "weave" },
{ GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE,
"Motion adaptive deinterlacing", "motion-adaptive" },
{ GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED,
"Motion compensated deinterlacing", "motion-compensated" },
#endif
{ 0, NULL, NULL },
};
if (!deinterlace_methods_type) {
deinterlace_methods_type =
g_enum_register_static("GstVaapiDeinterlaceMethods", methods_types);
}
return deinterlace_methods_type;
}
static inline GstVaapiPostproc *
get_vaapipostproc_from_pad(GstPad *pad)
{
return GST_VAAPIPOSTPROC(gst_pad_get_parent_element(pad));
}
/* GstVideoContext interface */
static void
gst_vaapipostproc_set_video_context(
GstVideoContext *context,
const gchar *type,
const GValue *value
)
{
GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(context);
gst_vaapi_set_display(type, value, &postproc->display);
}
static gboolean
gst_video_context_supported(GstVaapiPostproc *postproc, GType iface_type)
{
return (iface_type == GST_TYPE_VIDEO_CONTEXT);
}
static void
gst_video_context_interface_init(GstVideoContextInterface *iface)
{
iface->set_context = gst_vaapipostproc_set_video_context;
}
static gboolean
gst_vaapipostproc_create(GstVaapiPostproc *postproc, GstCaps *caps)
{
if (!gst_vaapi_ensure_display(postproc, &postproc->display))
return FALSE;
gst_caps_replace(&postproc->postproc_caps, caps);
return TRUE;
}
static void
gst_vaapipostproc_destroy(GstVaapiPostproc *postproc)
{
gst_caps_replace(&postproc->postproc_caps, NULL);
if (postproc->display) {
g_object_unref(postproc->display);
postproc->display = NULL;
}
}
static gboolean
gst_vaapipostproc_reset(GstVaapiPostproc *postproc, GstCaps *caps)
{
if (postproc->postproc_caps &&
gst_caps_is_always_compatible(caps, postproc->postproc_caps))
return TRUE;
gst_vaapipostproc_destroy(postproc);
return gst_vaapipostproc_create(postproc, caps);
}
static gboolean
gst_vaapipostproc_start(GstVaapiPostproc *postproc)
{
if (!gst_vaapi_ensure_display(postproc, &postproc->display))
return FALSE;
return TRUE;
}
static gboolean
gst_vaapipostproc_stop(GstVaapiPostproc *postproc)
{
if (postproc->display) {
g_object_unref(postproc->display);
postproc->display = NULL;
}
return TRUE;
}
static GstFlowReturn
gst_vaapipostproc_process(GstVaapiPostproc *postproc, GstBuffer *buf)
{
GstVaapiVideoBuffer *vbuf = GST_VAAPI_VIDEO_BUFFER(buf);
GstVaapiSurfaceProxy *proxy;
GstClockTime timestamp;
GstFlowReturn ret;
GstBuffer *outbuf = NULL;
guint outbuf_flags, flags = 0;
gboolean tff;
/* Deinterlacing disabled, push frame */
if (!postproc->deinterlace) {
gst_vaapi_video_buffer_set_render_flags(vbuf, flags);
ret = gst_pad_push(postproc->srcpad, buf);
if (ret != GST_FLOW_OK)
goto error_push_buffer;
return GST_FLOW_OK;
}
timestamp = GST_BUFFER_TIMESTAMP(buf);
proxy = gst_vaapi_video_buffer_get_surface_proxy(vbuf);
tff = gst_vaapi_surface_proxy_get_tff(proxy);
/* First field */
outbuf = gst_vaapi_video_buffer_new_with_surface_proxy(proxy);
if (!outbuf)
goto error_create_buffer;
vbuf = GST_VAAPI_VIDEO_BUFFER(outbuf);
outbuf_flags = flags;
outbuf_flags |= tff ?
GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD :
GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD;
gst_vaapi_video_buffer_set_render_flags(vbuf, outbuf_flags);
GST_BUFFER_TIMESTAMP(outbuf) = timestamp;
GST_BUFFER_DURATION(outbuf) = postproc->field_duration;
gst_buffer_set_caps(outbuf, postproc->srcpad_caps);
ret = gst_pad_push(postproc->srcpad, outbuf);
if (ret != GST_FLOW_OK)
goto error_push_buffer;
/* Second field */
outbuf = gst_vaapi_video_buffer_new_with_surface_proxy(proxy);
if (!outbuf)
goto error_create_buffer;
vbuf = GST_VAAPI_VIDEO_BUFFER(outbuf);
outbuf_flags = flags;
outbuf_flags |= tff ?
GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD :
GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD;
gst_vaapi_video_buffer_set_render_flags(vbuf, outbuf_flags);
GST_BUFFER_TIMESTAMP(outbuf) = timestamp + postproc->field_duration;
GST_BUFFER_DURATION(outbuf) = postproc->field_duration;
gst_buffer_set_caps(outbuf, postproc->srcpad_caps);
ret = gst_pad_push(postproc->srcpad, outbuf);
if (ret != GST_FLOW_OK)
goto error_push_buffer;
gst_buffer_unref(buf);
return GST_FLOW_OK;
/* ERRORS */
error_create_buffer:
{
GST_ERROR("failed to create output buffer");
gst_buffer_unref(buf);
return GST_FLOW_UNEXPECTED;
}
error_push_buffer:
{
if (ret != GST_FLOW_WRONG_STATE)
GST_ERROR("failed to push output buffer to video sink");
gst_buffer_unref(buf);
return GST_FLOW_UNEXPECTED;
}
}
static gboolean
gst_vaapipostproc_update_sink_caps(GstVaapiPostproc *postproc, GstCaps *caps)
{
gint fps_n, fps_d;
gboolean interlaced;
if (!gst_video_parse_caps_framerate(caps, &fps_n, &fps_d))
return FALSE;
postproc->fps_n = fps_n;
postproc->fps_d = fps_d;
switch (postproc->deinterlace_mode) {
case GST_VAAPI_DEINTERLACE_MODE_AUTO:
if (!gst_video_format_parse_caps_interlaced(caps, &interlaced))
return FALSE;
postproc->deinterlace = interlaced;
break;
case GST_VAAPI_DEINTERLACE_MODE_INTERLACED:
postproc->deinterlace = TRUE;
break;
case GST_VAAPI_DEINTERLACE_MODE_DISABLED:
postproc->deinterlace = FALSE;
break;
}
postproc->field_duration = gst_util_uint64_scale(
GST_SECOND,
postproc->fps_d,
(1 + postproc->deinterlace) * postproc->fps_n
);
gst_caps_replace(&postproc->sinkpad_caps, caps);
return TRUE;
}
static gboolean
gst_vaapipostproc_update_src_caps(GstVaapiPostproc *postproc, GstCaps *caps)
{
GstCaps *src_caps;
GstStructure *structure;
const GValue *v_width, *v_height, *v_par;
gint fps_n, fps_d;
if (postproc->srcpad_caps)
src_caps = gst_caps_make_writable(postproc->srcpad_caps);
else
src_caps = gst_caps_from_string(GST_VAAPI_SURFACE_CAPS_NAME);
if (!src_caps)
return FALSE;
postproc->srcpad_caps = src_caps;
structure = gst_caps_get_structure(caps, 0);
v_width = gst_structure_get_value(structure, "width");
v_height = gst_structure_get_value(structure, "height");
v_par = gst_structure_get_value(structure, "pixel-aspect-ratio");
structure = gst_caps_get_structure(src_caps, 0);
if (v_width && v_height) {
gst_structure_set_value(structure, "width", v_width);
gst_structure_set_value(structure, "height", v_height);
}
if (v_par)
gst_structure_set_value(structure, "pixel-aspect-ratio", v_par);
gst_structure_set(structure, "type", G_TYPE_STRING, "vaapi", NULL);
gst_structure_set(structure, "opengl", G_TYPE_BOOLEAN, USE_VAAPI_GLX, NULL);
if (!postproc->deinterlace)
gst_structure_remove_field(structure, "interlaced");
else {
/* Set double framerate in interlaced mode */
if (!gst_util_fraction_multiply(postproc->fps_n, postproc->fps_d,
2, 1,
&fps_n, &fps_d))
return FALSE;
gst_structure_set(
structure,
"interlaced", G_TYPE_BOOLEAN, FALSE,
"framerate", GST_TYPE_FRACTION, fps_n, fps_d,
NULL
);
}
return gst_pad_set_caps(postproc->srcpad, src_caps);
}
static gboolean
gst_vaapipostproc_ensure_allowed_caps(GstVaapiPostproc *postproc)
{
if (postproc->allowed_caps)
return TRUE;
postproc->allowed_caps =
gst_caps_from_string(gst_vaapipostproc_sink_caps_str);
if (!postproc->allowed_caps)
return FALSE;
/* XXX: append VA/VPP filters */
return TRUE;
}
static GstCaps *
gst_vaapipostproc_get_caps(GstPad *pad)
{
GstVaapiPostproc * const postproc = get_vaapipostproc_from_pad(pad);
GstCaps *out_caps;
if (gst_vaapipostproc_ensure_allowed_caps(postproc))
out_caps = gst_caps_ref(postproc->allowed_caps);
else
out_caps = gst_caps_new_empty();
gst_object_unref(postproc);
return out_caps;
}
static gboolean
gst_vaapipostproc_set_caps(GstPad *pad, GstCaps *caps)
{
GstVaapiPostproc * const postproc = get_vaapipostproc_from_pad(pad);
gboolean success = FALSE;
g_return_val_if_fail(pad == postproc->sinkpad, FALSE);
do {
if (!gst_vaapipostproc_update_sink_caps(postproc, caps))
break;
if (!gst_vaapipostproc_update_src_caps(postproc, caps))
break;
if (!gst_vaapipostproc_reset(postproc, postproc->sinkpad_caps))
break;
success = TRUE;
} while (0);
gst_object_unref(postproc);
return success;
}
static GstFlowReturn
gst_vaapipostproc_chain(GstPad *pad, GstBuffer *buf)
{
GstVaapiPostproc * const postproc = get_vaapipostproc_from_pad(pad);
GstFlowReturn ret;
ret = gst_vaapipostproc_process(postproc, buf);
gst_object_unref(postproc);
return ret;
}
static gboolean
gst_vaapipostproc_sink_event(GstPad *pad, GstEvent *event)
{
GstVaapiPostproc * const postproc = get_vaapipostproc_from_pad(pad);
gboolean success;
GST_DEBUG("handle sink event '%s'", GST_EVENT_TYPE_NAME(event));
/* Propagate event downstream */
success = gst_pad_push_event(postproc->srcpad, event);
gst_object_unref(postproc);
return success;
}
static gboolean
gst_vaapipostproc_src_event(GstPad *pad, GstEvent *event)
{
GstVaapiPostproc * const postproc = get_vaapipostproc_from_pad(pad);
gboolean success;
GST_DEBUG("handle src event '%s'", GST_EVENT_TYPE_NAME(event));
/* Propagate event upstream */
success = gst_pad_push_event(postproc->sinkpad, event);
gst_object_unref(postproc);
return success;
}
static gboolean
gst_vaapipostproc_query(GstPad *pad, GstQuery *query)
{
GstVaapiPostproc * const postproc = get_vaapipostproc_from_pad(pad);
gboolean success;
GST_DEBUG("sharing display %p", postproc->display);
if (gst_vaapi_reply_to_query(query, postproc->display))
success = TRUE;
else
success = gst_pad_query_default(pad, query);
gst_object_unref(postproc);
return success;
}
static void
gst_vaapipostproc_finalize(GObject *object)
{
GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(object);
gst_vaapipostproc_destroy(postproc);
gst_caps_replace(&postproc->sinkpad_caps, NULL);
gst_caps_replace(&postproc->srcpad_caps, NULL);
gst_caps_replace(&postproc->allowed_caps, NULL);
G_OBJECT_CLASS(parent_class)->finalize(object);
}
static void
gst_vaapipostproc_set_property(
GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec
)
{
GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(object);
switch (prop_id) {
case PROP_DEINTERLACE_MODE:
postproc->deinterlace_mode = g_value_get_enum(value);
break;
case PROP_DEINTERLACE_METHOD:
postproc->deinterlace_method = g_value_get_enum(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
static void
gst_vaapipostproc_get_property(
GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec
)
{
GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(object);
switch (prop_id) {
case PROP_DEINTERLACE_MODE:
g_value_set_enum(value, postproc->deinterlace_mode);
break;
case PROP_DEINTERLACE_METHOD:
g_value_set_enum(value, postproc->deinterlace_method);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
static GstStateChangeReturn
gst_vaapipostproc_change_state(GstElement *element, GstStateChange transition)
{
GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(element);
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
if (!gst_vaapipostproc_start(postproc))
return GST_STATE_CHANGE_FAILURE;
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break;
default:
break;
}
ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
if (ret != GST_STATE_CHANGE_SUCCESS)
return ret;
switch (transition) {
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
break;
case GST_STATE_CHANGE_READY_TO_NULL:
if (!gst_vaapipostproc_stop(postproc))
return GST_STATE_CHANGE_FAILURE;
break;
default:
break;
}
return GST_STATE_CHANGE_SUCCESS;
}
static void
gst_vaapipostproc_class_init(GstVaapiPostprocClass *klass)
{
GObjectClass * const object_class = G_OBJECT_CLASS(klass);
GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
GST_DEBUG_CATEGORY_INIT(gst_debug_vaapipostproc,
GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
object_class->finalize = gst_vaapipostproc_finalize;
object_class->set_property = gst_vaapipostproc_set_property;
object_class->get_property = gst_vaapipostproc_get_property;
element_class->change_state = gst_vaapipostproc_change_state;
/**
* GstVaapiSink:deinterlace-mode:
*
* This selects whether the deinterlacing should always be applied or if
* they should only be applied on content that has the "interlaced" flag
* on the caps.
*/
g_object_class_install_property
(object_class,
PROP_DEINTERLACE_MODE,
g_param_spec_enum("deinterlace",
"Deinterlace",
"Deinterlace mode to use",
GST_TYPE_VAAPI_DEINTERLACE_MODES,
DEFAULT_DEINTERLACE_MODE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstVaapiSink:deinterlace-method:
*
* This selects the deinterlacing method to apply.
*/
g_object_class_install_property
(object_class,
PROP_DEINTERLACE_METHOD,
g_param_spec_enum("deinterlace-method",
"Deinterlace method",
"Deinterlace method to use",
GST_TYPE_VAAPI_DEINTERLACE_METHODS,
DEFAULT_DEINTERLACE_METHOD,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
static void
gst_vaapipostproc_base_init(gpointer klass)
{
GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
GstPadTemplate *pad_template;
gst_element_class_set_details(element_class, &gst_vaapipostproc_details);
/* sink pad */
pad_template = gst_static_pad_template_get(&gst_vaapipostproc_sink_factory);
gst_element_class_add_pad_template(element_class, pad_template);
gst_object_unref(pad_template);
/* src pad */
pad_template = gst_static_pad_template_get(&gst_vaapipostproc_src_factory);
gst_element_class_add_pad_template(element_class, pad_template);
gst_object_unref(pad_template);
}
static void
gst_vaapipostproc_init(GstVaapiPostproc *postproc, GstVaapiPostprocClass *klass)
{
GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
postproc->allowed_caps = NULL;
postproc->postproc_caps = NULL;
postproc->display = NULL;
postproc->surface_width = 0;
postproc->surface_height = 0;
postproc->deinterlace = FALSE;
postproc->deinterlace_mode = DEFAULT_DEINTERLACE_MODE;
postproc->deinterlace_method = DEFAULT_DEINTERLACE_METHOD;
postproc->field_duration = GST_CLOCK_TIME_NONE;
postproc->fps_n = 0;
postproc->fps_d = 0;
/* Pad through which data comes in to the element */
postproc->sinkpad = gst_pad_new_from_template(
gst_element_class_get_pad_template(element_class, "sink"),
"sink"
);
postproc->sinkpad_caps = NULL;
gst_pad_set_getcaps_function(postproc->sinkpad, gst_vaapipostproc_get_caps);
gst_pad_set_setcaps_function(postproc->sinkpad, gst_vaapipostproc_set_caps);
gst_pad_set_chain_function(postproc->sinkpad, gst_vaapipostproc_chain);
gst_pad_set_event_function(postproc->sinkpad, gst_vaapipostproc_sink_event);
gst_pad_set_query_function(postproc->sinkpad, gst_vaapipostproc_query);
gst_element_add_pad(GST_ELEMENT(postproc), postproc->sinkpad);
/* Pad through which data goes out of the element */
postproc->srcpad = gst_pad_new_from_template(
gst_element_class_get_pad_template(element_class, "src"),
"src"
);
postproc->srcpad_caps = NULL;
gst_pad_set_event_function(postproc->srcpad, gst_vaapipostproc_src_event);
gst_pad_set_query_function(postproc->srcpad, gst_vaapipostproc_query);
gst_element_add_pad(GST_ELEMENT(postproc), postproc->srcpad);
}

View file

@ -0,0 +1,123 @@
/*
* gstvaapipostproc.h - VA-API video post processing
*
* Copyright (C) 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_VAAPIPOSTPROC_H
#define GST_VAAPIPOSTPROC_H
#include <gst/gst.h>
#include <gst/vaapi/gstvaapidisplay.h>
#include <gst/vaapi/gstvaapisurface.h>
#include <gst/vaapi/gstvaapisurfacepool.h>
#include <gst/vaapi/gstvaapivideobuffer.h>
G_BEGIN_DECLS
#define GST_TYPE_VAAPIPOSTPROC \
(gst_vaapipostproc_get_type())
#define GST_VAAPIPOSTPROC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), \
GST_TYPE_VAAPIPOSTPROC, \
GstVaapiPostproc))
#define GST_VAAPIPOSTPROC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass), \
GST_TYPE_VAAPIPOSTPROC, \
GstVaapiPostprocClass))
#define GST_IS_VAAPIPOSTPROC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_VAAPIPOSTPROC))
#define GST_IS_VAAPIPOSTPROC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_VAAPIPOSTPROC))
#define GST_VAAPIPOSTPROC_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS((obj), \
GST_TYPE_VAAPIPOSTPROC, \
GstVaapiPostprocClass))
typedef struct _GstVaapiPostproc GstVaapiPostproc;
typedef struct _GstVaapiPostprocClass GstVaapiPostprocClass;
typedef enum _GstVaapiDeinterlaceMode GstVaapiDeinterlaceMode;
typedef enum _GstVaapiDeinterlaceMethod GstVaapiDeinterlaceMethod;
/**
* GstVaapiDeinterlaceMode:
* @GST_VAAPI_DEINTERLACE_MODE_AUTO: Auto detect needs for deinterlacing.
* @GST_VAAPI_DEINTERLACE_MODE_INTERLACED: Force deinterlacing.
* @GST_VAAPI_DEINTERLACE_MODE_DISABLED: Never perform deinterlacing.
*/
enum _GstVaapiDeinterlaceMode {
GST_VAAPI_DEINTERLACE_MODE_AUTO = 0,
GST_VAAPI_DEINTERLACE_MODE_INTERLACED,
GST_VAAPI_DEINTERLACE_MODE_DISABLED,
};
/**
* GstVaapiDeinterlaceMethod:
* @GST_VAAPI_DEINTERLACE_METHOD_BOB: Basic bob deinterlacing algorithm.
* @GST_VAAPI_DEINTERLACE_METHOD_WEAVE: Weave deinterlacing algorithm.
* @GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE: Motion adaptive deinterlacing algorithm.
* @GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED: Motion compensated deinterlacing algorithm.
*/
enum _GstVaapiDeinterlaceMethod {
GST_VAAPI_DEINTERLACE_METHOD_BOB = 1,
GST_VAAPI_DEINTERLACE_METHOD_WEAVE,
GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE,
GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED,
};
struct _GstVaapiPostproc {
/*< private >*/
GstElement parent_instance;
GstPad *sinkpad;
GstCaps *sinkpad_caps;
GstPad *srcpad;
GstCaps *srcpad_caps;
GstCaps *allowed_caps;
GstCaps *postproc_caps;
GstVaapiDisplay *display;
guint surface_width;
guint surface_height;
/* Deinterlacing */
gboolean deinterlace;
GstVaapiDeinterlaceMode deinterlace_mode;
GstVaapiDeinterlaceMethod deinterlace_method;
GstClockTime field_duration;
gint fps_n;
gint fps_d;
};
struct _GstVaapiPostprocClass {
/*< private >*/
GstElementClass parent_class;
};
GType
gst_vaapipostproc_get_type(void);
G_END_DECLS
#endif /* GST_VAAPIPOSTPROC_H */