diff --git a/ChangeLog b/ChangeLog index 1a70e56e9d..b45781b353 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2007-07-13 Sebastian Dröge + + * ext/mad/gstmad.c: (_do_init), (gst_mad_init), (index_seek), + (normal_seek), (gst_mad_sink_event), (clip_outgoing_buffer), + (gst_mad_chain), (gst_mad_change_state): + * ext/mad/gstmad.h: + Implement buffer clipping and use GST_BOILERPLATE instead of manual + GType magic. Part one of bug #308312. + 2007-07-12 Stefan Kost * configure.ac: diff --git a/ext/mad/gstmad.c b/ext/mad/gstmad.c index 6c5082099e..890c683dff 100644 --- a/ext/mad/gstmad.c +++ b/ext/mad/gstmad.c @@ -23,6 +23,7 @@ #include #include "gstmad.h" +#include /* elementfactory information */ @@ -70,7 +71,7 @@ GST_STATIC_PAD_TEMPLATE ("sink", static void gst_mad_base_init (gpointer g_class); static void gst_mad_class_init (GstMadClass * klass); -static void gst_mad_init (GstMad * mad); +static void gst_mad_init (GstMad * mad, GstMadClass * klass); static void gst_mad_dispose (GObject * object); static void gst_mad_set_property (GObject * object, guint prop_id, @@ -97,34 +98,14 @@ static GstStateChangeReturn gst_mad_change_state (GstElement * element, static void gst_mad_set_index (GstElement * element, GstIndex * index); static GstIndex *gst_mad_get_index (GstElement * element); - -static GstElementClass *parent_class = NULL; - -GType -gst_mad_get_type (void) +static void +_do_init (GType type) { - static GType mad_type = 0; - - if (!mad_type) { - static const GTypeInfo mad_info = { - sizeof (GstMadClass), - gst_mad_base_init, - NULL, - (GClassInitFunc) gst_mad_class_init, - NULL, - NULL, - sizeof (GstMad), - 0, - (GInstanceInitFunc) gst_mad_init, - }; - - mad_type = - g_type_register_static (GST_TYPE_ELEMENT, "GstMad", &mad_info, 0); - } GST_DEBUG_CATEGORY_INIT (mad_debug, "mad", 0, "mad mp3 decoding"); - return mad_type; } +GST_BOILERPLATE_FULL (GstMad, gst_mad, GstElement, GST_TYPE_ELEMENT, _do_init); + #define GST_TYPE_MAD_LAYER (gst_mad_layer_get_type()) G_GNUC_UNUSED static GType gst_mad_layer_get_type (void) @@ -239,7 +220,7 @@ gst_mad_class_init (GstMadClass * klass) } static void -gst_mad_init (GstMad * mad) +gst_mad_init (GstMad * mad, GstMadClass * klass) { GstPadTemplate *template; @@ -273,6 +254,7 @@ gst_mad_init (GstMad * mad) mad->vbr_rate = 0; mad->restart = TRUE; mad->segment_start = 0; + gst_segment_init (&mad->segment, GST_FORMAT_TIME); mad->header.mode = -1; mad->header.emphasis = -1; mad->tags = NULL; @@ -621,6 +603,13 @@ index_seek (GstMad * mad, GstPad * pad, GstEvent * event) gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur, &stop_type, &stop); + if (format == GST_FORMAT_TIME) { + gst_segment_set_seek (&mad->segment, rate, format, flags, cur_type, + cur, stop_type, stop, NULL); + } else { + gst_segment_init (&mad->segment, GST_FORMAT_UNDEFINED); + } + entry = gst_index_get_assoc_entry (mad->index, mad->index_id, GST_INDEX_LOOKUP_BEFORE, 0, format, cur); @@ -695,6 +684,9 @@ normal_seek (GstMad * mad, GstPad * pad, GstEvent * event) time_stop = stop; } + gst_segment_set_seek (&mad->segment, rate, GST_FORMAT_TIME, flags, cur_type, + time_cur, stop_type, time_stop, NULL); + GST_DEBUG ("seek to time %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT, GST_TIME_ARGS (time_cur), GST_TIME_ARGS (time_stop)); @@ -944,9 +936,12 @@ gst_mad_sink_event (GstPad * pad, GstEvent * event) switch (GST_EVENT_TYPE (event)) { case GST_EVENT_NEWSEGMENT:{ GstFormat format; + gboolean update; + gdouble rate, applied_rate; + gint64 start, stop, pos; - gst_event_parse_new_segment (event, NULL, NULL, &format, NULL, NULL, - NULL); + gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate, + &format, &start, &stop, &pos); if (format == GST_FORMAT_TIME) { /* FIXME: is this really correct? */ @@ -955,6 +950,8 @@ gst_mad_sink_event (GstPad * pad, GstEvent * event) /* we don't need to restart when we get here */ mad->restart = FALSE; mad->framed = TRUE; + gst_segment_set_newsegment_full (&mad->segment, update, rate, + applied_rate, GST_FORMAT_TIME, start, stop, pos); } else { GST_DEBUG ("dropping newsegment event in format %s", gst_format_get_name (format)); @@ -1226,6 +1223,51 @@ gst_mad_check_caps_reset (GstMad * mad) } } +/* + clips buffer to currently configured segment. Returns FALSE if the buffer + has to be dropped. +*/ +static gboolean +clip_outgoing_buffer (GstMad * mad, GstBuffer * buffer) +{ + gint64 start, stop, cstart, cstop, diff; + gboolean res = TRUE; + + if (mad->segment.format != GST_FORMAT_TIME) + goto beach; + + start = GST_BUFFER_TIMESTAMP (buffer); + stop = start + GST_BUFFER_DURATION (buffer); + + if (gst_segment_clip (&mad->segment, GST_FORMAT_TIME, + start, stop, &cstart, &cstop)) { + diff = cstart - start; + if (diff > 0) { + GST_BUFFER_TIMESTAMP (buffer) = cstart; + GST_BUFFER_DURATION (buffer) -= diff; + + /* time->frames->bytes */ + diff = 4 * mad->channels * GST_CLOCK_TIME_TO_FRAMES (diff, mad->rate); + GST_BUFFER_DATA (buffer) += diff; + GST_BUFFER_SIZE (buffer) -= diff; + } + diff = cstop - stop; + if (diff > 0) { + GST_BUFFER_DURATION (buffer) -= diff; + /* time->frames->bytes */ + diff = 4 * mad->channels * GST_CLOCK_TIME_TO_FRAMES (diff, mad->rate); + /* update size */ + GST_BUFFER_SIZE (buffer) -= diff; + } + } else { + GST_DEBUG_OBJECT (mad, "buffer is outside configured segment"); + res = FALSE; + } + +beach: + return res; +} + static GstFlowReturn gst_mad_chain (GstPad * pad, GstBuffer * buffer) { @@ -1516,6 +1558,9 @@ gst_mad_chain (GstPad * pad, GstBuffer * buffer) GST_DEBUG ("Sending NEWSEGMENT event, start=%" GST_TIME_FORMAT, GST_TIME_ARGS (start)); + gst_segment_set_newsegment (&mad->segment, FALSE, 1.0, + GST_FORMAT_TIME, start, GST_CLOCK_TIME_NONE, start); + gst_pad_push_event (mad->srcpad, gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, start, GST_CLOCK_TIME_NONE, start)); @@ -1563,10 +1608,23 @@ gst_mad_chain (GstPad * pad, GstBuffer * buffer) } } - result = gst_pad_push (mad->srcpad, outbuffer); - if (result != GST_FLOW_OK) { - /* Head for the exit, dropping samples as we go */ - goto_exit = TRUE; + if (clip_outgoing_buffer (mad, outbuffer)) { + GST_LOG_OBJECT (mad, + "pushing buffer, off=%" G_GUINT64_FORMAT ", ts=%" GST_TIME_FORMAT, + GST_BUFFER_OFFSET (outbuffer), + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuffer))); + mad->segment.last_stop = GST_BUFFER_TIMESTAMP (outbuffer); + result = gst_pad_push (mad->srcpad, outbuffer); + if (result != GST_FLOW_OK) { + /* Head for the exit, dropping samples as we go */ + goto_exit = TRUE; + } + } else { + GST_LOG_OBJECT (mad, "Dropping buffer" + ", off=%" G_GUINT64_FORMAT ", ts=%" GST_TIME_FORMAT, + GST_BUFFER_OFFSET (outbuffer), + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuffer))); + gst_buffer_unref (outbuffer); } } @@ -1639,7 +1697,7 @@ gst_mad_change_state (GstElement * element, GstStateChange transition) mad->caps_set = FALSE; mad->times_pending = mad->pending_rate = mad->pending_channels = 0; mad->vbr_average = 0; - mad->segment_start = 0; + gst_segment_init (&mad->segment, GST_FORMAT_TIME); mad->new_header = TRUE; mad->framed = FALSE; mad->framecount = 0; diff --git a/ext/mad/gstmad.h b/ext/mad/gstmad.h index 74479a2b21..ce8c9565c0 100644 --- a/ext/mad/gstmad.h +++ b/ext/mad/gstmad.h @@ -64,6 +64,7 @@ struct _GstMad gboolean in_error; /* set when mad's in an error state */ gboolean restart; guint64 segment_start; + GstSegment segment; gboolean need_newsegment; /* info */