/*
* 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
PROP_DEINTERLACE_METHOD,
PROP_DENOISE,
PROP_SHARPEN,
+ PROP_HUE,
+ PROP_SATURATION,
+ PROP_BRIGHTNESS,
+ PROP_CONTRAST,
};
#define DEFAULT_FORMAT GST_VIDEO_FORMAT_ENCODED
}
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 *
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) &&
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 = is_interlaced_buffer(postproc, inbuf);
+ 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 */
- deint_method = postproc->deinterlace_method;
- deint_refs = deint_method_is_advanced(deint_method);
if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_DEINTERLACE) {
fieldbuf = create_output_buffer(postproc);
if (!fieldbuf)
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)
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)
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);
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_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;
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);
}