More riff stuff that I forgot to commit first
authorRonald S. Bultje <rbultje@ronald.bitfreak.net>
Sun, 7 Dec 2003 23:05:58 +0000 (23:05 +0000)
committerRonald S. Bultje <rbultje@ronald.bitfreak.net>
Sun, 7 Dec 2003 23:05:58 +0000 (23:05 +0000)
Original commit message from CVS:
More riff stuff that I forgot to commit first

gst/matroska/matroska-demux.c
gst/matroska/matroska-demux.h

index c0bd51c..45e562b 100644 (file)
@@ -27,7 +27,8 @@
 #include <string.h>
 
 /* For AVI compatibility mode... Who did that? */
-#include <gst/riff/riff.h>
+#include <gst/riff/riff-ids.h>
+#include <gst/riff/riff-media.h>
 
 #include "matroska-demux.h"
 #include "matroska-ids.h"
@@ -82,6 +83,8 @@ static gboolean gst_matroska_demux_handle_src_query   (GstPad      *pad,
 /* gst internal change state handler */
 static GstElementStateReturn
                gst_matroska_demux_change_state       (GstElement  *element);
+static void    gst_matroska_demux_set_clock          (GstElement  *element,
+                                                      GstClock    *clock);
 
 /* gobject bla bla */
 static void     gst_matroska_demux_get_property       (GObject     *object,
@@ -187,6 +190,7 @@ gst_matroska_demux_class_init (GstMatroskaDemuxClass *klass)
 
   gstelement_class->change_state = gst_matroska_demux_change_state;
   gstelement_class->send_event = gst_matroska_demux_send_event;
+  gstelement_class->set_clock = gst_matroska_demux_set_clock;
 }
 
 static void 
@@ -261,11 +265,22 @@ gst_matroska_demux_reset (GstElement *element)
   demux->index = NULL;
 
   /* reset timers */
+  demux->clock = NULL;
   demux->time_scale = 1000000;
   demux->duration = 0;
   demux->pos = 0;
   demux->created = G_MININT64;
   demux->seek_pending = GST_CLOCK_TIME_NONE;
+
+  demux->metadata_parsed = FALSE;
+  demux->index_parsed = FALSE;
+}
+
+static void
+gst_matroska_demux_set_clock (GstElement  *element,
+                             GstClock    *clock)
+{
+  GST_MATROSKA_DEMUX (element)->clock = clock;
 }
 
 static gint
@@ -293,6 +308,7 @@ static gboolean
 gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
 {
   GstElementClass *klass = GST_ELEMENT_GET_CLASS (demux);
+  GstEbmlRead *ebml = GST_EBML_READ (demux);
   GstMatroskaTrackContext *context;
   GstPadTemplate *templ = NULL;
   GstCaps *caps = NULL;
@@ -303,7 +319,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
   if (demux->num_streams >= GST_MATROSKA_DEMUX_MAX_STREAMS) {
     GST_WARNING ("Maximum number of streams (%d) exceeded, skipping",
                 GST_MATROSKA_DEMUX_MAX_STREAMS);
-    return gst_ebml_read_skip (GST_EBML_READ (demux)); /* skip-and-continue */
+    return gst_ebml_read_skip (ebml); /* skip-and-continue */
   }
 
   /* allocate generic... if we know the type, we'll g_renew()
@@ -315,12 +331,12 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
   demux->num_streams++;
 
   /* start with the master */
-  if (!gst_ebml_read_master (GST_EBML_READ (demux), &id))
+  if (!gst_ebml_read_master (ebml, &id))
     return FALSE;
 
   /* try reading the trackentry headers */
   while (res) {
-    if (!(id = gst_ebml_peek_id (GST_EBML_READ (demux), &demux->level_up))) {
+    if (!(id = gst_ebml_peek_id (ebml, &demux->level_up))) {
       res = FALSE;
       break;
     } else if (demux->level_up > 0) {
@@ -332,7 +348,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
       /* track number (unique stream ID) */
       case GST_MATROSKA_ID_TRACKNUMBER: {
         guint64 num;
-        if (!gst_ebml_read_uint (GST_EBML_READ (demux), &id, &num)) {
+        if (!gst_ebml_read_uint (ebml, &id, &num)) {
           res = FALSE;
           break;
         }
@@ -343,7 +359,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
       /* track UID (unique identifier) */
       case GST_MATROSKA_ID_TRACKUID: {
         guint64 num;
-        if (!gst_ebml_read_uint (GST_EBML_READ (demux), &id, &num)) {
+        if (!gst_ebml_read_uint (ebml, &id, &num)) {
           res = FALSE;
           break;
         }
@@ -358,7 +374,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
           GST_WARNING ("More than one tracktype defined in a trackentry - skipping");
           break;
         }
-        if (!gst_ebml_read_uint (GST_EBML_READ (demux), &id, &num)) {
+        if (!gst_ebml_read_uint (ebml, &id, &num)) {
           res = FALSE;
           break;
         }
@@ -404,14 +420,14 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
           GST_WARNING ("trackvideo EBML entry in non-video track - ignoring track");
           res = FALSE;
           break;
-        } else if (!gst_ebml_read_master (GST_EBML_READ (demux), &id)) {
+        } else if (!gst_ebml_read_master (ebml, &id)) {
           res = FALSE;
           break;
         }
         videocontext = (GstMatroskaTrackVideoContext *) context;
 
         while (res) {
-          if (!(id = gst_ebml_peek_id (GST_EBML_READ (demux), &demux->level_up))) {
+          if (!(id = gst_ebml_peek_id (ebml, &demux->level_up))) {
             res = FALSE;
             break;
           } else if (demux->level_up > 0) {
@@ -423,7 +439,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
             /* fixme, this should be one-up, but I get it here (?) */
             case GST_MATROSKA_ID_TRACKDEFAULTDURATION: {
               guint64 num;
-              if (!gst_ebml_read_uint (GST_EBML_READ (demux), &id, &num)) {
+              if (!gst_ebml_read_uint (ebml, &id, &num)) {
                 res = FALSE;
                 break;
               }
@@ -434,7 +450,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
             /* video framerate */
             case GST_MATROSKA_ID_VIDEOFRAMERATE: {
               gdouble num;
-              if (!gst_ebml_read_float (GST_EBML_READ (demux), &id, &num)) {
+              if (!gst_ebml_read_float (ebml, &id, &num)) {
                 res = FALSE;
                 break;
               }
@@ -445,7 +461,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
             /* width of the size to display the video at */
             case GST_MATROSKA_ID_VIDEODISPLAYWIDTH: {
               guint64 num;
-              if (!gst_ebml_read_uint (GST_EBML_READ (demux), &id, &num)) {
+              if (!gst_ebml_read_uint (ebml, &id, &num)) {
                 res = FALSE;
                 break;
               }
@@ -456,7 +472,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
             /* height of the size to display the video at */
             case GST_MATROSKA_ID_VIDEODISPLAYHEIGHT: {
               guint64 num;
-              if (!gst_ebml_read_uint (GST_EBML_READ (demux), &id, &num)) {
+              if (!gst_ebml_read_uint (ebml, &id, &num)) {
                 res = FALSE;
                 break;
               }
@@ -467,7 +483,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
             /* width of the video in the file */
             case GST_MATROSKA_ID_VIDEOPIXELWIDTH: {
               guint64 num;
-              if (!gst_ebml_read_uint (GST_EBML_READ (demux), &id, &num)) {
+              if (!gst_ebml_read_uint (ebml, &id, &num)) {
                 res = FALSE;
                 break;
               }
@@ -478,7 +494,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
             /* height of the video in the file */
             case GST_MATROSKA_ID_VIDEOPIXELHEIGHT: {
               guint64 num;
-              if (!gst_ebml_read_uint (GST_EBML_READ (demux), &id, &num)) {
+              if (!gst_ebml_read_uint (ebml, &id, &num)) {
                 res = FALSE;
                 break;
               }
@@ -489,7 +505,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
             /* whether the video is interlaced */
             case GST_MATROSKA_ID_VIDEOFLAGINTERLACED: {
               guint64 num;
-              if (!gst_ebml_read_uint (GST_EBML_READ (demux), &id, &num)) {
+              if (!gst_ebml_read_uint (ebml, &id, &num)) {
                 res = FALSE;
                 break;
               }
@@ -505,7 +521,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
               * which creates a 3D-like effect) */
             case GST_MATROSKA_ID_VIDEOSTEREOMODE: {
               guint64 num;
-              if (!gst_ebml_read_uint (GST_EBML_READ (demux), &id, &num)) {
+              if (!gst_ebml_read_uint (ebml, &id, &num)) {
                 res = FALSE;
                 break;
               }
@@ -524,7 +540,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
             /* aspect ratio behaviour */
             case GST_MATROSKA_ID_VIDEOASPECTRATIO: {
               guint64 num;
-              if (!gst_ebml_read_uint (GST_EBML_READ (demux), &id, &num)) {
+              if (!gst_ebml_read_uint (ebml, &id, &num)) {
                 res = FALSE;
                 break;
               }
@@ -542,7 +558,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
             /* colourspace (only matters for raw video) fourcc */
             case GST_MATROSKA_ID_VIDEOCOLOURSPACE: {
               guint64 num;
-              if (!gst_ebml_read_uint (GST_EBML_READ (demux), &id, &num)) {
+              if (!gst_ebml_read_uint (ebml, &id, &num)) {
                 res = FALSE;
                 break;
               }
@@ -556,7 +572,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
               /* pass-through */
 
             case GST_EBML_ID_VOID:
-              if (!gst_ebml_read_skip (GST_EBML_READ (demux)))
+              if (!gst_ebml_read_skip (ebml))
                 res = FALSE;
               break;
           }
@@ -576,14 +592,14 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
           GST_WARNING ("trackaudio EBML entry in non-audio track - ignoring track");
           res = FALSE;
           break;
-        } else if (!gst_ebml_read_master (GST_EBML_READ (demux), &id)) {
+        } else if (!gst_ebml_read_master (ebml, &id)) {
           res = FALSE;
           break;
         }
         audiocontext = (GstMatroskaTrackAudioContext *) context;
 
         while (res) {
-          if (!(id = gst_ebml_peek_id (GST_EBML_READ (demux), &demux->level_up))) {
+          if (!(id = gst_ebml_peek_id (ebml, &demux->level_up))) {
             res = FALSE;
             break;
           } else if (demux->level_up > 0) {
@@ -595,7 +611,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
             /* samplerate */
             case GST_MATROSKA_ID_AUDIOSAMPLINGFREQ: {
               gdouble num;
-              if (!gst_ebml_read_float (GST_EBML_READ (demux), &id, &num)) {
+              if (!gst_ebml_read_float (ebml, &id, &num)) {
                 res = FALSE;
                 break;
               }
@@ -606,7 +622,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
             /* bitdepth */
             case GST_MATROSKA_ID_AUDIOBITDEPTH: {
               guint64 num;
-              if (!gst_ebml_read_uint (GST_EBML_READ (demux), &id, &num)) {
+              if (!gst_ebml_read_uint (ebml, &id, &num)) {
                 res = FALSE;
                 break;
               }
@@ -617,7 +633,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
             /* channels */
             case GST_MATROSKA_ID_AUDIOCHANNELS: {
               guint64 num;
-              if (!gst_ebml_read_uint (GST_EBML_READ (demux), &id, &num)) {
+              if (!gst_ebml_read_uint (ebml, &id, &num)) {
                 res = FALSE;
                 break;
               }
@@ -631,7 +647,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
               /* pass-through */
 
             case GST_EBML_ID_VOID:
-              if (!gst_ebml_read_skip (GST_EBML_READ (demux)))
+              if (!gst_ebml_read_skip (ebml))
                 res = FALSE;
               break;
           }
@@ -647,7 +663,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
       /* codec identifier */
       case GST_MATROSKA_ID_CODECID: {
         gchar *text;
-        if (!gst_ebml_read_ascii (GST_EBML_READ (demux), &id, &text)) {
+        if (!gst_ebml_read_ascii (ebml, &id, &text)) {
           res = FALSE;
           break;
         }
@@ -659,7 +675,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
       case GST_MATROSKA_ID_CODECPRIVATE: {
         guint8 *data;
         guint64 size;
-        if (!gst_ebml_read_binary (GST_EBML_READ (demux), &id, &data, &size)) {
+        if (!gst_ebml_read_binary (ebml, &id, &data, &size)) {
           res = FALSE;
           break;
         }
@@ -671,7 +687,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
       /* name of the codec */
       case GST_MATROSKA_ID_CODECNAME: {
         gchar *text;
-        if (!gst_ebml_read_utf8 (GST_EBML_READ (demux), &id, &text)) {
+        if (!gst_ebml_read_utf8 (ebml, &id, &text)) {
           res = FALSE;
           break;
         }
@@ -682,7 +698,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
       /* name of this track */
       case GST_MATROSKA_ID_TRACKNAME: {
         gchar *text;
-        if (!gst_ebml_read_utf8 (GST_EBML_READ (demux), &id, &text)) {
+        if (!gst_ebml_read_utf8 (ebml, &id, &text)) {
           res = FALSE;
           break;
         }
@@ -693,7 +709,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
       /* language (matters for audio/subtitles, mostly) */
       case GST_MATROSKA_ID_TRACKLANGUAGE: {
         gchar *text;
-        if (!gst_ebml_read_utf8 (GST_EBML_READ (demux), &id, &text)) {
+        if (!gst_ebml_read_utf8 (ebml, &id, &text)) {
           res = FALSE;
           break;
         }
@@ -704,7 +720,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
       /* whether this is actually used */
       case GST_MATROSKA_ID_TRACKFLAGENABLED: {
         guint64 num;
-        if (!gst_ebml_read_uint (GST_EBML_READ (demux), &id, &num)) {
+        if (!gst_ebml_read_uint (ebml, &id, &num)) {
           res = FALSE;
           break;
         }
@@ -718,7 +734,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
       /* whether it's the default for this track type */
       case GST_MATROSKA_ID_TRACKFLAGDEFAULT: {
         guint64 num;
-        if (!gst_ebml_read_uint (GST_EBML_READ (demux), &id, &num)) {
+        if (!gst_ebml_read_uint (ebml, &id, &num)) {
           res = FALSE;
           break;
         }
@@ -733,7 +749,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
        * boundaries) */
       case GST_MATROSKA_ID_TRACKFLAGLACING: {
         guint64 num;
-        if (!gst_ebml_read_uint (GST_EBML_READ (demux), &id, &num)) {
+        if (!gst_ebml_read_uint (ebml, &id, &num)) {
           res = FALSE;
           break;
         }
@@ -747,7 +763,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
       /* default length (in time) of one data block in this track */
       case GST_MATROSKA_ID_TRACKDEFAULTDURATION: {
         guint64 num;
-        if (!gst_ebml_read_uint (GST_EBML_READ (demux), &id, &num)) {
+        if (!gst_ebml_read_uint (ebml, &id, &num)) {
           res = FALSE;
           break;
         }
@@ -765,7 +781,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux *demux)
       case GST_MATROSKA_ID_TRACKMINCACHE:
       case GST_MATROSKA_ID_TRACKMAXCACHE:
       case GST_EBML_ID_VOID:
-        if (!gst_ebml_read_skip (GST_EBML_READ (demux)))
+        if (!gst_ebml_read_skip (ebml))
           res = FALSE;
         break;
     }
@@ -1058,11 +1074,24 @@ gst_matroska_demux_handle_src_event (GstPad   *pad,
 }
 
 static gboolean
-gst_matroska_demux_handle_sink_event (GstMatroskaDemux *demux,
-                                     GstEvent         *event)
+gst_matroska_demux_handle_seek_event (GstMatroskaDemux *demux)
 {
+  GstEbmlRead *ebml = GST_EBML_READ (demux);
+  GstMatroskaIndex *entry = gst_matroskademux_seek (demux);
+  GstEvent *event;
   guint i;
 
+  if (!entry)
+    return FALSE;
+
+  /* seek (relative to segment) */
+  if (!(event = gst_ebml_read_seek (ebml,
+                       entry->pos + demux->segment_start)))
+    return FALSE;
+  gst_event_unref (event); /* byte - we want time */
+  event = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
+                                       entry->time);
+
   /* forward to all src pads */
   for (i = 0; i < demux->num_streams; i++) {
     if (GST_PAD_IS_USABLE (demux->src[i]->pad)) {
@@ -1071,10 +1100,6 @@ gst_matroska_demux_handle_sink_event (GstMatroskaDemux *demux,
     }
   }
 
-  if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
-    gst_element_set_eos (GST_ELEMENT (demux));
-  }
-
   gst_event_unref (event);
 
   return TRUE;
@@ -1083,11 +1108,12 @@ gst_matroska_demux_handle_sink_event (GstMatroskaDemux *demux,
 static gboolean
 gst_matroska_demux_init_stream (GstMatroskaDemux *demux)
 {
+  GstEbmlRead *ebml = GST_EBML_READ (demux);
   guint32 id;
   gchar *doctype;
   guint version;
 
-  if (!gst_ebml_read_header (GST_EBML_READ (demux), &doctype, &version))
+  if (!gst_ebml_read_header (ebml, &doctype, &version))
     return FALSE;
 
   if (!doctype || strcmp (doctype, "matroska") != 0) {
@@ -1109,7 +1135,7 @@ gst_matroska_demux_init_stream (GstMatroskaDemux *demux)
   while (1) {
     guint last_level;
 
-    if (!(id = gst_ebml_peek_id (GST_EBML_READ (demux), &last_level)))
+    if (!(id = gst_ebml_peek_id (ebml, &last_level)))
       return FALSE;
 
     if (id == GST_MATROSKA_ID_SEGMENT)
@@ -1118,22 +1144,29 @@ gst_matroska_demux_init_stream (GstMatroskaDemux *demux)
     /* oi! */
     GST_WARNING ("Expected a Segment ID (0x%x), but received 0x%x!",
                 GST_MATROSKA_ID_SEGMENT, id);
-    if (!gst_ebml_read_skip (GST_EBML_READ (demux)))
+    if (!gst_ebml_read_skip (ebml))
       return FALSE;
   }
 
   /* we now have a EBML segment */
-  return gst_ebml_read_master (GST_EBML_READ (demux), &id);
+  if (!gst_ebml_read_master (ebml, &id))
+    return FALSE;
+  /* seeks are from the beginning of the segment,
+   * after the segment ID/length */
+  demux->segment_start = gst_bytestream_tell (ebml->bs);
+
+  return TRUE;
 }
 
 static gboolean
 gst_matroska_demux_parse_tracks (GstMatroskaDemux *demux)
 {
+  GstEbmlRead *ebml = GST_EBML_READ (demux);
   gboolean res = TRUE;
   guint32 id;
 
   while (res) {
-    if (!(id = gst_ebml_peek_id (GST_EBML_READ (demux), &demux->level_up))) {
+    if (!(id = gst_ebml_peek_id (ebml, &demux->level_up))) {
       res = FALSE;
       break;
     } else if (demux->level_up) {
@@ -1153,7 +1186,7 @@ gst_matroska_demux_parse_tracks (GstMatroskaDemux *demux)
         /* fall-through */
 
       case GST_EBML_ID_VOID:
-        if (!gst_ebml_read_skip (GST_EBML_READ (demux)))
+        if (!gst_ebml_read_skip (ebml))
           res = FALSE;
         break;
     }
@@ -1168,14 +1201,28 @@ gst_matroska_demux_parse_tracks (GstMatroskaDemux *demux)
 }
 
 static gboolean
-gst_matroska_demux_parse_index (GstMatroskaDemux *demux)
+gst_matroska_demux_parse_index (GstMatroskaDemux *demux,
+                               gboolean          prevent_eos)
 {
+  GstEbmlRead *ebml = GST_EBML_READ (demux);
   gboolean res = TRUE;
   guint32 id;
   GstMatroskaIndex idx;
+  guint64 length = 0;
+
+  if (prevent_eos) {
+    length = gst_bytestream_length (ebml->bs);
+    gst_clock_set_active (demux->clock, FALSE);
+  }
 
   while (res) {
-    if (!(id = gst_ebml_peek_id (GST_EBML_READ (demux), &demux->level_up))) {
+    /* We're an element that can be seeked to. If we are, then
+     * we want to prevent EOS, since that'll kill us. So we cache
+     * file size and seek until there, and don't call EOS upon os. */
+    if (prevent_eos && length == gst_bytestream_tell (ebml->bs)) {
+      res = FALSE;
+      break;
+    } else if (!(id = gst_ebml_peek_id (ebml, &demux->level_up))) {
       res = FALSE;
       break;
     } else if (demux->level_up) {
@@ -1186,7 +1233,7 @@ gst_matroska_demux_parse_index (GstMatroskaDemux *demux)
     switch (id) {
       /* one single index entry ('point') */
       case GST_MATROSKA_ID_POINTENTRY:
-        if (!gst_ebml_read_master (GST_EBML_READ (demux), &id)) {
+        if (!gst_ebml_read_master (ebml, &id)) {
           res = FALSE;
           break;
         }
@@ -1198,7 +1245,10 @@ gst_matroska_demux_parse_index (GstMatroskaDemux *demux)
         idx.track = (guint16) -1;
 
         while (res) {
-          if (!(id = gst_ebml_peek_id (GST_EBML_READ (demux), &demux->level_up))) {
+          if (prevent_eos && length == gst_bytestream_tell (ebml->bs)) {
+            res = FALSE;
+            break;
+          } else if (!(id = gst_ebml_peek_id (ebml, &demux->level_up))) {
             res = FALSE;
             break;
           } else if (demux->level_up) {
@@ -1210,24 +1260,27 @@ gst_matroska_demux_parse_index (GstMatroskaDemux *demux)
             /* one single index entry ('point') */
             case GST_MATROSKA_ID_CUETIME: {
               gint64 time;
-              if (!gst_ebml_read_date (GST_EBML_READ (demux), &id, &time)) {
+              if (!gst_ebml_read_uint (ebml, &id, &time)) {
                 res = FALSE;
                 break;
               }
-              idx.time = time;
+              idx.time = time * demux->time_scale;
               break;
             }
 
             /* position in the file + track to which it belongs */
             case GST_MATROSKA_ID_CUETRACKPOSITION:
-              if (!gst_ebml_read_master (GST_EBML_READ (demux), &id)) {
+              if (!gst_ebml_read_master (ebml, &id)) {
                 res = FALSE;
                 break;
               }
 
               while (res) {
-                if (!(id = gst_ebml_peek_id (GST_EBML_READ (demux),
-                                            &demux->level_up))) {
+                if (prevent_eos && length == gst_bytestream_tell (ebml->bs)) {
+                  res = FALSE;
+                  break;
+                } else if (!(id = gst_ebml_peek_id (ebml,
+                                       &demux->level_up))) {
                   res = FALSE;
                   break;
                 } else if (demux->level_up) {
@@ -1239,7 +1292,7 @@ gst_matroska_demux_parse_index (GstMatroskaDemux *demux)
                   /* track number */
                   case GST_MATROSKA_ID_CUETRACK: {
                     guint64 num;
-                    if (!gst_ebml_read_uint (GST_EBML_READ (demux), &id, &num)) {
+                    if (!gst_ebml_read_uint (ebml, &id, &num)) {
                       res = FALSE;
                       break;
                     }
@@ -1250,7 +1303,7 @@ gst_matroska_demux_parse_index (GstMatroskaDemux *demux)
                   /* position in file */
                   case GST_MATROSKA_ID_CUECLUSTERPOSITION: {
                     guint64 num;
-                    if (!gst_ebml_read_uint (GST_EBML_READ (demux), &id, &num)) {
+                    if (!gst_ebml_read_uint (ebml, &id, &num)) {
                       res = FALSE;
                       break;
                     }
@@ -1263,7 +1316,7 @@ gst_matroska_demux_parse_index (GstMatroskaDemux *demux)
                     /* fall-through */
 
                   case GST_EBML_ID_VOID:
-                    if (!gst_ebml_read_skip (GST_EBML_READ (demux)))
+                    if (!gst_ebml_read_skip (ebml))
                       res = FALSE;
                     break;
                 }
@@ -1281,7 +1334,7 @@ gst_matroska_demux_parse_index (GstMatroskaDemux *demux)
               /* fall-through */
 
             case GST_EBML_ID_VOID:
-              if (!gst_ebml_read_skip (GST_EBML_READ (demux)))
+              if (!gst_ebml_read_skip (ebml))
                 res = FALSE;
               break;
           }
@@ -1314,7 +1367,7 @@ gst_matroska_demux_parse_index (GstMatroskaDemux *demux)
         /* fall-through */
 
       case GST_EBML_ID_VOID:
-        if (!gst_ebml_read_skip (GST_EBML_READ (demux)))
+        if (!gst_ebml_read_skip (ebml))
           res = FALSE;
         break;
     }
@@ -1325,17 +1378,22 @@ gst_matroska_demux_parse_index (GstMatroskaDemux *demux)
     }
   }
 
+  if (prevent_eos) {
+    gst_clock_set_active (demux->clock, TRUE);
+  }
+
   return res;
 }
 
 static gboolean
 gst_matroska_demux_parse_info (GstMatroskaDemux *demux)
 {
+  GstEbmlRead *ebml = GST_EBML_READ (demux);
   gboolean res = TRUE;
   guint32 id;
 
   while (res) {
-    if (!(id = gst_ebml_peek_id (GST_EBML_READ (demux), &demux->level_up))) {
+    if (!(id = gst_ebml_peek_id (ebml, &demux->level_up))) {
       res = FALSE;
       break;
     } else if (demux->level_up) {
@@ -1347,7 +1405,7 @@ gst_matroska_demux_parse_info (GstMatroskaDemux *demux)
       /* cluster timecode */
       case GST_MATROSKA_ID_TIMECODESCALE: {
         guint64 num;
-        if (!gst_ebml_read_uint (GST_EBML_READ (demux), &id, &num)) {
+        if (!gst_ebml_read_uint (ebml, &id, &num)) {
           res = FALSE;
           break;
         }
@@ -1357,7 +1415,7 @@ gst_matroska_demux_parse_info (GstMatroskaDemux *demux)
 
       case GST_MATROSKA_ID_DURATION: {
         gdouble num;
-        if (!gst_ebml_read_float (GST_EBML_READ (demux), &id, &num)) {
+        if (!gst_ebml_read_float (ebml, &id, &num)) {
           res = FALSE;
           break;
         }
@@ -1367,7 +1425,7 @@ gst_matroska_demux_parse_info (GstMatroskaDemux *demux)
 
       case GST_MATROSKA_ID_WRITINGAPP: {
         gchar *text;
-        if (!gst_ebml_read_utf8 (GST_EBML_READ (demux), &id, &text)) {
+        if (!gst_ebml_read_utf8 (ebml, &id, &text)) {
           res = FALSE;
           break;
         }
@@ -1377,7 +1435,7 @@ gst_matroska_demux_parse_info (GstMatroskaDemux *demux)
 
       case GST_MATROSKA_ID_MUXINGAPP: {
         gchar *text;
-        if (!gst_ebml_read_utf8 (GST_EBML_READ (demux), &id, &text)) {
+        if (!gst_ebml_read_utf8 (ebml, &id, &text)) {
           res = FALSE;
           break;
         }
@@ -1387,7 +1445,7 @@ gst_matroska_demux_parse_info (GstMatroskaDemux *demux)
 
       case GST_MATROSKA_ID_DATEUTC: {
         gint64 time;
-        if (!gst_ebml_read_date (GST_EBML_READ (demux), &id, &time)) {
+        if (!gst_ebml_read_date (ebml, &id, &time)) {
           res = FALSE;
           break;
         }
@@ -1400,7 +1458,7 @@ gst_matroska_demux_parse_info (GstMatroskaDemux *demux)
         /* fall-through */
 
       case GST_EBML_ID_VOID:
-        if (!gst_ebml_read_skip (GST_EBML_READ (demux)))
+        if (!gst_ebml_read_skip (ebml))
           res = FALSE;
         break;
     }
@@ -1415,13 +1473,27 @@ gst_matroska_demux_parse_info (GstMatroskaDemux *demux)
 }
 
 static gboolean
-gst_matroska_demux_parse_metadata (GstMatroskaDemux *demux)
+gst_matroska_demux_parse_metadata (GstMatroskaDemux *demux,
+                                  gboolean          prevent_eos)
 {
+  GstEbmlRead *ebml = GST_EBML_READ (demux);
   gboolean res = TRUE;
   guint32 id;
+  guint64 length = 0;
+
+  if (prevent_eos) {
+    length = gst_bytestream_length (ebml->bs);
+    gst_clock_set_active (demux->clock, FALSE);
+  }
 
   while (res) {
-    if (!(id = gst_ebml_peek_id (GST_EBML_READ (demux), &demux->level_up))) {
+    /* We're an element that can be seeked to. If we are, then
+     * we want to prevent EOS, since that'll kill us. So we cache
+     * file size and seek until there, and don't call EOS upon os. */
+    if (prevent_eos && length == gst_bytestream_tell (ebml->bs)) {
+      res = FALSE;
+      break;
+    } else if (!(id = gst_ebml_peek_id (ebml, &demux->level_up))) {
       res = FALSE;
       break;
     } else if (demux->level_up) {
@@ -1435,7 +1507,7 @@ gst_matroska_demux_parse_metadata (GstMatroskaDemux *demux)
         /* fall-through */
 
       case GST_EBML_ID_VOID:
-        if (!gst_ebml_read_skip (GST_EBML_READ (demux)))
+        if (!gst_ebml_read_skip (ebml))
           res = FALSE;
         break;
     }
@@ -1446,6 +1518,10 @@ gst_matroska_demux_parse_metadata (GstMatroskaDemux *demux)
     }
   }
 
+  if (prevent_eos) {
+    gst_clock_set_active (demux->clock, TRUE);
+  }
+
   return res;
 }
 
@@ -1521,11 +1597,12 @@ static gboolean
 gst_matroska_demux_parse_blockgroup (GstMatroskaDemux *demux,
                                     guint64           cluster_time)
 {
+  GstEbmlRead *ebml = GST_EBML_READ (demux);
   gboolean res = TRUE;
   guint32 id;
 
   while (res) {
-    if (!(id = gst_ebml_peek_id (GST_EBML_READ (demux), &demux->level_up))) {
+    if (!(id = gst_ebml_peek_id (ebml, &demux->level_up))) {
       res = FALSE;
       break;
     } else if (demux->level_up) {
@@ -1545,7 +1622,7 @@ gst_matroska_demux_parse_blockgroup (GstMatroskaDemux *demux,
         gint n, stream, flags, laces = 0;
         guint64 num;
 
-        if (!gst_ebml_read_buffer (GST_EBML_READ (demux), &id, &buf)) {
+        if (!gst_ebml_read_buffer (ebml, &id, &buf)) {
           res = FALSE;
           break;
         }
@@ -1563,10 +1640,13 @@ gst_matroska_demux_parse_blockgroup (GstMatroskaDemux *demux,
 
         /* fetch stream from num */
         stream = gst_matroska_demux_stream_from_num (demux, num);
-        if (size <= 3 || stream < 0 || stream >= demux->num_streams ||
-            !GST_PAD_IS_USABLE (demux->src[stream]->pad)) {
+        if (size <= 3 || stream < 0 || stream >= demux->num_streams) {
+          gst_buffer_unref (buf);
+          GST_WARNING ("Invalid stream %d or size %u", stream, size);
+          break;
+        }
+        if (!GST_PAD_IS_USABLE (demux->src[stream]->pad)) {
           gst_buffer_unref (buf);
-          res = FALSE;
           break;
         }
 
@@ -1576,12 +1656,11 @@ gst_matroska_demux_parse_blockgroup (GstMatroskaDemux *demux,
         data += 2; size -= 2;
         flags = * (guint8 *) data;
         data += 1; size -= 1;
-
         switch ((flags & 0x06) >> 1) {
           case 0x0: /* no lacing */
             laces = 1;
             lace_size = g_new (gint, 1);
-            lace_size[0] = GST_BUFFER_SIZE (buf) - size;
+            lace_size[0] = size;
             break;
 
           case 0x1: /* xiph lacing */
@@ -1593,11 +1672,11 @@ gst_matroska_demux_parse_blockgroup (GstMatroskaDemux *demux,
             }
             laces = (* (guint8 *) data) + 1;
             data += 1; size -= 1;
-            lace_size = g_new (gint, laces);
+            lace_size = g_new0 (gint, laces);
 
             switch ((flags & 0x06) >> 1) {
               case 0x1: /* xiph lacing */ {
-                guint total = 0, temp;
+                guint temp, total = 0;
                 for (n = 0; res && n < laces - 1; n++) {
                   while (1) {
                      if (size == 0) {
@@ -1618,7 +1697,7 @@ gst_matroska_demux_parse_blockgroup (GstMatroskaDemux *demux,
 
               case 0x2: /* fixed-size lacing */
                 for (n = 0; n < laces; n++)
-                  lace_size[n] = (GST_BUFFER_SIZE (buf) - size) / laces;
+                  lace_size[n] = size / laces;
                 break;
 
               case 0x3: /* EBML lacing */ {
@@ -1652,7 +1731,8 @@ gst_matroska_demux_parse_blockgroup (GstMatroskaDemux *demux,
         if (res) {
           for (n = 0; n < laces; n++) {
             GstBuffer *sub = gst_buffer_create_sub (buf,
-                               GST_BUFFER_SIZE (buf) - size, lace_size[n]);
+                                                   GST_BUFFER_SIZE (buf) - size,
+                                                   lace_size[n]);
 
             if (cluster_time != GST_CLOCK_TIME_NONE)
               GST_BUFFER_TIMESTAMP (sub) = cluster_time + time;
@@ -1660,6 +1740,8 @@ gst_matroska_demux_parse_blockgroup (GstMatroskaDemux *demux,
             /* FIXME: duration */
 
             gst_pad_push (demux->src[stream]->pad, GST_DATA (sub));
+
+            size -= lace_size[n];
           }
         }
 
@@ -1670,11 +1752,11 @@ gst_matroska_demux_parse_blockgroup (GstMatroskaDemux *demux,
 
       case GST_MATROSKA_ID_BLOCKDURATION: {
         guint64 num;
-        if (!gst_ebml_read_uint (GST_EBML_READ (demux), &id, &num)) {
+        if (!gst_ebml_read_uint (ebml, &id, &num)) {
           res = FALSE;
           break;
         }
-        GST_DEBUG ("FIXME: implement support for BlockDuration");
+        GST_WARNING ("FIXME: implement support for BlockDuration");
         break;
       }
 
@@ -1683,7 +1765,7 @@ gst_matroska_demux_parse_blockgroup (GstMatroskaDemux *demux,
         /* fall-through */
 
       case GST_EBML_ID_VOID:
-        if (!gst_ebml_read_skip (GST_EBML_READ (demux)))
+        if (!gst_ebml_read_skip (ebml))
           res = FALSE;
         break;
     }
@@ -1700,25 +1782,21 @@ gst_matroska_demux_parse_blockgroup (GstMatroskaDemux *demux,
 static gboolean
 gst_matroska_demux_parse_cluster (GstMatroskaDemux *demux)
 {
+  GstEbmlRead *ebml = GST_EBML_READ (demux);
   gboolean res = TRUE;
   guint32 id;
   guint64 cluster_time = GST_CLOCK_TIME_NONE;
 
-  /* Not intending to look like a moron, but we only seek when
-   * we've parsed the headers (for indexes etc.) - so we do that
-   * here... Yes, this is ugly. Thanks for noticing. */
+  /* We seek after index/header parsing before doing a new
+   * buffer. So here. */
   if (demux->seek_pending != GST_CLOCK_TIME_NONE) {
-    GstMatroskaIndex *entry = gst_matroskademux_seek (demux);
-    if (entry != NULL) {
-      GstEvent *discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
-                                                       entry->time);
-      gst_ebml_read_seek (GST_EBML_READ (demux), entry->pos);
-      gst_matroska_demux_handle_sink_event (demux, discont);
-    }
+    if (!gst_matroska_demux_handle_seek_event (demux))
+      return FALSE;
+    demux->seek_pending = GST_CLOCK_TIME_NONE;
   }
 
   while (res) {
-    if (!(id = gst_ebml_peek_id (GST_EBML_READ (demux), &demux->level_up))) {
+    if (!(id = gst_ebml_peek_id (ebml, &demux->level_up))) {
       res = FALSE;
       break;
     } else if (demux->level_up) {
@@ -1730,7 +1808,7 @@ gst_matroska_demux_parse_cluster (GstMatroskaDemux *demux)
       /* cluster timecode */
       case GST_MATROSKA_ID_CLUSTERTIMECODE: {
         guint64 num;
-        if (!gst_ebml_read_uint (GST_EBML_READ (demux), &id, &num)) {
+        if (!gst_ebml_read_uint (ebml, &id, &num)) {
           res = FALSE;
           break;
         }
@@ -1740,7 +1818,7 @@ gst_matroska_demux_parse_cluster (GstMatroskaDemux *demux)
 
       /* a group of blocks inside a cluster */
       case GST_MATROSKA_ID_BLOCKGROUP:
-        if (!gst_ebml_read_master (GST_EBML_READ (demux), &id)) {
+        if (!gst_ebml_read_master (ebml, &id)) {
           res = FALSE;
           break;
         }
@@ -1752,7 +1830,7 @@ gst_matroska_demux_parse_cluster (GstMatroskaDemux *demux)
         /* fall-through */
 
       case GST_EBML_ID_VOID:
-        if (!gst_ebml_read_skip (GST_EBML_READ (demux)))
+        if (!gst_ebml_read_skip (ebml))
           res = FALSE;
         break;
     }
@@ -1769,11 +1847,12 @@ gst_matroska_demux_parse_cluster (GstMatroskaDemux *demux)
 static gboolean
 gst_matroska_demux_parse_contents (GstMatroskaDemux *demux)
 {
+  GstEbmlRead *ebml = GST_EBML_READ (demux);
   gboolean res = TRUE;
   guint32 id;
 
   while (res) {
-    if (!(id = gst_ebml_peek_id (GST_EBML_READ (demux), &demux->level_up))) {
+    if (!(id = gst_ebml_peek_id (ebml, &demux->level_up))) {
       res = FALSE;
       break;
     } else if (demux->level_up) {
@@ -1782,12 +1861,160 @@ gst_matroska_demux_parse_contents (GstMatroskaDemux *demux)
     }
 
     switch (id) {
+      case GST_MATROSKA_ID_SEEKENTRY: {
+        guint32 seek_id = 0;
+        guint64 seek_pos = (guint64) -1, t;
+
+        if (!gst_ebml_read_master (ebml, &id)) {
+          res = FALSE;
+          break;
+        }
+
+        while (res) {
+          if (!(id = gst_ebml_peek_id (ebml, &demux->level_up))) {
+            res = FALSE;
+            break;
+          } else if (demux->level_up) {
+            demux->level_up--;
+            break;
+          }
+
+          switch (id) {
+            case GST_MATROSKA_ID_SEEKID:
+              if (!gst_ebml_read_uint (ebml, &id, &t))
+                res = FALSE;
+              seek_id = t;
+              break;
+
+            case GST_MATROSKA_ID_SEEKPOSITION:
+              if (!gst_ebml_read_uint (ebml, &id, &seek_pos))
+                res = FALSE;
+              break;
+
+            default:
+              GST_WARNING ("Unknown seekhead ID 0x%x", id);
+              /* fall-through */
+
+            case GST_EBML_ID_VOID:
+              if (!gst_ebml_read_skip (ebml))
+                res = FALSE;
+              break;
+          }
+
+          if (demux->level_up) {
+            demux->level_up--;
+            break;
+          }
+        }
+
+        if (!seek_id || seek_pos == (guint64) -1) {
+          GST_WARNING ("Incomplete seekhead entry (0x%x/%"
+                      G_GUINT64_FORMAT ")", seek_id, seek_pos);
+          break;
+        }
+
+        switch (seek_id) {
+          case GST_MATROSKA_ID_CUES:
+          case GST_MATROSKA_ID_TAGS: {
+            guint level_up = demux->level_up;
+            guint64 before_pos, length;
+            GstEbmlLevel *level;
+            GstEvent *event;
+
+            /* remember */
+            length = gst_bytestream_length (ebml->bs);
+            before_pos = gst_bytestream_tell (ebml->bs);
+
+            /* check for validity */
+            if (seek_pos + demux->segment_start + 12 >= length) {
+              g_warning ("Seekhead reference lies outside file!");
+              break;
+            }
+
+            /* seek */
+            if (!(event = gst_ebml_read_seek (ebml,
+                               seek_pos + demux->segment_start)))
+              return FALSE;
+            gst_event_unref (event);
+
+            /* we don't want to lose our seekhead level, so we add
+             * a dummy. This is a crude hack. */
+            level = g_new (GstEbmlLevel, 1);
+            level->start = 0;
+            level->length = G_MAXUINT64;
+            ebml->level = g_list_append (ebml->level, level);
+
+            /* check ID */
+            if (!(id = gst_ebml_peek_id (ebml, &demux->level_up))) {
+              res = FALSE;
+              break;
+            }
+            if (id != seek_id) {
+              g_warning ("We looked for ID=0x%x but got ID=0x%x (pos=%llu)",
+                        seek_id, id, seek_pos + demux->segment_start);
+              goto finish;
+            }
+
+            /* read master + parse */
+            switch (id) {
+              case GST_MATROSKA_ID_CUES:
+                if (!gst_ebml_read_master (ebml, &id))
+                  res = FALSE;
+                else if (!gst_matroska_demux_parse_index (demux, TRUE) &&
+                        gst_bytestream_length (ebml->bs) !=
+                               gst_bytestream_tell (ebml->bs))
+                  res = FALSE;
+                else
+                  demux->index_parsed = TRUE;
+                break;
+              case GST_MATROSKA_ID_TAGS:
+                if (!gst_ebml_read_master (ebml, &id))
+                  res = FALSE;
+                else if (!gst_matroska_demux_parse_metadata (demux, TRUE) &&
+                        gst_bytestream_length (ebml->bs) !=
+                               gst_bytestream_tell (ebml->bs))
+                  res = FALSE;
+                else
+                  demux->metadata_parsed = TRUE;
+                break;
+            }
+            if (!res)
+              break;
+
+          finish:
+            /* remove dummy level */
+            while (ebml->level) {
+              guint64 length;
+              level = g_list_last (ebml->level)->data;
+              ebml->level = g_list_remove (ebml->level, level);
+              length = level->length;
+              g_free (level);
+              if (length == G_MAXUINT64)
+                break;
+            }
+
+            /* seek back */
+            if (!(event = gst_ebml_read_seek (ebml, before_pos)))
+              return FALSE;
+            gst_event_unref (event);
+            demux->level_up = level_up;
+            break;
+          }
+
+          default:
+            GST_INFO ("Ignoring seekhead entry for ID=0x%x", seek_id);
+            break;
+        }
+
+        break;
+      }
+
       default:
-        GST_WARNING ("seekhead unimplemented");
+        GST_WARNING ("Unknown seekhead ID 0x%x", id);
         /* fall-through */
 
       case GST_EBML_ID_VOID:
-        if (!gst_ebml_read_skip (GST_EBML_READ (demux)))
+        if (!gst_ebml_read_skip (ebml))
           res = FALSE;
         break;
     }
@@ -1804,26 +2031,24 @@ gst_matroska_demux_parse_contents (GstMatroskaDemux *demux)
 static gboolean
 gst_matroska_demux_loop_stream (GstMatroskaDemux *demux)
 {
-  GstEvent *status;
+  GstEbmlRead *ebml = GST_EBML_READ (demux);
   gboolean res = TRUE;
-  guint32 id, remain;
+  guint32 id;
 
   /* we've found our segment, start reading the different contents in here */
   while (res) {
-    if (!(id = gst_ebml_peek_id (GST_EBML_READ (demux), &demux->level_up))) {
+    if (!(id = gst_ebml_peek_id (ebml, &demux->level_up))) {
       res = FALSE;
       break;
     } else if (demux->level_up) {
-      /* end of segment */
       demux->level_up--;
-      gst_matroska_demux_handle_sink_event (demux, gst_event_new (GST_EVENT_EOS));
       break;
     }
 
     switch (id) {
       /* stream info */
       case GST_MATROSKA_ID_INFO: {
-        if (!gst_ebml_read_master (GST_EBML_READ (demux), &id)) {
+        if (!gst_ebml_read_master (ebml, &id)) {
           res = FALSE;
           break;
         }
@@ -1833,7 +2058,7 @@ gst_matroska_demux_loop_stream (GstMatroskaDemux *demux)
 
       /* track info headers */
       case GST_MATROSKA_ID_TRACKS: {
-        if (!gst_ebml_read_master (GST_EBML_READ (demux), &id)) {
+        if (!gst_ebml_read_master (ebml, &id)) {
           res = FALSE;
           break;
         }
@@ -1843,27 +2068,33 @@ gst_matroska_demux_loop_stream (GstMatroskaDemux *demux)
 
       /* stream index */
       case GST_MATROSKA_ID_CUES: {
-        if (!gst_ebml_read_master (GST_EBML_READ (demux), &id)) {
-          res = FALSE;
-          break;
-        }
-        res = gst_matroska_demux_parse_index (demux);
+        if (!demux->index_parsed) {
+          if (!gst_ebml_read_master (ebml, &id)) {
+            res = FALSE;
+            break;
+          }
+          res = gst_matroska_demux_parse_index (demux, FALSE);
+        } else
+          res = gst_ebml_read_skip (ebml);
         break;
       }
 
       /* metadata */
       case GST_MATROSKA_ID_TAGS: {
-        if (!gst_ebml_read_master (GST_EBML_READ (demux), &id)) {
-          res = FALSE;
-          break;
-        }
-        res = gst_matroska_demux_parse_metadata (demux);
+        if (!demux->index_parsed) {
+          if (!gst_ebml_read_master (ebml, &id)) {
+            res = FALSE;
+            break;
+          }
+          res = gst_matroska_demux_parse_metadata (demux, FALSE);
+        } else
+          res = gst_ebml_read_skip (ebml);
         break;
       }
 
       /* file index (if seekable, seek to Cues/Tags to parse it) */
       case GST_MATROSKA_ID_SEEKHEAD: {
-        if (!gst_ebml_read_master (GST_EBML_READ (demux), &id)) {
+        if (!gst_ebml_read_master (ebml, &id)) {
           res = FALSE;
           break;
         }
@@ -1872,7 +2103,7 @@ gst_matroska_demux_loop_stream (GstMatroskaDemux *demux)
       }
 
       case GST_MATROSKA_ID_CLUSTER: {
-        if (!gst_ebml_read_master (GST_EBML_READ (demux), &id)) {
+        if (!gst_ebml_read_master (ebml, &id)) {
           res = FALSE;
           break;
         }
@@ -1894,19 +2125,13 @@ gst_matroska_demux_loop_stream (GstMatroskaDemux *demux)
         /* fall-through */
 
       case GST_EBML_ID_VOID:
-        if (!gst_ebml_read_skip (GST_EBML_READ (demux)))
+        if (!gst_ebml_read_skip (ebml))
           res = FALSE;
         break;
     }
 
-    /* check BS for EOS */
-    gst_bytestream_get_status (GST_EBML_READ (demux)->bs, &remain, &status);
-    if (demux->level_up || (status && GST_EVENT_TYPE (status) == GST_EVENT_EOS)) {
-      /* end of segment */
-      if (status)
-        gst_event_unref (status);
+    if (demux->level_up) {
       demux->level_up--;
-      gst_matroska_demux_handle_sink_event (demux, gst_event_new (GST_EVENT_EOS));
       break;
     }
   }
@@ -1931,161 +2156,6 @@ gst_matroska_demux_loop (GstElement *element)
 }
 
 static GstCaps *
-gst_matroska_demux_vfw_caps (guint32             codec_fcc,
-                            gst_riff_strf_vids *vids)
-{
-  GstCaps *caps = NULL;
-
-  switch (codec_fcc) {
-    case GST_MAKE_FOURCC('I','4','2','0'):
-    case GST_MAKE_FOURCC('Y','U','Y','2'):
-      caps = GST_CAPS_NEW (
-                  "matroskademux_vfw_video_src_raw",
-                  "video/x-raw-yuv",
-                    "format",  GST_PROPS_FOURCC (codec_fcc)
-                );
-      break;
-
-    case GST_MAKE_FOURCC('M','J','P','G'): /* YUY2 MJPEG */
-    case GST_MAKE_FOURCC('J','P','E','G'): /* generic (mostly RGB) MJPEG */
-    case GST_MAKE_FOURCC('P','I','X','L'): /* Miro/Pinnacle fourccs */
-    case GST_MAKE_FOURCC('V','I','X','L'): /* Miro/Pinnacle fourccs */
-      caps = GST_CAPS_NEW (
-                  "matroskademux_vfw_video_src_jpeg",
-                  "video/x-jpeg",
-                    NULL
-                );
-      break;
-
-    case GST_MAKE_FOURCC('H','F','Y','U'):
-      caps = GST_CAPS_NEW (
-                  "matroskademux_vfw_video_src_hfyu",
-                  "video/x-huffyuv",
-                    NULL
-                );
-      break;
-
-    case GST_MAKE_FOURCC('M','P','E','G'):
-    case GST_MAKE_FOURCC('M','P','G','I'):
-      caps = GST_CAPS_NEW (
-                  "matroskademux_vfw_video_src_mpeg",
-                  "video/mpeg",
-                    "systemstream", GST_PROPS_BOOLEAN (FALSE),
-                   "mpegversion", GST_PROPS_BOOLEAN (1)
-                );
-      break;
-
-    case GST_MAKE_FOURCC('H','2','6','3'):
-    case GST_MAKE_FOURCC('i','2','6','3'):
-    case GST_MAKE_FOURCC('L','2','6','3'):
-    case GST_MAKE_FOURCC('M','2','6','3'):
-    case GST_MAKE_FOURCC('V','D','O','W'):
-    case GST_MAKE_FOURCC('V','I','V','O'):
-    case GST_MAKE_FOURCC('x','2','6','3'):
-      caps = GST_CAPS_NEW (
-                  "matroskademux_vfw_video_src_263",
-                  "video/x-h263",
-                    NULL
-                );
-      break;
-
-    case GST_MAKE_FOURCC('D','I','V','3'):
-    case GST_MAKE_FOURCC('D','I','V','4'):
-    case GST_MAKE_FOURCC('D','I','V','5'):
-      caps = GST_CAPS_NEW (
-                  "matroskademux_vfw_video_src_divx3",
-                  "video/x-divx",
-                   "divxversion", GST_PROPS_INT(3)
-                );
-      break;
-
-    case GST_MAKE_FOURCC('d','i','v','x'):
-    case GST_MAKE_FOURCC('D','I','V','X'):
-    case GST_MAKE_FOURCC('D','X','5','0'):
-      caps = GST_CAPS_NEW (
-                  "matroskademux_vfw_video_src_divx5",
-                  "video/x-divx",
-                   "divxversion", GST_PROPS_INT(5)
-                );
-      break;
-
-    case GST_MAKE_FOURCC('X','V','I','D'):
-    case GST_MAKE_FOURCC('x','v','i','d'):
-      caps = GST_CAPS_NEW (
-                  "matroskademux_vfw_video_src",
-                  "video/x-xvid",
-                    NULL
-                );
-      break;
-
-    case GST_MAKE_FOURCC('M','P','G','4'):
-      caps = GST_CAPS_NEW (
-                  "matroskademux_vfw_video_src",
-                  "video/x-msmpeg",
-                   "msmpegversion", GST_PROPS_INT (41)
-                );
-      break;
-
-    case GST_MAKE_FOURCC('M','P','4','2'):
-      caps = GST_CAPS_NEW (
-                  "matroskademux_vfw_video_src",
-                  "video/x-msmpeg",
-                   "msmpegversion", GST_PROPS_INT (42)
-                );
-      break;
-
-    case GST_MAKE_FOURCC('M','P','4','3'):
-      caps = GST_CAPS_NEW (
-                  "matroskademux_vfw_video_src",
-                  "video/x-msmpeg",
-                   "msmpegversion", GST_PROPS_INT (43)
-                );
-      break;
-
-    case GST_MAKE_FOURCC('3','I','V','1'):
-    case GST_MAKE_FOURCC('3','I','V','2'):
-      caps = GST_CAPS_NEW (
-                 "matroskademux_vfw_video_src_3ivx",
-                 "video/x-3ivx",
-                   NULL
-               );
-      break;
-
-    case GST_MAKE_FOURCC('D','V','S','D'):
-    case GST_MAKE_FOURCC('d','v','s','d'):
-      caps = GST_CAPS_NEW (
-                  "matroskademux_vfw_video_src",
-                  "video/x-dv",
-                    "systemstream", GST_PROPS_BOOLEAN (FALSE)
-                );
-      break;
-
-    case GST_MAKE_FOURCC('W','M','V','1'):
-      caps = GST_CAPS_NEW (
-                  "matroskademux_vfw_video_src_wmv1",
-                  "video/x-wmv",
-                    "wmvversion", GST_PROPS_INT (1)
-                );
-      break;
-
-    case GST_MAKE_FOURCC('W','M','V','2'):
-      caps = GST_CAPS_NEW (
-                  "matroskademux_vfw_video_src_wmv2",
-                  "video/x-wmv",
-                    "wmvversion", GST_PROPS_INT (2)
-                );
-      break;
-
-    default:
-      GST_WARNING ("matroskademux: unkown VFW video format " GST_FOURCC_FORMAT,
-                  GST_FOURCC_ARGS (codec_fcc));
-      break;
-  }
-
-  return caps;
-}
-
-static GstCaps *
 gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext *videocontext,
                               const gchar                  *codec_id,
                               gpointer                      data,
@@ -2097,6 +2167,7 @@ gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext *videocontext,
 
   if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC)) {
     gst_riff_strf_vids *vids = NULL;
+    GstCaps *t;
 
     if (data) {
       vids = (gst_riff_strf_vids *) data;
@@ -2122,9 +2193,17 @@ gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext *videocontext,
       vids->ypels_meter = GUINT32_FROM_LE (vids->ypels_meter);
       vids->num_colors  = GUINT32_FROM_LE (vids->num_colors);
       vids->imp_colors  = GUINT32_FROM_LE (vids->imp_colors);
+
+      caps = gst_riff_create_video_caps (vids->compression, NULL, vids);
+    } else {
+      caps = gst_riff_create_video_template_caps ();
     }
 
-    caps = gst_matroska_demux_vfw_caps (vids->compression, vids);
+    for (t = caps; t != NULL; t = t->next) {
+      gst_props_remove_entry_by_name (t->properties, "width");
+      gst_props_remove_entry_by_name (t->properties, "height");
+      gst_props_remove_entry_by_name (t->properties, "framerate");
+    }
   } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED)) {
     /* how nice, this is undocumented... */
     if (videocontext != NULL) {
@@ -2223,6 +2302,7 @@ gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext *videocontext,
           height = gst_props_entry_new ("height",
                                        GST_PROPS_INT (h));
         }
+#if 0
         if (videocontext->display_width > 0 &&
            videocontext->display_height > 0) {
           gint w = 100 * videocontext->display_width / videocontext->pixel_width;
@@ -2233,6 +2313,7 @@ gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext *videocontext,
           pixel_height = gst_props_entry_new ("pixel_height",
                                              GST_PROPS_INT (h));
         }
+#endif
         if (context->default_duration > 0) {
           gfloat framerate = 1. * GST_SECOND / context->default_duration;
 
@@ -2248,12 +2329,12 @@ gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext *videocontext,
                                     GST_PROPS_INT_RANGE (16, 4096));
         height = gst_props_entry_new ("height",
                                      GST_PROPS_INT_RANGE (16, 4096));
-
+#if 0
         pixel_width = gst_props_entry_new ("pixel_width",
                                           GST_PROPS_INT_RANGE (0, 255));
         pixel_height = gst_props_entry_new ("pixel_height",
                                            GST_PROPS_INT_RANGE (0, 255));
-
+#endif
         fps = gst_props_entry_new ("framerate",
                                   GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT));
       }
@@ -2282,110 +2363,6 @@ gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext *videocontext,
 }
 
 static GstCaps *
-gst_matroskademux_acm_caps (guint16             codec_id,
-                            gst_riff_strf_auds *auds)
-{
-  GstCaps *caps = NULL;
-
-  switch (codec_id) {
-    case GST_RIFF_WAVE_FORMAT_MPEGL3: /* mp3 */
-      caps = GST_CAPS_NEW ("matroskademux_acm_audio_src_mp3",
-                          "audio/mpeg",
-                            "layer", GST_PROPS_INT (3));
-      break;
-
-    case GST_RIFF_WAVE_FORMAT_MPEGL12: /* mp1 or mp2 */
-      caps = GST_CAPS_NEW ("matroskademux_acm_audio_src_mp12",
-                          "audio/mpeg",
-                            "layer", GST_PROPS_INT (2));
-      break;
-
-    case GST_RIFF_WAVE_FORMAT_PCM: /* PCM/wav */ {
-      GstPropsEntry *width = NULL, *depth = NULL, *signedness = NULL;
-
-      if (auds != NULL) {
-        gint ba = GUINT16_FROM_LE (auds->blockalign);
-        gint ch = GUINT16_FROM_LE (auds->channels);
-        gint ws = GUINT16_FROM_LE (auds->size);
-
-        width = gst_props_entry_new ("width",
-                                    GST_PROPS_INT (ba * 8 / ch));
-        depth = gst_props_entry_new ("depth",
-                                    GST_PROPS_INT (ws));
-        signedness = gst_props_entry_new ("signed",
-                                         GST_PROPS_BOOLEAN (ws != 8));
-      } else {
-        signedness = gst_props_entry_new ("signed",
-                                         GST_PROPS_LIST (
-                                           GST_PROPS_BOOLEAN (TRUE),
-                                           GST_PROPS_BOOLEAN (FALSE)));
-        width = gst_props_entry_new ("width",
-                                    GST_PROPS_LIST (
-                                      GST_PROPS_INT (8),
-                                      GST_PROPS_INT (16)));
-        depth = gst_props_entry_new ("depth",
-                                    GST_PROPS_LIST (
-                                      GST_PROPS_INT (8),
-                                      GST_PROPS_INT (16)));
-      }
-
-      caps = GST_CAPS_NEW ("matroskademux_acm_audio_src_pcm",
-                          "audio/x-raw-int",
-                            "endianness",
-                               GST_PROPS_INT (G_LITTLE_ENDIAN));
-      gst_props_add_entry (caps->properties, width);
-      gst_props_add_entry (caps->properties, depth);
-      gst_props_add_entry (caps->properties, signedness);
-    }
-      break;
-
-    case GST_RIFF_WAVE_FORMAT_MULAW:
-      if (auds != NULL && auds->size != 8) {
-        g_warning ("invalid depth (%d) of mulaw audio, overwriting.",
-                  auds->size);
-      }
-      caps = GST_CAPS_NEW ("matroskademux_acm_audio_src",
-                          "audio/x-mulaw",
-                            NULL);
-      break;
-
-    case GST_RIFF_WAVE_FORMAT_ALAW:
-      if (auds != NULL && auds->size != 8) {
-        g_warning ("invalid depth (%d) of alaw audio, overwriting.",
-                  auds->size);
-      }
-      caps = GST_CAPS_NEW ("matroskademux_acm_audio_src",
-                          "audio/x-alaw",
-                            NULL);
-      break;
-
-    case GST_RIFF_WAVE_FORMAT_VORBIS1: /* ogg/vorbis mode 1 */
-    case GST_RIFF_WAVE_FORMAT_VORBIS2: /* ogg/vorbis mode 2 */
-    case GST_RIFF_WAVE_FORMAT_VORBIS3: /* ogg/vorbis mode 3 */
-    case GST_RIFF_WAVE_FORMAT_VORBIS1PLUS: /* ogg/vorbis mode 1+ */
-    case GST_RIFF_WAVE_FORMAT_VORBIS2PLUS: /* ogg/vorbis mode 2+ */
-    case GST_RIFF_WAVE_FORMAT_VORBIS3PLUS: /* ogg/vorbis mode 3+ */
-      caps = GST_CAPS_NEW ("matroskademux_acm_audio_src_vorbis",
-                          "audio/x-vorbis",
-                            NULL);
-      break;
-
-    case GST_RIFF_WAVE_FORMAT_A52:
-      caps = GST_CAPS_NEW ("matroskademux_acm_audio_src_ac3",
-                          "audio/x-ac3",
-                            NULL);
-      break;
-
-    default:
-      GST_WARNING ("matroskademux: unkown ACM audio format 0x%04x",
-                  codec_id);
-      break;
-  }
-
-  return caps;
-}
-
-static GstCaps *
 gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext *audiocontext,
                               const gchar                  *codec_id,
                               gpointer                      data,
@@ -2479,7 +2456,8 @@ gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext *audiocontext,
                         "audio/x-vorbis",
                           NULL);
   } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_ACM)) {
-      gst_riff_strf_auds *auds = NULL;
+    gst_riff_strf_auds *auds = NULL;
+    GstCaps *t;
 
     if (data) {
       auds = (gst_riff_strf_auds *) data;
@@ -2491,9 +2469,16 @@ gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext *audiocontext,
       auds->av_bps     = GUINT32_FROM_LE (auds->av_bps);
       auds->blockalign = GUINT16_FROM_LE (auds->blockalign);
       auds->size       = GUINT16_FROM_LE (auds->size);
+
+      caps = gst_riff_create_audio_caps (auds->format, NULL, auds);
+    } else {
+      caps = gst_riff_create_audio_template_caps ();
     }
 
-    caps = gst_matroskademux_acm_caps (auds->format, auds);
+    for (t = caps; t != NULL; t = t->next) {
+      gst_props_remove_entry_by_name (t->properties, "rate");
+      gst_props_remove_entry_by_name (t->properties, "channels");
+    }
   } else if (!strncmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_MPEG2,
                       strlen (GST_MATROSKA_CODEC_ID_AUDIO_MPEG2)) ||
              !strncmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_MPEG4,
@@ -2628,6 +2613,7 @@ gst_matroska_demux_plugin_init (GstPlugin *plugin)
   GstCaps *videosrccaps = NULL, *audiosrccaps = NULL,
          *subtitlesrccaps = NULL, *temp;
   const gchar *video_id[] = {
+    GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC,
     GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED,
     GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_SP,
     GST_MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP,
@@ -2646,6 +2632,7 @@ gst_matroska_demux_plugin_init (GstPlugin *plugin)
     GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE,
     GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT,
     GST_MATROSKA_CODEC_ID_AUDIO_AC3,
+    GST_MATROSKA_CODEC_ID_AUDIO_ACM,
     GST_MATROSKA_CODEC_ID_AUDIO_VORBIS,
     GST_MATROSKA_CODEC_ID_AUDIO_MPEG2,
     GST_MATROSKA_CODEC_ID_AUDIO_MPEG4,
@@ -2659,40 +2646,10 @@ gst_matroska_demux_plugin_init (GstPlugin *plugin)
     /* FILLME */
     NULL,
   };
-  guint32 video_fourcc[] = {
-    GST_MAKE_FOURCC ('I','4','2','0'),
-    GST_MAKE_FOURCC ('Y','U','Y','2'),
-    GST_MAKE_FOURCC ('M','J','P','G'),
-    GST_MAKE_FOURCC ('H','F','Y','U'),
-    GST_MAKE_FOURCC ('M','P','E','G'),
-    GST_MAKE_FOURCC ('H','2','6','3'),
-    GST_MAKE_FOURCC ('D','I','V','3'),
-    GST_MAKE_FOURCC ('D','X','5','0'),
-    GST_MAKE_FOURCC ('X','V','I','D'),
-    GST_MAKE_FOURCC ('M','P','G','4'),
-    GST_MAKE_FOURCC ('M','P','4','2'),
-    GST_MAKE_FOURCC ('M','P','4','3'),
-    GST_MAKE_FOURCC ('3','I','V','1'),
-    GST_MAKE_FOURCC ('D','V','S','D'),
-    GST_MAKE_FOURCC ('W','M','V','1'),
-    GST_MAKE_FOURCC ('W','M','V','2'),
-    /* FILLME */
-    0,
-  };
-  guint16 audio_tag[] = {
-    GST_RIFF_WAVE_FORMAT_MPEGL3,
-    GST_RIFF_WAVE_FORMAT_MPEGL12,
-    GST_RIFF_WAVE_FORMAT_PCM,
-    GST_RIFF_WAVE_FORMAT_MULAW,
-    GST_RIFF_WAVE_FORMAT_ALAW,
-    GST_RIFF_WAVE_FORMAT_VORBIS1,
-    GST_RIFF_WAVE_FORMAT_A52,
-    /* FILLME */
-    0,
-  };
 
   /* this filter needs the riff parser */
-  if (!gst_library_load ("gstbytestream"))
+  if (!gst_library_load ("gstbytestream") ||
+      !gst_library_load ("riff")) /* for fourcc stuff */
     return FALSE;
 
   /* video src template */
@@ -2700,10 +2657,6 @@ gst_matroska_demux_plugin_init (GstPlugin *plugin)
     temp = gst_matroska_demux_video_caps (NULL, video_id[i], NULL, 0);
     videosrccaps = gst_caps_append (videosrccaps, temp);
   }
-  for (i = 0; video_fourcc[i] != 0; i++) {
-    temp = gst_matroska_demux_vfw_caps (video_fourcc[i], NULL);
-    videosrccaps = gst_caps_append (videosrccaps, temp);
-  }
   for (i = 0; complex_id[i] != NULL; i++) {
     temp = gst_matroska_demux_complex_caps (NULL, video_id[i], NULL, 0);
     videosrccaps = gst_caps_append (videosrccaps, temp);
@@ -2718,10 +2671,6 @@ gst_matroska_demux_plugin_init (GstPlugin *plugin)
     temp = gst_matroska_demux_audio_caps (NULL, audio_id[i], NULL, 0);
     audiosrccaps = gst_caps_append (audiosrccaps, temp);
   }
-  for (i = 0; audio_tag[i] != 0; i++) {
-    temp = gst_matroskademux_acm_caps (audio_tag[i], NULL);
-    audiosrccaps = gst_caps_append (audiosrccaps, temp);
-  }
   audiosrctempl = gst_pad_template_new ("audio_%02d",
                                        GST_PAD_SRC,
                                        GST_PAD_SOMETIMES,
index 4e2062a..7356e69 100644 (file)
@@ -63,6 +63,7 @@ typedef struct _GstMatroskaDemux {
   GstMatroskaTrackContext *src[GST_MATROSKA_DEMUX_MAX_STREAMS];
   guint          num_streams,
                  num_v_streams, num_a_streams, num_t_streams;
+  GstClock     *clock;
 
   /* metadata */
   GstCaps       *metadata,
@@ -74,6 +75,13 @@ typedef struct _GstMatroskaDemux {
   GstMatroskaDemuxState state;
   guint          level_up;
 
+  /* did we parse metadata/cues already? */
+  gboolean       metadata_parsed,
+                index_parsed;
+
+  /* start-of-segment */
+  guint64        segment_start;
+
   /* a cue (index) table */
   GstMatroskaIndex *index;
   guint          num_indexes;