From a61dceb24df9556246aaa290af5d494549f592c3 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 31 Jan 2004 17:19:21 +0000 Subject: [PATCH] ext/alsa/gstalsa.c: start clock on PAUSED=>PLAYING, not later Original commit message from CVS: 2004-01-31 Benjamin Otte * ext/alsa/gstalsa.c: (gst_alsa_change_state), (gst_alsa_start): start clock on PAUSED=>PLAYING, not later * ext/alsa/gstalsasink.c: (gst_alsa_sink_check_event): extract correct time for different discont formats (gst_alsa_sink_get_time): don't segfault when no format is negotiated yet, just return 0 * ext/ogg/gstoggdemux.c: (gst_ogg_demux_src_event), (gst_ogg_demux_handle_event), (gst_ogg_demux_push), (gst_ogg_pad_push): handle flush and discont events correctly * ext/vorbis/vorbisdec.c: (vorbis_dec_event), (vorbis_dec_chain): handle discont events correctly --- ChangeLog | 15 +++++++++ ext/alsa/gstalsa.c | 4 +-- ext/alsa/gstalsasink.c | 13 ++++++-- ext/ogg/gstoggdemux.c | 76 +++++++++++++++++++++++++++++------------- ext/vorbis/vorbisdec.c | 25 +++++++++++--- 5 files changed, 101 insertions(+), 32 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0ecaac15a5..94b685e00e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2004-01-31 Benjamin Otte + + * ext/alsa/gstalsa.c: (gst_alsa_change_state), (gst_alsa_start): + start clock on PAUSED=>PLAYING, not later + * ext/alsa/gstalsasink.c: (gst_alsa_sink_check_event): + extract correct time for different discont formats + (gst_alsa_sink_get_time): + don't segfault when no format is negotiated yet, just return 0 + * ext/ogg/gstoggdemux.c: (gst_ogg_demux_src_event), + (gst_ogg_demux_handle_event), (gst_ogg_demux_push), + (gst_ogg_pad_push): + handle flush and discont events correctly + * ext/vorbis/vorbisdec.c: (vorbis_dec_event), (vorbis_dec_chain): + handle discont events correctly + 2004-01-31 Thomas Vander Stichele * gst-libs/gst/play/play.c: (gst_play_error_quark), diff --git a/ext/alsa/gstalsa.c b/ext/alsa/gstalsa.c index b41765bc91..85b297ec59 100644 --- a/ext/alsa/gstalsa.c +++ b/ext/alsa/gstalsa.c @@ -720,8 +720,8 @@ gst_alsa_change_state (GstElement *element) GST_ERROR_OBJECT (this, "Error unpausing sound: %s", snd_strerror (err)); return GST_STATE_FAILURE; } - gst_alsa_clock_start (this->clock); } + gst_alsa_clock_start (this->clock); break; case GST_STATE_PLAYING_TO_PAUSED: if (GST_ALSA_CAPS_IS_SET (this, GST_ALSA_CAPS_PAUSE)) { @@ -836,7 +836,7 @@ gst_alsa_start (GstAlsa *this) g_assert_not_reached (); break; } - gst_alsa_clock_start (this->clock); + /* gst_alsa_clock_start (this->clock); */ return TRUE; } void diff --git a/ext/alsa/gstalsasink.c b/ext/alsa/gstalsasink.c index 3c205cf06c..e82698d8da 100644 --- a/ext/alsa/gstalsasink.c +++ b/ext/alsa/gstalsasink.c @@ -215,7 +215,16 @@ gst_alsa_sink_check_event (GstAlsaSink *sink, gint pad_nr) } if (gst_event_discont_get_value (event, GST_FORMAT_TIME, &value)) { gst_element_set_time (GST_ELEMENT (this), value); - } + } else if (gst_event_discont_get_value (event, GST_FORMAT_DEFAULT, &value)) { + value = gst_alsa_samples_to_timestamp (this, value); + gst_element_set_time (GST_ELEMENT (this), value); + } else if (gst_event_discont_get_value (event, GST_FORMAT_BYTES, &value)) { + value = gst_alsa_bytes_to_timestamp (this, value); + gst_element_set_time (GST_ELEMENT (this), value); + } else { + GST_ERROR_OBJECT (this, "couldn't extract time from discont event. Bad things might happen!"); + } + break; } @@ -471,7 +480,7 @@ gst_alsa_sink_get_time (GstAlsa *this) { snd_pcm_sframes_t delay; - if (snd_pcm_delay (this->handle, &delay) == 0) { + if (snd_pcm_delay (this->handle, &delay) == 0 && this->format) { return GST_SECOND * (GstClockTime) (this->transmitted > delay ? this->transmitted - delay : 0) / this->format->rate; } else { return 0; diff --git a/ext/ogg/gstoggdemux.c b/ext/ogg/gstoggdemux.c index a24c250033..c6c9a04c66 100644 --- a/ext/ogg/gstoggdemux.c +++ b/ext/ogg/gstoggdemux.c @@ -61,15 +61,32 @@ typedef struct { ogg_stream_state stream; guint64 offset; /* end offset of last buffer */ guint64 known_offset; /* last known offset */ + gint64 packetno; /* number of next expected packet */ + guint64 length; /* length of stream or 0 */ - glong pages; + glong pages; /* number of pages in stream or 0 */ + + guint flags; } GstOggPad; +typedef enum { + GST_OGG_PAD_NEEDS_DISCONT = (1 << 0), + GST_OGG_PAD_NEEDS_FLUSH = (1 << 1) +} +GstOggPadFlags; + /* all information needed for one ogg chain (relevant for chained bitstreams) */ typedef struct { GSList * pads; /* list of GstOggPad */ } GstOggChain; #define CURRENT_CHAIN(ogg) (&g_array_index ((ogg)->chains, GstOggChain, (ogg)->current_chain)) +#define FOR_PAD_IN_CURRENT_CHAIN(ogg, _pad, ...) G_STMT_START{ \ + GSList *_walk; \ + for (_walk = CURRENT_CHAIN (ogg)->pads; _walk; _walk = g_slist_next (_walk)) { \ + GstOggPad *_pad = (GstOggPad *) _walk->data; \ + __VA_ARGS__ \ + } \ +}G_STMT_END typedef enum { GST_OGG_FLAG_BOS = GST_ELEMENT_FLAG_LAST, @@ -307,19 +324,19 @@ gst_ogg_demux_src_event (GstPad *pad, GstEvent *event) cur = gst_ogg_get_pad_by_pad (ogg, pad); /* FIXME: optimize this so events from inactive chains work? * in theory there shouldn't be an exisiting pad for inactive chains */ - if (cur == NULL) return FALSE; + if (cur == NULL) goto error; switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: { gint64 offset; if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_DEFAULT) - break; + goto error; offset = GST_EVENT_SEEK_OFFSET (event); switch (GST_EVENT_SEEK_METHOD (event)) { case GST_SEEK_METHOD_END: if (cur->length == 0 || offset > 0) - goto out; + goto error; offset = cur->length + offset; break; case GST_SEEK_METHOD_CUR: @@ -329,21 +346,23 @@ gst_ogg_demux_src_event (GstPad *pad, GstEvent *event) break; default: g_warning ("invalid seek method in seek event"); - break; + goto error; } - g_print ("DEBUG: oggdemux: offset %lld, known %lld\n", offset, cur->known_offset); if (offset < cur->known_offset) { - GstEvent *restart = gst_event_new_seek (GST_FORMAT_BYTES | GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH, 0); + GstEvent *restart = gst_event_new_seek (GST_FORMAT_BYTES | GST_SEEK_METHOD_SET | GST_EVENT_SEEK_FLAGS (event), 0); if (!gst_pad_send_event (GST_PAD_PEER (ogg->sinkpad), restart)) - break; - } - else { - GstEvent *flush = gst_event_new_flush (); - if (!gst_pad_send_event (GST_PAD_PEER (ogg->sinkpad), flush)) - break; + goto error; + } else { + FOR_PAD_IN_CURRENT_CHAIN (ogg, pad, + if (GST_PAD_IS_USABLE (pad->pad)) + gst_pad_push (pad->pad, GST_DATA (gst_event_new (GST_EVENT_FLUSH))); + ); } GST_OGG_SET_STATE (ogg, GST_OGG_STATE_SEEK); + FOR_PAD_IN_CURRENT_CHAIN (ogg, pad, + pad->flags |= GST_OGG_PAD_NEEDS_DISCONT; + ); GST_DEBUG_OBJECT (ogg, "initiating seeking to offset %"G_GUINT64_FORMAT, offset); ogg->seek_pad = cur; ogg->seek_to = offset; @@ -351,10 +370,12 @@ gst_ogg_demux_src_event (GstPad *pad, GstEvent *event) return TRUE; } default: - break; + return gst_pad_event_default (pad, event); } -out: + g_assert_not_reached (); + +error: gst_event_unref (event); return FALSE; } @@ -386,6 +407,9 @@ gst_ogg_demux_handle_event (GstPad *pad, GstEvent *event) ogg_sync_reset (&ogg->sync); gst_event_unref (event); GST_FLAG_UNSET (ogg, GST_OGG_FLAG_WAIT_FOR_DISCONT); + FOR_PAD_IN_CURRENT_CHAIN (ogg, pad, + pad->flags |= GST_OGG_PAD_NEEDS_DISCONT; + ); break; case GST_EVENT_EOS: if (ogg->state == GST_OGG_STATE_SETUP) { @@ -648,14 +672,6 @@ br: GST_DEBUG_OBJECT (ogg, "ended seek at offset %"G_GUINT64_FORMAT" (requested %"G_GUINT64_FORMAT, cur->known_offset, ogg->seek_to); ogg->seek_pad = NULL; ogg->seek_to = 0; - /* send discont everywhere */ - for (walk = CURRENT_CHAIN (ogg)->pads; walk; walk = g_slist_next (walk)) { - GstOggPad *send = (GstOggPad *) walk->data; - GstEvent *event = gst_event_new_discontinuous (FALSE, - GST_FORMAT_DEFAULT, send->known_offset); - if (GST_PAD_IS_USABLE (send->pad)) - gst_pad_push (send->pad, GST_DATA (event)); - } } } /* fallthrough */ @@ -696,7 +712,7 @@ gst_ogg_pad_push (GstOggDemux *ogg, GstOggPad *pad) gst_ogg_pad_reset (ogg, pad); break; case 1: { - /* only push data when plazing, not during seek or similar */ + /* only push data when playing, not during seek or similar */ if (ogg->state != GST_OGG_STATE_PLAY) continue; if (!pad->pad) { @@ -720,6 +736,18 @@ gst_ogg_pad_push (GstOggDemux *ogg, GstOggPad *pad) gst_pad_set_active (pad->pad, TRUE); gst_element_add_pad (GST_ELEMENT (ogg), pad->pad); } + /* check for discont */ + if (packet.packetno != pad->packetno++) { + pad->flags |= GST_OGG_PAD_NEEDS_DISCONT; + pad->packetno = packet.packetno + 1; + } + /* send discont if needed */ + if ((pad->flags & GST_OGG_PAD_NEEDS_DISCONT) && GST_PAD_IS_USABLE (pad->pad)) { + GstEvent *event = gst_event_new_discontinuous (FALSE, + GST_FORMAT_DEFAULT, pad->known_offset); /* FIXME: this might be wrong because we can only use the last known offset */ + gst_pad_push (pad->pad, GST_DATA (event)); + pad->flags &= (~GST_OGG_PAD_NEEDS_DISCONT); + }; /* optimization: use a bufferpool containing the ogg packet? */ buf = gst_pad_alloc_buffer (pad->pad, GST_BUFFER_OFFSET_NONE, packet.bytes); memcpy (buf->data, packet.packet, packet.bytes); diff --git a/ext/vorbis/vorbisdec.c b/ext/vorbis/vorbisdec.c index 74c3f15d93..82cb749178 100644 --- a/ext/vorbis/vorbisdec.c +++ b/ext/vorbis/vorbisdec.c @@ -247,7 +247,7 @@ vorbis_dec_src_event (GstPad *pad, GstEvent *event) static void vorbis_dec_event (GstVorbisDec *dec, GstEvent *event) { - guint64 value; + guint64 value, time, bytes; GST_LOG_OBJECT (dec, "handling event"); switch (GST_EVENT_TYPE (event)) { @@ -259,12 +259,29 @@ vorbis_dec_event (GstVorbisDec *dec, GstEvent *event) GST_WARNING_OBJECT (dec, "discont event didn't include offset, we might set it wrong now"); } - dec->packetno = 3; + if (dec->packetno < 3) { + if (dec->granulepos != 0) + GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("can't handle discont before parsing first 3 packets")); + dec->packetno = 0; + gst_pad_push (dec->srcpad, GST_DATA (gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, (guint64) 0, + GST_FORMAT_DEFAULT, (guint64) 0, GST_FORMAT_BYTES, (guint64) 0, 0))); + } else { + dec->packetno = 3; + /* if one of them works, all of them work */ + if (vorbis_dec_from_granulepos (dec, GST_FORMAT_TIME, dec->granulepos, &time) && + vorbis_dec_from_granulepos (dec, GST_FORMAT_DEFAULT, dec->granulepos, &value) && + vorbis_dec_from_granulepos (dec, GST_FORMAT_BYTES, dec->granulepos, &bytes)) { + gst_pad_push (dec->srcpad, GST_DATA (gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, time, + GST_FORMAT_DEFAULT, value, GST_FORMAT_BYTES, bytes, 0))); + } else { + GST_ERROR_OBJECT (dec, "failed to parse data for DISCONT event, not sending any"); + } + } break; default: + gst_pad_event_default (dec->sinkpad, event); break; } - gst_pad_event_default (dec->sinkpad, event); } static void @@ -292,7 +309,7 @@ vorbis_dec_chain (GstPad *pad, GstData *data) if (packet.packet[0] / 2 != packet.packetno) { /* FIXME: just skip? */ GST_ELEMENT_ERROR (GST_ELEMENT (vd), STREAM, DECODE, - (NULL), ("unexpected packet type %d", (gint) packet.packet[0])); + (NULL), ("unexpected packet type %d, expected %d", (gint) packet.packet[0], (gint) packet.packetno)); gst_data_unref (data); return; }