/*
* gstvaapipostproc.c - VA-API video postprocessing
*
- * Copyright (C) 2012-2013 Intel Corporation
+ * Copyright (C) 2012-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
#include "gst/vaapi/sysdeps.h"
#include <gst/video/video.h>
-#include <gst/video/videocontext.h>
#include "gstvaapipostproc.h"
#include "gstvaapipluginutil.h"
/* Default templates */
static const char gst_vaapipostproc_sink_caps_str[] =
+#if GST_CHECK_VERSION(1,1,0)
+ GST_VIDEO_CAPS_MAKE_WITH_FEATURES(
+ GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE, "{ ENCODED, NV12, I420, YV12 }") ", "
+#else
GST_VAAPI_SURFACE_CAPS ", "
+#endif
GST_CAPS_INTERLACED_MODES "; "
#if GST_CHECK_VERSION(1,0,0)
GST_VIDEO_CAPS_MAKE(GST_VIDEO_FORMATS_ALL) ", "
GST_CAPS_INTERLACED_MODES;
static const char gst_vaapipostproc_src_caps_str[] =
+#if GST_CHECK_VERSION(1,1,0)
+ GST_VIDEO_CAPS_MAKE_WITH_FEATURES(
+ GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE, "{ ENCODED, NV12, I420, YV12 }") ", "
+#else
GST_VAAPI_SURFACE_CAPS ", "
+#endif
GST_CAPS_INTERLACED_FALSE;
static GstStaticPadTemplate gst_vaapipostproc_sink_factory =
GST_PAD_ALWAYS,
GST_STATIC_CAPS(gst_vaapipostproc_src_caps_str));
-/* GstImplementsInterface interface */
-#if !GST_CHECK_VERSION(1,0,0)
-static gboolean
-gst_vaapipostproc_implements_interface_supported(
- GstImplementsInterface *iface,
- GType type
-)
-{
- return (type == GST_TYPE_VIDEO_CONTEXT);
-}
-
-static void
-gst_vaapipostproc_implements_iface_init(GstImplementsInterfaceClass *iface)
-{
- iface->supported = gst_vaapipostproc_implements_interface_supported;
-}
-#endif
-
-/* 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);
-
- if (postproc->uploader)
- gst_vaapi_uploader_ensure_display(postproc->uploader, postproc->display);
-}
-
-static void
-gst_video_context_interface_init(GstVideoContextInterface *iface)
-{
- iface->set_context = gst_vaapipostproc_set_video_context;
-}
-
-#define GstVideoContextClass GstVideoContextInterface
G_DEFINE_TYPE_WITH_CODE(
GstVaapiPostproc,
gst_vaapipostproc,
GST_TYPE_BASE_TRANSFORM,
-#if !GST_CHECK_VERSION(1,0,0)
- G_IMPLEMENT_INTERFACE(GST_TYPE_IMPLEMENTS_INTERFACE,
- gst_vaapipostproc_implements_iface_init);
-#endif
- G_IMPLEMENT_INTERFACE(GST_TYPE_VIDEO_CONTEXT,
- gst_video_context_interface_init))
+ GST_VAAPI_PLUGIN_BASE_INIT_INTERFACES)
enum {
PROP_0,
PROP_FORMAT,
+ PROP_WIDTH,
+ PROP_HEIGHT,
+ PROP_FORCE_ASPECT_RATIO,
PROP_DEINTERLACE_MODE,
PROP_DEINTERLACE_METHOD,
+ PROP_DENOISE,
+ PROP_SHARPEN,
+ PROP_HUE,
+ PROP_SATURATION,
+ PROP_BRIGHTNESS,
+ PROP_CONTRAST,
};
#define DEFAULT_FORMAT GST_VIDEO_FORMAT_ENCODED
return deinterlace_mode_type;
}
+static void
+ds_reset(GstVaapiDeinterlaceState *ds)
+{
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS(ds->buffers); i++)
+ gst_buffer_replace(&ds->buffers[i], NULL);
+ ds->buffers_index = 0;
+ ds->num_surfaces = 0;
+ ds->deint = FALSE;
+ ds->tff = FALSE;
+}
+
+static void
+ds_add_buffer(GstVaapiDeinterlaceState *ds, GstBuffer *buf)
+{
+ gst_buffer_replace(&ds->buffers[ds->buffers_index], buf);
+ ds->buffers_index = (ds->buffers_index + 1) % G_N_ELEMENTS(ds->buffers);
+}
+
+static inline GstBuffer *
+ds_get_buffer(GstVaapiDeinterlaceState *ds, guint index)
+{
+ /* Note: the index increases towards older buffers.
+ i.e. buffer at index 0 means the immediately preceding buffer
+ in the history, buffer at index 1 means the one preceding the
+ surface at index 0, etc. */
+ const guint n = ds->buffers_index + G_N_ELEMENTS(ds->buffers) - index - 1;
+ return ds->buffers[n % G_N_ELEMENTS(ds->buffers)];
+}
+
+static void
+ds_set_surfaces(GstVaapiDeinterlaceState *ds)
+{
+ GstVaapiVideoMeta *meta;
+ guint i;
+
+ ds->num_surfaces = 0;
+ for (i = 0; i < G_N_ELEMENTS(ds->buffers); i++) {
+ GstBuffer * const buf = ds_get_buffer(ds, i);
+ if (!buf)
+ break;
+
+ meta = gst_buffer_get_vaapi_video_meta(buf);
+ ds->surfaces[ds->num_surfaces++] =
+ gst_vaapi_video_meta_get_surface(meta);
+ }
+}
+
static GstVaapiFilterOpInfo *
find_filter_op(GPtrArray *filter_ops, GstVaapiFilterOp op)
{
static inline gboolean
gst_vaapipostproc_ensure_display(GstVaapiPostproc *postproc)
{
- return gst_vaapi_ensure_display(postproc, GST_VAAPI_DISPLAY_TYPE_ANY,
- &postproc->display);
+ return gst_vaapi_plugin_base_ensure_display(GST_VAAPI_PLUGIN_BASE(postproc));
}
static gboolean
{
if (!gst_vaapipostproc_ensure_display(postproc))
return FALSE;
-
- if (!postproc->uploader) {
- postproc->uploader = gst_vaapi_uploader_new(postproc->display);
- if (!postproc->uploader)
- return FALSE;
- }
-
- if (!gst_vaapi_uploader_ensure_display(postproc->uploader,
- postproc->display))
- return FALSE;
- return TRUE;
-}
-
-static gboolean
-gst_vaapipostproc_ensure_uploader_caps(GstVaapiPostproc *postproc)
-{
-#if !GST_CHECK_VERSION(1,0,0)
- if (postproc->is_raw_yuv && !gst_vaapi_uploader_ensure_caps(
- postproc->uploader, postproc->sinkpad_caps, NULL))
+ if (!gst_vaapi_plugin_base_ensure_uploader(GST_VAAPI_PLUGIN_BASE(postproc)))
return FALSE;
-#endif
return TRUE;
}
if (!gst_vaapipostproc_ensure_display(postproc))
return FALSE;
- postproc->filter = gst_vaapi_filter_new(postproc->display);
+ postproc->filter = gst_vaapi_filter_new(
+ GST_VAAPI_PLUGIN_BASE_DISPLAY(postproc));
if (!postproc->filter)
return FALSE;
return TRUE;
static gboolean
gst_vaapipostproc_create(GstVaapiPostproc *postproc)
{
+ if (!gst_vaapi_plugin_base_open(GST_VAAPI_PLUGIN_BASE(postproc)))
+ return FALSE;
if (!gst_vaapipostproc_ensure_display(postproc))
return FALSE;
if (!gst_vaapipostproc_ensure_uploader(postproc))
return FALSE;
- if (!gst_vaapipostproc_ensure_uploader_caps(postproc))
- return FALSE;
if (gst_vaapipostproc_ensure_filter(postproc))
postproc->use_vpp = TRUE;
return TRUE;
postproc->filter_ops = NULL;
}
gst_vaapi_filter_replace(&postproc->filter, NULL);
+ gst_vaapi_video_pool_replace(&postproc->filter_pool, NULL);
}
static void
gst_vaapipostproc_destroy(GstVaapiPostproc *postproc)
{
-#if GST_CHECK_VERSION(1,0,0)
- g_clear_object(&postproc->sinkpad_buffer_pool);
-#endif
- g_clear_object(&postproc->uploader);
+ ds_reset(&postproc->deinterlace_state);
gst_vaapipostproc_destroy_filter(postproc);
- gst_vaapi_display_replace(&postproc->display, NULL);
gst_caps_replace(&postproc->allowed_sinkpad_caps, NULL);
- gst_caps_replace(&postproc->sinkpad_caps, NULL);
gst_caps_replace(&postproc->allowed_srcpad_caps, NULL);
- gst_caps_replace(&postproc->srcpad_caps, NULL);
+ gst_vaapi_plugin_base_close(GST_VAAPI_PLUGIN_BASE(postproc));
}
static gboolean
{
GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
+ ds_reset(&postproc->deinterlace_state);
+ if (!gst_vaapi_plugin_base_open(GST_VAAPI_PLUGIN_BASE(postproc)))
+ return FALSE;
if (!gst_vaapipostproc_ensure_display(postproc))
return FALSE;
return TRUE;
{
GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
- gst_vaapi_display_replace(&postproc->display, NULL);
+ ds_reset(&postproc->deinterlace_state);
+ gst_vaapi_plugin_base_close(GST_VAAPI_PLUGIN_BASE(postproc));
return TRUE;
}
static gboolean
-is_interlaced_buffer(GstVaapiPostproc *postproc, GstBuffer *buf)
+should_deinterlace_buffer(GstVaapiPostproc *postproc, GstBuffer *buf)
{
- if (!(postproc->flags & GST_VAAPI_POSTPROC_FLAG_DEINTERLACE))
+ if (!(postproc->flags & GST_VAAPI_POSTPROC_FLAG_DEINTERLACE) ||
+ postproc->deinterlace_mode == GST_VAAPI_DEINTERLACE_MODE_DISABLED)
return FALSE;
+ if (postproc->deinterlace_mode == GST_VAAPI_DEINTERLACE_MODE_INTERLACED)
+ return TRUE;
+
+ g_assert(postproc->deinterlace_mode == GST_VAAPI_DEINTERLACE_MODE_AUTO);
+
switch (GST_VIDEO_INFO_INTERLACE_MODE(&postproc->sinkpad_info)) {
+ case GST_VIDEO_INTERLACE_MODE_INTERLEAVED:
+ return TRUE;
+ case GST_VIDEO_INTERLACE_MODE_PROGRESSIVE:
+ return FALSE;
case GST_VIDEO_INTERLACE_MODE_MIXED:
#if GST_CHECK_VERSION(1,0,0)
- if (!GST_BUFFER_FLAG_IS_SET(buf, GST_VIDEO_BUFFER_FLAG_INTERLACED))
- return FALSE;
+ if (GST_BUFFER_FLAG_IS_SET(buf, GST_VIDEO_BUFFER_FLAG_INTERLACED))
+ return TRUE;
#else
- if (GST_BUFFER_FLAG_IS_SET(buf, GST_VIDEO_BUFFER_PROGRESSIVE))
- return FALSE;
+ if (!GST_BUFFER_FLAG_IS_SET(buf, GST_VIDEO_BUFFER_PROGRESSIVE))
+ return TRUE;
#endif
break;
default:
+ GST_ERROR("unhandled \"interlace-mode\", disabling deinterlacing" );
break;
}
- return TRUE;
+ return FALSE;
}
static GstBuffer *
goto error_create_buffer;
#if !GST_CHECK_VERSION(1,0,0)
- gst_buffer_set_caps(outbuf, postproc->srcpad_caps);
+ gst_buffer_set_caps(outbuf, GST_VAAPI_PLUGIN_BASE_SRC_PAD_CAPS(postproc));
#endif
return outbuf;
0, -1);
}
+static gboolean
+deint_method_is_advanced(GstVaapiDeinterlaceMethod deint_method)
+{
+ gboolean is_advanced;
+
+ switch (deint_method) {
+ case GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE:
+ case GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED:
+ is_advanced = TRUE;
+ break;
+ default:
+ is_advanced = FALSE;
+ break;
+ }
+ return is_advanced;
+}
+
+static GstVaapiDeinterlaceMethod
+get_next_deint_method(GstVaapiDeinterlaceMethod deint_method)
+{
+ switch (deint_method) {
+ case GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED:
+ deint_method = GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE;
+ break;
+ default:
+ /* Default to basic "bob" for all others */
+ deint_method = GST_VAAPI_DEINTERLACE_METHOD_BOB;
+ break;
+ }
+ return deint_method;
+}
+
+static gboolean
+set_best_deint_method(GstVaapiPostproc *postproc, guint flags,
+ GstVaapiDeinterlaceMethod *deint_method_ptr)
+{
+ GstVaapiDeinterlaceMethod deint_method = postproc->deinterlace_method;
+ gboolean success;
+
+ for (;;) {
+ success = gst_vaapi_filter_set_deinterlacing(postproc->filter,
+ deint_method, flags);
+ if (success || deint_method == GST_VAAPI_DEINTERLACE_METHOD_BOB)
+ break;
+ deint_method = get_next_deint_method(deint_method);
+ }
+ *deint_method_ptr = deint_method;
+ return success;
+}
+
static GstFlowReturn
gst_vaapipostproc_process_vpp(GstBaseTransform *trans, GstBuffer *inbuf,
GstBuffer *outbuf)
{
GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
+ GstVaapiDeinterlaceState * const ds = &postproc->deinterlace_state;
GstVaapiVideoMeta *inbuf_meta, *outbuf_meta;
GstVaapiSurface *inbuf_surface, *outbuf_surface;
GstVaapiFilterStatus status;
- guint flags;
+ GstClockTime timestamp;
+ GstFlowReturn ret;
+ GstBuffer *fieldbuf;
+ GstVaapiDeinterlaceMethod deint_method;
+ guint flags, deint_flags;
+ gboolean tff, deint, deint_refs, deint_changed;
+ GstVaapiRectangle *crop_rect = NULL;
/* Validate filters */
if ((postproc->flags & GST_VAAPI_POSTPROC_FLAG_FORMAT) &&
!gst_vaapi_filter_set_format(postproc->filter, postproc->format))
return GST_FLOW_NOT_SUPPORTED;
+ if ((postproc->flags & GST_VAAPI_POSTPROC_FLAG_DENOISE) &&
+ !gst_vaapi_filter_set_denoising_level(postproc->filter,
+ postproc->denoise_level))
+ return GST_FLOW_NOT_SUPPORTED;
+
+ if ((postproc->flags & GST_VAAPI_POSTPROC_FLAG_SHARPEN) &&
+ !gst_vaapi_filter_set_sharpening_level(postproc->filter,
+ postproc->sharpen_level))
+ return GST_FLOW_NOT_SUPPORTED;
+
+ if ((postproc->flags & GST_VAAPI_POSTPROC_FLAG_HUE) &&
+ !gst_vaapi_filter_set_hue(postproc->filter,
+ postproc->hue))
+ return GST_FLOW_NOT_SUPPORTED;
+
+ if ((postproc->flags & GST_VAAPI_POSTPROC_FLAG_SATURATION) &&
+ !gst_vaapi_filter_set_saturation(postproc->filter,
+ postproc->saturation))
+ return GST_FLOW_NOT_SUPPORTED;
+
+ if ((postproc->flags & GST_VAAPI_POSTPROC_FLAG_BRIGHTNESS) &&
+ !gst_vaapi_filter_set_brightness(postproc->filter,
+ postproc->brightness))
+ return GST_FLOW_NOT_SUPPORTED;
+
+ if ((postproc->flags & GST_VAAPI_POSTPROC_FLAG_CONTRAST) &&
+ !gst_vaapi_filter_set_contrast(postproc->filter,
+ postproc->contrast))
+ return GST_FLOW_NOT_SUPPORTED;
+
inbuf_meta = gst_buffer_get_vaapi_video_meta(inbuf);
if (!inbuf_meta)
goto error_invalid_buffer;
inbuf_surface = gst_vaapi_video_meta_get_surface(inbuf_meta);
+#if GST_CHECK_VERSION(1,0,0)
+ GstVideoCropMeta * const crop_meta =
+ gst_buffer_get_video_crop_meta(inbuf);
+ if (crop_meta) {
+ GstVaapiRectangle tmp_rect;
+ crop_rect = &tmp_rect;
+ crop_rect->x = crop_meta->x;
+ crop_rect->y = crop_meta->y;
+ crop_rect->width = crop_meta->width;
+ crop_rect->height = crop_meta->height;
+ }
+#endif
+ if (!crop_rect)
+ crop_rect = (GstVaapiRectangle *)
+ gst_vaapi_video_meta_get_render_rect(inbuf_meta);
+
+ timestamp = GST_BUFFER_TIMESTAMP(inbuf);
+ tff = GST_BUFFER_FLAG_IS_SET(inbuf, GST_VIDEO_BUFFER_FLAG_TFF);
+ deint = should_deinterlace_buffer(postproc, inbuf);
+
+ /* Drop references if deinterlacing conditions changed */
+ deint_changed = deint != ds->deint;
+ if (deint_changed || (ds->num_surfaces > 0 && tff != ds->tff))
+ ds_reset(ds);
+
+ deint_method = postproc->deinterlace_method;
+ deint_refs = deint_method_is_advanced(deint_method);
+ if (deint_refs) {
+ GstBuffer * const prev_buf = ds_get_buffer(ds, 0);
+ GstClockTime prev_pts, pts = GST_BUFFER_TIMESTAMP(inbuf);
+ /* Reset deinterlacing state when there is a discontinuity */
+ if (prev_buf && (prev_pts = GST_BUFFER_TIMESTAMP(prev_buf)) != pts) {
+ const GstClockTimeDiff pts_diff = GST_CLOCK_DIFF(prev_pts, pts);
+ if (pts_diff < 0 || pts_diff > postproc->field_duration * 2)
+ ds_reset(ds);
+ }
+ }
+
+ ds->deint = deint;
+ ds->tff = tff;
+
flags = gst_vaapi_video_meta_get_render_flags(inbuf_meta) &
- ~(GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD|
- GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD);
+ ~GST_VAAPI_PICTURE_STRUCTURE_MASK;
+ /* First field */
+ if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_DEINTERLACE) {
+ fieldbuf = create_output_buffer(postproc);
+ if (!fieldbuf)
+ goto error_create_buffer;
+
+ outbuf_meta = gst_vaapi_video_meta_new_from_pool(postproc->filter_pool);
+ if (!outbuf_meta)
+ goto error_create_meta;
+ outbuf_surface = gst_vaapi_video_meta_get_surface(outbuf_meta);
+
+ if (deint) {
+ deint_flags = (tff ? GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD : 0);
+ if (tff)
+ deint_flags |= GST_VAAPI_DEINTERLACE_FLAG_TFF;
+ if (!set_best_deint_method(postproc, deint_flags, &deint_method))
+ goto error_op_deinterlace;
+
+ if (deint_method != postproc->deinterlace_method) {
+ GST_DEBUG("unsupported deinterlace-method %u. Using %u instead",
+ postproc->deinterlace_method, deint_method);
+ postproc->deinterlace_method = deint_method;
+ deint_refs = deint_method_is_advanced(deint_method);
+ }
+
+ if (deint_refs) {
+ ds_set_surfaces(ds);
+ if (!gst_vaapi_filter_set_deinterlacing_references(
+ postproc->filter, ds->surfaces, ds->num_surfaces,
+ NULL, 0))
+ goto error_op_deinterlace;
+ }
+ }
+ else if (deint_changed) {
+ // Reset internal filter to non-deinterlacing mode
+ deint_method = GST_VAAPI_DEINTERLACE_METHOD_NONE;
+ if (!gst_vaapi_filter_set_deinterlacing(postproc->filter,
+ deint_method, 0))
+ goto error_op_deinterlace;
+ }
+
+ gst_vaapi_filter_set_cropping_rectangle(postproc->filter, crop_rect);
+ status = gst_vaapi_filter_process(postproc->filter, inbuf_surface,
+ outbuf_surface, flags);
+ if (status != GST_VAAPI_FILTER_STATUS_SUCCESS)
+ goto error_process_vpp;
+
+ gst_buffer_set_vaapi_video_meta(fieldbuf, outbuf_meta);
+ gst_vaapi_video_meta_unref(outbuf_meta);
+
+ GST_BUFFER_TIMESTAMP(fieldbuf) = timestamp;
+ GST_BUFFER_DURATION(fieldbuf) = postproc->field_duration;
+ ret = gst_pad_push(trans->srcpad, fieldbuf);
+ if (ret != GST_FLOW_OK)
+ goto error_push_buffer;
+ }
+ fieldbuf = NULL;
+
+ /* Second field */
outbuf_meta = gst_vaapi_video_meta_new_from_pool(postproc->filter_pool);
if (!outbuf_meta)
goto error_create_meta;
outbuf_surface = gst_vaapi_video_meta_get_surface(outbuf_meta);
+ if (deint) {
+ deint_flags = (tff ? 0 : GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD);
+ if (tff)
+ deint_flags |= GST_VAAPI_DEINTERLACE_FLAG_TFF;
+ if (!gst_vaapi_filter_set_deinterlacing(postproc->filter,
+ deint_method, deint_flags))
+ goto error_op_deinterlace;
+
+ if (deint_refs && !gst_vaapi_filter_set_deinterlacing_references(
+ postproc->filter, ds->surfaces, ds->num_surfaces, NULL, 0))
+ goto error_op_deinterlace;
+ }
+ else if (deint_changed && !gst_vaapi_filter_set_deinterlacing(
+ postproc->filter, deint_method, 0))
+ goto error_op_deinterlace;
+
+ gst_vaapi_filter_set_cropping_rectangle(postproc->filter, crop_rect);
status = gst_vaapi_filter_process(postproc->filter, inbuf_surface,
outbuf_surface, flags);
if (status != GST_VAAPI_FILTER_STATUS_SUCCESS)
goto error_process_vpp;
- gst_buffer_copy_into(outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
+ if (!(postproc->flags & GST_VAAPI_POSTPROC_FLAG_DEINTERLACE))
+ gst_buffer_copy_into(outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
+ else {
+ GST_BUFFER_TIMESTAMP(outbuf) = timestamp + postproc->field_duration;
+ GST_BUFFER_DURATION(outbuf) = postproc->field_duration;
+ }
gst_buffer_set_vaapi_video_meta(outbuf, outbuf_meta);
gst_vaapi_video_meta_unref(outbuf_meta);
+
+ if (deint && deint_refs)
+ ds_add_buffer(ds, inbuf);
return GST_FLOW_OK;
/* ERRORS */
GST_ERROR("failed to validate source buffer");
return GST_FLOW_ERROR;
}
+error_create_buffer:
+ {
+ GST_ERROR("failed to create output buffer");
+ return GST_FLOW_ERROR;
+ }
error_create_meta:
{
GST_ERROR("failed to create new output buffer meta");
+ gst_buffer_replace(&fieldbuf, NULL);
gst_vaapi_video_meta_unref(outbuf_meta);
return GST_FLOW_ERROR;
}
+error_op_deinterlace:
+ {
+ GST_ERROR("failed to apply deinterlacing filter");
+ gst_buffer_replace(&fieldbuf, NULL);
+ gst_vaapi_video_meta_unref(outbuf_meta);
+ return GST_FLOW_NOT_SUPPORTED;
+ }
error_process_vpp:
{
GST_ERROR("failed to apply VPP filters (error %d)", status);
+ gst_buffer_replace(&fieldbuf, NULL);
gst_vaapi_video_meta_unref(outbuf_meta);
return GST_FLOW_ERROR;
}
+error_push_buffer:
+ {
+ if (ret != GST_FLOW_FLUSHING)
+ GST_ERROR("failed to push output buffer to video sink");
+ return GST_FLOW_ERROR;
+ }
}
static GstFlowReturn
timestamp = GST_BUFFER_TIMESTAMP(inbuf);
tff = GST_BUFFER_FLAG_IS_SET(inbuf, GST_VIDEO_BUFFER_FLAG_TFF);
- deint = is_interlaced_buffer(postproc, inbuf);
+ deint = should_deinterlace_buffer(postproc, inbuf);
flags = gst_vaapi_video_meta_get_render_flags(meta) &
- ~(GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD|
- GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD);
+ ~GST_VAAPI_PICTURE_STRUCTURE_MASK;
/* First field */
fieldbuf = create_output_buffer(postproc);
(1 + deinterlace) * GST_VIDEO_INFO_FPS_N(&vi));
postproc->is_raw_yuv = GST_VIDEO_INFO_IS_YUV(&vi);
-#if !GST_CHECK_VERSION(1,0,0)
- if (postproc->is_raw_yuv) {
- /* Ensure the uploader is set up for upstream allocated buffers */
- GstVaapiUploader * const uploader = postproc->uploader;
- if (!gst_vaapi_uploader_ensure_display(uploader, postproc->display))
- return FALSE;
- if (!gst_vaapi_uploader_ensure_caps(uploader, caps, NULL))
- return FALSE;
- }
-#endif
return TRUE;
}
if (postproc->format != GST_VIDEO_INFO_FORMAT(&postproc->sinkpad_info))
postproc->flags |= GST_VAAPI_POSTPROC_FLAG_FORMAT;
+
+ if ((postproc->width || postproc->height) &&
+ postproc->width != GST_VIDEO_INFO_WIDTH(&postproc->sinkpad_info) &&
+ postproc->height != GST_VIDEO_INFO_HEIGHT(&postproc->sinkpad_info))
+ postproc->flags |= GST_VAAPI_POSTPROC_FLAG_SIZE;
return TRUE;
}
return TRUE;
/* Create VA caps */
+#if GST_CHECK_VERSION(1,1,0)
+ out_caps = gst_static_pad_template_get_caps(
+ &gst_vaapipostproc_sink_factory);
+#else
out_caps = gst_caps_from_string(GST_VAAPI_SURFACE_CAPS ", "
GST_CAPS_INTERLACED_MODES);
+#endif
if (!out_caps) {
GST_ERROR("failed to create VA sink caps");
return FALSE;
/* Append YUV caps */
if (gst_vaapipostproc_ensure_uploader(postproc)) {
- yuv_caps = gst_vaapi_uploader_get_caps(postproc->uploader);
- if (yuv_caps)
- gst_caps_append(out_caps, gst_caps_ref(yuv_caps));
+ yuv_caps = GST_VAAPI_PLUGIN_BASE_UPLOADER_CAPS(postproc);
+ if (yuv_caps) {
+ out_caps = gst_caps_make_writable(out_caps);
+ gst_caps_append(out_caps, gst_caps_copy(yuv_caps));
+ }
else
GST_WARNING("failed to create YUV sink caps");
}
return TRUE;
}
-/* Build list of supported formats */
-static gboolean
-build_format_list_value(GArray *formats, GValue *out_value)
-{
- GValue v_format = { 0, };
- guint i;
-#if GST_CHECK_VERSION(1,0,0)
- const gchar *str;
-
- g_value_init(out_value, GST_TYPE_LIST);
-
- g_value_init(&v_format, G_TYPE_STRING);
- g_value_set_string(&v_format, "encoded");
- gst_value_list_append_value(out_value, &v_format);
-
- for (i = 0; i < formats->len; i++) {
- GstVideoFormat const format =
- g_array_index(formats, GstVideoFormat, i);
-
- str = gst_vaapi_video_format_to_string(format);
- if (!str)
- continue;
- g_value_set_string(&v_format, str);
- gst_value_list_append_value(out_value, &v_format);
- }
-#else
- guint32 fourcc;
-
- g_value_init(out_value, GST_TYPE_LIST);
- g_value_init(&v_format, GST_TYPE_FOURCC);
- for (i = 0; i < formats->len; i++) {
- GstVideoFormat const format =
- g_array_index(formats, GstVideoFormat, i);
-
- fourcc = gst_video_format_to_fourcc(format);
- if (!fourcc)
- continue;
- gst_value_set_fourcc(&v_format, fourcc);
- gst_value_list_append_value(out_value, &v_format);
- }
-#endif
-
- g_value_unset(&v_format);
- return TRUE;
-}
-
/* Fixup output caps so that to reflect the supported set of pixel formats */
static GstCaps *
expand_allowed_srcpad_caps(GstVaapiPostproc *postproc, GstCaps *caps)
{
- GValue value = { 0, };
+ GValue value = G_VALUE_INIT, v_format = G_VALUE_INIT;
guint i, num_structures;
gboolean had_filter;
goto cleanup;
/* Reset "format" field for each structure */
- if (!build_format_list_value(postproc->filter_formats, &value))
+ if (!gst_vaapi_value_set_format_list(&value, postproc->filter_formats))
goto cleanup;
+ if (gst_vaapi_value_set_format(&v_format, GST_VIDEO_FORMAT_ENCODED)) {
+ gst_value_list_prepend_value(&value, &v_format);
+ g_value_unset(&v_format);
+ }
num_structures = gst_caps_get_size(caps);
for (i = 0; i < num_structures; i++) {
return postproc->allowed_srcpad_caps != NULL;
}
+static void
+find_best_size(GstVaapiPostproc *postproc, GstVideoInfo *vip,
+ guint *width_ptr, guint *height_ptr)
+{
+ guint width, height;
+
+ width = GST_VIDEO_INFO_WIDTH(vip);
+ height = GST_VIDEO_INFO_HEIGHT(vip);
+ if (postproc->width && postproc->height) {
+ width = postproc->width;
+ height = postproc->height;
+ }
+ else if (postproc->keep_aspect) {
+ const gdouble ratio = (gdouble)width / height;
+ if (postproc->width) {
+ width = postproc->width;
+ height = postproc->width / ratio;
+ }
+ else if (postproc->height) {
+ height = postproc->height;
+ width = postproc->height * ratio;
+ }
+ }
+ else if (postproc->width)
+ width = postproc->width;
+ else if (postproc->height)
+ height = postproc->height;
+
+ *width_ptr = width;
+ *height_ptr = height;
+}
+
static GstCaps *
gst_vaapipostproc_transform_caps_impl(GstBaseTransform *trans,
GstPadDirection direction, GstCaps *caps)
GstVideoInfo vi;
GstVideoFormat format;
GstCaps *out_caps;
- gint fps_n, fps_d, par_n, par_d;
+ guint width, height;
+
+ /* Generate the sink pad caps, that could be fixated afterwards */
+ if (direction == GST_PAD_SRC) {
+ if (!ensure_allowed_sinkpad_caps(postproc))
+ return NULL;
+ return gst_caps_ref(postproc->allowed_sinkpad_caps);
+ }
+ /* Generate complete set of src pad caps if non-fixated sink pad
+ caps are provided */
if (!gst_caps_is_fixed(caps)) {
- out_caps = NULL;
- if (direction == GST_PAD_SINK) {
- /* Generate the allowed set of caps on the src pad */
- if (ensure_allowed_srcpad_caps(postproc))
- out_caps = gst_caps_ref(postproc->allowed_srcpad_caps);
- }
- else {
- /* Generate the allowed set of caps on the sink pad */
- if (ensure_allowed_sinkpad_caps(postproc))
- out_caps = gst_caps_ref(postproc->allowed_sinkpad_caps);
- }
- return out_caps;
+ if (!ensure_allowed_srcpad_caps(postproc))
+ return NULL;
+ return gst_caps_ref(postproc->allowed_srcpad_caps);
}
- /* Generate the other pad caps, based on the current pad caps, as
- specified by the direction argument */
+ /* Generate the expected src pad caps, from the current fixated
+ sink pad caps */
if (!gst_video_info_from_caps(&vi, caps))
return NULL;
- format = GST_VIDEO_INFO_FORMAT(&vi);
- if (format == GST_VIDEO_FORMAT_UNKNOWN)
- return NULL;
+ // Set double framerate in interlaced mode
+ if (is_deinterlace_enabled(postproc, &vi)) {
+ gint fps_n = GST_VIDEO_INFO_FPS_N(&vi);
+ gint fps_d = GST_VIDEO_INFO_FPS_D(&vi);
+ if (!gst_util_fraction_multiply(fps_n, fps_d, 2, 1, &fps_n, &fps_d))
+ return NULL;
+ GST_VIDEO_INFO_FPS_N(&vi) = fps_n;
+ GST_VIDEO_INFO_FPS_D(&vi) = fps_d;
+ }
- fps_n = GST_VIDEO_INFO_FPS_N(&vi);
- fps_d = GST_VIDEO_INFO_FPS_D(&vi);
- if (direction == GST_PAD_SINK) {
- if (is_deinterlace_enabled(postproc, &vi)) {
- /* Set double framerate in interlaced mode */
- if (!gst_util_fraction_multiply(fps_n, fps_d, 2, 1, &fps_n, &fps_d))
- return NULL;
- }
- format = GST_VIDEO_FORMAT_ENCODED;
+ // Signal the other pad that we only generate progressive frames
+ GST_VIDEO_INFO_INTERLACE_MODE(&vi) = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
- /* Signal the other pad that we generate only progressive frames */
- GST_VIDEO_INFO_INTERLACE_MODE(&vi) =
- GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
- }
- else {
- if (is_deinterlace_enabled(postproc, &vi)) {
- /* Set half framerate in interlaced mode */
- if (!gst_util_fraction_multiply(fps_n, fps_d, 1, 2, &fps_n, &fps_d))
- return NULL;
- }
- }
+ // Update size from user-specified parameters
+#if GST_CHECK_VERSION(1,1,0)
+ format = postproc->format;
+#else
+ format = GST_VIDEO_FORMAT_ENCODED;
+#endif
+ find_best_size(postproc, &vi, &width, &height);
+ gst_video_info_set_format(&vi, format, width, height);
- if (format != GST_VIDEO_FORMAT_ENCODED) {
- out_caps = gst_video_info_to_caps(&vi);
- if (!out_caps)
- return NULL;
- }
- else {
- /* XXX: gst_video_info_to_caps() from GStreamer 0.10 does not
- reconstruct suitable caps for "encoded" video formats */
- out_caps = gst_caps_from_string(GST_VAAPI_SURFACE_CAPS_NAME);
- if (!out_caps)
- return NULL;
+#if GST_CHECK_VERSION(1,1,0)
+ out_caps = gst_video_info_to_caps(&vi);
+ if (!out_caps)
+ return NULL;
- par_n = GST_VIDEO_INFO_PAR_N(&vi);
- par_d = GST_VIDEO_INFO_PAR_D(&vi);
- gst_caps_set_simple(out_caps,
- "type", G_TYPE_STRING, "vaapi",
- "opengl", G_TYPE_BOOLEAN, USE_GLX,
- "width", G_TYPE_INT, GST_VIDEO_INFO_WIDTH(&vi),
- "height", G_TYPE_INT, GST_VIDEO_INFO_HEIGHT(&vi),
- "framerate", GST_TYPE_FRACTION, fps_n, fps_d,
- "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d,
- NULL);
- }
+ gst_caps_set_features(out_caps, 0,
+ gst_caps_features_new(GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE, NULL));
+#else
+ /* XXX: gst_video_info_to_caps() from GStreamer 0.10 does not
+ reconstruct suitable caps for "encoded" video formats */
+ out_caps = gst_caps_from_string(GST_VAAPI_SURFACE_CAPS_NAME);
+ if (!out_caps)
+ return NULL;
+
+ gst_caps_set_simple(out_caps,
+ "type", G_TYPE_STRING, "vaapi",
+ "opengl", G_TYPE_BOOLEAN, USE_GLX,
+ "width", G_TYPE_INT, GST_VIDEO_INFO_WIDTH(&vi),
+ "height", G_TYPE_INT, GST_VIDEO_INFO_HEIGHT(&vi),
+ "framerate", GST_TYPE_FRACTION, GST_VIDEO_INFO_FPS_N(&vi),
+ GST_VIDEO_INFO_FPS_D(&vi),
+ "pixel-aspect-ratio", GST_TYPE_FRACTION, GST_VIDEO_INFO_PAR_N(&vi),
+ GST_VIDEO_INFO_PAR_D(&vi),
+ NULL);
gst_caps_set_interlaced(out_caps, &vi);
+#endif
return out_caps;
}
gst_vaapipostproc_transform_caps_impl
#endif
+#if GST_CHECK_VERSION(1,0,0)
+typedef gsize GstBaseTransformSizeType;
+#else
+typedef guint GstBaseTransformSizeType;
+#endif
+
static gboolean
gst_vaapipostproc_transform_size(GstBaseTransform *trans,
- GstPadDirection direction, GstCaps *caps, gsize size,
- GstCaps *othercaps, gsize *othersize)
+ GstPadDirection direction, GstCaps *caps, GstBaseTransformSizeType size,
+ GstCaps *othercaps, GstBaseTransformSizeType *othersize)
{
GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
return TRUE;
}
-static GstBuffer *
-get_source_buffer(GstVaapiPostproc *postproc, GstBuffer *inbuf)
-{
- GstVaapiVideoMeta *meta;
- GstBuffer *outbuf;
-
- meta = gst_buffer_get_vaapi_video_meta(inbuf);
- if (meta)
- return gst_buffer_ref(inbuf);
-
-#if GST_CHECK_VERSION(1,0,0)
- outbuf = NULL;
- goto error_invalid_buffer;
- return outbuf;
-
- /* ERRORS */
-error_invalid_buffer:
- {
- GST_ERROR("failed to validate source buffer");
- return NULL;
- }
-#else
- outbuf = gst_vaapi_uploader_get_buffer(postproc->uploader);
- if (!outbuf)
- goto error_create_buffer;
- if (!gst_vaapi_uploader_process(postproc->uploader, inbuf, outbuf))
- goto error_copy_buffer;
-
- gst_buffer_copy_metadata(outbuf, inbuf,
- GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
- return outbuf;
-
- /* ERRORS */
-error_create_buffer:
- {
- GST_ERROR("failed to create buffer");
- return NULL;
- }
-error_copy_buffer:
- {
- GST_ERROR("failed to upload buffer to VA surface");
- gst_buffer_unref(outbuf);
- return NULL;
- }
-#endif
-}
-
static GstFlowReturn
gst_vaapipostproc_transform(GstBaseTransform *trans, GstBuffer *inbuf,
GstBuffer *outbuf)
GstBuffer *buf;
GstFlowReturn ret;
- buf = get_source_buffer(postproc, inbuf);
- if (!buf)
+ ret = gst_vaapi_plugin_base_get_input_buffer(
+ GST_VAAPI_PLUGIN_BASE(postproc), inbuf, &buf);
+ if (ret != GST_FLOW_OK)
return GST_FLOW_ERROR;
ret = GST_FLOW_NOT_SUPPORTED;
}
static gboolean
-ensure_sinkpad_buffer_pool(GstVaapiPostproc *postproc, GstCaps *caps)
-{
-#if GST_CHECK_VERSION(1,0,0)
- GstBufferPool *pool;
- GstCaps *pool_caps;
- GstStructure *config;
- GstVideoInfo vi;
- gboolean need_pool;
-
- if (!gst_vaapipostproc_ensure_display(postproc))
- return FALSE;
-
- if (postproc->sinkpad_buffer_pool) {
- config = gst_buffer_pool_get_config(postproc->sinkpad_buffer_pool);
- gst_buffer_pool_config_get_params(config, &pool_caps, NULL, NULL, NULL);
- need_pool = !gst_caps_is_equal(caps, pool_caps);
- gst_structure_free(config);
- if (!need_pool)
- return TRUE;
- g_clear_object(&postproc->sinkpad_buffer_pool);
- postproc->sinkpad_buffer_size = 0;
- }
-
- pool = gst_vaapi_video_buffer_pool_new(postproc->display);
- if (!pool)
- goto error_create_pool;
-
- gst_video_info_init(&vi);
- gst_video_info_from_caps(&vi, caps);
- if (GST_VIDEO_INFO_FORMAT(&vi) == GST_VIDEO_FORMAT_ENCODED) {
- GST_DEBUG("assume sink pad buffer pool format is NV12");
- gst_video_info_set_format(&vi, GST_VIDEO_FORMAT_NV12,
- GST_VIDEO_INFO_WIDTH(&vi), GST_VIDEO_INFO_HEIGHT(&vi));
- }
- postproc->sinkpad_buffer_size = vi.size;
-
- config = gst_buffer_pool_get_config(pool);
- gst_buffer_pool_config_set_params(config, caps,
- postproc->sinkpad_buffer_size, 0, 0);
- gst_buffer_pool_config_add_option(config,
- GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META);
- gst_buffer_pool_config_add_option(config,
- GST_BUFFER_POOL_OPTION_VIDEO_META);
- if (!gst_buffer_pool_set_config(pool, config))
- goto error_pool_config;
- postproc->sinkpad_buffer_pool = pool;
- return TRUE;
-
- /* ERRORS */
-error_create_pool:
- {
- GST_ERROR("failed to create buffer pool");
- return FALSE;
- }
-error_pool_config:
- {
- GST_ERROR("failed to reset buffer pool config");
- gst_object_unref(pool);
- return FALSE;
- }
-#else
- return TRUE;
-#endif
-}
-
-static gboolean
ensure_srcpad_buffer_pool(GstVaapiPostproc *postproc, GstCaps *caps)
{
GstVideoInfo vi;
return TRUE;
postproc->filter_pool_info = vi;
- pool = gst_vaapi_surface_pool_new(postproc->display,
+ pool = gst_vaapi_surface_pool_new(GST_VAAPI_PLUGIN_BASE_DISPLAY(postproc),
&postproc->filter_pool_info);
if (!pool)
return FALSE;
if (caps_changed) {
gst_vaapipostproc_destroy(postproc);
- gst_caps_replace(&postproc->sinkpad_caps, caps);
- gst_caps_replace(&postproc->srcpad_caps, out_caps);
if (!gst_vaapipostproc_create(postproc))
return FALSE;
+ if (!gst_vaapi_plugin_base_set_caps(GST_VAAPI_PLUGIN_BASE(trans),
+ caps, out_caps))
+ return FALSE;
}
- if (!ensure_sinkpad_buffer_pool(postproc, caps))
- return FALSE;
if (!ensure_srcpad_buffer_pool(postproc, out_caps))
return FALSE;
return TRUE;
GST_INFO_OBJECT(trans, "query type `%s'", GST_QUERY_TYPE_NAME(query));
- if (gst_vaapi_reply_to_query(query, postproc->display)) {
- GST_DEBUG("sharing display %p", postproc->display);
+ if (gst_vaapi_reply_to_query(query, GST_VAAPI_PLUGIN_BASE_DISPLAY(postproc))) {
+ GST_DEBUG("sharing display %p", GST_VAAPI_PLUGIN_BASE_DISPLAY(postproc));
return TRUE;
}
GstQuery *decide_query, GstQuery *query)
{
GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
- GstCaps *caps = NULL;
- gboolean need_pool;
+ GstVaapiPluginBase * const plugin = GST_VAAPI_PLUGIN_BASE(trans);
/* Let vaapidecode allocate the video buffers */
if (!postproc->is_raw_yuv)
return FALSE;
-
- gst_query_parse_allocation(query, &caps, &need_pool);
-
- if (need_pool) {
- if (!caps)
- goto error_no_caps;
- if (!ensure_sinkpad_buffer_pool(postproc, caps))
- return FALSE;
- gst_query_add_allocation_pool(query, postproc->sinkpad_buffer_pool,
- postproc->sinkpad_buffer_size, 0, 0);
- }
-
- gst_query_add_allocation_meta(query,
- GST_VAAPI_VIDEO_META_API_TYPE, NULL);
- gst_query_add_allocation_meta(query,
- GST_VIDEO_META_API_TYPE, NULL);
- gst_query_add_allocation_meta(query,
- GST_VIDEO_CROP_META_API_TYPE, NULL);
- gst_query_add_allocation_meta(query,
- GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, NULL);
- return TRUE;
-
- /* ERRORS */
-error_no_caps:
- {
- GST_ERROR("no caps specified");
+ if (!gst_vaapi_plugin_base_propose_allocation(plugin, query))
return FALSE;
- }
+ return TRUE;
}
#endif
gst_vaapipostproc_destroy(postproc);
+ gst_vaapi_plugin_base_finalize(GST_VAAPI_PLUGIN_BASE(postproc));
G_OBJECT_CLASS(gst_vaapipostproc_parent_class)->finalize(object);
}
case PROP_FORMAT:
postproc->format = g_value_get_enum(value);
break;
+ case PROP_WIDTH:
+ postproc->width = g_value_get_uint(value);
+ break;
+ case PROP_HEIGHT:
+ postproc->height = g_value_get_uint(value);
+ break;
+ case PROP_FORCE_ASPECT_RATIO:
+ postproc->keep_aspect = g_value_get_boolean(value);
+ break;
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;
+ case PROP_DENOISE:
+ postproc->denoise_level = g_value_get_float(value);
+ postproc->flags |= GST_VAAPI_POSTPROC_FLAG_DENOISE;
+ break;
+ case PROP_SHARPEN:
+ postproc->sharpen_level = g_value_get_float(value);
+ postproc->flags |= GST_VAAPI_POSTPROC_FLAG_SHARPEN;
+ break;
+ case PROP_HUE:
+ postproc->hue = g_value_get_float(value);
+ postproc->flags |= GST_VAAPI_POSTPROC_FLAG_HUE;
+ break;
+ case PROP_SATURATION:
+ postproc->saturation = g_value_get_float(value);
+ postproc->flags |= GST_VAAPI_POSTPROC_FLAG_SATURATION;
+ break;
+ case PROP_BRIGHTNESS:
+ postproc->brightness = g_value_get_float(value);
+ postproc->flags |= GST_VAAPI_POSTPROC_FLAG_BRIGHTNESS;
+ break;
+ case PROP_CONTRAST:
+ postproc->contrast = g_value_get_float(value);
+ postproc->flags |= GST_VAAPI_POSTPROC_FLAG_CONTRAST;
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
case PROP_FORMAT:
g_value_set_enum(value, postproc->format);
break;
+ case PROP_WIDTH:
+ g_value_set_uint(value, postproc->width);
+ break;
+ case PROP_HEIGHT:
+ g_value_set_uint(value, postproc->height);
+ break;
+ case PROP_FORCE_ASPECT_RATIO:
+ g_value_set_boolean(value, postproc->keep_aspect);
+ break;
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;
+ case PROP_DENOISE:
+ g_value_set_float(value, postproc->denoise_level);
+ break;
+ case PROP_SHARPEN:
+ g_value_set_float(value, postproc->sharpen_level);
+ break;
+ case PROP_HUE:
+ g_value_set_float(value, postproc->hue);
+ break;
+ case PROP_SATURATION:
+ g_value_set_float(value, postproc->saturation);
+ break;
+ case PROP_BRIGHTNESS:
+ g_value_set_float(value, postproc->brightness);
+ break;
+ case PROP_CONTRAST:
+ g_value_set_float(value, postproc->contrast);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
GST_DEBUG_CATEGORY_INIT(gst_debug_vaapipostproc,
GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
+ gst_vaapi_plugin_base_class_init(GST_VAAPI_PLUGIN_BASE_CLASS(klass));
+
object_class->finalize = gst_vaapipostproc_finalize;
object_class->set_property = gst_vaapipostproc_set_property;
object_class->get_property = gst_vaapipostproc_get_property;
g_object_class_install_property(object_class,
PROP_FORMAT, filter_op->pspec);
+ /**
+ * GstVaapiPostproc:width:
+ *
+ * The forced output width in pixels. If set to zero, the width is
+ * calculated from the height if aspect ration is preserved, or
+ * inherited from the sink caps width
+ */
+ g_object_class_install_property
+ (object_class,
+ PROP_WIDTH,
+ g_param_spec_uint("width",
+ "Width",
+ "Forced output width",
+ 0, G_MAXINT, 0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstVaapiPostproc:height:
+ *
+ * The forced output height in pixels. If set to zero, the height
+ * is calculated from the width if aspect ration is preserved, or
+ * inherited from the sink caps height
+ */
+ g_object_class_install_property
+ (object_class,
+ PROP_HEIGHT,
+ g_param_spec_uint("height",
+ "Height",
+ "Forced output height",
+ 0, G_MAXINT, 0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstVaapiPostproc:force-aspect-ratio:
+ *
+ * When enabled, scaling respects video aspect ratio; when
+ * disabled, the video is distorted to fit the width and height
+ * properties.
+ */
+ g_object_class_install_property
+ (object_class,
+ PROP_FORCE_ASPECT_RATIO,
+ g_param_spec_boolean("force-aspect-ratio",
+ "Force aspect ratio",
+ "When enabled, scaling will respect original aspect ratio",
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstVaapiPostproc:denoise:
+ *
+ * The level of noise reduction to apply.
+ */
+ filter_op = find_filter_op(filter_ops, GST_VAAPI_FILTER_OP_DENOISE);
+ if (filter_op)
+ g_object_class_install_property(object_class,
+ PROP_DENOISE, filter_op->pspec);
+
+ /**
+ * GstVaapiPostproc:sharpen:
+ *
+ * The level of sharpening to apply for positive values, or the
+ * level of blurring for negative values.
+ */
+ filter_op = find_filter_op(filter_ops, GST_VAAPI_FILTER_OP_SHARPEN);
+ if (filter_op)
+ g_object_class_install_property(object_class,
+ PROP_SHARPEN, filter_op->pspec);
+
+ /**
+ * GstVaapiPostproc:hue:
+ *
+ * The color hue, expressed as a float value. Range is -180.0 to
+ * 180.0. Default value is 0.0 and represents no modification.
+ */
+ filter_op = find_filter_op(filter_ops, GST_VAAPI_FILTER_OP_HUE);
+ if (filter_op)
+ g_object_class_install_property(object_class,
+ PROP_HUE, filter_op->pspec);
+
+ /**
+ * GstVaapiPostproc:saturation:
+ *
+ * The color saturation, expressed as a float value. Range is 0.0
+ * to 2.0. Default value is 1.0 and represents no modification.
+ */
+ filter_op = find_filter_op(filter_ops, GST_VAAPI_FILTER_OP_SATURATION);
+ if (filter_op)
+ g_object_class_install_property(object_class,
+ PROP_SATURATION, filter_op->pspec);
+
+ /**
+ * GstVaapiPostproc:brightness:
+ *
+ * The color brightness, expressed as a float value. Range is -1.0
+ * to 1.0. Default value is 0.0 and represents no modification.
+ */
+ filter_op = find_filter_op(filter_ops, GST_VAAPI_FILTER_OP_BRIGHTNESS);
+ if (filter_op)
+ g_object_class_install_property(object_class,
+ PROP_BRIGHTNESS, filter_op->pspec);
+
+ /**
+ * GstVaapiPostproc:contrast:
+ *
+ * The color contrast, expressed as a float value. Range is 0.0 to
+ * 2.0. Default value is 1.0 and represents no modification.
+ */
+ filter_op = find_filter_op(filter_ops, GST_VAAPI_FILTER_OP_CONTRAST);
+ if (filter_op)
+ g_object_class_install_property(object_class,
+ PROP_CONTRAST, filter_op->pspec);
+
g_ptr_array_unref(filter_ops);
}
static void
gst_vaapipostproc_init(GstVaapiPostproc *postproc)
{
+ gst_vaapi_plugin_base_init(GST_VAAPI_PLUGIN_BASE(postproc), GST_CAT_DEFAULT);
+
postproc->format = DEFAULT_FORMAT;
postproc->deinterlace_mode = DEFAULT_DEINTERLACE_MODE;
postproc->deinterlace_method = DEFAULT_DEINTERLACE_METHOD;
postproc->field_duration = GST_CLOCK_TIME_NONE;
+ postproc->keep_aspect = TRUE;
gst_video_info_init(&postproc->sinkpad_info);
gst_video_info_init(&postproc->srcpad_info);