diff --git a/gst/goom/gstgoom.c b/gst/goom/gstgoom.c index 30a6c8ce66..1c90e4bbb3 100644 --- a/gst/goom/gstgoom.c +++ b/gst/goom/gstgoom.c @@ -1,6 +1,7 @@ /* gstgoom.c: implementation of goom drawing element * Copyright (C) <2001> Richard Boulton * (C) <2006> Wim Taymans + * (C) <2011> Wim Taymans * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -86,9 +87,6 @@ static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", ); -static void gst_goom_class_init (GstGoomClass * klass); -static void gst_goom_base_init (GstGoomClass * klass); -static void gst_goom_init (GstGoom * goom); static void gst_goom_finalize (GObject * object); static GstStateChangeReturn gst_goom_change_state (GstElement * element, @@ -100,48 +98,8 @@ static gboolean gst_goom_sink_event (GstPad * pad, GstEvent * event); static gboolean gst_goom_src_query (GstPad * pad, GstQuery * query); -static gboolean gst_goom_sink_setcaps (GstPad * pad, GstCaps * caps); -static gboolean gst_goom_src_setcaps (GstPad * pad, GstCaps * caps); - -static GstElementClass *parent_class = NULL; - -GType -gst_goom_get_type (void) -{ - static GType type = 0; - - if (!type) { - static const GTypeInfo info = { - sizeof (GstGoomClass), - (GBaseInitFunc) gst_goom_base_init, - NULL, - (GClassInitFunc) gst_goom_class_init, - NULL, - NULL, - sizeof (GstGoom), - 0, - (GInstanceInitFunc) gst_goom_init, - }; - - type = g_type_register_static (GST_TYPE_ELEMENT, "GstGoom", &info, 0); - } - return type; -} - -static void -gst_goom_base_init (GstGoomClass * klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - - gst_element_class_set_details_simple (element_class, "GOOM: what a GOOM!", - "Visualization", - "Takes frames of data and outputs video frames using the GOOM filter", - "Wim Taymans "); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&sink_template)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&src_template)); -} +#define gst_goom_parent_class parent_class +G_DEFINE_TYPE (GstGoom, gst_goom, GST_TYPE_ELEMENT); static void gst_goom_class_init (GstGoomClass * klass) @@ -152,10 +110,17 @@ gst_goom_class_init (GstGoomClass * klass) gobject_class = (GObjectClass *) klass; gstelement_class = (GstElementClass *) klass; - parent_class = g_type_class_peek_parent (klass); - gobject_class->finalize = gst_goom_finalize; + gst_element_class_set_details_simple (gstelement_class, "GOOM: what a GOOM!", + "Visualization", + "Takes frames of data and outputs video frames using the GOOM filter", + "Wim Taymans "); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&sink_template)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&src_template)); + gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_goom_change_state); } @@ -168,13 +133,9 @@ gst_goom_init (GstGoom * goom) GST_DEBUG_FUNCPTR (gst_goom_chain)); gst_pad_set_event_function (goom->sinkpad, GST_DEBUG_FUNCPTR (gst_goom_sink_event)); - gst_pad_set_setcaps_function (goom->sinkpad, - GST_DEBUG_FUNCPTR (gst_goom_sink_setcaps)); gst_element_add_pad (GST_ELEMENT (goom), goom->sinkpad); goom->srcpad = gst_pad_new_from_static_template (&src_template, "src"); - gst_pad_set_setcaps_function (goom->srcpad, - GST_DEBUG_FUNCPTR (gst_goom_src_setcaps)); gst_pad_set_event_function (goom->srcpad, GST_DEBUG_FUNCPTR (gst_goom_src_event)); gst_pad_set_query_function (goom->srcpad, @@ -203,6 +164,8 @@ gst_goom_finalize (GObject * object) goom->plugin = NULL; g_object_unref (goom->adapter); + if (goom->pool) + gst_object_unref (goom->pool); G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -220,14 +183,11 @@ gst_goom_reset (GstGoom * goom) } static gboolean -gst_goom_sink_setcaps (GstPad * pad, GstCaps * caps) +gst_goom_sink_setcaps (GstGoom * goom, GstCaps * caps) { - GstGoom *goom; GstStructure *structure; gboolean res; - goom = GST_GOOM (GST_PAD_PARENT (pad)); - structure = gst_caps_get_structure (caps, 0); res = gst_structure_get_int (structure, "channels", &goom->channels); @@ -235,24 +195,21 @@ gst_goom_sink_setcaps (GstPad * pad, GstCaps * caps) goom->bps = goom->channels * sizeof (gint16); - return res; + return TRUE; } static gboolean -gst_goom_src_setcaps (GstPad * pad, GstCaps * caps) +gst_goom_src_setcaps (GstGoom * goom, GstCaps * caps) { - GstGoom *goom; GstStructure *structure; - - goom = GST_GOOM (GST_PAD_PARENT (pad)); + gboolean res; structure = gst_caps_get_structure (caps, 0); - if (!gst_structure_get_int (structure, "width", &goom->width) || !gst_structure_get_int (structure, "height", &goom->height) || !gst_structure_get_fraction (structure, "framerate", &goom->fps_n, &goom->fps_d)) - return FALSE; + goto error; goom_set_resolution (goom->plugin, goom->width, goom->height); @@ -266,32 +223,46 @@ gst_goom_src_setcaps (GstPad * pad, GstCaps * caps) GST_DEBUG_OBJECT (goom, "dimension %dx%d, framerate %d/%d, spf %d", goom->width, goom->height, goom->fps_n, goom->fps_d, goom->spf); - return TRUE; + res = gst_pad_push_event (goom->srcpad, gst_event_new_caps (caps)); + + return res; + + /* ERRORS */ +error: + { + GST_DEBUG_OBJECT (goom, "error parsing caps"); + return FALSE; + } } static gboolean gst_goom_src_negotiate (GstGoom * goom) { + gboolean res; GstCaps *othercaps, *target; GstStructure *structure; - const GstCaps *templ; + GstCaps *templ; + GstQuery *query; + GstBufferPool *pool = NULL; + guint size, min, max, prefix, alignment; templ = gst_pad_get_pad_template_caps (goom->srcpad); GST_DEBUG_OBJECT (goom, "performing negotiation"); /* see what the peer can do */ - othercaps = gst_pad_peer_get_caps (goom->srcpad); + othercaps = gst_pad_peer_get_caps (goom->srcpad, NULL); if (othercaps) { target = gst_caps_intersect (othercaps, templ); gst_caps_unref (othercaps); + gst_caps_unref (templ); if (gst_caps_is_empty (target)) goto no_format; gst_caps_truncate (target); } else { - target = gst_caps_ref ((GstCaps *) templ); + target = templ; } structure = gst_caps_get_structure (target, 0); @@ -300,7 +271,42 @@ gst_goom_src_negotiate (GstGoom * goom) gst_structure_fixate_field_nearest_fraction (structure, "framerate", DEFAULT_FPS_N, DEFAULT_FPS_D); - gst_pad_set_caps (goom->srcpad, target); + res = gst_goom_src_setcaps (goom, target); + + /* try to get a bufferpool now */ + /* find a pool for the negotiated caps now */ + query = gst_query_new_allocation (target, TRUE); + + if (gst_pad_peer_query (goom->srcpad, query)) { + /* we got configuration from our peer, parse them */ + gst_query_parse_allocation_params (query, &size, &min, &max, &prefix, + &alignment, &pool); + } else { + size = goom->outsize; + min = max = 0; + prefix = 0; + alignment = 1; + } + + if (pool == NULL) { + GstStructure *config; + + /* we did not get a pool, make one ourselves then */ + pool = gst_buffer_pool_new (); + + config = gst_buffer_pool_get_config (pool); + gst_buffer_pool_config_set (config, target, size, min, max, prefix, 0, + alignment); + gst_buffer_pool_set_config (pool, config); + } + + if (goom->pool) + gst_object_unref (goom->pool); + goom->pool = pool; + + /* and activate */ + gst_buffer_pool_set_active (pool, TRUE); + gst_caps_unref (target); return TRUE; @@ -327,7 +333,7 @@ gst_goom_src_event (GstPad * pad, GstEvent * event) GstClockTimeDiff diff; GstClockTime timestamp; - gst_event_parse_qos (event, &proportion, &diff, ×tamp); + gst_event_parse_qos (event, NULL, &proportion, &diff, ×tamp); /* save stuff for the _chain() function */ GST_OBJECT_LOCK (goom); @@ -361,6 +367,14 @@ gst_goom_sink_event (GstPad * pad, GstEvent * event) goom = GST_GOOM (gst_pad_get_parent (pad)); switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_CAPS: + { + GstCaps *caps; + + gst_event_parse_caps (event, &caps); + res = gst_goom_sink_setcaps (goom, caps); + break; + } case GST_EVENT_FLUSH_START: res = gst_pad_push_event (goom->srcpad, event); break; @@ -368,22 +382,12 @@ gst_goom_sink_event (GstPad * pad, GstEvent * event) gst_goom_reset (goom); res = gst_pad_push_event (goom->srcpad, event); break; - case GST_EVENT_NEWSEGMENT: + case GST_EVENT_SEGMENT: { - GstFormat format; - gdouble rate, arate; - gint64 start, stop, time; - gboolean update; - /* the newsegment values are used to clip the input samples * and to convert the incomming timestamps to running time so * we can do QoS */ - gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, - &start, &stop, &time); - - /* now configure the values */ - gst_segment_set_newsegment_full (&goom->segment, update, - rate, arate, format, start, stop, time); + gst_event_copy_segment (event, &goom->segment); res = gst_pad_push_event (goom->srcpad, event); break; @@ -454,29 +458,26 @@ gst_goom_src_query (GstPad * pad, GstQuery * query) return res; } +/* make sure we are negotiated */ static GstFlowReturn -get_buffer (GstGoom * goom, GstBuffer ** outbuf) +ensure_negotiated (GstGoom * goom) { - GstFlowReturn ret; + gboolean reconfigure; - if (GST_PAD_CAPS (goom->srcpad) == NULL) { + GST_OBJECT_LOCK (goom->srcpad); + reconfigure = GST_PAD_NEEDS_RECONFIGURE (goom->srcpad); + GST_OBJECT_FLAG_UNSET (goom->srcpad, GST_PAD_NEED_RECONFIGURE); + GST_OBJECT_UNLOCK (goom->srcpad); + + /* we don't know an output format yet, pick one */ + if (reconfigure || !gst_pad_has_current_caps (goom->srcpad)) { if (!gst_goom_src_negotiate (goom)) return GST_FLOW_NOT_NEGOTIATED; } - - GST_DEBUG_OBJECT (goom, "allocating output buffer with caps %" - GST_PTR_FORMAT, GST_PAD_CAPS (goom->srcpad)); - - ret = - gst_pad_alloc_buffer_and_set_caps (goom->srcpad, - GST_BUFFER_OFFSET_NONE, goom->outsize, - GST_PAD_CAPS (goom->srcpad), outbuf); - if (ret != GST_FLOW_OK) - return ret; - return GST_FLOW_OK; } + static GstFlowReturn gst_goom_chain (GstPad * pad, GstBuffer * buffer) { @@ -490,14 +491,11 @@ gst_goom_chain (GstPad * pad, GstBuffer * buffer) goto beach; } - /* If we don't have an output format yet, preallocate a buffer to try and - * set one */ - if (GST_PAD_CAPS (goom->srcpad) == NULL) { - ret = get_buffer (goom, &outbuf); - if (ret != GST_FLOW_OK) { - gst_buffer_unref (buffer); - goto beach; - } + /* Make sure have an output format */ + ret = ensure_negotiated (goom); + if (ret != GST_FLOW_OK) { + gst_buffer_unref (buffer); + goto beach; } /* don't try to combine samples from discont buffer */ @@ -507,7 +505,7 @@ gst_goom_chain (GstPad * pad, GstBuffer * buffer) GST_DEBUG_OBJECT (goom, "Input buffer has %d samples, time=%" G_GUINT64_FORMAT, - GST_BUFFER_SIZE (buffer) / goom->bps, GST_BUFFER_TIMESTAMP (buffer)); + gst_buffer_get_size (buffer) / goom->bps, GST_BUFFER_TIMESTAMP (buffer)); /* Collect samples until we have enough for an output frame */ gst_adapter_push (goom->adapter, buffer); @@ -565,7 +563,7 @@ gst_goom_chain (GstPad * pad, GstBuffer * buffer) /* get next GOOM_SAMPLES, we have at least this amount of samples */ data = - (const guint16 *) gst_adapter_peek (goom->adapter, + (const guint16 *) gst_adapter_map (goom->adapter, GOOM_SAMPLES * goom->bps); if (goom->channels == 2) { @@ -583,18 +581,21 @@ gst_goom_chain (GstPad * pad, GstBuffer * buffer) /* alloc a buffer if we don't have one yet, this happens * when we pushed a buffer in this while loop before */ if (outbuf == NULL) { - ret = get_buffer (goom, &outbuf); + GST_DEBUG_OBJECT (goom, "allocating output buffer"); + ret = gst_buffer_pool_acquire_buffer (goom->pool, &outbuf, NULL); if (ret != GST_FLOW_OK) { + gst_adapter_unmap (goom->adapter, 0); goto beach; } } GST_BUFFER_TIMESTAMP (outbuf) = timestamp; GST_BUFFER_DURATION (outbuf) = goom->duration; - GST_BUFFER_SIZE (outbuf) = goom->outsize; out_frame = (guchar *) goom_update (goom->plugin, goom->datain, 0, 0); - memcpy (GST_BUFFER_DATA (outbuf), out_frame, goom->outsize); + gst_buffer_fill (outbuf, 0, out_frame, goom->outsize); + + gst_adapter_unmap (goom->adapter, 0); GST_DEBUG ("Pushing frame with time=%" GST_TIME_FORMAT ", duration=%" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp), @@ -645,6 +646,11 @@ gst_goom_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: + if (goom->pool) { + gst_buffer_pool_set_active (goom->pool, FALSE); + gst_object_unref (goom->pool); + goom->pool = NULL; + } break; case GST_STATE_CHANGE_READY_TO_NULL: break; diff --git a/gst/goom/gstgoom.h b/gst/goom/gstgoom.h index 382d05315c..16e745d93f 100644 --- a/gst/goom/gstgoom.h +++ b/gst/goom/gstgoom.h @@ -57,6 +57,7 @@ struct _GstGoom gint height; GstClockTime duration; guint outsize; + GstBufferPool *pool; /* samples per frame */ guint spf;