ext/a52dec/gsta52dec.*: Add segment handling, buffer clipping and basic reverse playback.

Original commit message from CVS:
* ext/a52dec/gsta52dec.c: (clear_queued), (flush_queued),
(gst_a52dec_drain), (gst_a52dec_push), (gst_a52dec_sink_event),
(gst_a52dec_chain), (gst_a52dec_change_state):
* ext/a52dec/gsta52dec.h:
Add segment handling, buffer clipping and basic reverse playback.
This commit is contained in:
Wim Taymans 2008-06-02 11:59:07 +00:00
parent c2e3aede74
commit 8a0500bf3b
4 changed files with 103 additions and 21 deletions

View file

@ -1,3 +1,11 @@
2008-06-02 Wim Taymans <wim.taymans@collabora.co.uk>
* ext/a52dec/gsta52dec.c: (clear_queued), (flush_queued),
(gst_a52dec_drain), (gst_a52dec_push), (gst_a52dec_sink_event),
(gst_a52dec_chain), (gst_a52dec_change_state):
* ext/a52dec/gsta52dec.h:
Add segment handling, buffer clipping and basic reverse playback.
2008-05-28 Stefan Kost <ensonic@users.sf.net> 2008-05-28 Stefan Kost <ensonic@users.sf.net>
* docs/plugins/Makefile.am: * docs/plugins/Makefile.am:

2
common

@ -1 +1 @@
Subproject commit 032f2d973bd5c9a9b457cb5fc72d13dafe85c01e Subproject commit 130fa8f739ff09aedb520c33239f53d06cfe9bd5

View file

@ -341,6 +341,48 @@ gst_a52dec_channels (int flags, GstAudioChannelPosition ** _pos)
return chans; return chans;
} }
static void
clear_queued (GstA52Dec * dec)
{
g_list_foreach (dec->queued, (GFunc) gst_mini_object_unref, NULL);
g_list_free (dec->queued);
dec->queued = NULL;
}
static GstFlowReturn
flush_queued (GstA52Dec * dec)
{
GstFlowReturn ret = GST_FLOW_OK;
while (dec->queued) {
GstBuffer *buf = GST_BUFFER_CAST (dec->queued->data);
GST_LOG_OBJECT (dec, "pushing buffer %p, timestamp %"
GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT, buf,
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
/* iterate ouput queue an push downstream */
ret = gst_pad_push (dec->srcpad, buf);
dec->queued = g_list_delete_link (dec->queued, dec->queued);
}
return ret;
}
static GstFlowReturn
gst_a52dec_drain (GstA52Dec * dec)
{
GstFlowReturn ret = GST_FLOW_OK;
if (dec->segment.rate < 0.0) {
/* if we have some queued frames for reverse playback, flush
* them now */
ret = flush_queued (dec);
}
return ret;
}
static GstFlowReturn static GstFlowReturn
gst_a52dec_push (GstA52Dec * a52dec, gst_a52dec_push (GstA52Dec * a52dec,
GstPad * srcpad, int flags, sample_t * samples, GstClockTime timestamp) GstPad * srcpad, int flags, sample_t * samples, GstClockTime timestamp)
@ -371,6 +413,10 @@ gst_a52dec_push (GstA52Dec * a52dec,
} }
GST_BUFFER_TIMESTAMP (buf) = timestamp; GST_BUFFER_TIMESTAMP (buf) = timestamp;
GST_BUFFER_DURATION (buf) = 256 * GST_SECOND / a52dec->sample_rate; GST_BUFFER_DURATION (buf) = 256 * GST_SECOND / a52dec->sample_rate;
result = GST_FLOW_OK;
if ((buf = gst_audio_buffer_clip (buf, &a52dec->segment,
a52dec->sample_rate, (SAMPLE_WIDTH / 8) * chans))) {
/* set discont when needed */ /* set discont when needed */
if (a52dec->discont) { if (a52dec->discont) {
GST_LOG_OBJECT (a52dec, "marking DISCONT"); GST_LOG_OBJECT (a52dec, "marking DISCONT");
@ -378,12 +424,20 @@ gst_a52dec_push (GstA52Dec * a52dec,
a52dec->discont = FALSE; a52dec->discont = FALSE;
} }
if (a52dec->segment.rate > 0.0) {
GST_DEBUG_OBJECT (a52dec, GST_DEBUG_OBJECT (a52dec,
"Pushing buffer with ts %" GST_TIME_FORMAT " duration %" GST_TIME_FORMAT, "Pushing buffer with ts %" GST_TIME_FORMAT " duration %"
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
return gst_pad_push (srcpad, buf); result = gst_pad_push (srcpad, buf);
} else {
/* reverse playback, queue frame till later when we get a discont. */
GST_DEBUG_OBJECT (a52dec, "queued frame");
a52dec->queued = g_list_prepend (a52dec->queued, buf);
}
}
return result;
} }
static gboolean static gboolean
@ -428,26 +482,40 @@ gst_a52dec_sink_event (GstPad * pad, GstEvent * event)
GST_LOG ("Handling %s event", GST_EVENT_TYPE_NAME (event)); GST_LOG ("Handling %s event", GST_EVENT_TYPE_NAME (event));
switch (GST_EVENT_TYPE (event)) { switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_NEWSEGMENT:{ case GST_EVENT_NEWSEGMENT:
GstFormat format; {
gint64 val; GstFormat fmt;
gboolean update;
gint64 start, end, pos;
gdouble rate;
gst_event_parse_new_segment (event, NULL, NULL, &format, &val, NULL, gst_event_parse_new_segment (event, &update, &rate, &fmt, &start, &end,
NULL); &pos);
if (format != GST_FORMAT_TIME || !GST_CLOCK_TIME_IS_VALID (val)) {
if (fmt != GST_FORMAT_TIME || !GST_CLOCK_TIME_IS_VALID (start)) {
GST_WARNING ("No time in newsegment event %p (format is %s)", GST_WARNING ("No time in newsegment event %p (format is %s)",
event, gst_format_get_name (format)); event, gst_format_get_name (fmt));
gst_event_unref (event); gst_event_unref (event);
a52dec->sent_segment = FALSE; a52dec->sent_segment = FALSE;
/* set some dummy values, FIXME do proper conversion */
} else { } else {
a52dec->time = val; a52dec->time = start;
a52dec->sent_segment = TRUE; a52dec->sent_segment = TRUE;
ret = gst_pad_push_event (a52dec->srcpad, event); ret = gst_pad_push_event (a52dec->srcpad, event);
} }
/* drain queued buffers before activating the segment so that we can clip
* against the old segment first */
gst_a52dec_drain (a52dec);
gst_segment_set_newsegment (&a52dec->segment, update, rate, fmt, start,
end, pos);
break; break;
} }
case GST_EVENT_TAG: case GST_EVENT_TAG:
ret = gst_pad_push_event (a52dec->srcpad, event);
break;
case GST_EVENT_EOS: case GST_EVENT_EOS:
gst_a52dec_drain (a52dec);
ret = gst_pad_push_event (a52dec->srcpad, event); ret = gst_pad_push_event (a52dec->srcpad, event);
break; break;
case GST_EVENT_FLUSH_START: case GST_EVENT_FLUSH_START:
@ -458,6 +526,7 @@ gst_a52dec_sink_event (GstPad * pad, GstEvent * event)
gst_buffer_unref (a52dec->cache); gst_buffer_unref (a52dec->cache);
a52dec->cache = NULL; a52dec->cache = NULL;
} }
clear_queued (a52dec);
gst_segment_init (&a52dec->segment, GST_FORMAT_UNDEFINED); gst_segment_init (&a52dec->segment, GST_FORMAT_UNDEFINED);
ret = gst_pad_push_event (a52dec->srcpad, event); ret = gst_pad_push_event (a52dec->srcpad, event);
break; break;
@ -626,6 +695,7 @@ gst_a52dec_chain (GstPad * pad, GstBuffer * buf)
if (GST_BUFFER_IS_DISCONT (buf)) { if (GST_BUFFER_IS_DISCONT (buf)) {
GST_LOG_OBJECT (a52dec, "received DISCONT"); GST_LOG_OBJECT (a52dec, "received DISCONT");
gst_a52dec_drain (a52dec);
/* clear cache on discont and mark a discont in the element */ /* clear cache on discont and mark a discont in the element */
if (a52dec->cache) { if (a52dec->cache) {
gst_buffer_unref (a52dec->cache); gst_buffer_unref (a52dec->cache);
@ -827,6 +897,7 @@ gst_a52dec_change_state (GstElement * element, GstStateChange transition)
gst_buffer_unref (a52dec->cache); gst_buffer_unref (a52dec->cache);
a52dec->cache = NULL; a52dec->cache = NULL;
} }
clear_queued (a52dec);
break; break;
case GST_STATE_CHANGE_READY_TO_NULL: case GST_STATE_CHANGE_READY_TO_NULL:
a52_free (a52dec->state); a52_free (a52dec->state);

View file

@ -65,6 +65,9 @@ struct _GstA52Dec {
GstBuffer *cache; GstBuffer *cache;
GstClockTime time; GstClockTime time;
/* reverse */
GList *queued;
}; };
struct _GstA52DecClass { struct _GstA52DecClass {