From daf6c7ad5201c32c6b2d125594b36828f7aeb956 Mon Sep 17 00:00:00 2001 From: Carl-Anton Ingmarsson Date: Sat, 4 Jul 2009 15:46:02 +0200 Subject: [PATCH] vdpauvideopostprocess: add support for noise reduction --- sys/vdpau/gstvdpdevice.c | 2 + sys/vdpau/gstvdpdevice.h | 1 + sys/vdpau/gstvdpvideopostprocess.c | 269 ++++++++++++++++++++--------- sys/vdpau/gstvdpvideopostprocess.h | 3 + 4 files changed, 198 insertions(+), 77 deletions(-) diff --git a/sys/vdpau/gstvdpdevice.c b/sys/vdpau/gstvdpdevice.c index 6123171c68..a762b451f6 100644 --- a/sys/vdpau/gstvdpdevice.c +++ b/sys/vdpau/gstvdpdevice.c @@ -104,6 +104,8 @@ gst_vdp_device_constructed (GObject * object) {VDP_FUNC_ID_VIDEO_MIXER_RENDER, &device->vdp_video_mixer_render}, {VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES, &device->vdp_video_mixer_set_feature_enables}, + {VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES, + &device->vdp_video_mixer_set_attribute_values}, {VDP_FUNC_ID_OUTPUT_SURFACE_CREATE, &device->vdp_output_surface_create}, {VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY, &device->vdp_output_surface_destroy}, {VDP_FUNC_ID_OUTPUT_SURFACE_QUERY_CAPABILITIES, diff --git a/sys/vdpau/gstvdpdevice.h b/sys/vdpau/gstvdpdevice.h index 3650c3a041..1ef145be4a 100644 --- a/sys/vdpau/gstvdpdevice.h +++ b/sys/vdpau/gstvdpdevice.h @@ -74,6 +74,7 @@ struct _GstVdpDevice VdpVideoMixerDestroy *vdp_video_mixer_destroy; VdpVideoMixerRender *vdp_video_mixer_render; VdpVideoMixerSetFeatureEnables *vdp_video_mixer_set_feature_enables; + VdpVideoMixerSetAttributeValues *vdp_video_mixer_set_attribute_values; VdpOutputSurfaceCreate *vdp_output_surface_create; VdpOutputSurfaceDestroy *vdp_output_surface_destroy; diff --git a/sys/vdpau/gstvdpvideopostprocess.c b/sys/vdpau/gstvdpvideopostprocess.c index 9e70502fbd..43a2d7fdba 100644 --- a/sys/vdpau/gstvdpvideopostprocess.c +++ b/sys/vdpau/gstvdpvideopostprocess.c @@ -66,7 +66,9 @@ enum PROP_0, PROP_FORCE_ASPECT_RATIO, PROP_DEINTERLACE_MODE, - PROP_DEINTERLACE_METHOD + PROP_DEINTERLACE_METHOD, + PROP_NOISE_REDUCTION, + PROP_NOISE_REDUCTION_LEVEL }; /* the capabilities of the inputs and outputs. @@ -134,6 +136,30 @@ gst_vdp_deinterlace_modes_get_type (void) return deinterlace_modes_type; } +static void +gst_vdp_vpp_activate_feature (GstVdpVideoPostProcess * vpp, + VdpVideoMixerFeature feature, gboolean activate) +{ + VdpVideoMixerFeature features[1]; + VdpBool enable[1]; + VdpStatus status; + + features[0] = feature; + if (activate) + enable[0] = VDP_TRUE; + else + enable[0] = VDP_FALSE; + + status = + vpp->device->vdp_video_mixer_set_feature_enables (vpp->mixer, 1, + features, enable); + if (status != VDP_STATUS_OK) { + GST_WARNING_OBJECT (vpp, "Couldn't set deinterlace method on mixer, " + "error returned from vdpau was: %s", + vpp->device->vdp_get_error_string (status)); + } +} + static VdpVideoMixerFeature gst_vdp_feature_from_deinterlace_method (GstVdpDeinterlaceMethods method) { @@ -163,6 +189,14 @@ gst_vdp_feature_from_deinterlace_method (GstVdpDeinterlaceMethods method) return feature; } +static void +gst_vdp_vpp_activate_deinterlace_method (GstVdpVideoPostProcess * vpp, + GstVdpDeinterlaceMethods method, gboolean activate) +{ + gst_vdp_vpp_activate_feature (vpp, + gst_vdp_feature_from_deinterlace_method (method), activate); +} + static void gst_vdp_picture_clear (GstVdpPicture pic) { @@ -304,6 +338,98 @@ gst_vdp_vpp_add_buffer (GstVdpVideoPostProcess * vpp, GstVdpVideoBuffer * buf) } } +static GstFlowReturn +gst_vdp_vpp_create_mixer (GstVdpVideoPostProcess * vpp, GstVdpDevice * device) +{ +#define VDP_NUM_MIXER_PARAMETER 3 +#define MAX_NUM_FEATURES 5 + + GstStructure *structure; + gint chroma_type; + gint width, height; + + VdpStatus status; + + VdpVideoMixerFeature features[5]; + guint n_features = 0; + VdpVideoMixerParameter parameters[VDP_NUM_MIXER_PARAMETER] = { + VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH, + VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT, + VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE + }; + const void *parameter_values[VDP_NUM_MIXER_PARAMETER]; + + structure = gst_caps_get_structure (GST_PAD_CAPS (vpp->sinkpad), 0); + if (!gst_structure_get_int (structure, "chroma-type", &chroma_type) || + !gst_structure_get_int (structure, "width", &width) || + !gst_structure_get_int (structure, "height", &height)) + return GST_FLOW_ERROR; + + parameter_values[0] = &width; + parameter_values[1] = &height; + parameter_values[2] = &chroma_type; + + if (gst_vdp_vpp_is_interlaced (vpp) + && vpp->method != GST_VDP_DEINTERLACE_METHOD_BOB) { + features[n_features++] = + gst_vdp_feature_from_deinterlace_method (vpp->method); + } + if (vpp->noise_reduction) + features[n_features++] = VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION; + + status = + device->vdp_video_mixer_create (device->device, n_features, features, + VDP_NUM_MIXER_PARAMETER, parameters, parameter_values, &vpp->mixer); + if (status != VDP_STATUS_OK) { + GST_ELEMENT_ERROR (vpp, RESOURCE, READ, + ("Could not create vdpau video mixer"), + ("Error returned from vdpau was: %s", + device->vdp_get_error_string (status))); + return GST_FLOW_ERROR; + } + + vpp->device = g_object_ref (device); + + if (vpp->noise_reduction) { + VdpVideoMixerAttribute attributes[1]; + const void *attribute_values[1]; + + attributes[0] = VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL; + attribute_values[0] = &vpp->noise_reduction; + + status = + vpp->device->vdp_video_mixer_set_attribute_values (vpp->mixer, 1, + attributes, attribute_values); + if (status != VDP_STATUS_OK) { + GST_WARNING_OBJECT (vpp, "Couldn't set noise reduction level on mixer, " + "error returned from vdpau was: %s", + vpp->device->vdp_get_error_string (status)); + } + } + + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_vdp_vpp_alloc_output_buffer (GstVdpVideoPostProcess * vpp, GstCaps * caps, + GstVdpOutputBuffer ** outbuf) +{ + GstFlowReturn ret; + + ret = gst_pad_alloc_buffer_and_set_caps (vpp->srcpad, 0, 0, + caps, (GstBuffer **) outbuf); + if (ret != GST_FLOW_OK) + return ret; + + if (!vpp->device) { + ret = gst_vdp_vpp_create_mixer (vpp, (*outbuf)->device); + } + + if (ret != GST_FLOW_OK) + gst_buffer_unref (GST_BUFFER (*outbuf)); + return ret; +} + static gint gst_greatest_common_divisor (gint a, gint b) { @@ -448,74 +574,6 @@ gst_vdp_vpp_stop (GstVdpVideoPostProcess * vpp) gst_vdp_vpp_flush (vpp); } -static GstFlowReturn -gst_vdp_vpp_alloc_output_buffer (GstVdpVideoPostProcess * vpp, GstCaps * caps, - GstVdpOutputBuffer ** outbuf) -{ - GstFlowReturn ret; - - ret = gst_pad_alloc_buffer_and_set_caps (vpp->srcpad, 0, 0, - caps, (GstBuffer **) outbuf); - if (ret != GST_FLOW_OK) - return ret; - - if (!vpp->device) { -#define VDP_NUM_MIXER_PARAMETER 3 -#define MAX_NUM_FEATURES 5 - - GstStructure *structure; - gint chroma_type; - gint width, height; - - VdpStatus status; - GstVdpDevice *device; - - VdpVideoMixerFeature features[5]; - guint n_features = 0; - VdpVideoMixerParameter parameters[VDP_NUM_MIXER_PARAMETER] = { - VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH, - VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT, - VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE - }; - const void *parameter_values[VDP_NUM_MIXER_PARAMETER]; - - structure = gst_caps_get_structure (GST_PAD_CAPS (vpp->sinkpad), 0); - if (!gst_structure_get_int (structure, "chroma-type", &chroma_type) || - !gst_structure_get_int (structure, "width", &width) || - !gst_structure_get_int (structure, "height", &height)) - goto error; - - parameter_values[0] = &width; - parameter_values[1] = &height; - parameter_values[2] = &chroma_type; - - if (gst_vdp_vpp_is_interlaced (vpp) - && vpp->method != GST_VDP_DEINTERLACE_METHOD_BOB) { - features[n_features++] = - gst_vdp_feature_from_deinterlace_method (vpp->method); - } - - device = vpp->device = g_object_ref ((*outbuf)->device); - - status = - device->vdp_video_mixer_create (device->device, n_features, features, - VDP_NUM_MIXER_PARAMETER, parameters, parameter_values, &vpp->mixer); - if (status != VDP_STATUS_OK) { - GST_ELEMENT_ERROR (vpp, RESOURCE, READ, - ("Could not create vdpau video mixer"), - ("Error returned from vdpau was: %s", - device->vdp_get_error_string (status))); - goto error; - } - } - - return ret; - -error: - gst_buffer_unref (GST_BUFFER (*outbuf)); - return GST_FLOW_ERROR; -} - static GstFlowReturn gst_vdp_vpp_chain (GstPad * pad, GstBuffer * buffer) { @@ -775,6 +833,12 @@ gst_vdp_vpp_get_property (GObject * object, guint property_id, GValue * value, case PROP_DEINTERLACE_METHOD: g_value_set_enum (value, vpp->method); break; + case PROP_NOISE_REDUCTION: + g_value_set_boolean (value, vpp->noise_reduction); + break; + case PROP_NOISE_REDUCTION_LEVEL: + g_value_set_float (value, vpp->noise_reduction_level); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -796,25 +860,63 @@ gst_vdp_vpp_set_property (GObject * object, guint property_id, vpp->mode = g_value_get_enum (value); break; case PROP_DEINTERLACE_METHOD: + { + GstVdpDeinterlaceMethods oldvalue; + + oldvalue = vpp->method; vpp->method = g_value_get_enum (value); - if (vpp->method != GST_VDP_DEINTERLACE_METHOD_BOB && vpp->device) { - VdpVideoMixerFeature features[1]; - VdpBool enable[1]; + if (oldvalue == vpp->method) + break; + + if (vpp->device) { + if (oldvalue != GST_VDP_DEINTERLACE_METHOD_BOB) + gst_vdp_vpp_activate_deinterlace_method (vpp, oldvalue, FALSE); + + if (vpp->method != GST_VDP_DEINTERLACE_METHOD_BOB && vpp->device) + gst_vdp_vpp_activate_deinterlace_method (vpp, oldvalue, TRUE); + } + break; + } + case PROP_NOISE_REDUCTION: + { + gboolean old_value; + + old_value = vpp->noise_reduction; + vpp->noise_reduction = g_value_get_boolean (value); + if (!vpp->noise_reduction == !old_value) + break; + + if (vpp->device) + gst_vdp_vpp_activate_feature (vpp, + VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION, vpp->noise_reduction); + break; + } + case PROP_NOISE_REDUCTION_LEVEL: + { + gfloat noise_reduction; + + noise_reduction = g_value_get_float (value); + + if (vpp->device) { + VdpVideoMixerAttribute attributes[1]; + const void *attribute_values[1]; VdpStatus status; - features[0] = gst_vdp_feature_from_deinterlace_method (vpp->method); - enable[0] = TRUE; + attributes[0] = VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL; + attribute_values[0] = &noise_reduction; status = - vpp->device->vdp_video_mixer_set_feature_enables (vpp->mixer, 1, - features, enable); + vpp->device->vdp_video_mixer_set_attribute_values (vpp->mixer, 1, + attributes, attribute_values); if (status != VDP_STATUS_OK) { - GST_WARNING_OBJECT (vpp, "Couldn't set deinterlace method on mixer, " + GST_WARNING_OBJECT (vpp, + "Couldn't set noise reduction level on mixer, " "error returned from vdpau was: %s", vpp->device->vdp_get_error_string (status)); } } break; + } default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -872,6 +974,16 @@ gst_vdp_vpp_class_init (GstVdpVideoPostProcessClass * klass) GST_TYPE_VDP_DEINTERLACE_METHODS, GST_VDP_DEINTERLACE_METHOD_BOB, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_NOISE_REDUCTION, + g_param_spec_boolean ("noise-reduction", "Noise reduction", + "Specifies whether noise reduction should be performed on the video", + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_NOISE_REDUCTION_LEVEL, + g_param_spec_float ("noise-reduction-level", "Noise reduction level", + "The amount of noise reduction that should be done", 0.0, 1.0, 0.0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gstelement_class->change_state = gst_vdp_vpp_change_state; } @@ -885,6 +997,9 @@ gst_vdp_vpp_init (GstVdpVideoPostProcess * vpp, vpp->mode = GST_VDP_DEINTERLACE_MODE_AUTO; vpp->method = GST_VDP_DEINTERLACE_METHOD_BOB; + vpp->noise_reduction = FALSE; + vpp->noise_reduction_level = 0.0; + /* SRC PAD */ vpp->srcpad = gst_pad_new_from_static_template (&src_template, "src"); gst_element_add_pad (GST_ELEMENT (vpp), vpp->srcpad); diff --git a/sys/vdpau/gstvdpvideopostprocess.h b/sys/vdpau/gstvdpvideopostprocess.h index 3ec6d12e62..3cba25cd85 100644 --- a/sys/vdpau/gstvdpvideopostprocess.h +++ b/sys/vdpau/gstvdpvideopostprocess.h @@ -81,6 +81,9 @@ struct _GstVdpVideoPostProcess gboolean force_aspect_ratio; GstVdpDeinterlaceModes mode; GstVdpDeinterlaceMethods method; + + gboolean noise_reduction; + gfloat noise_reduction_level; }; struct _GstVdpVideoPostProcessClass