changeset 10685:f54ffeb29447

Support for linked seek heads, multiple seek heads, multiple cues.
author mosu
date Sun, 24 Aug 2003 12:34:42 +0000
parents 99eb26749a14
children 8eb690f0e342
files libmpdemux/demux_mkv.cpp
diffstat 1 files changed, 129 insertions(+), 94 deletions(-) [+]
line wrap: on
line diff
--- a/libmpdemux/demux_mkv.cpp	Sat Aug 23 22:51:10 2003 +0000
+++ b/libmpdemux/demux_mkv.cpp	Sun Aug 24 12:34:42 2003 +0000
@@ -19,9 +19,6 @@
 #include "../libvo/sub.h"
 }
 
-#include <iostream>
-#include <cassert>
-#include <typeinfo>
 #include <vector>
 
 #include <ebml/EbmlHead.h>
@@ -198,6 +195,8 @@
   int num_indexes, cues_found, cues_searched;
   int64_t *cluster_positions;
   int num_cluster_pos;
+  vector<uint64_t> *parsed_seekheads;
+  vector<uint64_t> *parsed_cues;
 
   int64_t skip_to_timecode;
   bool v_skip_to_keyframe, a_skip_to_keyframe;
@@ -798,6 +797,16 @@
     mkv_d->num_cluster_pos = 0;
 }
 
+static int find_in_vector(vector<uint64_t> &vec, uint64_t value) {
+  unsigned int i;
+
+  for (i = 0; i < vec.size(); i++)
+    if (vec[i] == value)
+      return 1;
+
+  return 0;
+}
+
 #define in_parent(p) (mkv_d->in->getFilePointer() < \
                       (p->GetElementPosition() + p->ElementSize()))
 #define FINDFIRST(p, c) (static_cast<c *> \
@@ -805,7 +814,7 @@
 #define FINDNEXT(p, c, e) (static_cast<c *> \
   (((EbmlMaster *)p)->FindNextElt(*e, false)))
 
-static int parse_cues(mkv_demuxer_t *mkv_d) {
+static void parse_cues(mkv_demuxer_t *mkv_d, uint64_t pos) {
   EbmlElement *l2 = NULL;
   EbmlStream *es;
   KaxCues *cues;
@@ -820,6 +829,13 @@
   uint32_t tnum = 0;
   mkv_index_entry_t *entry;
 
+  if (find_in_vector(*mkv_d->parsed_cues, pos))
+    return;
+
+  mkv_d->parsed_cues->push_back(pos);
+
+  mkv_d->in->setFilePointer(pos);
+
   es = mkv_d->es;
   tc_scale = mkv_d->tc_scale;
   upper_lvl_el = 0;
@@ -829,14 +845,14 @@
   cues = (KaxCues *)es->FindNextElement(mkv_d->segment->Generic().Context,
                                         upper_lvl_el, 0xFFFFFFFFL, true, 1);
   if (cues == NULL)
-    return 0;
+    return;
 
   if (!(EbmlId(*cues) == KaxCues::ClassInfos.GlobalId)) {
-    mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] No KaxCues element found but but %s.\n"
+    mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] No KaxCues element found but %s.\n"
            "[mkv] \\---- [ parsing cues ] -----------\n",
            cues->Generic().DebugName);
     
-    return 0;
+    return;
   }
 
   mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |+ found cues\n");
@@ -907,7 +923,92 @@
 
   mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] \\---- [ parsing cues ] -----------\n");
 
-  return 1;
+  mkv_d->cues_found = 1;
+}
+
+static void parse_seekhead(mkv_demuxer_t *mkv_d, uint64_t pos) {
+  EbmlElement *l2 = NULL;
+  EbmlStream *es;
+  KaxSeekHead *kseekhead;
+  KaxSeek *kseek;
+  KaxSeekID *ksid;
+  KaxSeekPosition *kspos;
+  int upper_lvl_el, i, k, s, id_found;
+  uint64_t seek_pos;
+  EbmlId *id;
+  EbmlElement *e;
+  binary *b;
+
+  if (find_in_vector(*mkv_d->parsed_seekheads, pos))
+    return;
+
+  mkv_d->parsed_seekheads->push_back(pos);
+
+  es = mkv_d->es;
+  upper_lvl_el = 0;
+
+  mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] /---- [ parsing seek head ] ---------\n");
+
+  mkv_d->in->setFilePointer(pos);
+
+  kseekhead =
+    (KaxSeekHead *)es->FindNextElement(mkv_d->segment->Generic().Context,
+                                       upper_lvl_el, 0xFFFFFFFFL, true, 1);
+  if (kseekhead == NULL)
+    return;
+
+  if (!(EbmlId(*kseekhead) == KaxSeekHead::ClassInfos.GlobalId)) {
+    mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] No KaxSeekead element found but %s.\n"
+           "[mkv] \\---- [ parsing seek head ] ---------\n",
+           kseekhead->Generic().DebugName);
+    
+    return;
+  }
+
+  kseekhead->Read(*es, KaxSeekHead::ClassInfos.Context, upper_lvl_el, l2,
+                  true);
+
+  for (i = 0; i < (int)kseekhead->ListSize(); i++) {
+    kseek = (KaxSeek *)(*kseekhead)[i];
+    if (!(EbmlId(*kseek) == KaxSeek::ClassInfos.GlobalId))
+      continue;
+
+    seek_pos = 0;
+    id = NULL;
+
+    for (k = 0; k < (int)kseek->ListSize(); k++) {
+      e = (*kseek)[k];
+
+      if (EbmlId(*e) == KaxSeekID::ClassInfos.GlobalId) {
+        ksid = (KaxSeekID *)e;
+
+        b = ksid->GetBuffer();
+        s = ksid->GetSize();
+        if (id != NULL)
+          delete id;
+        id = new EbmlId(b, s);
+
+      } else if (EbmlId(*e) == KaxSeekPosition::ClassInfos.GlobalId) {
+        kspos = (KaxSeekPosition *)e;
+        seek_pos = mkv_d->segment->GetGlobalPosition(uint64(*kspos));
+
+      }
+    }
+
+    if ((seek_pos != 0) && (id != NULL)) {
+      if (*id == KaxSeekHead::ClassInfos.GlobalId)
+        parse_seekhead(mkv_d, seek_pos);
+      else if (*id == KaxCues::ClassInfos.GlobalId)
+        parse_cues(mkv_d, seek_pos);
+    }
+
+    if (id != NULL)
+      delete id;
+  }
+
+  delete kseekhead;
+
+  mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] \\---- [ parsing seek head ] ---------\n");
 }
 
 extern "C" void print_wave_header(WAVEFORMATEX *h);
@@ -924,8 +1025,9 @@
   mkv_track_t *track;
   sh_audio_t *sh_a;
   sh_video_t *sh_v;
-  uint64_t seek_pos, current_pos, cues_pos;
-  int seek_element_is_cue;
+  vector<uint64_t> seekheads_to_parse;
+  vector<uint64_t> cues_to_parse;
+  int64_t current_pos;
 
 #ifdef USE_ICONV
   subcp_open();
@@ -991,7 +1093,8 @@
     
     mkv_d->segment = (KaxSegment *)l0;
     mkv_d->tc_scale = MKVD_TIMECODESCALE;
-    cues_pos = 0;
+    mkv_d->parsed_seekheads = new vector<uint64_t>;
+    mkv_d->parsed_cues = new vector<uint64_t>;
 
     upper_lvl_el = 0;
     exit_loop = 0;
@@ -1225,77 +1328,14 @@
         l1->SkipData(*es, l1->Generic().Context);
 
       } else if (EbmlId(*l1) == KaxSeekHead::ClassInfos.GlobalId) {
-
-        KaxSeek *kseek;
-        KaxSeekID *ksid;
-        KaxSeekPosition *kspos;
-
-        mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |+ found seek head\n");
-
-        l1->Read(*es, KaxSeekHead::ClassInfos.Context, upper_lvl_el, l2, true);
-
-        kseek = FINDFIRST(l1, KaxSeek);
-
-        while (kseek != NULL) {
-          mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + seek entry\n");
-
-          seek_element_is_cue = 0;
-          seek_pos = 0;
-
-          ksid = FINDFIRST(kseek, KaxSeekID);
-          if (ksid != NULL) {
-            binary *b;
-            int s;
-
-            b = ksid->GetBuffer();
-            s = ksid->GetSize();
-            EbmlId id(b, s);
-
-            if (id == KaxCues::ClassInfos.GlobalId)
-              seek_element_is_cue = 1;
-
-            mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |   + seek ID: ");
-            for (i = 0; i < s; i++)
-              mp_msg(MSGT_DEMUX, MSGL_V, "0x%02x ",
-                     ((unsigned char *)b)[i]);
-            mp_msg(MSGT_DEMUX, MSGL_V, "(%s)\n",
-                   (id == KaxInfo::ClassInfos.GlobalId) ?
-                   "KaxInfo" :
-                   (id == KaxCluster::ClassInfos.GlobalId) ?
-                   "KaxCluster" :
-                   (id == KaxTracks::ClassInfos.GlobalId) ?
-                   "KaxTracks" :
-                   (id == KaxCues::ClassInfos.GlobalId) ?
-                   "KaxCues" :
-                   (id == KaxAttachments::ClassInfos.GlobalId) ?
-                   "KaxAttachments" :
-                   (id == KaxChapters::ClassInfos.GlobalId) ?
-                   "KaxChapters" :
-                   "unknown");
-          }
-
-          kspos = FINDFIRST(kseek, KaxSeekPosition);
-          if (kspos != NULL) {
-            seek_pos = uint64(*kspos);
-            mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |   + seek position: %llu\n",
-                   seek_pos);
-          }
-
-          if (!mkv_d->cues_found && (kspos != NULL) &&
-              seek_element_is_cue && (s->end_pos != 0))
-              cues_pos = mkv_d->segment->GetGlobalPosition(seek_pos);
-
-          kseek = FINDNEXT(l1, KaxSeek, kseek);
-
-        } // while (kseek != NULL)
+        if (!find_in_vector(seekheads_to_parse, l1->GetElementPosition()))
+          seekheads_to_parse.push_back(l1->GetElementPosition());
+        l1->SkipData(*es, l1->Generic().Context);
 
       } else if ((EbmlId(*l1) == KaxCues::ClassInfos.GlobalId) &&
                  !mkv_d->cues_found) {
-        // If the cues are up front then by all means read them now!
-        current_pos = io.getFilePointer();
-        io.setFilePointer(l1->GetElementPosition());
-        mkv_d->cues_found = parse_cues(mkv_d);
-        stream_reset(s);
+        if (!find_in_vector(cues_to_parse, l1->GetElementPosition()))
+          cues_to_parse.push_back(l1->GetElementPosition());
         l1->SkipData(*es, l1->Generic().Context);
 
       } else if (EbmlId(*l1) == KaxCluster::ClassInfos.GlobalId) {
@@ -1344,6 +1384,7 @@
     }
 
     current_pos = io.getFilePointer();
+
     // Try to find the very first timecode (cluster timecode).
     l2 = es->FindNextElement(l1->Generic().Context, upper_lvl_el,
                              0xFFFFFFFFL, true, 1);
@@ -1355,19 +1396,14 @@
       delete l2;
     } else
       mkv_d->first_tc = 0;
+
+    // Parse all cues and seek heads
+    for (i = 0; i < (int)cues_to_parse.size(); i++)
+      parse_cues(mkv_d, cues_to_parse[i]);
+    for (i = 0; i < (int)seekheads_to_parse.size(); i++)
+      parse_seekhead(mkv_d, seekheads_to_parse[i]);
+
     io.setFilePointer(current_pos);
-    
-    // If we have found an entry for the cues in the meta seek data but no
-    // cues at the front of the file then read them now. This way the
-    // timecode scale will have been initialized correctly.
-    if (cues_pos && !mkv_d->cues_found) {
-      current_pos = io.getFilePointer();
-      io.setFilePointer(cues_pos);
-      mkv_d->cues_found = parse_cues(mkv_d);
-      if (s->eof)
-        stream_reset(s);
-      io.setFilePointer(current_pos);
-    }
 
   } catch (exception &ex) {
     mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] caught exception\n");
@@ -2134,9 +2170,8 @@
         break;
 
       if (EbmlId(*l1) == KaxCues::ClassInfos.GlobalId) {
-        mkv_d->in->setFilePointer(l1->GetElementPosition());
+        parse_cues(mkv_d, l1->GetElementPosition());
         delete l1;
-        mkv_d->cues_found = parse_cues(mkv_d);
         break;
       } else {
         if (EbmlId(*l1) == KaxCluster::ClassInfos.GlobalId)
@@ -2240,7 +2275,7 @@
              target_timecode, target_filepos);
       mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] seek found %p (%s).\n",
              mkv_d->saved_l1, mkv_d->saved_l1 == NULL ? "null" :
-             typeid(*mkv_d->saved_l1).name());
+             mkv_d->saved_l1->Generic().DebugName);
     }
 
     if (mkv_d->video != NULL)