vaapipostproc: reset deinterlacer state when there is a discontinuity.
[platform/upstream/gstreamer-vaapi.git] / gst / vaapi / gstvaapipostproc.c
index ace0e61..428cba4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  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
@@ -105,6 +105,10 @@ enum {
     PROP_DEINTERLACE_METHOD,
     PROP_DENOISE,
     PROP_SHARPEN,
+    PROP_HUE,
+    PROP_SATURATION,
+    PROP_BRIGHTNESS,
+    PROP_CONTRAST,
 };
 
 #define DEFAULT_FORMAT                  GST_VIDEO_FORMAT_ENCODED
@@ -314,25 +318,36 @@ gst_vaapipostproc_stop(GstBaseTransform *trans)
 }
 
 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 *
@@ -432,6 +447,7 @@ gst_vaapipostproc_process_vpp(GstBaseTransform *trans, GstBuffer *inbuf,
     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) &&
@@ -448,29 +464,76 @@ gst_vaapipostproc_process_vpp(GstBaseTransform *trans, GstBuffer *inbuf,
             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)
@@ -511,6 +574,7 @@ gst_vaapipostproc_process_vpp(GstBaseTransform *trans, GstBuffer *inbuf,
                 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)
@@ -549,6 +613,7 @@ gst_vaapipostproc_process_vpp(GstBaseTransform *trans, GstBuffer *inbuf,
                  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)
@@ -625,11 +690,10 @@ gst_vaapipostproc_process(GstBaseTransform *trans, GstBuffer *inbuf,
 
     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);
@@ -1226,6 +1290,22 @@ gst_vaapipostproc_set_property(
          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;
@@ -1267,6 +1347,18 @@ gst_vaapipostproc_get_property(
     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;
@@ -1435,6 +1527,50 @@ gst_vaapipostproc_class_init(GstVaapiPostprocClass *klass)
         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);
 }