static GstFlowReturn gst_ffmpegdeinterlace_chain (GstPad * pad,
GstBuffer * inbuf);
-
static void
-gst_ffmpegdeinterlace_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&src_factory));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&sink_factory));
- gst_element_class_set_details_simple (element_class,
- "FFMPEG Deinterlace element", "Filter/Effect/Video/Deinterlace",
- "Deinterlace video", "Luca Ognibene <luogni@tin.it>");
-}
-
-static void
gst_ffmpegdeinterlace_class_init (GstFFMpegDeinterlaceClass * klass)
{
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+ gobject_class->set_property = gst_ffmpegdeinterlace_set_property;
+ gobject_class->get_property = gst_ffmpegdeinterlace_get_property;
+
+ /**
+ * GstFFMpegDeinterlace:mode
+ *
+ * This selects whether the deinterlacing methods should
+ * always be applied or if they should only be applied
+ * on content that has the "interlaced" flag on the caps.
+ *
+ * Since: 0.10.13
+ */
+ g_object_class_install_property (gobject_class, PROP_MODE,
+ g_param_spec_enum ("mode", "Mode", "Deinterlace Mode",
+ GST_TYPE_FFMPEGDEINTERLACE_MODES,
+ DEFAULT_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+ );
++
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&src_factory));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&sink_factory));
+
+ gst_element_class_set_details_simple (element_class,
+ "FFMPEG Deinterlace element", "Filter/Effect/Video/Deinterlace",
+ "Deinterlace video", "Luca Ognibene <luogni@tin.it>");
}
+ static void
+ gst_ffmpegdeinterlace_update_passthrough (GstFFMpegDeinterlace * deinterlace)
+ {
+ deinterlace->passthrough =
+ (deinterlace->mode == GST_FFMPEGDEINTERLACE_MODE_DISABLED
+ || (!deinterlace->interlaced
+ && deinterlace->mode != GST_FFMPEGDEINTERLACE_MODE_INTERLACED));
+ GST_DEBUG_OBJECT (deinterlace, "Passthrough: %d", deinterlace->passthrough);
+ }
+
static gboolean
- gst_ffmpegdeinterlace_sink_event (GstPad * pad, GstEvent * event)
+ gst_ffmpegdeinterlace_sink_setcaps (GstPad * pad, GstCaps * caps)
{
GstFFMpegDeinterlace *deinterlace =
GST_FFMPEGDEINTERLACE (gst_pad_get_parent (pad));
- gboolean ret = FALSE;
+ GstStructure *structure = gst_caps_get_structure (caps, 0);
+ AVCodecContext *ctx;
+ GstCaps *src_caps;
+ gboolean ret;
+
+ if (!gst_structure_get_int (structure, "width", &deinterlace->width))
+ return FALSE;
+ if (!gst_structure_get_int (structure, "height", &deinterlace->height))
+ return FALSE;
+
+ deinterlace->interlaced = FALSE;
+ gst_structure_get_boolean (structure, "interlaced", &deinterlace->interlaced);
+ gst_ffmpegdeinterlace_update_passthrough (deinterlace);
+
+ ctx = avcodec_alloc_context ();
+ ctx->width = deinterlace->width;
+ ctx->height = deinterlace->height;
+ ctx->pix_fmt = PIX_FMT_NB;
+ gst_ffmpeg_caps_with_codectype (AVMEDIA_TYPE_VIDEO, caps, ctx);
+ if (ctx->pix_fmt == PIX_FMT_NB) {
+ av_free (ctx);
+ return FALSE;
+ }
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_CAPS:
- {
- GstStructure *structure;
- AVCodecContext *ctx;
- GstCaps *caps, *src_caps;
+ deinterlace->pixfmt = ctx->pix_fmt;
- gst_event_parse_caps (event, &caps);
- structure = gst_caps_get_structure (caps, 0);
+ av_free (ctx);
- if (!gst_structure_get_int (structure, "width", &deinterlace->width) ||
- !gst_structure_get_int (structure, "height", &deinterlace->height)) {
- goto done;
- }
+ deinterlace->to_size =
+ avpicture_get_size (deinterlace->pixfmt, deinterlace->width,
+ deinterlace->height);
- ctx = avcodec_alloc_context ();
- ctx->width = deinterlace->width;
- ctx->height = deinterlace->height;
- ctx->pix_fmt = PIX_FMT_NB;
- gst_ffmpeg_caps_with_codectype (AVMEDIA_TYPE_VIDEO, caps, ctx);
- if (ctx->pix_fmt == PIX_FMT_NB) {
- av_free (ctx);
- goto done;
- }
+ src_caps = gst_caps_copy (caps);
+ gst_caps_set_simple (src_caps, "interlaced", G_TYPE_BOOLEAN,
+ deinterlace->interlaced, NULL);
+ ret = gst_pad_set_caps (deinterlace->srcpad, src_caps);
+ gst_caps_unref (src_caps);
- deinterlace->pixfmt = ctx->pix_fmt;
+ return ret;
+ }
- av_free (ctx);
++static gboolean
++gst_ffmpegdeinterlace_sink_event (GstPad * pad, GstEvent * event)
++{
++ GstFFMpegDeinterlace *deinterlace =
++ GST_FFMPEGDEINTERLACE (gst_pad_get_parent (pad));
++ gboolean ret = FALSE;
+
- deinterlace->to_size =
- avpicture_get_size (deinterlace->pixfmt, deinterlace->width,
- deinterlace->height);
++ switch (GST_EVENT_TYPE (event)) {
++ case GST_EVENT_CAPS:
++ {
++ GstCaps *caps;
+
- src_caps = gst_caps_copy (caps);
++ gst_event_parse_caps (event, &caps);
++ ret = gst_ffmpegdeinterlace_sink_setcaps (pad, caps);
+ gst_event_unref (event);
-
- gst_caps_set_simple (src_caps, "interlaced", G_TYPE_BOOLEAN, FALSE, NULL);
- event = gst_event_new_caps (src_caps);
- gst_caps_unref (src_caps);
- }
+ break;
++ }
+ default:
++ ret = gst_pad_push_event (deinterlace->srcpad, event);
+ break;
+ }
+
- ret = gst_pad_push_event (deinterlace->srcpad, event);
-
- done:
+ gst_object_unref (deinterlace);
+
+ return ret;
+}
+
static void
-gst_ffmpegdeinterlace_init (GstFFMpegDeinterlace * deinterlace,
- GstFFMpegDeinterlaceClass * klass)
+gst_ffmpegdeinterlace_init (GstFFMpegDeinterlace * deinterlace)
{
deinterlace->sinkpad =
gst_pad_new_from_static_template (&sink_factory, "sink");
GST_FFMPEGDEINTERLACE (gst_pad_get_parent (pad));
GstBuffer *outbuf = NULL;
GstFlowReturn result;
+ guint8 *from_data, *to_data;
+ gsize from_size, to_size;
- if (GST_PAD_CAPS (deinterlace->srcpad))
- gst_ffmpegdeinterlace_sink_setcaps (deinterlace->sinkpad,
- GST_PAD_CAPS (deinterlace->sinkpad));
+ GST_OBJECT_LOCK (deinterlace);
+ if (deinterlace->reconfigure) {
+ if (deinterlace->new_mode != -1)
+ deinterlace->mode = deinterlace->new_mode;
+ deinterlace->new_mode = -1;
+
+ deinterlace->reconfigure = FALSE;
+ GST_OBJECT_UNLOCK (deinterlace);
- result =
- gst_pad_alloc_buffer (deinterlace->srcpad, GST_BUFFER_OFFSET_NONE,
- deinterlace->to_size, GST_PAD_CAPS (deinterlace->srcpad), &outbuf);
- if (result == GST_FLOW_OK) {
- gst_ffmpeg_avpicture_fill (&deinterlace->from_frame,
- GST_BUFFER_DATA (inbuf), deinterlace->pixfmt, deinterlace->width,
- deinterlace->height);
++ if (gst_pad_has_current_caps (deinterlace->srcpad)) {
++ GstCaps *caps;
++
++ caps = gst_pad_get_current_caps (deinterlace->sinkpad);
++ gst_ffmpegdeinterlace_sink_setcaps (deinterlace->sinkpad, caps);
++ gst_caps_unref (caps);
++ }
+ } else {
+ GST_OBJECT_UNLOCK (deinterlace);
+ }
+
+ if (deinterlace->passthrough)
+ return gst_pad_push (deinterlace->srcpad, inbuf);
+
+ outbuf = gst_buffer_new_and_alloc (deinterlace->to_size);
- gst_ffmpeg_avpicture_fill (&deinterlace->to_frame, GST_BUFFER_DATA (outbuf),
- deinterlace->pixfmt, deinterlace->width, deinterlace->height);
+ from_data = gst_buffer_map (inbuf, &from_size, NULL, GST_MAP_READ);
+ gst_ffmpeg_avpicture_fill (&deinterlace->from_frame, from_data,
+ deinterlace->pixfmt, deinterlace->width, deinterlace->height);
- avpicture_deinterlace (&deinterlace->to_frame, &deinterlace->from_frame,
- deinterlace->pixfmt, deinterlace->width, deinterlace->height);
+ to_data = gst_buffer_map (outbuf, &to_size, NULL, GST_MAP_WRITE);
+ gst_ffmpeg_avpicture_fill (&deinterlace->to_frame, to_data,
+ deinterlace->pixfmt, deinterlace->width, deinterlace->height);
- gst_buffer_copy_metadata (outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS);
+ avpicture_deinterlace (&deinterlace->to_frame, &deinterlace->from_frame,
+ deinterlace->pixfmt, deinterlace->width, deinterlace->height);
+ gst_buffer_unmap (outbuf, to_data, to_size);
+ gst_buffer_unmap (inbuf, from_data, from_size);
- result = gst_pad_push (deinterlace->srcpad, outbuf);
- }
+ gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
+
+ result = gst_pad_push (deinterlace->srcpad, outbuf);
gst_buffer_unref (inbuf);
return gst_element_register (plugin, "ffdeinterlace",
GST_RANK_NONE, GST_TYPE_FFMPEGDEINTERLACE);
}
- if (self->mode != new_mode && GST_PAD_CAPS (self->srcpad)) {
+
+ static void
+ gst_ffmpegdeinterlace_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+ {
+ GstFFMpegDeinterlace *self;
+
+ g_return_if_fail (GST_IS_FFMPEGDEINTERLACE (object));
+ self = GST_FFMPEGDEINTERLACE (object);
+
+ switch (prop_id) {
+ case PROP_MODE:{
+ gint new_mode;
+
+ GST_OBJECT_LOCK (self);
+ new_mode = g_value_get_enum (value);
++ if (self->mode != new_mode && gst_pad_has_current_caps (self->srcpad)) {
+ self->reconfigure = TRUE;
+ self->new_mode = new_mode;
+ } else {
+ self->mode = new_mode;
+ gst_ffmpegdeinterlace_update_passthrough (self);
+ }
+ GST_OBJECT_UNLOCK (self);
+ break;
+ }
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
+ }
+
+ }
+
+ static void
+ gst_ffmpegdeinterlace_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+ {
+ GstFFMpegDeinterlace *self;
+
+ g_return_if_fail (GST_IS_FFMPEGDEINTERLACE (object));
+ self = GST_FFMPEGDEINTERLACE (object);
+
+ switch (prop_id) {
+ case PROP_MODE:
+ g_value_set_enum (value, self->mode);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
+ }
+ }