}
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;
}
{
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;
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,
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:
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;
return TRUE;
}
default:
- break;
+ return gst_pad_event_default (pad, event);
}
-out:
+ g_assert_not_reached ();
+
+error:
gst_event_unref (event);
return FALSE;
}
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) {
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 */
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) {
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);
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)) {
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
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;
}