matroska: refactor code common to matroskademux and matroskaparse
authorDebarshi Ray <rishi@gnu.org>
Mon, 23 May 2011 15:06:44 +0000 (18:06 +0300)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Mon, 23 May 2011 15:21:52 +0000 (17:21 +0200)
Replace the following functions with their gst_matroska_read_common_*
counterparts:
    - gst_matroska_{demux,parse}_parse_index
    - gst_matroska_{demux,parse}_parse_skip
    - gst_matroska_{demux,parse}_stream_from_num

Introduce GstMatroskaReadCommon to contain those members of
GstMatroskaDemux and GstMatroskaParse that were used by the above
functions.

https://bugzilla.gnome.org/show_bug.cgi?id=650877

gst/matroska/Makefile.am
gst/matroska/matroska-demux.c
gst/matroska/matroska-demux.h
gst/matroska/matroska-parse.c
gst/matroska/matroska-parse.h
gst/matroska/matroska-read-common.c [new file with mode: 0644]
gst/matroska/matroska-read-common.h [new file with mode: 0644]

index 195c680..7d56973 100644 (file)
@@ -8,6 +8,7 @@ libgstmatroska_la_SOURCES = \
        matroska-parse.c \
        matroska-ids.c \
        matroska-mux.c \
+       matroska-read-common.c \
        webm-mux.c \
        lzo.c
 
@@ -19,6 +20,7 @@ noinst_HEADERS = \
        matroska-parse.h \
        matroska-ids.h \
        matroska-mux.h \
+       matroska-read-common.h \
        webm-mux.h \
        lzo.h
 
index 1f3dbd4..5358652 100644 (file)
@@ -208,9 +208,9 @@ gst_matroska_demux_finalize (GObject * object)
 {
   GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (object);
 
-  if (demux->src) {
-    g_ptr_array_free (demux->src, TRUE);
-    demux->src = NULL;
+  if (demux->common.src) {
+    g_ptr_array_free (demux->common.src, TRUE);
+    demux->common.src = NULL;
   }
 
   if (demux->global_tags) {
@@ -263,11 +263,11 @@ gst_matroska_demux_init (GstMatroskaDemux * demux,
   gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
 
   /* initial stream no. */
-  demux->src = NULL;
+  demux->common.src = NULL;
 
   demux->writing_app = NULL;
   demux->muxing_app = NULL;
-  demux->index = NULL;
+  demux->common.index = NULL;
   demux->global_tags = NULL;
 
   demux->adapter = gst_adapter_new ();
@@ -325,9 +325,10 @@ gst_matroska_demux_combine_flows (GstMatroskaDemux * demux,
     goto done;
 
   /* only return NOT_LINKED if all other pads returned NOT_LINKED */
-  g_assert (demux->src->len == demux->num_streams);
-  for (i = 0; i < demux->src->len; i++) {
-    GstMatroskaTrackContext *ostream = g_ptr_array_index (demux->src, i);
+  g_assert (demux->common.src->len == demux->common.num_streams);
+  for (i = 0; i < demux->common.src->len; i++) {
+    GstMatroskaTrackContext *ostream = g_ptr_array_index (demux->common.src,
+        i);
 
     if (ostream == NULL)
       continue;
@@ -363,10 +364,11 @@ gst_matroska_demux_reset (GstElement * element)
   demux->state = GST_MATROSKA_DEMUX_STATE_START;
 
   /* clean up existing streams */
-  if (demux->src) {
-    g_assert (demux->src->len == demux->num_streams);
-    for (i = 0; i < demux->src->len; i++) {
-      GstMatroskaTrackContext *context = g_ptr_array_index (demux->src, i);
+  if (demux->common.src) {
+    g_assert (demux->common.src->len == demux->common.num_streams);
+    for (i = 0; i < demux->common.src->len; i++) {
+      GstMatroskaTrackContext *context = g_ptr_array_index (demux->common.src,
+          i);
 
       if (context->pad != NULL)
         gst_element_remove_pad (GST_ELEMENT (demux), context->pad);
@@ -374,11 +376,11 @@ gst_matroska_demux_reset (GstElement * element)
       gst_caps_replace (&context->caps, NULL);
       gst_matroska_track_free (context);
     }
-    g_ptr_array_free (demux->src, TRUE);
+    g_ptr_array_free (demux->common.src, TRUE);
   }
-  demux->src = g_ptr_array_new ();
+  demux->common.src = g_ptr_array_new ();
 
-  demux->num_streams = 0;
+  demux->common.num_streams = 0;
   demux->num_a_streams = 0;
   demux->num_t_streams = 0;
   demux->num_v_streams = 0;
@@ -390,9 +392,9 @@ gst_matroska_demux_reset (GstElement * element)
   demux->muxing_app = NULL;
 
   /* reset indexes */
-  if (demux->index) {
-    g_array_free (demux->index, TRUE);
-    demux->index = NULL;
+  if (demux->common.index) {
+    g_array_free (demux->common.index, TRUE);
+    demux->common.index = NULL;
   }
 
   if (demux->clusters) {
@@ -402,10 +404,10 @@ gst_matroska_demux_reset (GstElement * element)
 
   /* reset timers */
   demux->clock = NULL;
-  demux->time_scale = 1000000;
+  demux->common.time_scale = 1000000;
   demux->created = G_MININT64;
 
-  demux->index_parsed = FALSE;
+  demux->common.index_parsed = FALSE;
   demux->tracks_parsed = FALSE;
   demux->segmentinfo_parsed = FALSE;
   demux->attachments_parsed = FALSE;
@@ -450,11 +452,11 @@ gst_matroska_demux_reset (GstElement * element)
     demux->new_segment = NULL;
   }
 
-  if (demux->element_index) {
-    gst_object_unref (demux->element_index);
-    demux->element_index = NULL;
+  if (demux->common.element_index) {
+    gst_object_unref (demux->common.element_index);
+    demux->common.element_index = NULL;
   }
-  demux->element_index_writer_id = -1;
+  demux->common.element_index_writer_id = -1;
 
   if (demux->global_tags) {
     gst_tag_list_free (demux->global_tags);
@@ -584,27 +586,6 @@ gst_matroska_demux_get_length (GstMatroskaDemux * demux)
 }
 
 static gint
-gst_matroska_demux_stream_from_num (GstMatroskaDemux * demux, guint track_num)
-{
-  guint n;
-
-  g_assert (demux->src->len == demux->num_streams);
-  for (n = 0; n < demux->src->len; n++) {
-    GstMatroskaTrackContext *context = g_ptr_array_index (demux->src, n);
-
-    if (context->num == track_num) {
-      return n;
-    }
-  }
-
-  if (n == demux->num_streams)
-    GST_WARNING_OBJECT (demux,
-        "Failed to find corresponding pad for tracknum %d", track_num);
-
-  return -1;
-}
-
-static gint
 gst_matroska_demux_encoding_cmp (GstMatroskaTrackEncoding * a,
     GstMatroskaTrackEncoding * b)
 {
@@ -1151,9 +1132,10 @@ gst_matroska_demux_tracknumber_unique (GstMatroskaDemux * demux, guint64 num)
 {
   gint i;
 
-  g_assert (demux->src->len == demux->num_streams);
-  for (i = 0; i < demux->src->len; i++) {
-    GstMatroskaTrackContext *context = g_ptr_array_index (demux->src, i);
+  g_assert (demux->common.src->len == demux->common.num_streams);
+  for (i = 0; i < demux->common.src->len; i++) {
+    GstMatroskaTrackContext *context = g_ptr_array_index (demux->common.src,
+        i);
 
     if (context->num == num)
       return FALSE;
@@ -1187,8 +1169,8 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml)
   /* allocate generic... if we know the type, we'll g_renew()
    * with the precise type */
   context = g_new0 (GstMatroskaTrackContext, 1);
-  g_ptr_array_add (demux->src, context);
-  context->index = demux->num_streams;
+  g_ptr_array_add (demux->common.src, context);
+  context->index = demux->common.num_streams;
   context->index_writer_id = -1;
   context->type = 0;            /* no type yet */
   context->default_duration = 0;
@@ -1200,8 +1182,8 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml)
       GST_MATROSKA_TRACK_LACING;
   context->last_flow = GST_FLOW_OK;
   context->to_offset = G_MAXINT64;
-  demux->num_streams++;
-  g_assert (demux->src->len == demux->num_streams);
+  demux->common.num_streams++;
+  g_assert (demux->common.src->len == demux->common.num_streams);
 
   GST_DEBUG_OBJECT (demux, "Stream number %d", context->index);
 
@@ -1293,7 +1275,8 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml)
             context->type = 0;
             break;
         }
-        g_ptr_array_index (demux->src, demux->num_streams - 1) = context;
+        g_ptr_array_index (demux->common.src, demux->common.num_streams - 1)
+            = context;
         break;
       }
 
@@ -1312,7 +1295,8 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml)
           break;
         }
         videocontext = (GstMatroskaTrackVideoContext *) context;
-        g_ptr_array_index (demux->src, demux->num_streams - 1) = context;
+        g_ptr_array_index (demux->common.src, demux->common.num_streams - 1)
+            = context;
 
         while (ret == GST_FLOW_OK &&
             gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
@@ -1532,7 +1516,8 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml)
           break;
 
         audiocontext = (GstMatroskaTrackAudioContext *) context;
-        g_ptr_array_index (demux->src, demux->num_streams - 1) = context;
+        g_ptr_array_index (demux->common.src, demux->common.num_streams - 1)
+            = context;
 
         while (ret == GST_FLOW_OK &&
             gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
@@ -1832,9 +1817,9 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml)
     if (ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED)
       GST_WARNING_OBJECT (ebml, "Unknown stream/codec in track entry header");
 
-    demux->num_streams--;
-    g_ptr_array_remove_index (demux->src, demux->num_streams);
-    g_assert (demux->src->len == demux->num_streams);
+    demux->common.num_streams--;
+    g_ptr_array_remove_index (demux->common.src, demux->common.num_streams);
+    g_assert (demux->common.src->len == demux->common.num_streams);
     if (context) {
       gst_matroska_track_free (context);
     }
@@ -2127,14 +2112,14 @@ gst_matroskademux_do_index_seek (GstMatroskaDemux * demux,
   GstMatroskaIndex *entry = NULL;
   GArray *index;
 
-  if (!demux->index || !demux->index->len)
+  if (!demux->common.index || !demux->common.index->len)
     return NULL;
 
   /* find entry just before or at the requested position */
   if (track && track->index_table)
     index = track->index_table;
   else
-    index = demux->index;
+    index = demux->common.index;
 
   entry =
       gst_util_array_binary_search (index->data, index->len,
@@ -2187,11 +2172,11 @@ gst_matroska_demux_send_event (GstMatroskaDemux * demux, GstEvent * event)
 
   is_newsegment = (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT);
 
-  g_assert (demux->src->len == demux->num_streams);
-  for (i = 0; i < demux->src->len; i++) {
+  g_assert (demux->common.src->len == demux->common.num_streams);
+  for (i = 0; i < demux->common.src->len; i++) {
     GstMatroskaTrackContext *stream;
 
-    stream = g_ptr_array_index (demux->src, i);
+    stream = g_ptr_array_index (demux->common.src, i);
     gst_event_ref (event);
     gst_pad_push_event (stream->pad, event);
     ret = TRUE;
@@ -2249,10 +2234,10 @@ gst_matroska_demux_get_seek_track (GstMatroskaDemux * demux,
   if (track && track->type == GST_MATROSKA_TRACK_TYPE_VIDEO)
     return track;
 
-  for (i = 0; i < demux->src->len; i++) {
+  for (i = 0; i < demux->common.src->len; i++) {
     GstMatroskaTrackContext *stream;
 
-    stream = g_ptr_array_index (demux->src, i);
+    stream = g_ptr_array_index (demux->common.src, i);
     if (stream->type == GST_MATROSKA_TRACK_TYPE_VIDEO && stream->index_table)
       track = stream;
   }
@@ -2269,9 +2254,10 @@ gst_matroska_demux_reset_streams (GstMatroskaDemux * demux, GstClockTime time,
 
   GST_DEBUG_OBJECT (demux, "resetting stream state");
 
-  g_assert (demux->src->len == demux->num_streams);
-  for (i = 0; i < demux->src->len; i++) {
-    GstMatroskaTrackContext *context = g_ptr_array_index (demux->src, i);
+  g_assert (demux->common.src->len == demux->common.num_streams);
+  for (i = 0; i < demux->common.src->len; i++) {
+    GstMatroskaTrackContext *context = g_ptr_array_index (demux->common.src,
+        i);
     context->pos = time;
     context->set_discont = TRUE;
     context->eos = FALSE;
@@ -2297,10 +2283,10 @@ gst_matroska_demux_move_to_entry (GstMatroskaDemux * demux,
 
   /* seek (relative to matroska segment) */
   /* position might be invalid; will error when streaming resumes ... */
-  demux->offset = entry->pos + demux->ebml_segment_start;
+  demux->offset = entry->pos + demux->common.ebml_segment_start;
 
   GST_DEBUG_OBJECT (demux, "Seeked to offset %" G_GUINT64_FORMAT ", block %d, "
-      "time %" GST_TIME_FORMAT, entry->pos + demux->ebml_segment_start,
+      "time %" GST_TIME_FORMAT, entry->pos + demux->common.ebml_segment_start,
       entry->block, GST_TIME_ARGS (entry->time));
 
   /* update the time */
@@ -2310,8 +2296,8 @@ gst_matroska_demux_move_to_entry (GstMatroskaDemux * demux,
   demux->seek_first = TRUE;
   demux->last_stop_end = GST_CLOCK_TIME_NONE;
 
-  for (i = 0; i < demux->src->len; i++) {
-    GstMatroskaTrackContext *stream = g_ptr_array_index (demux->src, i);
+  for (i = 0; i < demux->common.src->len; i++) {
+    GstMatroskaTrackContext *stream = g_ptr_array_index (demux->common.src, i);
 
     if (reset) {
       stream->to_offset = G_MAXINT64;
@@ -2487,7 +2473,7 @@ gst_matroska_demux_search_pos (GstMatroskaDemux * demux, GstClockTime time)
 
   /* estimate using start and current position */
   GST_OBJECT_LOCK (demux);
-  opos = demux->offset - demux->ebml_segment_start;
+  opos = demux->offset - demux->common.ebml_segment_start;
   otime = demux->segment.last_stop;
   GST_OBJECT_UNLOCK (demux);
 
@@ -2500,7 +2486,7 @@ retry:
     newpos = 0;
   /* favour undershoot */
   newpos = newpos * 90 / 100;
-  newpos += demux->ebml_segment_start;
+  newpos += demux->common.ebml_segment_start;
 
   GST_DEBUG_OBJECT (demux,
       "estimated offset for %" GST_TIME_FORMAT ": %" G_GINT64_FORMAT,
@@ -2558,7 +2544,7 @@ retry:
     }
     if (demux->cluster_time != GST_CLOCK_TIME_NONE &&
         cluster_time == GST_CLOCK_TIME_NONE) {
-      cluster_time = demux->cluster_time * demux->time_scale;
+      cluster_time = demux->cluster_time * demux->common.time_scale;
       cluster_offset = demux->cluster_offset;
       GST_DEBUG_OBJECT (demux, "found cluster at offset %" G_GINT64_FORMAT
           " with time %" GST_TIME_FORMAT, cluster_offset,
@@ -2609,7 +2595,7 @@ retry:
 
   entry = g_new0 (GstMatroskaIndex, 1);
   entry->time = prev_cluster_time;
-  entry->pos = prev_cluster_offset - demux->ebml_segment_start;
+  entry->pos = prev_cluster_offset - demux->common.ebml_segment_start;
   GST_DEBUG_OBJECT (demux, "simulated index entry; time %" GST_TIME_FORMAT
       ", pos %" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->time), entry->pos);
 
@@ -2673,7 +2659,7 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux,
               seeksegment.last_stop, &demux->seek_index, &demux->seek_entry)) ==
       NULL) {
     /* pull mode without index can scan later on */
-    if (demux->index || demux->streaming) {
+    if (demux->common.index || demux->streaming) {
       GST_DEBUG_OBJECT (demux, "No matching seek entry in index");
       GST_OBJECT_UNLOCK (demux);
       return FALSE;
@@ -2687,7 +2673,7 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux,
     /* upstream takes care of flushing and all that
      * ... and newsegment event handling takes care of the rest */
     return perform_seek_to_offset (demux,
-        entry->pos + demux->ebml_segment_start);
+        entry->pos + demux->common.ebml_segment_start);
   }
 
   flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
@@ -2709,7 +2695,7 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux,
   GST_PAD_STREAM_LOCK (demux->sinkpad);
 
   /* pull mode without index can do some scanning */
-  if (!demux->streaming && !demux->index) {
+  if (!demux->streaming && !demux->common.index) {
     /* need to stop flushing upstream as we need it next */
     if (flush)
       gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ());
@@ -2840,7 +2826,7 @@ gst_matroska_demux_handle_seek_push (GstMatroskaDemux * demux, GstPad * pad,
   }
 
   /* check for having parsed index already */
-  if (!demux->index_parsed) {
+  if (!demux->common.index_parsed) {
     gboolean building_index;
     guint64 offset = 0;
 
@@ -2958,8 +2944,8 @@ gst_matroska_demux_seek_to_previous_keyframe (GstMatroskaDemux * demux)
     goto exit;
   }
 
-  for (i = 0; i < demux->src->len; i++) {
-    GstMatroskaTrackContext *stream = g_ptr_array_index (demux->src, i);
+  for (i = 0; i < demux->common.src->len; i++) {
+    GstMatroskaTrackContext *stream = g_ptr_array_index (demux->common.src, i);
 
     GST_DEBUG_OBJECT (demux, "segment start %" GST_TIME_FORMAT
         ", stream %d at %" GST_TIME_FORMAT,
@@ -2993,23 +2979,6 @@ exit:
   return ret;
 }
 
-/* skip unknown or alike element */
-static GstFlowReturn
-gst_matroska_demux_parse_skip (GstMatroskaDemux * demux, GstEbmlRead * ebml,
-    const gchar * parent_name, guint id)
-{
-  if (id == GST_EBML_ID_VOID) {
-    GST_DEBUG_OBJECT (demux, "Skipping EBML Void element");
-  } else if (id == GST_EBML_ID_CRC32) {
-    GST_DEBUG_OBJECT (demux, "Skipping EBML CRC32 element");
-  } else {
-    GST_WARNING_OBJECT (demux,
-        "Unknown %s subelement 0x%x - ignoring", parent_name, id);
-  }
-
-  return gst_ebml_read_skip (ebml);
-}
-
 static GstFlowReturn
 gst_matroska_demux_parse_header (GstMatroskaDemux * demux, GstEbmlRead * ebml)
 {
@@ -3121,7 +3090,8 @@ gst_matroska_demux_parse_header (GstMatroskaDemux * demux, GstEbmlRead * ebml)
       }
 
       default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "EBML header", id);
+        ret = gst_matroska_read_common_parse_skip (&demux->common, ebml,
+            "EBML header", id);
         if (ret != GST_FLOW_OK)
           return ret;
         break;
@@ -3190,7 +3160,8 @@ gst_matroska_demux_parse_tracks (GstMatroskaDemux * demux, GstEbmlRead * ebml)
         break;
 
       default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "Track", id);
+        ret = gst_matroska_read_common_parse_skip (&demux->common, ebml,
+            "Track", id);
         break;
     }
   }
@@ -3202,306 +3173,6 @@ gst_matroska_demux_parse_tracks (GstMatroskaDemux * demux, GstEbmlRead * ebml)
 }
 
 static GstFlowReturn
-gst_matroska_demux_parse_index_cuetrack (GstMatroskaDemux * demux,
-    GstEbmlRead * ebml, guint * nentries)
-{
-  guint32 id;
-  GstFlowReturn ret;
-  GstMatroskaIndex idx;
-
-  idx.pos = (guint64) - 1;
-  idx.track = 0;
-  idx.time = GST_CLOCK_TIME_NONE;
-  idx.block = 1;
-
-  DEBUG_ELEMENT_START (demux, ebml, "CueTrackPositions");
-
-  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
-    DEBUG_ELEMENT_STOP (demux, ebml, "CueTrackPositions", ret);
-    return ret;
-  }
-
-  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
-    if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
-      break;
-
-    switch (id) {
-        /* track number */
-      case GST_MATROSKA_ID_CUETRACK:
-      {
-        guint64 num;
-
-        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
-          break;
-
-        if (num == 0) {
-          idx.track = 0;
-          GST_WARNING_OBJECT (demux, "Invalid CueTrack 0");
-          break;
-        }
-
-        GST_DEBUG_OBJECT (demux, "CueTrack: %" G_GUINT64_FORMAT, num);
-        idx.track = num;
-        break;
-      }
-
-        /* position in file */
-      case GST_MATROSKA_ID_CUECLUSTERPOSITION:
-      {
-        guint64 num;
-
-        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
-          break;
-
-        if (num > G_MAXINT64) {
-          GST_WARNING_OBJECT (demux, "CueClusterPosition %" G_GUINT64_FORMAT
-              " too large", num);
-          break;
-        }
-
-        idx.pos = num;
-        break;
-      }
-
-        /* number of block in the cluster */
-      case GST_MATROSKA_ID_CUEBLOCKNUMBER:
-      {
-        guint64 num;
-
-        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
-          break;
-
-        if (num == 0) {
-          GST_WARNING_OBJECT (demux, "Invalid CueBlockNumber 0");
-          break;
-        }
-
-        GST_DEBUG_OBJECT (demux, "CueBlockNumber: %" G_GUINT64_FORMAT, num);
-        idx.block = num;
-
-        /* mild sanity check, disregard strange cases ... */
-        if (idx.block > G_MAXUINT16) {
-          GST_DEBUG_OBJECT (demux, "... looks suspicious, ignoring");
-          idx.block = 1;
-        }
-        break;
-      }
-
-      default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "CueTrackPositions",
-            id);
-        break;
-
-      case GST_MATROSKA_ID_CUECODECSTATE:
-      case GST_MATROSKA_ID_CUEREFERENCE:
-        ret = gst_ebml_read_skip (ebml);
-        break;
-    }
-  }
-
-  DEBUG_ELEMENT_STOP (demux, ebml, "CueTrackPositions", ret);
-
-  if ((ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED)
-      && idx.pos != (guint64) - 1 && idx.track > 0) {
-    g_array_append_val (demux->index, idx);
-    (*nentries)++;
-  } else if (ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED) {
-    GST_DEBUG_OBJECT (demux, "CueTrackPositions without valid content");
-  }
-
-  return ret;
-}
-
-static GstFlowReturn
-gst_matroska_demux_parse_index_pointentry (GstMatroskaDemux * demux,
-    GstEbmlRead * ebml)
-{
-  guint32 id;
-  GstFlowReturn ret;
-  GstClockTime time = GST_CLOCK_TIME_NONE;
-  guint nentries = 0;
-
-  DEBUG_ELEMENT_START (demux, ebml, "CuePoint");
-
-  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
-    DEBUG_ELEMENT_STOP (demux, ebml, "CuePoint", ret);
-    return ret;
-  }
-
-  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
-    if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
-      break;
-
-    switch (id) {
-        /* one single index entry ('point') */
-      case GST_MATROSKA_ID_CUETIME:
-      {
-        if ((ret = gst_ebml_read_uint (ebml, &id, &time)) != GST_FLOW_OK)
-          break;
-
-        GST_DEBUG_OBJECT (demux, "CueTime: %" G_GUINT64_FORMAT, time);
-        time = time * demux->time_scale;
-        break;
-      }
-
-        /* position in the file + track to which it belongs */
-      case GST_MATROSKA_ID_CUETRACKPOSITIONS:
-      {
-        if ((ret =
-                gst_matroska_demux_parse_index_cuetrack (demux, ebml,
-                    &nentries)) != GST_FLOW_OK)
-          break;
-        break;
-      }
-
-      default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "CuePoint", id);
-        break;
-    }
-  }
-
-  DEBUG_ELEMENT_STOP (demux, ebml, "CuePoint", ret);
-
-  if (nentries > 0) {
-    if (time == GST_CLOCK_TIME_NONE) {
-      GST_WARNING_OBJECT (demux, "CuePoint without valid time");
-      g_array_remove_range (demux->index, demux->index->len - nentries,
-          nentries);
-    } else {
-      gint i;
-
-      for (i = demux->index->len - nentries; i < demux->index->len; i++) {
-        GstMatroskaIndex *idx =
-            &g_array_index (demux->index, GstMatroskaIndex, i);
-
-        idx->time = time;
-        GST_DEBUG_OBJECT (demux, "Index entry: pos=%" G_GUINT64_FORMAT
-            ", time=%" GST_TIME_FORMAT ", track=%u, block=%u", idx->pos,
-            GST_TIME_ARGS (idx->time), (guint) idx->track, (guint) idx->block);
-      }
-    }
-  } else {
-    GST_DEBUG_OBJECT (demux, "Empty CuePoint");
-  }
-
-  return ret;
-}
-
-static gint
-gst_matroska_index_compare (GstMatroskaIndex * i1, GstMatroskaIndex * i2)
-{
-  if (i1->time < i2->time)
-    return -1;
-  else if (i1->time > i2->time)
-    return 1;
-  else if (i1->block < i2->block)
-    return -1;
-  else if (i1->block > i2->block)
-    return 1;
-  else
-    return 0;
-}
-
-static GstFlowReturn
-gst_matroska_demux_parse_index (GstMatroskaDemux * demux, GstEbmlRead * ebml)
-{
-  guint32 id;
-  GstFlowReturn ret = GST_FLOW_OK;
-  guint i;
-
-  if (demux->index)
-    g_array_free (demux->index, TRUE);
-  demux->index =
-      g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128);
-
-  DEBUG_ELEMENT_START (demux, ebml, "Cues");
-
-  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
-    DEBUG_ELEMENT_STOP (demux, ebml, "Cues", ret);
-    return ret;
-  }
-
-  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
-    if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
-      break;
-
-    switch (id) {
-        /* one single index entry ('point') */
-      case GST_MATROSKA_ID_POINTENTRY:
-        ret = gst_matroska_demux_parse_index_pointentry (demux, ebml);
-        break;
-
-      default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "Cues", id);
-        break;
-    }
-  }
-  DEBUG_ELEMENT_STOP (demux, ebml, "Cues", ret);
-
-  /* Sort index by time, smallest time first, for easier searching */
-  g_array_sort (demux->index, (GCompareFunc) gst_matroska_index_compare);
-
-  /* Now sort the track specific index entries into their own arrays */
-  for (i = 0; i < demux->index->len; i++) {
-    GstMatroskaIndex *idx = &g_array_index (demux->index, GstMatroskaIndex, i);
-    gint track_num;
-    GstMatroskaTrackContext *ctx;
-
-    if (demux->element_index) {
-      gint writer_id;
-
-      if (idx->track != 0 &&
-          (track_num =
-              gst_matroska_demux_stream_from_num (demux, idx->track)) != -1) {
-        ctx = g_ptr_array_index (demux->src, track_num);
-
-        if (ctx->index_writer_id == -1)
-          gst_index_get_writer_id (demux->element_index, GST_OBJECT (ctx->pad),
-              &ctx->index_writer_id);
-        writer_id = ctx->index_writer_id;
-      } else {
-        if (demux->element_index_writer_id == -1)
-          gst_index_get_writer_id (demux->element_index, GST_OBJECT (demux),
-              &demux->element_index_writer_id);
-        writer_id = demux->element_index_writer_id;
-      }
-
-      GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %"
-          G_GUINT64_FORMAT " for writer id %d", GST_TIME_ARGS (idx->time),
-          idx->pos, writer_id);
-      gst_index_add_association (demux->element_index, writer_id,
-          GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, idx->time,
-          GST_FORMAT_BYTES, idx->pos + demux->ebml_segment_start, NULL);
-    }
-
-    if (idx->track == 0)
-      continue;
-
-    track_num = gst_matroska_demux_stream_from_num (demux, idx->track);
-    if (track_num == -1)
-      continue;
-
-    ctx = g_ptr_array_index (demux->src, track_num);
-
-    if (ctx->index_table == NULL)
-      ctx->index_table =
-          g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128);
-
-    g_array_append_vals (ctx->index_table, idx, 1);
-  }
-
-  demux->index_parsed = TRUE;
-
-  /* sanity check; empty index normalizes to no index */
-  if (demux->index->len == 0) {
-    g_array_free (demux->index, TRUE);
-    demux->index = NULL;
-  }
-
-  return ret;
-}
-
-static GstFlowReturn
 gst_matroska_demux_parse_info (GstMatroskaDemux * demux, GstEbmlRead * ebml)
 {
   GstFlowReturn ret = GST_FLOW_OK;
@@ -3529,7 +3200,7 @@ gst_matroska_demux_parse_info (GstMatroskaDemux * demux, GstEbmlRead * ebml)
 
 
         GST_DEBUG_OBJECT (demux, "TimeCodeScale: %" G_GUINT64_FORMAT, num);
-        demux->time_scale = num;
+        demux->common.time_scale = num;
         break;
       }
 
@@ -3596,7 +3267,8 @@ gst_matroska_demux_parse_info (GstMatroskaDemux * demux, GstEbmlRead * ebml)
       }
 
       default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "SegmentInfo", id);
+        ret = gst_matroska_read_common_parse_skip (&demux->common, ebml,
+            "SegmentInfo", id);
         break;
 
         /* fall through */
@@ -3617,7 +3289,7 @@ gst_matroska_demux_parse_info (GstMatroskaDemux * demux, GstEbmlRead * ebml)
     GstClockTime dur_u;
 
     dur_u = gst_gdouble_to_guint64 (dur_f *
-        gst_guint64_to_gdouble (demux->time_scale));
+        gst_guint64_to_gdouble (demux->common.time_scale));
     if (GST_CLOCK_TIME_IS_VALID (dur_u) && dur_u <= G_MAXINT64)
       gst_segment_set_duration (&demux->segment, GST_FORMAT_TIME, dur_u);
   }
@@ -3692,7 +3364,8 @@ gst_matroska_demux_parse_metadata_id_simple_tag (GstMatroskaDemux * demux,
         break;
 
       default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "SimpleTag", id);
+        ret = gst_matroska_read_common_parse_skip (&demux->common, ebml,
+            "SimpleTag", id);
         break;
         /* fall-through */
 
@@ -3778,7 +3451,8 @@ gst_matroska_demux_parse_metadata_id_tag (GstMatroskaDemux * demux,
         break;
 
       default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "Tag", id);
+        ret = gst_matroska_read_common_parse_skip (&demux->common, ebml,
+            "Tag", id);
         break;
     }
   }
@@ -3834,7 +3508,8 @@ gst_matroska_demux_parse_metadata (GstMatroskaDemux * demux, GstEbmlRead * ebml)
         break;
 
       default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "Tags", id);
+        ret = gst_matroska_read_common_parse_skip (&demux->common, ebml,
+            "Tags", id);
         break;
         /* FIXME: Use to limit the tags to specific pads */
       case GST_MATROSKA_ID_TARGETS:
@@ -3917,7 +3592,8 @@ gst_matroska_demux_parse_attached_file (GstMatroskaDemux * demux,
         break;
 
       default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "AttachedFile", id);
+        ret = gst_matroska_read_common_parse_skip (&demux->common, ebml,
+            "AttachedFile", id);
         break;
       case GST_MATROSKA_ID_FILEUID:
         ret = gst_ebml_read_skip (ebml);
@@ -4030,7 +3706,8 @@ gst_matroska_demux_parse_attachments (GstMatroskaDemux * demux,
         break;
 
       default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "Attachments", id);
+        ret = gst_matroska_read_common_parse_skip (&demux->common, ebml,
+            "Attachments", id);
         break;
     }
   }
@@ -4157,11 +3834,11 @@ gst_matroska_demux_sync_streams (GstMatroskaDemux * demux)
   GST_LOG_OBJECT (demux, "Sync to %" GST_TIME_FORMAT,
       GST_TIME_ARGS (demux->segment.last_stop));
 
-  g_assert (demux->num_streams == demux->src->len);
-  for (stream_nr = 0; stream_nr < demux->src->len; stream_nr++) {
+  g_assert (demux->common.num_streams == demux->common.src->len);
+  for (stream_nr = 0; stream_nr < demux->common.src->len; stream_nr++) {
     GstMatroskaTrackContext *context;
 
-    context = g_ptr_array_index (demux->src, stream_nr);
+    context = g_ptr_array_index (demux->common.src, stream_nr);
 
     GST_LOG_OBJECT (demux,
         "Checking for resync on stream %d (%" GST_TIME_FORMAT ")", stream_nr,
@@ -4769,14 +4446,15 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
         size -= n;
 
         /* fetch stream from num */
-        stream_num = gst_matroska_demux_stream_from_num (demux, num);
+        stream_num = gst_matroska_read_common_stream_from_num (&demux->common,
+            num);
         if (G_UNLIKELY (size < 3)) {
           GST_WARNING_OBJECT (demux, "Invalid size %u", size);
           /* non-fatal, try next block(group) */
           ret = GST_FLOW_OK;
           goto done;
         } else if (G_UNLIKELY (stream_num < 0 ||
-                stream_num >= demux->num_streams)) {
+                stream_num >= demux->common.num_streams)) {
           /* let's not give up on a stray invalid track number */
           GST_WARNING_OBJECT (demux,
               "Invalid stream %d for track number %" G_GUINT64_FORMAT
@@ -4784,7 +4462,7 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
           goto done;
         }
 
-        stream = g_ptr_array_index (demux->src, stream_num);
+        stream = g_ptr_array_index (demux->common.src, stream_num);
 
         /* time (relative to cluster time) */
         time = ((gint16) GST_READ_UINT16_BE (data));
@@ -4944,7 +4622,8 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
       }
 
       default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "BlockGroup", id);
+        ret = gst_matroska_read_common_parse_skip (&demux->common, ebml,
+            "BlockGroup", id);
         break;
 
       case GST_MATROSKA_ID_BLOCKVIRTUAL:
@@ -4971,7 +4650,7 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
     gint64 lace_time = 0;
     gboolean delta_unit;
 
-    stream = g_ptr_array_index (demux->src, stream_num);
+    stream = g_ptr_array_index (demux->common.src, stream_num);
 
     if (cluster_time != GST_CLOCK_TIME_NONE) {
       /* FIXME: What to do with negative timestamps? Give timestamp 0 or -1?
@@ -4980,11 +4659,11 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
         lace_time = 0;
       } else {
         if (stream->timecodescale == 1.0)
-          lace_time = (cluster_time + time) * demux->time_scale;
+          lace_time = (cluster_time + time) * demux->common.time_scale;
         else
           lace_time =
               gst_util_guint64_to_gdouble ((cluster_time + time) *
-              demux->time_scale) * stream->timecodescale;
+              demux->common.time_scale) * stream->timecodescale;
       }
     } else {
       lace_time = GST_CLOCK_TIME_NONE;
@@ -5008,11 +4687,12 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
 
     if (block_duration) {
       if (stream->timecodescale == 1.0)
-        duration = gst_util_uint64_scale (block_duration, demux->time_scale, 1);
+        duration = gst_util_uint64_scale (block_duration,
+            demux->common.time_scale, 1);
       else
         duration =
             gst_util_gdouble_to_guint64 (gst_util_guint64_to_gdouble
-            (gst_util_uint64_scale (block_duration, demux->time_scale,
+            (gst_util_uint64_scale (block_duration, demux->common.time_scale,
                     1)) * stream->timecodescale);
     } else if (stream->default_duration) {
       duration = stream->default_duration * laces;
@@ -5214,16 +4894,16 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
           GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (sub)),
           GST_TIME_ARGS (GST_BUFFER_DURATION (sub)));
 
-      if (demux->element_index) {
+      if (demux->common.element_index) {
         if (stream->index_writer_id == -1)
-          gst_index_get_writer_id (demux->element_index,
+          gst_index_get_writer_id (demux->common.element_index,
               GST_OBJECT (stream->pad), &stream->index_writer_id);
 
         GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %"
             G_GUINT64_FORMAT " for writer id %d",
             GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (sub)), cluster_offset,
             stream->index_writer_id);
-        gst_index_add_association (demux->element_index,
+        gst_index_add_association (demux->common.element_index,
             stream->index_writer_id, GST_BUFFER_FLAG_IS_SET (sub,
                 GST_BUFFER_FLAG_DELTA_UNIT) ? 0 : GST_ASSOCIATION_FLAG_KEY_UNIT,
             GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (sub), GST_FORMAT_BYTES,
@@ -5360,7 +5040,8 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux,
       }
 
       default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "SeekHead", id);
+        ret = gst_matroska_read_common_parse_skip (&demux->common, ebml,
+            "SeekHead", id);
         break;
     }
   }
@@ -5398,18 +5079,19 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux,
       }
 
       /* check for validity */
-      if (seek_pos + demux->ebml_segment_start + 12 >= length) {
+      if (seek_pos + demux->common.ebml_segment_start + 12 >= length) {
         GST_WARNING_OBJECT (demux,
             "SeekHead reference lies outside file!" " (%"
             G_GUINT64_FORMAT "+%" G_GUINT64_FORMAT "+12 >= %"
-            G_GUINT64_FORMAT ")", seek_pos, demux->ebml_segment_start, length);
+            G_GUINT64_FORMAT ")", seek_pos, demux->common.ebml_segment_start,
+            length);
         break;
       }
 
       /* only pick up index location when streaming */
       if (demux->streaming) {
         if (seek_id == GST_MATROSKA_ID_CUES) {
-          demux->index_offset = seek_pos + demux->ebml_segment_start;
+          demux->index_offset = seek_pos + demux->common.ebml_segment_start;
           GST_DEBUG_OBJECT (demux, "Cues located at offset %" G_GUINT64_FORMAT,
               demux->index_offset);
         }
@@ -5417,7 +5099,7 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux,
       }
 
       /* seek */
-      demux->offset = seek_pos + demux->ebml_segment_start;
+      demux->offset = seek_pos + demux->common.ebml_segment_start;
 
       /* check ID */
       if ((ret = gst_matroska_demux_peek_id_length_pull (demux, &id, &length,
@@ -5427,7 +5109,7 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux,
       if (id != seek_id) {
         GST_WARNING_OBJECT (demux,
             "We looked for ID=0x%x but got ID=0x%x (pos=%" G_GUINT64_FORMAT ")",
-            seek_id, id, seek_pos + demux->ebml_segment_start);
+            seek_id, id, seek_pos + demux->common.ebml_segment_start);
       } else {
         /* now parse */
         ret = gst_matroska_demux_parse_id (demux, id, length, needed);
@@ -5441,7 +5123,7 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux,
 
     case GST_MATROSKA_ID_CLUSTER:
     {
-      guint64 pos = seek_pos + demux->ebml_segment_start;
+      guint64 pos = seek_pos + demux->common.ebml_segment_start;
 
       GST_LOG_OBJECT (demux, "Cluster position");
       if (G_UNLIKELY (!demux->clusters))
@@ -5489,7 +5171,8 @@ gst_matroska_demux_parse_contents (GstMatroskaDemux * demux, GstEbmlRead * ebml)
       }
 
       default:
-        ret = gst_matroska_demux_parse_skip (demux, ebml, "SeekHead", id);
+        ret = gst_matroska_read_common_parse_skip (&demux->common,
+            ebml, "SeekHead", id);
         break;
     }
   }
@@ -5757,7 +5440,7 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
               demux->offset);
           /* seeks are from the beginning of the segment,
            * after the segment ID/length */
-          demux->ebml_segment_start = demux->offset;
+          demux->common.ebml_segment_start = demux->offset;
           demux->state = GST_MATROSKA_DEMUX_STATE_HEADER;
           break;
         default:
@@ -5840,16 +5523,17 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
             goto parse_failed;
           GST_DEBUG_OBJECT (demux, "ClusterTimeCode: %" G_GUINT64_FORMAT, num);
           demux->cluster_time = num;
-          if (demux->element_index) {
-            if (demux->element_index_writer_id == -1)
-              gst_index_get_writer_id (demux->element_index,
-                  GST_OBJECT (demux), &demux->element_index_writer_id);
+          if (demux->common.element_index) {
+            if (demux->common.element_index_writer_id == -1)
+              gst_index_get_writer_id (demux->common.element_index,
+                  GST_OBJECT (demux), &demux->common.element_index_writer_id);
             GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %"
                 G_GUINT64_FORMAT " for writer id %d",
                 GST_TIME_ARGS (demux->cluster_time), demux->cluster_offset,
-                demux->element_index_writer_id);
-            gst_index_add_association (demux->element_index,
-                demux->element_index_writer_id, GST_ASSOCIATION_FLAG_KEY_UNIT,
+                demux->common.element_index_writer_id);
+            gst_index_add_association (demux->common.element_index,
+                demux->common.element_index_writer_id,
+                GST_ASSOCIATION_FLAG_KEY_UNIT,
                 GST_FORMAT_TIME, demux->cluster_time,
                 GST_FORMAT_BYTES, demux->cluster_offset, NULL);
           }
@@ -5896,12 +5580,12 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
           ret = gst_matroska_demux_parse_contents (demux, &ebml);
           break;
         case GST_MATROSKA_ID_CUES:
-          if (demux->index_parsed) {
+          if (demux->common.index_parsed) {
             GST_READ_CHECK (gst_matroska_demux_flush (demux, read));
             break;
           }
           GST_READ_CHECK (gst_matroska_demux_take (demux, read, &ebml));
-          ret = gst_matroska_demux_parse_index (demux, &ebml);
+          ret = gst_matroska_read_common_parse_index (&demux->common, &ebml);
           /* only push based; delayed index building */
           if (ret == GST_FLOW_OK
               && demux->state == GST_MATROSKA_DEMUX_STATE_SEEK) {
@@ -6029,12 +5713,13 @@ gst_matroska_demux_loop (GstPad * pad)
     goto pause;
 
   /* check if we're at the end of a configured segment */
-  if (G_LIKELY (demux->src->len)) {
+  if (G_LIKELY (demux->common.src->len)) {
     guint i;
 
-    g_assert (demux->num_streams == demux->src->len);
-    for (i = 0; i < demux->src->len; i++) {
-      GstMatroskaTrackContext *context = g_ptr_array_index (demux->src, i);
+    g_assert (demux->common.num_streams == demux->common.src->len);
+    for (i = 0; i < demux->common.src->len; i++) {
+      GstMatroskaTrackContext *context = g_ptr_array_index (demux->common.src,
+          i);
       GST_DEBUG_OBJECT (context->pad, "pos %" GST_TIME_FORMAT,
           GST_TIME_ARGS (context->pos));
       if (context->eos == FALSE)
@@ -6274,7 +5959,7 @@ gst_matroska_demux_handle_sink_event (GstPad * pad, GstEvent * event)
         gst_event_unref (event);
         GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
             (NULL), ("got eos and didn't receive a complete header object"));
-      } else if (demux->num_streams == 0) {
+      } else if (demux->common.num_streams == 0) {
         GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
             (NULL), ("got eos but no streams (yet)"));
       } else {
@@ -7093,11 +6778,12 @@ gst_matroska_demux_set_index (GstElement * element, GstIndex * index)
   GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (element);
 
   GST_OBJECT_LOCK (demux);
-  if (demux->element_index)
-    gst_object_unref (demux->element_index);
-  demux->element_index = index ? gst_object_ref (index) : NULL;
+  if (demux->common.element_index)
+    gst_object_unref (demux->common.element_index);
+  demux->common.element_index = index ? gst_object_ref (index) : NULL;
   GST_OBJECT_UNLOCK (demux);
-  GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->element_index);
+  GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT,
+      demux->common.element_index);
 }
 
 static GstIndex *
@@ -7107,8 +6793,8 @@ gst_matroska_demux_get_index (GstElement * element)
   GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (element);
 
   GST_OBJECT_LOCK (demux);
-  if (demux->element_index)
-    result = gst_object_ref (demux->element_index);
+  if (demux->common.element_index)
+    result = gst_object_ref (demux->common.element_index);
   GST_OBJECT_UNLOCK (demux);
 
   GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
index a35a593..a40366f 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "ebml-read.h"
 #include "matroska-ids.h"
+#include "matroska-read-common.h"
 
 G_BEGIN_DECLS
 
@@ -55,14 +56,11 @@ typedef struct _GstMatroskaDemux {
 
   /* < private > */
 
-  GstIndex                *element_index;
-  gint                     element_index_writer_id;
+  GstMatroskaReadCommon    common;
 
   /* pads */
   GstPad                  *sinkpad;
-  GPtrArray               *src;
   GstClock                *clock;
-  guint                    num_streams;
   guint                    num_v_streams;
   guint                    num_a_streams;
   guint                    num_t_streams;
@@ -80,24 +78,15 @@ typedef struct _GstMatroskaDemux {
   gboolean                 seek_first;
 
   /* did we parse cues/tracks/segmentinfo already? */
-  gboolean                 index_parsed;
   gboolean                 tracks_parsed;
   gboolean                 segmentinfo_parsed;
   gboolean                 attachments_parsed;
   GList                   *tags_parsed;
   GList                   *seek_parsed;
 
-  /* start-of-segment */
-  guint64                  ebml_segment_start;
-
-  /* a cue (index) table */
-  GArray                  *index;
   /* cluster positions (optional) */
   GArray                  *clusters;
 
-  /* timescale in the file */
-  guint64                  time_scale;
-
   /* keeping track of playback position */
   GstSegment               segment;
   gboolean                 segment_running;
index 7d48849..927438b 100644 (file)
@@ -170,9 +170,9 @@ gst_matroska_parse_finalize (GObject * object)
 {
   GstMatroskaParse *parse = GST_MATROSKA_PARSE (object);
 
-  if (parse->src) {
-    g_ptr_array_free (parse->src, TRUE);
-    parse->src = NULL;
+  if (parse->common.src) {
+    g_ptr_array_free (parse->common.src, TRUE);
+    parse->common.src = NULL;
   }
 
   if (parse->global_tags) {
@@ -232,11 +232,11 @@ gst_matroska_parse_init (GstMatroskaParse * parse,
   gst_element_add_pad (GST_ELEMENT (parse), parse->srcpad);
 
   /* initial stream no. */
-  parse->src = NULL;
+  parse->common.src = NULL;
 
   parse->writing_app = NULL;
   parse->muxing_app = NULL;
-  parse->index = NULL;
+  parse->common.index = NULL;
   parse->global_tags = NULL;
 
   parse->adapter = gst_adapter_new ();
@@ -295,19 +295,20 @@ gst_matroska_parse_reset (GstElement * element)
   parse->state = GST_MATROSKA_PARSE_STATE_START;
 
   /* clean up existing streams */
-  if (parse->src) {
-    g_assert (parse->src->len == parse->num_streams);
-    for (i = 0; i < parse->src->len; i++) {
-      GstMatroskaTrackContext *context = g_ptr_array_index (parse->src, i);
+  if (parse->common.src) {
+    g_assert (parse->common.src->len == parse->common.num_streams);
+    for (i = 0; i < parse->common.src->len; i++) {
+      GstMatroskaTrackContext *context = g_ptr_array_index (parse->common.src,
+          i);
 
       gst_caps_replace (&context->caps, NULL);
       gst_matroska_track_free (context);
     }
-    g_ptr_array_free (parse->src, TRUE);
+    g_ptr_array_free (parse->common.src, TRUE);
   }
-  parse->src = g_ptr_array_new ();
+  parse->common.src = g_ptr_array_new ();
 
-  parse->num_streams = 0;
+  parse->common.num_streams = 0;
   parse->num_a_streams = 0;
   parse->num_t_streams = 0;
   parse->num_v_streams = 0;
@@ -319,17 +320,17 @@ gst_matroska_parse_reset (GstElement * element)
   parse->muxing_app = NULL;
 
   /* reset indexes */
-  if (parse->index) {
-    g_array_free (parse->index, TRUE);
-    parse->index = NULL;
+  if (parse->common.index) {
+    g_array_free (parse->common.index, TRUE);
+    parse->common.index = NULL;
   }
 
   /* reset timers */
   parse->clock = NULL;
-  parse->time_scale = 1000000;
+  parse->common.time_scale = 1000000;
   parse->created = G_MININT64;
 
-  parse->index_parsed = FALSE;
+  parse->common.index_parsed = FALSE;
   parse->tracks_parsed = FALSE;
   parse->segmentinfo_parsed = FALSE;
   parse->attachments_parsed = FALSE;
@@ -374,11 +375,11 @@ gst_matroska_parse_reset (GstElement * element)
     parse->new_segment = NULL;
   }
 
-  if (parse->element_index) {
-    gst_object_unref (parse->element_index);
-    parse->element_index = NULL;
+  if (parse->common.element_index) {
+    gst_object_unref (parse->common.element_index);
+    parse->common.element_index = NULL;
   }
-  parse->element_index_writer_id = -1;
+  parse->common.element_index_writer_id = -1;
 
   if (parse->global_tags) {
     gst_tag_list_free (parse->global_tags);
@@ -508,27 +509,6 @@ gst_matroska_parse_get_length (GstMatroskaParse * parse)
 }
 
 static gint
-gst_matroska_parse_stream_from_num (GstMatroskaParse * parse, guint track_num)
-{
-  guint n;
-
-  g_assert (parse->src->len == parse->num_streams);
-  for (n = 0; n < parse->src->len; n++) {
-    GstMatroskaTrackContext *context = g_ptr_array_index (parse->src, n);
-
-    if (context->num == track_num) {
-      return n;
-    }
-  }
-
-  if (n == parse->num_streams)
-    GST_WARNING_OBJECT (parse,
-        "Failed to find corresponding pad for tracknum %d", track_num);
-
-  return -1;
-}
-
-static gint
 gst_matroska_parse_encoding_cmp (GstMatroskaTrackEncoding * a,
     GstMatroskaTrackEncoding * b)
 {
@@ -1041,9 +1021,10 @@ gst_matroska_parse_tracknumber_unique (GstMatroskaParse * parse, guint64 num)
 {
   gint i;
 
-  g_assert (parse->src->len == parse->num_streams);
-  for (i = 0; i < parse->src->len; i++) {
-    GstMatroskaTrackContext *context = g_ptr_array_index (parse->src, i);
+  g_assert (parse->common.src->len == parse->common.num_streams);
+  for (i = 0; i < parse->common.src->len; i++) {
+    GstMatroskaTrackContext *context = g_ptr_array_index (parse->common.src,
+        i);
 
     if (context->num == num)
       return FALSE;
@@ -1070,8 +1051,8 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml)
   /* allocate generic... if we know the type, we'll g_renew()
    * with the precise type */
   context = g_new0 (GstMatroskaTrackContext, 1);
-  g_ptr_array_add (parse->src, context);
-  context->index = parse->num_streams;
+  g_ptr_array_add (parse->common.src, context);
+  context->index = parse->common.num_streams;
   context->index_writer_id = -1;
   context->type = 0;            /* no type yet */
   context->default_duration = 0;
@@ -1083,8 +1064,8 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml)
       GST_MATROSKA_TRACK_LACING;
   context->last_flow = GST_FLOW_OK;
   context->to_offset = G_MAXINT64;
-  parse->num_streams++;
-  g_assert (parse->src->len == parse->num_streams);
+  parse->common.num_streams++;
+  g_assert (parse->common.src->len == parse->common.num_streams);
 
   GST_DEBUG_OBJECT (parse, "Stream number %d", context->index);
 
@@ -1176,7 +1157,8 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml)
             context->type = 0;
             break;
         }
-        g_ptr_array_index (parse->src, parse->num_streams - 1) = context;
+        g_ptr_array_index (parse->common.src, parse->common.num_streams - 1)
+            = context;
         break;
       }
 
@@ -1195,7 +1177,8 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml)
           break;
         }
         videocontext = (GstMatroskaTrackVideoContext *) context;
-        g_ptr_array_index (parse->src, parse->num_streams - 1) = context;
+        g_ptr_array_index (parse->common.src, parse->common.num_streams - 1)
+            = context;
 
         while (ret == GST_FLOW_OK &&
             gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
@@ -1415,7 +1398,8 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml)
           break;
 
         audiocontext = (GstMatroskaTrackAudioContext *) context;
-        g_ptr_array_index (parse->src, parse->num_streams - 1) = context;
+        g_ptr_array_index (parse->common.src, parse->common.num_streams - 1)
+            = context;
 
         while (ret == GST_FLOW_OK &&
             gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
@@ -1715,9 +1699,9 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml)
     if (ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED)
       GST_WARNING_OBJECT (ebml, "Unknown stream/codec in track entry header");
 
-    parse->num_streams--;
-    g_ptr_array_remove_index (parse->src, parse->num_streams);
-    g_assert (parse->src->len == parse->num_streams);
+    parse->common.num_streams--;
+    g_ptr_array_remove_index (parse->common.src, parse->common.num_streams);
+    g_assert (parse->common.src->len == parse->common.num_streams);
     if (context) {
       gst_matroska_track_free (context);
     }
@@ -1880,14 +1864,14 @@ gst_matroskaparse_do_index_seek (GstMatroskaParse * parse,
   GstMatroskaIndex *entry = NULL;
   GArray *index;
 
-  if (!parse->index || !parse->index->len)
+  if (!parse->common.index || !parse->common.index->len)
     return NULL;
 
   /* find entry just before or at the requested position */
   if (track && track->index_table)
     index = track->index_table;
   else
-    index = parse->index;
+    index = parse->common.index;
 
   entry =
       gst_util_array_binary_search (index->data, index->len,
@@ -1970,10 +1954,10 @@ gst_matroska_parse_get_seek_track (GstMatroskaParse * parse,
   if (track && track->type == GST_MATROSKA_TRACK_TYPE_VIDEO)
     return track;
 
-  for (i = 0; i < parse->src->len; i++) {
+  for (i = 0; i < parse->common.src->len; i++) {
     GstMatroskaTrackContext *stream;
 
-    stream = g_ptr_array_index (parse->src, i);
+    stream = g_ptr_array_index (parse->common.src, i);
     if (stream->type == GST_MATROSKA_TRACK_TYPE_VIDEO && stream->index_table)
       track = stream;
   }
@@ -1989,9 +1973,10 @@ gst_matroska_parse_reset_streams (GstMatroskaParse * parse, GstClockTime time,
 
   GST_DEBUG_OBJECT (parse, "resetting stream state");
 
-  g_assert (parse->src->len == parse->num_streams);
-  for (i = 0; i < parse->src->len; i++) {
-    GstMatroskaTrackContext *context = g_ptr_array_index (parse->src, i);
+  g_assert (parse->common.src->len == parse->common.num_streams);
+  for (i = 0; i < parse->common.src->len; i++) {
+    GstMatroskaTrackContext *context = g_ptr_array_index (parse->common.src,
+        i);
     context->pos = time;
     context->set_discont = TRUE;
     context->eos = FALSE;
@@ -2153,7 +2138,8 @@ gst_matroska_parse_handle_seek_event (GstMatroskaParse * parse,
   /* need to seek to cluster start to pick up cluster time */
   /* upstream takes care of flushing and all that
    * ... and newsegment event handling takes care of the rest */
-  return perform_seek_to_offset (parse, entry->pos + parse->ebml_segment_start);
+  return perform_seek_to_offset (parse, entry->pos
+      + parse->common.ebml_segment_start);
 }
 
 /*
@@ -2198,7 +2184,7 @@ gst_matroska_parse_handle_seek_push (GstMatroskaParse * parse, GstPad * pad,
   }
 
   /* check for having parsed index already */
-  if (!parse->index_parsed) {
+  if (!parse->common.index_parsed) {
     gboolean building_index;
     guint64 offset = 0;
 
@@ -2295,24 +2281,6 @@ gst_matroska_parse_handle_src_event (GstPad * pad, GstEvent * event)
   return res;
 }
 
-
-/* skip unknown or alike element */
-static GstFlowReturn
-gst_matroska_parse_parse_skip (GstMatroskaParse * parse, GstEbmlRead * ebml,
-    const gchar * parent_name, guint id)
-{
-  if (id == GST_EBML_ID_VOID) {
-    GST_DEBUG_OBJECT (parse, "Skipping EBML Void element");
-  } else if (id == GST_EBML_ID_CRC32) {
-    GST_DEBUG_OBJECT (parse, "Skipping EBML CRC32 element");
-  } else {
-    GST_WARNING_OBJECT (parse,
-        "Unknown %s subelement 0x%x - ignoring", parent_name, id);
-  }
-
-  return gst_ebml_read_skip (ebml);
-}
-
 static GstFlowReturn
 gst_matroska_parse_parse_header (GstMatroskaParse * parse, GstEbmlRead * ebml)
 {
@@ -2424,7 +2392,8 @@ gst_matroska_parse_parse_header (GstMatroskaParse * parse, GstEbmlRead * ebml)
       }
 
       default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "EBML header", id);
+        ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+            "EBML header", id);
         if (ret != GST_FLOW_OK)
           return ret;
         break;
@@ -2493,7 +2462,8 @@ gst_matroska_parse_parse_tracks (GstMatroskaParse * parse, GstEbmlRead * ebml)
         break;
 
       default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "Track", id);
+        ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+            "Track", id);
         break;
     }
   }
@@ -2505,306 +2475,6 @@ gst_matroska_parse_parse_tracks (GstMatroskaParse * parse, GstEbmlRead * ebml)
 }
 
 static GstFlowReturn
-gst_matroska_parse_parse_index_cuetrack (GstMatroskaParse * parse,
-    GstEbmlRead * ebml, guint * nentries)
-{
-  guint32 id;
-  GstFlowReturn ret;
-  GstMatroskaIndex idx;
-
-  idx.pos = (guint64) - 1;
-  idx.track = 0;
-  idx.time = GST_CLOCK_TIME_NONE;
-  idx.block = 1;
-
-  DEBUG_ELEMENT_START (parse, ebml, "CueTrackPositions");
-
-  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
-    DEBUG_ELEMENT_STOP (parse, ebml, "CueTrackPositions", ret);
-    return ret;
-  }
-
-  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
-    if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
-      break;
-
-    switch (id) {
-        /* track number */
-      case GST_MATROSKA_ID_CUETRACK:
-      {
-        guint64 num;
-
-        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
-          break;
-
-        if (num == 0) {
-          idx.track = 0;
-          GST_WARNING_OBJECT (parse, "Invalid CueTrack 0");
-          break;
-        }
-
-        GST_DEBUG_OBJECT (parse, "CueTrack: %" G_GUINT64_FORMAT, num);
-        idx.track = num;
-        break;
-      }
-
-        /* position in file */
-      case GST_MATROSKA_ID_CUECLUSTERPOSITION:
-      {
-        guint64 num;
-
-        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
-          break;
-
-        if (num > G_MAXINT64) {
-          GST_WARNING_OBJECT (parse, "CueClusterPosition %" G_GUINT64_FORMAT
-              " too large", num);
-          break;
-        }
-
-        idx.pos = num;
-        break;
-      }
-
-        /* number of block in the cluster */
-      case GST_MATROSKA_ID_CUEBLOCKNUMBER:
-      {
-        guint64 num;
-
-        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
-          break;
-
-        if (num == 0) {
-          GST_WARNING_OBJECT (parse, "Invalid CueBlockNumber 0");
-          break;
-        }
-
-        GST_DEBUG_OBJECT (parse, "CueBlockNumber: %" G_GUINT64_FORMAT, num);
-        idx.block = num;
-
-        /* mild sanity check, disregard strange cases ... */
-        if (idx.block > G_MAXUINT16) {
-          GST_DEBUG_OBJECT (parse, "... looks suspicious, ignoring");
-          idx.block = 1;
-        }
-        break;
-      }
-
-      default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "CueTrackPositions",
-            id);
-        break;
-
-      case GST_MATROSKA_ID_CUECODECSTATE:
-      case GST_MATROSKA_ID_CUEREFERENCE:
-        ret = gst_ebml_read_skip (ebml);
-        break;
-    }
-  }
-
-  DEBUG_ELEMENT_STOP (parse, ebml, "CueTrackPositions", ret);
-
-  if ((ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED)
-      && idx.pos != (guint64) - 1 && idx.track > 0) {
-    g_array_append_val (parse->index, idx);
-    (*nentries)++;
-  } else if (ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED) {
-    GST_DEBUG_OBJECT (parse, "CueTrackPositions without valid content");
-  }
-
-  return ret;
-}
-
-static GstFlowReturn
-gst_matroska_parse_parse_index_pointentry (GstMatroskaParse * parse,
-    GstEbmlRead * ebml)
-{
-  guint32 id;
-  GstFlowReturn ret;
-  GstClockTime time = GST_CLOCK_TIME_NONE;
-  guint nentries = 0;
-
-  DEBUG_ELEMENT_START (parse, ebml, "CuePoint");
-
-  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
-    DEBUG_ELEMENT_STOP (parse, ebml, "CuePoint", ret);
-    return ret;
-  }
-
-  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
-    if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
-      break;
-
-    switch (id) {
-        /* one single index entry ('point') */
-      case GST_MATROSKA_ID_CUETIME:
-      {
-        if ((ret = gst_ebml_read_uint (ebml, &id, &time)) != GST_FLOW_OK)
-          break;
-
-        GST_DEBUG_OBJECT (parse, "CueTime: %" G_GUINT64_FORMAT, time);
-        time = time * parse->time_scale;
-        break;
-      }
-
-        /* position in the file + track to which it belongs */
-      case GST_MATROSKA_ID_CUETRACKPOSITIONS:
-      {
-        if ((ret =
-                gst_matroska_parse_parse_index_cuetrack (parse, ebml,
-                    &nentries)) != GST_FLOW_OK)
-          break;
-        break;
-      }
-
-      default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "CuePoint", id);
-        break;
-    }
-  }
-
-  DEBUG_ELEMENT_STOP (parse, ebml, "CuePoint", ret);
-
-  if (nentries > 0) {
-    if (time == GST_CLOCK_TIME_NONE) {
-      GST_WARNING_OBJECT (parse, "CuePoint without valid time");
-      g_array_remove_range (parse->index, parse->index->len - nentries,
-          nentries);
-    } else {
-      gint i;
-
-      for (i = parse->index->len - nentries; i < parse->index->len; i++) {
-        GstMatroskaIndex *idx =
-            &g_array_index (parse->index, GstMatroskaIndex, i);
-
-        idx->time = time;
-        GST_DEBUG_OBJECT (parse, "Index entry: pos=%" G_GUINT64_FORMAT
-            ", time=%" GST_TIME_FORMAT ", track=%u, block=%u", idx->pos,
-            GST_TIME_ARGS (idx->time), (guint) idx->track, (guint) idx->block);
-      }
-    }
-  } else {
-    GST_DEBUG_OBJECT (parse, "Empty CuePoint");
-  }
-
-  return ret;
-}
-
-static gint
-gst_matroska_index_compare (GstMatroskaIndex * i1, GstMatroskaIndex * i2)
-{
-  if (i1->time < i2->time)
-    return -1;
-  else if (i1->time > i2->time)
-    return 1;
-  else if (i1->block < i2->block)
-    return -1;
-  else if (i1->block > i2->block)
-    return 1;
-  else
-    return 0;
-}
-
-static GstFlowReturn
-gst_matroska_parse_parse_index (GstMatroskaParse * parse, GstEbmlRead * ebml)
-{
-  guint32 id;
-  GstFlowReturn ret = GST_FLOW_OK;
-  guint i;
-
-  if (parse->index)
-    g_array_free (parse->index, TRUE);
-  parse->index =
-      g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128);
-
-  DEBUG_ELEMENT_START (parse, ebml, "Cues");
-
-  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
-    DEBUG_ELEMENT_STOP (parse, ebml, "Cues", ret);
-    return ret;
-  }
-
-  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
-    if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
-      break;
-
-    switch (id) {
-        /* one single index entry ('point') */
-      case GST_MATROSKA_ID_POINTENTRY:
-        ret = gst_matroska_parse_parse_index_pointentry (parse, ebml);
-        break;
-
-      default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "Cues", id);
-        break;
-    }
-  }
-  DEBUG_ELEMENT_STOP (parse, ebml, "Cues", ret);
-
-  /* Sort index by time, smallest time first, for easier searching */
-  g_array_sort (parse->index, (GCompareFunc) gst_matroska_index_compare);
-
-  /* Now sort the track specific index entries into their own arrays */
-  for (i = 0; i < parse->index->len; i++) {
-    GstMatroskaIndex *idx = &g_array_index (parse->index, GstMatroskaIndex, i);
-    gint track_num;
-    GstMatroskaTrackContext *ctx;
-
-    if (parse->element_index) {
-      gint writer_id;
-
-      if (idx->track != 0 &&
-          (track_num =
-              gst_matroska_parse_stream_from_num (parse, idx->track)) != -1) {
-        ctx = g_ptr_array_index (parse->src, track_num);
-
-        if (ctx->index_writer_id == -1)
-          gst_index_get_writer_id (parse->element_index, GST_OBJECT (ctx->pad),
-              &ctx->index_writer_id);
-        writer_id = ctx->index_writer_id;
-      } else {
-        if (parse->element_index_writer_id == -1)
-          gst_index_get_writer_id (parse->element_index, GST_OBJECT (parse),
-              &parse->element_index_writer_id);
-        writer_id = parse->element_index_writer_id;
-      }
-
-      GST_LOG_OBJECT (parse, "adding association %" GST_TIME_FORMAT "-> %"
-          G_GUINT64_FORMAT " for writer id %d", GST_TIME_ARGS (idx->time),
-          idx->pos, writer_id);
-      gst_index_add_association (parse->element_index, writer_id,
-          GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, idx->time,
-          GST_FORMAT_BYTES, idx->pos + parse->ebml_segment_start, NULL);
-    }
-
-    if (idx->track == 0)
-      continue;
-
-    track_num = gst_matroska_parse_stream_from_num (parse, idx->track);
-    if (track_num == -1)
-      continue;
-
-    ctx = g_ptr_array_index (parse->src, track_num);
-
-    if (ctx->index_table == NULL)
-      ctx->index_table =
-          g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128);
-
-    g_array_append_vals (ctx->index_table, idx, 1);
-  }
-
-  parse->index_parsed = TRUE;
-
-  /* sanity check; empty index normalizes to no index */
-  if (parse->index->len == 0) {
-    g_array_free (parse->index, TRUE);
-    parse->index = NULL;
-  }
-
-  return ret;
-}
-
-static GstFlowReturn
 gst_matroska_parse_parse_info (GstMatroskaParse * parse, GstEbmlRead * ebml)
 {
   GstFlowReturn ret = GST_FLOW_OK;
@@ -2832,7 +2502,7 @@ gst_matroska_parse_parse_info (GstMatroskaParse * parse, GstEbmlRead * ebml)
 
 
         GST_DEBUG_OBJECT (parse, "TimeCodeScale: %" G_GUINT64_FORMAT, num);
-        parse->time_scale = num;
+        parse->common.time_scale = num;
         break;
       }
 
@@ -2899,7 +2569,8 @@ gst_matroska_parse_parse_info (GstMatroskaParse * parse, GstEbmlRead * ebml)
       }
 
       default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "SegmentInfo", id);
+        ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+            "SegmentInfo", id);
         break;
 
         /* fall through */
@@ -2920,7 +2591,7 @@ gst_matroska_parse_parse_info (GstMatroskaParse * parse, GstEbmlRead * ebml)
     GstClockTime dur_u;
 
     dur_u = gst_gdouble_to_guint64 (dur_f *
-        gst_guint64_to_gdouble (parse->time_scale));
+        gst_guint64_to_gdouble (parse->common.time_scale));
     if (GST_CLOCK_TIME_IS_VALID (dur_u) && dur_u <= G_MAXINT64)
       gst_segment_set_duration (&parse->segment, GST_FORMAT_TIME, dur_u);
   }
@@ -2994,7 +2665,8 @@ gst_matroska_parse_parse_metadata_id_simple_tag (GstMatroskaParse * parse,
         break;
 
       default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "SimpleTag", id);
+        ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+            "SimpleTag", id);
         break;
         /* fall-through */
 
@@ -3080,7 +2752,8 @@ gst_matroska_parse_parse_metadata_id_tag (GstMatroskaParse * parse,
         break;
 
       default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "Tag", id);
+        ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+            "Tag", id);
         break;
     }
   }
@@ -3136,7 +2809,8 @@ gst_matroska_parse_parse_metadata (GstMatroskaParse * parse, GstEbmlRead * ebml)
         break;
 
       default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "Tags", id);
+        ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+            "Tags", id);
         break;
         /* FIXME: Use to limit the tags to specific pads */
       case GST_MATROSKA_ID_TARGETS:
@@ -3219,7 +2893,8 @@ gst_matroska_parse_parse_attached_file (GstMatroskaParse * parse,
         break;
 
       default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "AttachedFile", id);
+        ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+            "AttachedFile", id);
         break;
       case GST_MATROSKA_ID_FILEUID:
         ret = gst_ebml_read_skip (ebml);
@@ -3332,7 +3007,8 @@ gst_matroska_parse_parse_attachments (GstMatroskaParse * parse,
         break;
 
       default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "Attachments", id);
+        ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+            "Attachments", id);
         break;
     }
   }
@@ -3498,14 +3174,15 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
         size -= n;
 
         /* fetch stream from num */
-        stream_num = gst_matroska_parse_stream_from_num (parse, num);
+        stream_num = gst_matroska_read_common_stream_from_num (&parse->common,
+            num);
         if (G_UNLIKELY (size < 3)) {
           GST_WARNING_OBJECT (parse, "Invalid size %u", size);
           /* non-fatal, try next block(group) */
           ret = GST_FLOW_OK;
           goto done;
         } else if (G_UNLIKELY (stream_num < 0 ||
-                stream_num >= parse->num_streams)) {
+                stream_num >= parse->common.num_streams)) {
           /* let's not give up on a stray invalid track number */
           GST_WARNING_OBJECT (parse,
               "Invalid stream %d for track number %" G_GUINT64_FORMAT
@@ -3513,7 +3190,7 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
           goto done;
         }
 
-        stream = g_ptr_array_index (parse->src, stream_num);
+        stream = g_ptr_array_index (parse->common.src, stream_num);
 
         /* time (relative to cluster time) */
         time = ((gint16) GST_READ_UINT16_BE (data));
@@ -3640,7 +3317,8 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
       }
 
       default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "BlockGroup", id);
+        ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+            "BlockGroup", id);
         break;
 
       case GST_MATROSKA_ID_BLOCKVIRTUAL:
@@ -3667,7 +3345,7 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
     gint64 lace_time = 0;
     gboolean delta_unit;
 
-    stream = g_ptr_array_index (parse->src, stream_num);
+    stream = g_ptr_array_index (parse->common.src, stream_num);
 
     if (cluster_time != GST_CLOCK_TIME_NONE) {
       /* FIXME: What to do with negative timestamps? Give timestamp 0 or -1?
@@ -3676,11 +3354,11 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
         lace_time = 0;
       } else {
         if (stream->timecodescale == 1.0)
-          lace_time = (cluster_time + time) * parse->time_scale;
+          lace_time = (cluster_time + time) * parse->common.time_scale;
         else
           lace_time =
               gst_util_guint64_to_gdouble ((cluster_time + time) *
-              parse->time_scale) * stream->timecodescale;
+              parse->common.time_scale) * stream->timecodescale;
       }
     } else {
       lace_time = GST_CLOCK_TIME_NONE;
@@ -3707,11 +3385,12 @@ gst_matroska_parse_parse_blockgroup_or_simpleblock (GstMatroskaParse * parse,
 
     if (block_duration) {
       if (stream->timecodescale == 1.0)
-        duration = gst_util_uint64_scale (block_duration, parse->time_scale, 1);
+        duration = gst_util_uint64_scale (block_duration,
+            parse->common.time_scale, 1);
       else
         duration =
             gst_util_gdouble_to_guint64 (gst_util_guint64_to_gdouble
-            (gst_util_uint64_scale (block_duration, parse->time_scale,
+            (gst_util_uint64_scale (block_duration, parse->common.time_scale,
                     1)) * stream->timecodescale);
     } else if (stream->default_duration) {
       duration = stream->default_duration * laces;
@@ -4041,7 +3720,8 @@ gst_matroska_parse_parse_contents_seekentry (GstMatroskaParse * parse,
       }
 
       default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "SeekHead", id);
+        ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+            "SeekHead", id);
         break;
     }
   }
@@ -4077,17 +3757,18 @@ gst_matroska_parse_parse_contents_seekentry (GstMatroskaParse * parse,
       }
 
       /* check for validity */
-      if (seek_pos + parse->ebml_segment_start + 12 >= length) {
+      if (seek_pos + parse->common.ebml_segment_start + 12 >= length) {
         GST_WARNING_OBJECT (parse,
             "SeekHead reference lies outside file!" " (%"
             G_GUINT64_FORMAT "+%" G_GUINT64_FORMAT "+12 >= %"
-            G_GUINT64_FORMAT ")", seek_pos, parse->ebml_segment_start, length);
+            G_GUINT64_FORMAT ")", seek_pos, parse->common.ebml_segment_start,
+            length);
         break;
       }
 
       /* only pick up index location when streaming */
       if (seek_id == GST_MATROSKA_ID_CUES) {
-        parse->index_offset = seek_pos + parse->ebml_segment_start;
+        parse->index_offset = seek_pos + parse->common.ebml_segment_start;
         GST_DEBUG_OBJECT (parse, "Cues located at offset %" G_GUINT64_FORMAT,
             parse->index_offset);
       }
@@ -4133,7 +3814,8 @@ gst_matroska_parse_parse_contents (GstMatroskaParse * parse, GstEbmlRead * ebml)
       }
 
       default:
-        ret = gst_matroska_parse_parse_skip (parse, ebml, "SeekHead", id);
+        ret = gst_matroska_read_common_parse_skip (&parse->common, ebml,
+            "SeekHead", id);
         break;
     }
   }
@@ -4442,7 +4124,7 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id,
               parse->offset);
           /* seeks are from the beginning of the segment,
            * after the segment ID/length */
-          parse->ebml_segment_start = parse->offset;
+          parse->common.ebml_segment_start = parse->offset;
           parse->state = GST_MATROSKA_PARSE_STATE_HEADER;
           gst_matroska_parse_accumulate_streamheader (parse, ebml.buf);
           break;
@@ -4514,16 +4196,17 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id,
             goto parse_failed;
           GST_DEBUG_OBJECT (parse, "ClusterTimeCode: %" G_GUINT64_FORMAT, num);
           parse->cluster_time = num;
-          if (parse->element_index) {
-            if (parse->element_index_writer_id == -1)
-              gst_index_get_writer_id (parse->element_index,
-                  GST_OBJECT (parse), &parse->element_index_writer_id);
+          if (parse->common.element_index) {
+            if (parse->common.element_index_writer_id == -1)
+              gst_index_get_writer_id (parse->common.element_index,
+                  GST_OBJECT (parse), &parse->common.element_index_writer_id);
             GST_LOG_OBJECT (parse, "adding association %" GST_TIME_FORMAT "-> %"
                 G_GUINT64_FORMAT " for writer id %d",
                 GST_TIME_ARGS (parse->cluster_time), parse->cluster_offset,
-                parse->element_index_writer_id);
-            gst_index_add_association (parse->element_index,
-                parse->element_index_writer_id, GST_ASSOCIATION_FLAG_KEY_UNIT,
+                parse->common.element_index_writer_id);
+            gst_index_add_association (parse->common.element_index,
+                parse->common.element_index_writer_id,
+                GST_ASSOCIATION_FLAG_KEY_UNIT,
                 GST_FORMAT_TIME, parse->cluster_time,
                 GST_FORMAT_BYTES, parse->cluster_offset, NULL);
           }
@@ -4576,8 +4259,8 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id,
           break;
         case GST_MATROSKA_ID_CUES:
           GST_READ_CHECK (gst_matroska_parse_take (parse, read, &ebml));
-          if (!parse->index_parsed) {
-            ret = gst_matroska_parse_parse_index (parse, &ebml);
+          if (!parse->common.index_parsed) {
+            ret = gst_matroska_read_common_parse_index (&parse->common, &ebml);
             /* only push based; delayed index building */
             if (ret == GST_FLOW_OK
                 && parse->state == GST_MATROSKA_PARSE_STATE_SEEK) {
@@ -4955,7 +4638,7 @@ gst_matroska_parse_handle_sink_event (GstPad * pad, GstEvent * event)
         gst_event_unref (event);
         GST_ELEMENT_ERROR (parse, STREAM, DEMUX,
             (NULL), ("got eos and didn't receive a complete header object"));
-      } else if (parse->num_streams == 0) {
+      } else if (parse->common.num_streams == 0) {
         GST_ELEMENT_ERROR (parse, STREAM, DEMUX,
             (NULL), ("got eos but no streams (yet)"));
       } else {
@@ -4988,11 +4671,12 @@ gst_matroska_parse_set_index (GstElement * element, GstIndex * index)
   GstMatroskaParse *parse = GST_MATROSKA_PARSE (element);
 
   GST_OBJECT_LOCK (parse);
-  if (parse->element_index)
-    gst_object_unref (parse->element_index);
-  parse->element_index = index ? gst_object_ref (index) : NULL;
+  if (parse->common.element_index)
+    gst_object_unref (parse->common.element_index);
+  parse->common.element_index = index ? gst_object_ref (index) : NULL;
   GST_OBJECT_UNLOCK (parse);
-  GST_DEBUG_OBJECT (parse, "Set index %" GST_PTR_FORMAT, parse->element_index);
+  GST_DEBUG_OBJECT (parse, "Set index %" GST_PTR_FORMAT,
+      parse->common.element_index);
 }
 
 static GstIndex *
@@ -5002,8 +4686,8 @@ gst_matroska_parse_get_index (GstElement * element)
   GstMatroskaParse *parse = GST_MATROSKA_PARSE (element);
 
   GST_OBJECT_LOCK (parse);
-  if (parse->element_index)
-    result = gst_object_ref (parse->element_index);
+  if (parse->common.element_index)
+    result = gst_object_ref (parse->common.element_index);
   GST_OBJECT_UNLOCK (parse);
 
   GST_DEBUG_OBJECT (parse, "Returning index %" GST_PTR_FORMAT, result);
index 595ead2..452f6e0 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "ebml-read.h"
 #include "matroska-ids.h"
+#include "matroska-read-common.h"
 
 G_BEGIN_DECLS
 
@@ -55,15 +56,12 @@ typedef struct _GstMatroskaParse {
 
   /* < private > */
 
-  GstIndex                *element_index;
-  gint                     element_index_writer_id;
+  GstMatroskaReadCommon    common;
 
   /* pads */
   GstPad                  *sinkpad;
   GstPad                  *srcpad;
-  GPtrArray               *src;
   GstClock                *clock;
-  guint                    num_streams;
   guint                    num_v_streams;
   guint                    num_a_streams;
   guint                    num_t_streams;
@@ -85,22 +83,12 @@ typedef struct _GstMatroskaParse {
   gboolean                 seek_first;
 
   /* did we parse cues/tracks/segmentinfo already? */
-  gboolean                 index_parsed;
   gboolean                 tracks_parsed;
   gboolean                 segmentinfo_parsed;
   gboolean                 attachments_parsed;
   GList                   *tags_parsed;
   GList                   *seek_parsed;
 
-  /* start-of-segment */
-  guint64                  ebml_segment_start;
-
-  /* a cue (index) table */
-  GArray                  *index;
-
-  /* timescale in the file */
-  guint64                  time_scale;
-
   /* keeping track of playback position */
   GstSegment               segment;
   gboolean                 segment_running;
diff --git a/gst/matroska/matroska-read-common.c b/gst/matroska/matroska-read-common.c
new file mode 100644 (file)
index 0000000..9172c17
--- /dev/null
@@ -0,0 +1,382 @@
+/* GStreamer Matroska muxer/demuxer
+ * (c) 2011 Debarshi Ray <rishi@gnu.org>
+ *
+ * matroska-read-common.c: shared by matroska file/stream demuxer and parser
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "ebml-read.h"
+#include "matroska-ids.h"
+#include "matroska-read-common.h"
+
+GST_DEBUG_CATEGORY_STATIC (matroskareadcommon_debug);
+#define GST_CAT_DEFAULT matroskareadcommon_debug
+
+#define DEBUG_ELEMENT_START(common, ebml, element) \
+    GST_DEBUG_OBJECT (common, "Parsing " element " element at offset %" \
+        G_GUINT64_FORMAT, gst_ebml_read_get_pos (ebml))
+
+#define DEBUG_ELEMENT_STOP(common, ebml, element, ret) \
+    GST_DEBUG_OBJECT (common, "Parsing " element " element " \
+        " finished with '%s'", gst_flow_get_name (ret))
+
+static gint
+gst_matroska_index_compare (GstMatroskaIndex * i1, GstMatroskaIndex * i2)
+{
+  if (i1->time < i2->time)
+    return -1;
+  else if (i1->time > i2->time)
+    return 1;
+  else if (i1->block < i2->block)
+    return -1;
+  else if (i1->block > i2->block)
+    return 1;
+  else
+    return 0;
+}
+
+/* skip unknown or alike element */
+GstFlowReturn
+gst_matroska_read_common_parse_skip (GstMatroskaReadCommon * common,
+    GstEbmlRead * ebml, const gchar * parent_name, guint id)
+{
+  if (id == GST_EBML_ID_VOID) {
+    GST_DEBUG_OBJECT (common, "Skipping EBML Void element");
+  } else if (id == GST_EBML_ID_CRC32) {
+    GST_DEBUG_OBJECT (common, "Skipping EBML CRC32 element");
+  } else {
+    GST_WARNING_OBJECT (common,
+        "Unknown %s subelement 0x%x - ignoring", parent_name, id);
+  }
+
+  return gst_ebml_read_skip (ebml);
+}
+
+static GstFlowReturn
+gst_matroska_read_common_parse_index_cuetrack (GstMatroskaReadCommon * common,
+    GstEbmlRead * ebml, guint * nentries)
+{
+  guint32 id;
+  GstFlowReturn ret;
+  GstMatroskaIndex idx;
+
+  idx.pos = (guint64) - 1;
+  idx.track = 0;
+  idx.time = GST_CLOCK_TIME_NONE;
+  idx.block = 1;
+
+  DEBUG_ELEMENT_START (common, ebml, "CueTrackPositions");
+
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (common, ebml, "CueTrackPositions", ret);
+    return ret;
+  }
+
+  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
+    if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
+      break;
+
+    switch (id) {
+        /* track number */
+      case GST_MATROSKA_ID_CUETRACK:
+      {
+        guint64 num;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+        if (num == 0) {
+          idx.track = 0;
+          GST_WARNING_OBJECT (common, "Invalid CueTrack 0");
+          break;
+        }
+
+        GST_DEBUG_OBJECT (common, "CueTrack: %" G_GUINT64_FORMAT, num);
+        idx.track = num;
+        break;
+      }
+
+        /* position in file */
+      case GST_MATROSKA_ID_CUECLUSTERPOSITION:
+      {
+        guint64 num;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+        if (num > G_MAXINT64) {
+          GST_WARNING_OBJECT (common, "CueClusterPosition %" G_GUINT64_FORMAT
+              " too large", num);
+          break;
+        }
+
+        idx.pos = num;
+        break;
+      }
+
+        /* number of block in the cluster */
+      case GST_MATROSKA_ID_CUEBLOCKNUMBER:
+      {
+        guint64 num;
+
+        if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+          break;
+
+        if (num == 0) {
+          GST_WARNING_OBJECT (common, "Invalid CueBlockNumber 0");
+          break;
+        }
+
+        GST_DEBUG_OBJECT (common, "CueBlockNumber: %" G_GUINT64_FORMAT, num);
+        idx.block = num;
+
+        /* mild sanity check, disregard strange cases ... */
+        if (idx.block > G_MAXUINT16) {
+          GST_DEBUG_OBJECT (common, "... looks suspicious, ignoring");
+          idx.block = 1;
+        }
+        break;
+      }
+
+      default:
+        ret = gst_matroska_read_common_parse_skip (common, ebml,
+            "CueTrackPositions", id);
+        break;
+
+      case GST_MATROSKA_ID_CUECODECSTATE:
+      case GST_MATROSKA_ID_CUEREFERENCE:
+        ret = gst_ebml_read_skip (ebml);
+        break;
+    }
+  }
+
+  DEBUG_ELEMENT_STOP (common, ebml, "CueTrackPositions", ret);
+
+  if ((ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED)
+      && idx.pos != (guint64) - 1 && idx.track > 0) {
+    g_array_append_val (common->index, idx);
+    (*nentries)++;
+  } else if (ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED) {
+    GST_DEBUG_OBJECT (common, "CueTrackPositions without valid content");
+  }
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_matroska_read_common_parse_index_pointentry (GstMatroskaReadCommon *
+    common, GstEbmlRead * ebml)
+{
+  guint32 id;
+  GstFlowReturn ret;
+  GstClockTime time = GST_CLOCK_TIME_NONE;
+  guint nentries = 0;
+
+  DEBUG_ELEMENT_START (common, ebml, "CuePoint");
+
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (common, ebml, "CuePoint", ret);
+    return ret;
+  }
+
+  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
+    if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
+      break;
+
+    switch (id) {
+        /* one single index entry ('point') */
+      case GST_MATROSKA_ID_CUETIME:
+      {
+        if ((ret = gst_ebml_read_uint (ebml, &id, &time)) != GST_FLOW_OK)
+          break;
+
+        GST_DEBUG_OBJECT (common, "CueTime: %" G_GUINT64_FORMAT, time);
+        time = time * common->time_scale;
+        break;
+      }
+
+        /* position in the file + track to which it belongs */
+      case GST_MATROSKA_ID_CUETRACKPOSITIONS:
+      {
+        if ((ret =
+                gst_matroska_read_common_parse_index_cuetrack (common, ebml,
+                    &nentries)) != GST_FLOW_OK)
+          break;
+        break;
+      }
+
+      default:
+        ret = gst_matroska_read_common_parse_skip (common, ebml, "CuePoint",
+            id);
+        break;
+    }
+  }
+
+  DEBUG_ELEMENT_STOP (common, ebml, "CuePoint", ret);
+
+  if (nentries > 0) {
+    if (time == GST_CLOCK_TIME_NONE) {
+      GST_WARNING_OBJECT (common, "CuePoint without valid time");
+      g_array_remove_range (common->index, common->index->len - nentries,
+          nentries);
+    } else {
+      gint i;
+
+      for (i = common->index->len - nentries; i < common->index->len; i++) {
+        GstMatroskaIndex *idx =
+            &g_array_index (common->index, GstMatroskaIndex, i);
+
+        idx->time = time;
+        GST_DEBUG_OBJECT (common, "Index entry: pos=%" G_GUINT64_FORMAT
+            ", time=%" GST_TIME_FORMAT ", track=%u, block=%u", idx->pos,
+            GST_TIME_ARGS (idx->time), (guint) idx->track, (guint) idx->block);
+      }
+    }
+  } else {
+    GST_DEBUG_OBJECT (common, "Empty CuePoint");
+  }
+
+  return ret;
+}
+
+gint
+gst_matroska_read_common_stream_from_num (GstMatroskaReadCommon * common,
+    guint track_num)
+{
+  guint n;
+
+  g_assert (common->src->len == common->num_streams);
+  for (n = 0; n < common->src->len; n++) {
+    GstMatroskaTrackContext *context = g_ptr_array_index (common->src, n);
+
+    if (context->num == track_num) {
+      return n;
+    }
+  }
+
+  if (n == common->num_streams)
+    GST_WARNING_OBJECT (common,
+        "Failed to find corresponding pad for tracknum %d", track_num);
+
+  return -1;
+}
+
+GstFlowReturn
+gst_matroska_read_common_parse_index (GstMatroskaReadCommon * common,
+    GstEbmlRead * ebml)
+{
+  guint32 id;
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint i;
+
+  if (common->index)
+    g_array_free (common->index, TRUE);
+  common->index =
+      g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128);
+
+  DEBUG_ELEMENT_START (common, ebml, "Cues");
+
+  if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
+    DEBUG_ELEMENT_STOP (common, ebml, "Cues", ret);
+    return ret;
+  }
+
+  while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
+    if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
+      break;
+
+    switch (id) {
+        /* one single index entry ('point') */
+      case GST_MATROSKA_ID_POINTENTRY:
+        ret = gst_matroska_read_common_parse_index_pointentry (common, ebml);
+        break;
+
+      default:
+        ret = gst_matroska_read_common_parse_skip (common, ebml, "Cues", id);
+        break;
+    }
+  }
+  DEBUG_ELEMENT_STOP (common, ebml, "Cues", ret);
+
+  /* Sort index by time, smallest time first, for easier searching */
+  g_array_sort (common->index, (GCompareFunc) gst_matroska_index_compare);
+
+  /* Now sort the track specific index entries into their own arrays */
+  for (i = 0; i < common->index->len; i++) {
+    GstMatroskaIndex *idx = &g_array_index (common->index, GstMatroskaIndex,
+        i);
+    gint track_num;
+    GstMatroskaTrackContext *ctx;
+
+    if (common->element_index) {
+      gint writer_id;
+
+      if (idx->track != 0 &&
+          (track_num =
+              gst_matroska_read_common_stream_from_num (common,
+                  idx->track)) != -1) {
+        ctx = g_ptr_array_index (common->src, track_num);
+
+        if (ctx->index_writer_id == -1)
+          gst_index_get_writer_id (common->element_index,
+              GST_OBJECT (ctx->pad), &ctx->index_writer_id);
+        writer_id = ctx->index_writer_id;
+      } else {
+        if (common->element_index_writer_id == -1)
+          gst_index_get_writer_id (common->element_index, GST_OBJECT (common),
+              &common->element_index_writer_id);
+        writer_id = common->element_index_writer_id;
+      }
+
+      GST_LOG_OBJECT (common, "adding association %" GST_TIME_FORMAT "-> %"
+          G_GUINT64_FORMAT " for writer id %d", GST_TIME_ARGS (idx->time),
+          idx->pos, writer_id);
+      gst_index_add_association (common->element_index, writer_id,
+          GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, idx->time,
+          GST_FORMAT_BYTES, idx->pos + common->ebml_segment_start, NULL);
+    }
+
+    if (idx->track == 0)
+      continue;
+
+    track_num = gst_matroska_read_common_stream_from_num (common, idx->track);
+    if (track_num == -1)
+      continue;
+
+    ctx = g_ptr_array_index (common->src, track_num);
+
+    if (ctx->index_table == NULL)
+      ctx->index_table =
+          g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128);
+
+    g_array_append_vals (ctx->index_table, idx, 1);
+  }
+
+  common->index_parsed = TRUE;
+
+  /* sanity check; empty index normalizes to no index */
+  if (common->index->len == 0) {
+    g_array_free (common->index, TRUE);
+    common->index = NULL;
+  }
+
+  return ret;
+}
diff --git a/gst/matroska/matroska-read-common.h b/gst/matroska/matroska-read-common.h
new file mode 100644 (file)
index 0000000..df3f54b
--- /dev/null
@@ -0,0 +1,69 @@
+/* GStreamer Matroska muxer/demuxer
+ * (c) 2011 Debarshi Ray <rishi@gnu.org>
+ *
+ * matroska-read-common.h: shared by matroska file/stream demuxer and parser
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_MATROSKA_READ_COMMON_H__
+#define __GST_MATROSKA_READ_COMMON_H__
+
+#include <glib.h>
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+  GST_MATROSKA_READ_COMMON_STATE_START,
+  GST_MATROSKA_READ_COMMON_STATE_SEGMENT,
+  GST_MATROSKA_READ_COMMON_STATE_HEADER,
+  GST_MATROSKA_READ_COMMON_STATE_DATA,
+  GST_MATROSKA_READ_COMMON_STATE_SEEK,
+  GST_MATROSKA_READ_COMMON_STATE_SCANNING
+} GstMatroskaReadCommonState;
+
+typedef struct _GstMatroskaReadCommon {
+  GstIndex                *element_index;
+  gint                     element_index_writer_id;
+
+  /* pads */
+  GPtrArray               *src;
+  guint                    num_streams;
+
+  /* did we parse cues/tracks/segmentinfo already? */
+  gboolean                 index_parsed;
+
+  /* start-of-segment */
+  guint64                  ebml_segment_start;
+
+  /* a cue (index) table */
+  GArray                  *index;
+
+  /* timescale in the file */
+  guint64                  time_scale;
+} GstMatroskaReadCommon;
+
+GstFlowReturn gst_matroska_read_common_parse_index (GstMatroskaReadCommon *
+    common, GstEbmlRead * ebml);
+GstFlowReturn gst_matroska_read_common_parse_skip (GstMatroskaReadCommon *
+    common, GstEbmlRead * ebml, const gchar * parent_name, guint id);
+gint gst_matroska_read_common_stream_from_num (GstMatroskaReadCommon * common,
+    guint track_num);
+
+G_END_DECLS
+
+#endif /* __GST_MATROSKA_READ_COMMON_H__ */