diff options
author | Matthieu Bouron <matthieu.bouron@collabora.com> | 2013-08-13 18:42:55 +0100 |
---|---|---|
committer | Tim-Philipp Müller <tim@centricular.net> | 2013-08-17 00:25:49 +0100 |
commit | d69b6e53e463bc96b7457c3a3f99f1d07c891610 (patch) | |
tree | 64993bccce73868f4c51cc89e7e59441167f8ca3 | |
parent | 27bceba4adf6eaf3f0643958b4da4f8df791a0da (diff) |
aiffparse: fix push mode
Fix push mode by handling sink events (CAPS, SEGMENT) properly.
https://bugzilla.gnome.org/show_bug.cgi?id=705993
-rw-r--r-- | gst/aiff/aiffparse.c | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/gst/aiff/aiffparse.c b/gst/aiff/aiffparse.c index 9549caedf..6b6540d74 100644 --- a/gst/aiff/aiffparse.c +++ b/gst/aiff/aiffparse.c @@ -74,6 +74,8 @@ static gboolean gst_aiff_parse_sink_activate (GstPad * sinkpad, GstObject * parent); static gboolean gst_aiff_parse_sink_activate_mode (GstPad * sinkpad, GstObject * parent, GstPadMode mode, gboolean active); +static gboolean gst_aiff_parse_sink_event (GstPad * pad, GstObject * parent, + GstEvent * buf); static gboolean gst_aiff_parse_send_event (GstElement * element, GstEvent * event); static GstStateChangeReturn gst_aiff_parse_change_state (GstElement * element, @@ -191,6 +193,8 @@ gst_aiff_parse_init (GstAiffParse * aiffparse) GST_DEBUG_FUNCPTR (gst_aiff_parse_sink_activate)); gst_pad_set_activatemode_function (aiffparse->sinkpad, GST_DEBUG_FUNCPTR (gst_aiff_parse_sink_activate_mode)); + gst_pad_set_event_function (aiffparse->sinkpad, + GST_DEBUG_FUNCPTR (gst_aiff_parse_sink_event)); gst_pad_set_chain_function (aiffparse->sinkpad, GST_DEBUG_FUNCPTR (gst_aiff_parse_chain)); gst_element_add_pad (GST_ELEMENT_CAST (aiffparse), aiffparse->sinkpad); @@ -1670,6 +1674,130 @@ gst_aiff_parse_sink_activate_mode (GstPad * sinkpad, GstObject * parent, return res; }; +static GstFlowReturn +gst_aiff_parse_flush_data (GstAiffParse * aiff) +{ + GstFlowReturn ret = GST_FLOW_OK; + guint av; + + if ((av = gst_adapter_available (aiff->adapter)) > 0) { + aiff->dataleft = av; + aiff->end_offset = aiff->offset + av; + ret = gst_aiff_parse_stream_data (aiff); + } + + return ret; +} + + +static gboolean +gst_aiff_parse_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) +{ + GstAiffParse *aiff = GST_AIFF_PARSE (parent); + gboolean ret = TRUE; + + GST_DEBUG_OBJECT (aiff, "handling %s event", GST_EVENT_TYPE_NAME (event)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_CAPS: + { + /* discard, we'll come up with proper src caps */ + gst_event_unref (event); + break; + } + case GST_EVENT_SEGMENT: + { + gint64 start, stop, offset = 0, end_offset = -1; + GstSegment segment; + + /* some debug output */ + gst_event_copy_segment (event, &segment); + GST_DEBUG_OBJECT (aiff, "received segment %" GST_SEGMENT_FORMAT, + &segment); + + /* now we are either committed to TIME or BYTE format, + * and we only expect a BYTE segment, e.g. following a seek */ + if (segment.format == GST_FORMAT_BYTES) { + /* handle (un)signed issues */ + start = segment.start; + stop = segment.stop; + if (start > 0) { + offset = start; + start -= aiff->datastart; + start = MAX (start, 0); + } + if (stop > 0) { + end_offset = stop; + segment.stop -= aiff->datastart; + segment.stop = MAX (stop, 0); + } + if (aiff->state == AIFF_PARSE_DATA && + aiff->segment.format == GST_FORMAT_TIME) { + guint64 bps = aiff->bps; + + /* operating in format TIME, so we can convert */ + if (bps) { + if (start >= 0) + start = + gst_util_uint64_scale_ceil (start, GST_SECOND, + (guint64) aiff->bps); + if (stop >= 0) + stop = + gst_util_uint64_scale_ceil (stop, GST_SECOND, + (guint64) aiff->bps); + } else { + GST_DEBUG_OBJECT (aiff, "unable to compute segment start/stop"); + goto exit; + } + } + } else { + GST_DEBUG_OBJECT (aiff, "unsupported segment format, ignoring"); + goto exit; + } + + segment.start = start; + segment.stop = stop; + + /* accept upstream's notion of segment and distribute along */ + if (aiff->state == AIFF_PARSE_DATA) { + segment.format = aiff->segment.format; + segment.time = segment.position = segment.start; + segment.duration = aiff->segment.duration; + segment.base = gst_segment_to_running_time (&aiff->segment, + GST_FORMAT_TIME, aiff->segment.position); + } + + gst_segment_copy_into (&segment, &aiff->segment); + + if (aiff->start_segment) + gst_event_unref (aiff->start_segment); + + aiff->start_segment = gst_event_new_segment (&segment); + + /* stream leftover data in current segment */ + if (aiff->state == AIFF_PARSE_DATA) + gst_aiff_parse_flush_data (aiff); + /* and set up streaming thread for next one */ + aiff->offset = offset; + aiff->end_offset = end_offset; + if (aiff->end_offset > 0) { + aiff->dataleft = aiff->end_offset - aiff->offset; + } else { + /* infinity; upstream will EOS when done */ + aiff->dataleft = G_MAXUINT64; + } + exit: + gst_event_unref (event); + break; + } + default: + ret = gst_pad_event_default (aiff->sinkpad, parent, event); + break; + } + + return ret; +} + static GstStateChangeReturn gst_aiff_parse_change_state (GstElement * element, GstStateChange transition) { |