ext/alsa/gstalsa.c: start clock on PAUSED=>PLAYING, not later

Original commit message from CVS:
2004-01-31  Benjamin Otte  <in7y118@public.uni-hamburg.de>

* 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
This commit is contained in:
Benjamin Otte 2004-01-31 17:19:21 +00:00
parent e2469ac793
commit a61dceb24d
5 changed files with 101 additions and 32 deletions

View file

@ -1,3 +1,18 @@
2004-01-31 Benjamin Otte <in7y118@public.uni-hamburg.de>
* 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 <thomas at apestaart dot org> 2004-01-31 Thomas Vander Stichele <thomas at apestaart dot org>
* gst-libs/gst/play/play.c: (gst_play_error_quark), * gst-libs/gst/play/play.c: (gst_play_error_quark),

View file

@ -720,8 +720,8 @@ gst_alsa_change_state (GstElement *element)
GST_ERROR_OBJECT (this, "Error unpausing sound: %s", snd_strerror (err)); GST_ERROR_OBJECT (this, "Error unpausing sound: %s", snd_strerror (err));
return GST_STATE_FAILURE; return GST_STATE_FAILURE;
} }
gst_alsa_clock_start (this->clock);
} }
gst_alsa_clock_start (this->clock);
break; break;
case GST_STATE_PLAYING_TO_PAUSED: case GST_STATE_PLAYING_TO_PAUSED:
if (GST_ALSA_CAPS_IS_SET (this, GST_ALSA_CAPS_PAUSE)) { if (GST_ALSA_CAPS_IS_SET (this, GST_ALSA_CAPS_PAUSE)) {
@ -836,7 +836,7 @@ gst_alsa_start (GstAlsa *this)
g_assert_not_reached (); g_assert_not_reached ();
break; break;
} }
gst_alsa_clock_start (this->clock); /* gst_alsa_clock_start (this->clock); */
return TRUE; return TRUE;
} }
void void

View file

@ -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)) { if (gst_event_discont_get_value (event, GST_FORMAT_TIME, &value)) {
gst_element_set_time (GST_ELEMENT (this), 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; break;
} }
@ -471,7 +480,7 @@ gst_alsa_sink_get_time (GstAlsa *this)
{ {
snd_pcm_sframes_t delay; 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; return GST_SECOND * (GstClockTime) (this->transmitted > delay ? this->transmitted - delay : 0) / this->format->rate;
} else { } else {
return 0; return 0;

View file

@ -61,15 +61,32 @@ typedef struct {
ogg_stream_state stream; ogg_stream_state stream;
guint64 offset; /* end offset of last buffer */ guint64 offset; /* end offset of last buffer */
guint64 known_offset; /* last known offset */ guint64 known_offset; /* last known offset */
gint64 packetno; /* number of next expected packet */
guint64 length; /* length of stream or 0 */ guint64 length; /* length of stream or 0 */
glong pages; glong pages; /* number of pages in stream or 0 */
guint flags;
} GstOggPad; } 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) */ /* all information needed for one ogg chain (relevant for chained bitstreams) */
typedef struct { typedef struct {
GSList * pads; /* list of GstOggPad */ GSList * pads; /* list of GstOggPad */
} GstOggChain; } GstOggChain;
#define CURRENT_CHAIN(ogg) (&g_array_index ((ogg)->chains, GstOggChain, (ogg)->current_chain)) #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 { typedef enum {
GST_OGG_FLAG_BOS = GST_ELEMENT_FLAG_LAST, 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); cur = gst_ogg_get_pad_by_pad (ogg, pad);
/* FIXME: optimize this so events from inactive chains work? /* FIXME: optimize this so events from inactive chains work?
* in theory there shouldn't be an exisiting pad for inactive chains */ * 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)) { switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK: case GST_EVENT_SEEK:
{ {
gint64 offset; gint64 offset;
if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_DEFAULT) if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_DEFAULT)
break; goto error;
offset = GST_EVENT_SEEK_OFFSET (event); offset = GST_EVENT_SEEK_OFFSET (event);
switch (GST_EVENT_SEEK_METHOD (event)) { switch (GST_EVENT_SEEK_METHOD (event)) {
case GST_SEEK_METHOD_END: case GST_SEEK_METHOD_END:
if (cur->length == 0 || offset > 0) if (cur->length == 0 || offset > 0)
goto out; goto error;
offset = cur->length + offset; offset = cur->length + offset;
break; break;
case GST_SEEK_METHOD_CUR: case GST_SEEK_METHOD_CUR:
@ -329,21 +346,23 @@ gst_ogg_demux_src_event (GstPad *pad, GstEvent *event)
break; break;
default: default:
g_warning ("invalid seek method in seek event"); 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) { 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)) if (!gst_pad_send_event (GST_PAD_PEER (ogg->sinkpad), restart))
break; goto error;
} } else {
else { FOR_PAD_IN_CURRENT_CHAIN (ogg, pad,
GstEvent *flush = gst_event_new_flush (); if (GST_PAD_IS_USABLE (pad->pad))
if (!gst_pad_send_event (GST_PAD_PEER (ogg->sinkpad), flush)) gst_pad_push (pad->pad, GST_DATA (gst_event_new (GST_EVENT_FLUSH)));
break; );
} }
GST_OGG_SET_STATE (ogg, GST_OGG_STATE_SEEK); 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); GST_DEBUG_OBJECT (ogg, "initiating seeking to offset %"G_GUINT64_FORMAT, offset);
ogg->seek_pad = cur; ogg->seek_pad = cur;
ogg->seek_to = offset; ogg->seek_to = offset;
@ -351,10 +370,12 @@ gst_ogg_demux_src_event (GstPad *pad, GstEvent *event)
return TRUE; return TRUE;
} }
default: default:
break; return gst_pad_event_default (pad, event);
} }
out: g_assert_not_reached ();
error:
gst_event_unref (event); gst_event_unref (event);
return FALSE; return FALSE;
} }
@ -386,6 +407,9 @@ gst_ogg_demux_handle_event (GstPad *pad, GstEvent *event)
ogg_sync_reset (&ogg->sync); ogg_sync_reset (&ogg->sync);
gst_event_unref (event); gst_event_unref (event);
GST_FLAG_UNSET (ogg, GST_OGG_FLAG_WAIT_FOR_DISCONT); 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; break;
case GST_EVENT_EOS: case GST_EVENT_EOS:
if (ogg->state == GST_OGG_STATE_SETUP) { 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); 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_pad = NULL;
ogg->seek_to = 0; 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 */ /* fallthrough */
@ -696,7 +712,7 @@ gst_ogg_pad_push (GstOggDemux *ogg, GstOggPad *pad)
gst_ogg_pad_reset (ogg, pad); gst_ogg_pad_reset (ogg, pad);
break; break;
case 1: { 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) if (ogg->state != GST_OGG_STATE_PLAY)
continue; continue;
if (!pad->pad) { if (!pad->pad) {
@ -720,6 +736,18 @@ gst_ogg_pad_push (GstOggDemux *ogg, GstOggPad *pad)
gst_pad_set_active (pad->pad, TRUE); gst_pad_set_active (pad->pad, TRUE);
gst_element_add_pad (GST_ELEMENT (ogg), pad->pad); 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? */ /* optimization: use a bufferpool containing the ogg packet? */
buf = gst_pad_alloc_buffer (pad->pad, GST_BUFFER_OFFSET_NONE, packet.bytes); buf = gst_pad_alloc_buffer (pad->pad, GST_BUFFER_OFFSET_NONE, packet.bytes);
memcpy (buf->data, packet.packet, packet.bytes); memcpy (buf->data, packet.packet, packet.bytes);

View file

@ -247,7 +247,7 @@ vorbis_dec_src_event (GstPad *pad, GstEvent *event)
static void static void
vorbis_dec_event (GstVorbisDec *dec, GstEvent *event) vorbis_dec_event (GstVorbisDec *dec, GstEvent *event)
{ {
guint64 value; guint64 value, time, bytes;
GST_LOG_OBJECT (dec, "handling event"); GST_LOG_OBJECT (dec, "handling event");
switch (GST_EVENT_TYPE (event)) { switch (GST_EVENT_TYPE (event)) {
@ -259,12 +259,29 @@ vorbis_dec_event (GstVorbisDec *dec, GstEvent *event)
GST_WARNING_OBJECT (dec, GST_WARNING_OBJECT (dec,
"discont event didn't include offset, we might set it wrong now"); "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; break;
default: default:
gst_pad_event_default (dec->sinkpad, event);
break; break;
} }
gst_pad_event_default (dec->sinkpad, event);
} }
static void static void
@ -292,7 +309,7 @@ vorbis_dec_chain (GstPad *pad, GstData *data)
if (packet.packet[0] / 2 != packet.packetno) { if (packet.packet[0] / 2 != packet.packetno) {
/* FIXME: just skip? */ /* FIXME: just skip? */
GST_ELEMENT_ERROR (GST_ELEMENT (vd), STREAM, DECODE, 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); gst_data_unref (data);
return; return;
} }