changeset 11836:33351e4ce3de

mkv.cpp -> mkv_old.cpp, to avoid dependency name collision with mkv.c
author arpi
date Fri, 23 Jan 2004 21:34:28 +0000
parents 7d5b1df3b952
children 4e8f8efb6906
files libmpdemux/Makefile libmpdemux/demux_mkv.cpp libmpdemux/demux_mkv_old.cpp
diffstat 3 files changed, 3183 insertions(+), 3183 deletions(-) [+]
line wrap: on
line diff
--- a/libmpdemux/Makefile	Fri Jan 23 15:16:50 2004 +0000
+++ b/libmpdemux/Makefile	Fri Jan 23 21:34:28 2004 +0000
@@ -30,7 +30,7 @@
 SRCS += demux_mkv.c ebml.c
 endif
 ifeq ($(MATROSKA_EXTERNAL),yes)
-CPLUSPLUSSRCS += demux_mkv.cpp
+CPLUSPLUSSRCS += demux_mkv_old.cpp
 endif
 
 
--- a/libmpdemux/demux_mkv.cpp	Fri Jan 23 15:16:50 2004 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3182 +0,0 @@
-// Matroska demuxer
-// written by Moritz Bunkus <moritz@bunkus.org>
-// License: GPL of course ;)
-
-// $Id$
-
-extern "C" {
-#include "config.h"
-}
-
-#ifdef HAVE_MATROSKA
-
-#include <vector>
-
-#include <ebml/EbmlHead.h>
-#include <ebml/EbmlSubHead.h>
-#include <ebml/EbmlStream.h>
-#include <ebml/EbmlContexts.h>
-#include <ebml/EbmlVersion.h>
-#include <ebml/StdIOCallback.h>
-
-#include <matroska/KaxVersion.h>
-
-#include <matroska/KaxAttachments.h>
-#include <matroska/KaxBlock.h>
-#include <matroska/KaxBlockData.h>
-#include <matroska/KaxChapters.h>
-#include <matroska/KaxCluster.h>
-#include <matroska/KaxClusterData.h>
-#if LIBMATROSKA_VERSION >= 000503
-#include <matroska/KaxContentEncoding.h>
-#endif
-#include <matroska/KaxContexts.h>
-#include <matroska/KaxCues.h>
-#include <matroska/KaxCuesData.h>
-#include <matroska/KaxInfo.h>
-#include <matroska/KaxInfoData.h>
-#include <matroska/KaxSeekHead.h>
-#include <matroska/KaxSegment.h>
-#include <matroska/KaxTracks.h>
-#include <matroska/KaxTrackAudio.h>
-#include <matroska/KaxTrackVideo.h>
-#include <matroska/KaxTrackEntryData.h>
-#include <matroska/FileKax.h>
-
-extern "C" {
-#include <ctype.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#ifdef HAVE_ZLIB
-#include <zlib.h>
-#endif
-
-#include "../mp_msg.h"
-#include "../help_mp.h"
-#include "stream.h"
-#include "demuxer.h"
-#include "stheader.h"
-
-#include "../subreader.h"
-#include "../libvo/sub.h"
-
-}
-
-#include "matroska.h"
-
-using namespace libebml;
-using namespace libmatroska;
-using namespace std;
-
-#if LIBEBML_VERSION < 000500
-#error libebml version too old - need at least 0.5.0
-#endif
-
-// for e.g. "-slang ger"
-extern char *dvdsub_lang;
-extern char *audio_lang;
-// for "-chapter x-y"
-extern int dvd_chapter;
-extern int dvd_last_chapter;
-
-// default values for Matroska elements
-#define MKVD_TIMECODESCALE 1000000 // 1000000 = 1ms
-
-#define MKV_SUBTYPE_TEXT                  1
-#define MKV_SUBTYPE_SSA                   2
-#define MKV_SUBTYPE_VOBSUB                3
-
-#define MKV_SUBCOMPRESSION_NONE           0
-#define MKV_SUBCOMPRESSION_ZLIB           1
-
-#define safefree(m) { if (m != NULL) free(m); }
-void *safemalloc(int bytes) {
-  void *dst;
-
-  dst = malloc(bytes);
-  if (dst == NULL) {
-    mp_msg(MSGT_DEMUX, MSGL_FATAL, "[mkv] Could not allocate %d bytes of "
-          "memory.\n", bytes);
-    exit(1);
-  }
-
-  return dst;
-}
-
-void *safememdup(const void *src, int bytes) {
-  void *dst;
-
-  dst = safemalloc(bytes);
-  memcpy(dst, src, bytes);
-
-  return dst;
-}
-
-class mpstream_io_callback: public IOCallback {
-  private:
-    stream_t *s;
-  public:
-    mpstream_io_callback(stream_t *stream);
-
-    virtual uint32 read(void *buffer, size_t size);
-    virtual void setFilePointer(int64 offset, seek_mode mode = seek_beginning);
-    virtual size_t write(const void *buffer, size_t size);
-    virtual uint64 getFilePointer();
-    virtual void close();
-};
-
-mpstream_io_callback::mpstream_io_callback(stream_t *stream) {
-  s = stream;
-}
-
-uint32 mpstream_io_callback::read(void *buffer, size_t size) {
-  uint32_t result;
-
-  result = stream_read(s, (char *)buffer, size);
-
-  return result;
-}
-
-void mpstream_io_callback::setFilePointer(int64 offset, seek_mode mode) {
-  int64 new_pos;
-  
-  if (mode == seek_beginning)
-    new_pos = offset + s->start_pos;
-  else if (mode == seek_end)
-    new_pos = s->end_pos - offset;
-  else
-    new_pos = s->pos + offset;
-
-  if (new_pos > s->end_pos) {
-    mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] seek warning: new_pos %lld > end_pos "
-           "%lld\n", new_pos, s->end_pos);
-    return;
-  }
-
-  stream_seek(s, new_pos);
-}
-
-size_t mpstream_io_callback::write(const void */*buffer*/, size_t /*size*/) {
-  return 0;
-}
-
-uint64 mpstream_io_callback::getFilePointer() {
-  return s->pos - s->buf_len + s->buf_pos;
-}
-
-void mpstream_io_callback::close() {
-}
-
-typedef struct mkv_index_entry {
-  uint64_t timecode, filepos;
-  int is_key;
-} mkv_index_entry_t;
-
-typedef struct mkv_track_index {
-  uint32_t tnum;
-  int num_entries;
-  mkv_index_entry_t *entries;
-} mkv_track_index_t;
-
-typedef struct {
-  uint32_t order, type, scope;
-  uint32_t comp_algo;
-  unsigned char *comp_settings;
-  uint32_t comp_settings_len;
-  uint32_t enc_algo, sig_algo, sig_hash_algo;
-  unsigned char *enc_keyid, *sig_keyid, *signature;
-  uint32_t enc_keyid_len, sig_keyid_len, signature_len;
-} mkv_content_encoding_t;
-
-typedef struct {
-  int64_t start, end;
-} mkv_chapter_t;
-
-typedef struct mkv_track {
-  uint32_t tnum, xid;
-  
-  char *codec_id;
-  int ms_compat;
-  char *language;
-
-  char type; // 'v' = video, 'a' = audio, 's' = subs
-  
-  char v_fourcc[5];
-  uint32_t v_width, v_height, v_dwidth, v_dheight;
-  float v_frate;
-
-  uint32_t a_formattag;
-  uint32_t a_channels, a_bps;
-  float a_sfreq;
-
-  float default_duration;
-
-  int default_track;
-
-  void *private_data;
-  unsigned int private_size;
-
-  // For Vorbis audio
-  unsigned char *headers[3];
-  uint32_t header_sizes[3];
-
-  int ok;
-
-  // Stuff for RealMedia
-  bool realmedia;
-  demux_packet_t *rm_dp;
-  int rm_seqnum, rv_kf_base, rv_kf_pts;
-  float rv_pts;                 // previous video timestamp
-  float ra_pts;                 // previous audio timestamp
-
-  // Stuff for QuickTime
-  bool fix_i_bps;
-  float qt_last_a_pts;
-
-  // Stuff for VobSubs
-  mkv_sh_sub_t sh_sub;
-
-  // Generic content encoding support.
-  vector<mkv_content_encoding_t> *c_encodings;
-} mkv_track_t;
-
-typedef struct mkv_demuxer {
-  float duration, last_pts;
-  uint64_t last_filepos;
-
-  mkv_track_t **tracks;
-  int num_tracks;
-  mkv_track_t *video, *audio, *subs_track;
-
-  uint64_t tc_scale, cluster_tc, first_tc;
-
-  mpstream_io_callback *in;
-
-  uint64_t clear_subs_at[SUB_MAX_TEXT];
-
-  subtitle subs;
-  int subtitle_type;
-
-  EbmlStream *es;
-  EbmlElement *saved_l1, *saved_l2;
-  KaxSegment *segment;
-  KaxCluster *cluster;
-
-  mkv_track_index_t *index;
-  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;
-
-  vector<mkv_chapter_t> *chapters; // No support for nested chapters atm.
-  uint64_t stop_timecode;
-} mkv_demuxer_t;
-
-typedef struct {
-  uint32_t chunks;              // number of chunks
-  uint32_t timestamp;           // timestamp from packet header
-  uint32_t len;                 // length of actual data
-  uint32_t chunktab;            // offset to chunk offset array
-} dp_hdr_t;
-
-#if __GNUC__ == 2
-#pragma pack(2)
-#else
-#pragma pack(push,2)
-#endif
-
-typedef struct {
-  uint32_t size;
-  uint32_t fourcc1;
-  uint32_t fourcc2;
-  uint16_t width;
-  uint16_t height;
-  uint16_t bpp;
-  uint32_t unknown1;
-  uint32_t fps;
-  uint32_t type1;
-  uint32_t type2;
-} real_video_props_t;
-
-typedef struct {
-  uint32_t fourcc1;             // '.', 'r', 'a', 0xfd
-  uint16_t version1;            // 4 or 5
-  uint16_t unknown1;            // 00 000
-  uint32_t fourcc2;             // .ra4 or .ra5
-  uint32_t unknown2;            // ???
-  uint16_t version2;            // 4 or 5
-  uint32_t header_size;         // == 0x4e
-  uint16_t flavor;              // codec flavor id
-  uint32_t coded_frame_size;    // coded frame size
-  uint32_t unknown3;            // big number
-  uint32_t unknown4;            // bigger number
-  uint32_t unknown5;            // yet another number
-  uint16_t sub_packet_h;
-  uint16_t frame_size;
-  uint16_t sub_packet_size;
-  uint16_t unknown6;            // 00 00
-  uint16_t sample_rate;
-  uint16_t unknown8;            // 0
-  uint16_t sample_size;
-  uint16_t channels;
-} real_audio_v4_props_t;
-
-typedef struct {
-  uint32_t fourcc1;             // '.', 'r', 'a', 0xfd
-  uint16_t version1;            // 4 or 5
-  uint16_t unknown1;            // 00 000
-  uint32_t fourcc2;             // .ra4 or .ra5
-  uint32_t unknown2;            // ???
-  uint16_t version2;            // 4 or 5
-  uint32_t header_size;         // == 0x4e
-  uint16_t flavor;              // codec flavor id
-  uint32_t coded_frame_size;    // coded frame size
-  uint32_t unknown3;            // big number
-  uint32_t unknown4;            // bigger number
-  uint32_t unknown5;            // yet another number
-  uint16_t sub_packet_h;
-  uint16_t frame_size;
-  uint16_t sub_packet_size;
-  uint16_t unknown6;            // 00 00
-  uint8_t unknown7[6];          // 0, srate, 0
-  uint16_t sample_rate;
-  uint16_t unknown8;            // 0
-  uint16_t sample_size;
-  uint16_t channels;
-  uint32_t genr;                // "genr"
-  uint32_t fourcc3;             // fourcc
-} real_audio_v5_props_t;
-
-// I have to (re)define this struct here because g++ will not compile
-// components.h from the qtsdk if I include it.
-typedef struct {
-  uint32_t id_size;
-  uint32_t codec_type;
-  uint32_t reserved1;
-  uint16_t reserved2;
-  uint16_t data_reference_index;
-  uint16_t version;
-  uint16_t revision;
-  uint32_t vendor;
-  uint32_t temporal_quality;
-  uint32_t spatial_quality;
-  uint16_t width;
-  uint16_t height;
-  uint32_t horizontal_resolution; // 32bit fixed-point number
-  uint32_t vertical_resolution; // 32bit fixed-point number
-  uint32_t data_size;
-  uint16_t frame_count;
-  char compressor_name[32];
-  uint16_t depth;
-  uint16_t color_table_id;
-} qt_image_description_t;
-
-#if __GNUC__ == 2
-#pragma pack()
-#else
-#pragma pack(pop)
-#endif
-
-static uint16_t get_uint16(const void *buf) {
-  uint16_t      ret;
-  unsigned char *tmp;
-
-  tmp = (unsigned char *) buf;
-
-  ret = tmp[1] & 0xff;
-  ret = (ret << 8) + (tmp[0] & 0xff);
-
-  return ret;
-}
-
-static uint32_t get_uint32(const void *buf) {
-  uint32_t      ret;
-  unsigned char *tmp;
-
-  tmp = (unsigned char *) buf;
-
-  ret = tmp[3] & 0xff;
-  ret = (ret << 8) + (tmp[2] & 0xff);
-  ret = (ret << 8) + (tmp[1] & 0xff);
-  ret = (ret << 8) + (tmp[0] & 0xff);
-
-  return ret;
-}
-
-static uint16_t get_uint16_be(const void *buf) {
-  uint16_t ret;
-  unsigned char *tmp;
-
-  tmp = (unsigned char *) buf;
-
-  ret = tmp[0] & 0xff;
-  ret = (ret << 8) + (tmp[1] & 0xff);
-
-  return ret;
-}
-
-static uint32_t get_uint32_be(const void *buf) {
-  uint32_t ret;
-  unsigned char *tmp;
-
-  tmp = (unsigned char *) buf;
-
-  ret = tmp[0] & 0xff;
-  ret = (ret << 8) + (tmp[1] & 0xff);
-  ret = (ret << 8) + (tmp[2] & 0xff);
-  ret = (ret << 8) + (tmp[3] & 0xff);
-
-  return ret;
-}
-
-unsigned char read_char(unsigned char *p, int &pos, int size) {
-  if ((pos + 1) > size)
-    throw exception();
-  pos++;
-  return p[pos - 1];
-}
-
-unsigned short read_word(unsigned char *p, int &pos, int size) {
-  unsigned short v;
-
-  if ((pos + 2) > size)
-    throw exception();
-  v = p[pos];
-  v = (v << 8) | (p[pos + 1] & 0xff);
-  pos += 2;
-  return v;
-}
-
-unsigned int read_dword(unsigned char *p, int &pos, int size) {
-  unsigned int v;
-
-  if ((pos + 4) > size)
-    throw exception();
-  v = p[pos];
-  v = (v << 8) | (p[pos + 1] & 0xff);
-  v = (v << 8) | (p[pos + 2] & 0xff);
-  v = (v << 8) | (p[pos + 3] & 0xff);
-  pos += 4;
-  return v;
-}
-
-static void
-finish_text_sub_handling(mkv_demuxer_t *mkv_d, KaxBlock *block,
-                         int64_t duration, int first_line) {
-  int i;
-
-#ifdef USE_ICONV
-  subcp_recode1(&mkv_d->subs);
-#endif
-
-  vo_sub = &mkv_d->subs;
-  vo_osd_changed(OSDTYPE_SUBTITLE);
-
-  for (i = first_line; i <= (mkv_d->subs.lines - 1); i++)
-    mkv_d->clear_subs_at[i] =  block->GlobalTimecode() / 1000000 -
-      mkv_d->first_tc + duration;
-}
-
-static void handle_subtitles(demuxer_t *d, KaxBlock *block, int64_t duration) {
-  mkv_demuxer_t *mkv_d = (mkv_demuxer_t *)d->priv;
-  int len, line, state, i, first_line;
-  char *s1, *s2, *buffer;
-
-  if (duration == -1) {
-    mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Warning: No KaxBlockDuration "
-           "element for subtitle track found.\n");
-    return;
-  }
-
-  DataBuffer &data = block->GetBuffer(0);
-  len = data.Size();
-
-  buffer = (char *)data.Buffer();
-  s1 = buffer;
-
-  while (((*s1 == '\n') || (*s1 == '\r')) &&
-         ((unsigned int)(s1 - buffer) <= data.Size()))
-    s1++;
-
-  line = 0;
-  mkv_d->subs.lines++;
-  if (mkv_d->subs.lines > SUB_MAX_TEXT) {
-  	mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Warning: too many sublines to "
-           "render, skipping\n");
-  	mkv_d->subs.lines = SUB_MAX_TEXT;
-  	return;
-  }
-  first_line = mkv_d->subs.lines - 1;
-  s2 = mkv_d->subs.text[mkv_d->subs.lines - 1];
-  state = 0;
-
-  if (mkv_d->subtitle_type == MKV_SUBTYPE_SSA) {
-    /* Matroska's SSA format does not have timecodes embedded into 
-       the SAA line. Timescodes are encoded into the blocks timecode
-       and duration. */
-
-    /* Find text section. */
-    for (i = 0; (i < 8) && (*s1 != 0); s1++)
-      if (*s1 == ',')
-        i++;
-
-    if (*s1 == 0) {             // Broken line?
-      mkv_d->subs.lines--;
-      return;
-    }
-
-    /* Load text. */
-    while ((unsigned int)(s1 - buffer) < data.Size()) {
-      if (*s1 == '{')
-        state = 1;
-      else if ((*s1 == '}') && (state == 1))
-        state = 2;
-
-      if (state == 0) {
-        *s2 = *s1;
-        s2++;
-        if ((s2 - mkv_d->subs.text[mkv_d->subs.lines - 1]) >= 255)
-          break;
-      }
-      s1++;
-      
-      /* Newline */
-      if ((*s1 == '\\') && ((unsigned int)(s1 + 1 - buffer) < data.Size()) &&
-          ((*(s1 + 1) == 'N') || (*(s1 + 1) == 'n'))) {
-        *s2 = 0;
-        mkv_d->subs.lines++;
-        if (mkv_d->subs.lines > SUB_MAX_TEXT) {
-          mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Warning: too many sublines to "
-                 "render, skipping\n");
-          mkv_d->subs.lines = SUB_MAX_TEXT;
-          finish_text_sub_handling(mkv_d, block, duration, first_line);
-          return;
-        }
-        s2 = mkv_d->subs.text[mkv_d->subs.lines - 1];
-        s1 += 2;
-      }
-
-      if (state == 2)
-        state = 0;
-    }
-    *s2 = 0;
-
-  } else {
-    while ((unsigned int)(s1 - buffer) != data.Size()) {
-      if ((*s1 == '\n') || (*s1 == '\r')) {
-        if (state == 0) {       // normal char --> newline
-          if (mkv_d->subs.lines == SUB_MAX_TEXT)
-            break;
-          *s2 = 0;
-          mkv_d->clear_subs_at[mkv_d->subs.lines - 1]= 
-            block->GlobalTimecode() / 1000000 - mkv_d->first_tc + duration;
-          s2 = mkv_d->subs.text[mkv_d->subs.lines];
-          mkv_d->subs.lines++;
-          state = 1;
-        }
-      } else if (*s1 == '<')    // skip HTML tags
-        state = 2;
-      else if (*s1 == '>')
-        state = 0;
-      else if (state != 2) {      // normal character
-        state = 0;
-        if ((s2 - mkv_d->subs.text[mkv_d->subs.lines - 1]) < 255) {
-          *s2 = *s1;
-          s2++;
-        }
-      }
-      s1++;
-    }
-
-    *s2 = 0;
-  }
-
-  finish_text_sub_handling(mkv_d, block, duration, first_line);
-}
-
-static mkv_track_t *new_mkv_track(mkv_demuxer_t *d) {
-  mkv_track_t *t;
-  
-  t = (mkv_track_t *)safemalloc(sizeof(mkv_track_t));
-  memset(t, 0, sizeof(mkv_track_t));
-  d->tracks = (mkv_track_t **)realloc(d->tracks, (d->num_tracks + 1) *
-                                      sizeof(mkv_track_t *));
-  if (d->tracks == NULL)
-    return NULL;
-  d->tracks[d->num_tracks] = t;
-  d->num_tracks++;
-
-  // Set default values.
-  t->default_track = 1;
-  t->a_sfreq = 8000.0;
-  t->a_channels = 1;
-  t->language = strdup("eng");
-
-  t->c_encodings = new vector<mkv_content_encoding_t>;
-  
-  return t;
-}
-
-static mkv_track_t *find_track_by_num(mkv_demuxer_t *d, uint32_t n,
-                                      char track_type) {
-  int i;
-
-  for (i = 0; i < d->num_tracks; i++)
-    if ((d->tracks[i] != NULL) && (d->tracks[i]->type == track_type) &&
-        (d->tracks[i]->xid == n))
-      return d->tracks[i];
-  
-  return NULL;
-}
-
-static mkv_track_t *find_duplicate_track_by_num(mkv_demuxer_t *d, uint32_t n,
-                                                mkv_track_t *c) {
-  int i;
-  
-  for (i = 0; i < d->num_tracks; i++)
-    if ((d->tracks[i] != NULL) && (d->tracks[i]->tnum == n) &&
-        (d->tracks[i] != c))
-      return d->tracks[i];
-  
-  return NULL;
-}
-
-static mkv_track_t *find_track_by_language(mkv_demuxer_t *d, char *language,
-                                           mkv_track_t *c, char type = 's') {
-  int i;
-  
-  for (i = 0; i < d->num_tracks; i++)
-    if ((d->tracks[i] != NULL) && (d->tracks[i] != c) &&
-        (d->tracks[i]->language != NULL) &&
-        !strcmp(d->tracks[i]->language, language) &&
-        (d->tracks[i]->type == type))
-      return d->tracks[i];
-  
-  return NULL;
-}
-
-static bool mkv_parse_idx(mkv_track_t *t) {
-  uint32_t i, p, things_found;
-  int idx;
-  string line, s1, s2;
-  char *src;
-
-  if ((t->private_data == NULL) || (t->private_size < 1))
-    return false;
-
-  things_found = 0;
-  i = 0;
-  src = (char *)t->private_data;
-  do {
-    line = "";
-    while ((i < t->private_size) && (src[i] != '\n') && (src[i] != '\r')) {
-      if (!isspace(src[i]))
-        line += src[i];
-      i++;
-    }
-    while ((i < t->private_size) && ((src[i] == '\n') || (src[i] == '\r')))
-      i++;
-
-    if (!strncasecmp(line.c_str(), "size:", 5)) {
-      s1 = line.substr(5);
-      idx = s1.find('x');
-      if (idx >= 0) {
-        s2 = s1.substr(idx + 1);
-        s1.erase(idx);
-        t->sh_sub.width = strtol(s1.c_str(), NULL, 10);
-        t->sh_sub.height = strtol(s2.c_str(), NULL, 10);
-        things_found |= 1;
-        mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] VobSub IDX parser: size: %d x %d\n",
-               t->sh_sub.width, t->sh_sub.height);
-      }
-
-    } else if (!strncasecmp(line.c_str(), "palette:", 8)) {
-      s1 = line.substr(8);
-      for (p = 0; p < 15; p++) {
-        idx = s1.find(',');
-        if (idx < 0)
-          break;
-        s2 = s1.substr(0, idx);
-        s1.erase(0, idx + 1);
-        t->sh_sub.palette[p] = (unsigned int)strtol(s2.c_str(), NULL, 16);
-      }
-      if (idx >= 0) {
-        t->sh_sub.palette[15] = (unsigned int)strtol(s1.c_str(), NULL, 16);
-        things_found |= 2;
-        mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] VobSub IDX parser: palette: 0x%06x "
-               "0x%06x 0x%06x 0x%06x 0x%06x 0x%06x 0x%06x 0x%06x 0x%06x "
-               "0x%06x 0x%06x 0x%06x 0x%06x 0x%06x 0x%06x 0x%06x\n",
-               t->sh_sub.palette[0], t->sh_sub.palette[1],
-               t->sh_sub.palette[2], t->sh_sub.palette[3],
-               t->sh_sub.palette[4], t->sh_sub.palette[5],
-               t->sh_sub.palette[6], t->sh_sub.palette[7],
-               t->sh_sub.palette[8], t->sh_sub.palette[9],
-               t->sh_sub.palette[10], t->sh_sub.palette[11],
-               t->sh_sub.palette[12], t->sh_sub.palette[13],
-               t->sh_sub.palette[14], t->sh_sub.palette[15]);
-      }
-    }
-
-  } while ((i != t->private_size) && (things_found != 3));
-  t->sh_sub.type = 'v';
-
-  return (things_found == 3);
-}
-
-static bool reverse_encodings(mkv_track_t *track, unsigned char *&data,
-                              uint32_t &size, uint32_t type) {
-  int new_size, n;
-  unsigned char *new_data, *old_data;
-  bool modified;
-  vector<mkv_content_encoding_t>::iterator ce;
-
-  if (track->c_encodings->size() == 0)
-    return false;
-
-  new_data = data;
-  new_size = size;
-  modified = false;
-  for (ce = track->c_encodings->begin(); ce < track->c_encodings->end();
-       ce++) {
-    if ((ce->scope & type) == 0)
-      continue;
-
-#ifdef HAVE_ZLIB
-    if (ce->comp_algo == 0) {
-      int result;
-      z_stream zstream;
-
-      old_data = new_data;
-
-      zstream.zalloc = (alloc_func)0;
-      zstream.zfree = (free_func)0;
-      zstream.opaque = (voidpf)0;
-      result = inflateInit(&zstream);
-      if (result != Z_OK) {
-        mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Zlib initialization failed. "
-              "Result: %d\n", result);
-        safefree(new_data);
-        data = old_data;
-        size = new_size;
-        return modified;
-      }
-      zstream.next_in = (Bytef *)old_data;
-      zstream.avail_in = new_size;
-
-      n = 0;
-      new_data = NULL;
-      do {
-        n++;
-        new_data = (unsigned char *)realloc(new_data, n * 4000);
-        zstream.next_out = (Bytef *)&new_data[(n - 1) * 4000];
-        zstream.avail_out = 4000;
-        result = inflate(&zstream, Z_NO_FLUSH);
-        if ((result != Z_OK) && (result != Z_STREAM_END)) {
-          mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Zlib decompression failed. "
-                 "Result: %d \n", result);
-          safefree(new_data);
-          data = old_data;
-          size = new_size;
-          inflateEnd(&zstream);
-          return modified;
-        }
-      } while ((zstream.avail_out == 0) &&
-               (zstream.avail_in != 0) && (result != Z_STREAM_END));
-
-      mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv] zlib decompression: from %d to "
-            "%d \n", (int)new_size, (int)zstream.total_out);
-      new_size = zstream.total_out;
-      inflateEnd(&zstream);
-
-      if (modified)
-        safefree(old_data);
-      modified = true;
-    }
-#endif
-  }
-
-  data = new_data;
-  size = new_size;
-
-  return modified;
-}
-
-static int check_track_information(mkv_demuxer_t *d) {
-  int i, track_num;
-  unsigned char *c;
-  uint32_t u, offset, length;
-  mkv_track_t *t;
-  mkv_content_encoding_t *ce;
-  BITMAPINFOHEADER *bih;
-  WAVEFORMATEX *wfe;
-  
-  for (track_num = 0; track_num < d->num_tracks; track_num++) {
-    t = d->tracks[track_num];
-    
-    t->ok = 1;
-    for (i = 0; i < (int)t->c_encodings->size(); i++) {
-      ce = &(*t->c_encodings)[i];
-
-      if (ce->type == 1) {
-        mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Track number %u has been "
-              "encrypted and decryption has not yet been implemented. "
-              "Skipping track.\n", t->tnum);
-        t->ok = 0;
-        break;
-      }
-
-      if (ce->type != 0) {
-        mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Unknown content encoding type %u "
-              "for track %u. Skipping track.\n", ce->type, t->tnum);
-        t->ok = 0;
-        break;
-      }
-
-      if (ce->comp_algo == 0) {
-#if !defined(HAVE_ZLIB)
-        mp_msg(MSGT_DEMUX, MSGL_WARN, "Track %u was compressed with zlib but "
-              "mplayer has not been compiled with support for zlib "
-              "compression. Skipping track.\n", t->tnum);
-        t->ok = 0;
-        break;
-#endif
-      } else {
-        mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Track %u has been compressed "
-               "with an unknown/unsupported compression algorithm (%u). "
-               "Skipping track.\n", t->tnum, ce->comp_algo);
-        t->ok = 0;
-        break;
-      }
-    }
-
-    if (!t->ok)
-      continue;
-    t->ok = 0;
-
-    if (t->private_data != NULL) {
-      c = (unsigned char *)t->private_data;
-      length = t->private_size;
-      if (reverse_encodings(t, c, length, 2)) {
-        safefree(t->private_data);
-        t->private_data = c;
-        t->private_size = length;
-      }
-    }
-
-    switch (t->type) {
-      case 'v':                 // video track
-        if (t->codec_id == NULL)
-          continue;
-        if (!strcmp(t->codec_id, MKV_V_MSCOMP)) {
-          if ((t->private_data == NULL) ||
-              (t->private_size < sizeof(BITMAPINFOHEADER))) {
-            mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] WARNING: CodecID for track "
-                   "%u is '" MKV_V_MSCOMP "', but there was no "
-                   "BITMAPINFOHEADER struct present. Therefore we don't have "
-                   "a FourCC to identify the video codec used.\n", t->tnum);
-            continue;
-          } else {
-            t->ms_compat = 1;
-
-            bih = (BITMAPINFOHEADER *)t->private_data;
-
-            u = get_uint32(&bih->biWidth);
-            if (t->v_width != u) {
-              mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] WARNING: (MS "
-                     "compatibility mode, track %u) "
-                     "Matrosa says video width is %u, but the "
-                     "BITMAPINFOHEADER says %u.\n", t->tnum, t->v_width, u);
-              if (t->v_width == 0)
-                t->v_width = u;
-            }
-
-            u = get_uint32(&bih->biHeight);
-            if (t->v_height != u) {
-              mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] WARNING: (MS compatibility "
-                     "mode, track %u) "
-                     "Matrosa video height is %u, but the BITMAPINFOHEADER "
-                     "says %u.\n", t->tnum, t->v_height, u);
-              if (t->v_height == 0)
-                t->v_height = u;
-            }
-
-            memcpy(t->v_fourcc, &bih->biCompression, 4);
-          }
-        }
-
-        if (t->v_width == 0) {
-          mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] The width for track %u was "
-                 "not set.\n", t->tnum);
-          continue;
-        }
-        if (t->v_height == 0) {
-          mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] The height for track %u was "
-                 "not set.\n", t->tnum);
-          continue;
-        }
-
-        if (t->v_dwidth == 0)
-          t->v_dwidth = t->v_width;
-        if (t->v_dheight == 0)
-          t->v_dheight = t->v_height;
-
-        // This track seems to be ok.
-        t->ok = 1;
-        mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] Track ID %u: video (%s), "
-               "-vid %u\n", t->tnum, t->codec_id, t->xid);
-
-        break;
-
-      case 'a':                 // audio track
-        if (t->codec_id == NULL)
-          continue;
-        if (!strcmp(t->codec_id, MKV_A_ACM)) {
-          if ((t->private_data == NULL) ||
-              (t->private_size < sizeof(WAVEFORMATEX))) {
-            mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] WARNING: CodecID for track "
-                   "%u is '" MKV_A_ACM "', "
-                   "but there was no WAVEFORMATEX struct present. "
-                   "Therefore we don't have a format ID to identify the audio "
-                   "codec used.\n", t->tnum);
-            continue;
-          } else {
-            t->ms_compat = 1;
-
-            wfe = (WAVEFORMATEX *)t->private_data;
-            u = get_uint32(&wfe->nSamplesPerSec);
-            if (((uint32_t)t->a_sfreq) != u) {
-              mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] WARNING: (MS compatibility "
-                     "mode for track %u) "
-                     "Matroska says that there are %u samples per second, "
-                     "but WAVEFORMATEX says that there are %u.\n", t->tnum,
-                     (uint32_t)t->a_sfreq, u);
-              if (t->a_sfreq == 0.0)
-                t->a_sfreq = (float)u;
-            }
-
-            u = get_uint16(&wfe->nChannels);
-            if (t->a_channels != u) {
-              mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] WARNING: (MS "
-                     "compatibility mode for track %u) "
-                     "Matroska says that there are %u channels, but the "
-                     "WAVEFORMATEX says that there are %u.\n", t->tnum,
-                     t->a_channels, u);
-              if (t->a_channels == 0)
-                t->a_channels = u;
-            }
-
-            u = get_uint16(&wfe->wBitsPerSample);
-            if (t->a_bps != u) {
-              mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] WARNING: (MS "
-                     "compatibility mode for track %u) "
-                     "Matroska says that there are %u bits per sample, "
-                     "but the WAVEFORMATEX says that there are %u.\n", t->tnum,
-                     t->a_bps, u);
-              if (t->a_bps == 0)
-                t->a_bps = u;
-            }
-            
-            t->a_formattag = get_uint16(&wfe->wFormatTag);
-          }
-        } else {
-          if (!strcmp(t->codec_id, MKV_A_MP3) ||
-              !strcmp(t->codec_id, MKV_A_MP2))
-            t->a_formattag = 0x0055;
-          else if (!strncmp(t->codec_id, MKV_A_AC3, strlen(MKV_A_AC3)))
-            t->a_formattag = 0x2000;
-          else if (!strcmp(t->codec_id, MKV_A_DTS))
-            // uses same format tag as AC3, only supported with -hwac3
-            t->a_formattag = 0x2000;
-          else if (!strcmp(t->codec_id, MKV_A_PCM) ||
-                   !strcmp(t->codec_id, MKV_A_PCM_BE))
-            t->a_formattag = 0x0001;
-          else if (!strcmp(t->codec_id, MKV_A_AAC_2MAIN) ||
-                   !strncmp(t->codec_id, MKV_A_AAC_2LC,
-                            strlen(MKV_A_AAC_2LC)) ||
-                   !strcmp(t->codec_id, MKV_A_AAC_2SSR) ||
-                   !strcmp(t->codec_id, MKV_A_AAC_4MAIN) ||
-                   !strncmp(t->codec_id, MKV_A_AAC_4LC,
-                            strlen(MKV_A_AAC_4LC)) ||
-                   !strcmp(t->codec_id, MKV_A_AAC_4SSR) ||
-                   !strcmp(t->codec_id, MKV_A_AAC_4LTP))
-            t->a_formattag = mmioFOURCC('M', 'P', '4', 'A');
-          else if (!strcmp(t->codec_id, MKV_A_VORBIS)) {
-            if (t->private_data == NULL) {
-              mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] WARNING: CodecID for "
-                     "track %u is '" MKV_A_VORBIS
-                     "', but there are no header packets present.", t->tnum);
-              continue;
-            }
-
-            c = (unsigned char *)t->private_data;
-            if (c[0] != 2) {
-              mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Vorbis track does not "
-                     "contain valid headers.\n");
-              continue;
-            }
-
-            offset = 1;
-            for (i = 0; i < 2; i++) {
-              length = 0;
-              while ((c[offset] == (unsigned char )255) &&
-                     (length < t->private_size)) {
-                length += 255;
-                offset++;
-              }
-              if (offset >= (t->private_size - 1)) {
-                mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Vorbis track does not "
-                       "contain valid headers.\n");
-                continue;
-              }
-              length += c[offset];
-              offset++;
-              t->header_sizes[i] = length;
-            }
-
-            t->headers[0] = &c[offset];
-            t->headers[1] = &c[offset + t->header_sizes[0]];
-            t->headers[2] = &c[offset + t->header_sizes[0] +
-                               t->header_sizes[1]];
-            t->header_sizes[2] = t->private_size - offset -
-              t->header_sizes[0] - t->header_sizes[1];
-
-            t->a_formattag = 0xFFFE;
-          } else if (!strcmp(t->codec_id, MKV_A_QDMC) ||
-                     !strcmp(t->codec_id, MKV_A_QDMC2)) {
-            ;
-          } else if (!strcmp(t->codec_id, MKV_A_FLAC)) {
-            if ((t->private_data == NULL) || (t->private_size == 0)) {
-              mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] FLAC track does not "
-                     "contain valid headers.\n");
-              continue;
-            }
-            t->a_formattag = mmioFOURCC('f', 'L', 'a', 'C');
-          } else if (t->private_size >= sizeof(real_audio_v4_props_t)) {
-            if (!strcmp(t->codec_id, MKV_A_REAL28))
-              t->a_formattag = mmioFOURCC('2', '8', '_', '8');
-            else if (!strcmp(t->codec_id, MKV_A_REALATRC))
-              t->a_formattag = mmioFOURCC('a', 't', 'r', 'c');
-            else if (!strcmp(t->codec_id, MKV_A_REALCOOK))
-              t->a_formattag = mmioFOURCC('c', 'o', 'o', 'k');
-            else if (!strcmp(t->codec_id, MKV_A_REALDNET))
-              t->a_formattag = mmioFOURCC('d', 'n', 'e', 't');
-            else if (!strcmp(t->codec_id, MKV_A_REALSIPR))
-              t->a_formattag = mmioFOURCC('s', 'i', 'p', 'r');
-          } else {
-            mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Unknown/unsupported audio "
-                   "codec ID '%s' for track %u or missing/faulty private "
-                   "codec data.\n", t->codec_id, t->tnum);
-            continue;
-          }
-        }
-
-        if (t->a_sfreq == 0.0) {
-          mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] The sampling frequency was not "
-                 "set for track %u.\n", t->tnum);
-          continue;
-        }
-
-        if (t->a_channels == 0) {
-          mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] The number of channels was not "
-                 "set for track %u.\n", t->tnum);
-          continue;
-        }
-
-        // This track seems to be ok.
-        t->ok = 1;
-        mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] Track ID %u: audio (%s), -aid "
-               "%u%s%s\n", t->tnum, t->codec_id, t->xid,
-               t->language != NULL ? ", -alang " : "",
-               t->language != NULL ? t->language : "");
-        break;
-
-      case 's':
-        if (!strcmp(t->codec_id, MKV_S_VOBSUB)) {
-          if (mkv_parse_idx(t)) {
-            t->ok = 1;
-            mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] Track ID %u: subtitles (%s), "
-                   "-sid %u%s%s\n", t->tnum, t->codec_id,
-                   t->xid, t->language != NULL ? ", -slang " : "",
-                   t->language != NULL ? t->language : "");
-          }
-
-        } else {                // Text subtitles do not need any data
-          t->ok = 1;            // except the CodecID.
-          mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] Track ID %u: subtitles (%s), "
-                 "-sid %u%s%s\n", t->tnum, t->codec_id, t->xid,
-                 t->language != NULL ? ", -slang " : "",
-                 t->language != NULL ? t->language : "");
-        }
-        break;
-
-      default:                  // unknown track type!? error in demuxer...
-        mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] Error in demux_mkv.cpp: unknown "
-               "demuxer type for track %u: '%c'\n", t->tnum, t->type);
-        continue;
-    }
-
-    if (t->ok)
-      mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Track %u seems to be ok.\n", t->tnum);
-  }
-
-  return 1;
-}
-
-static void free_mkv_demuxer(mkv_demuxer_t *d) {
-  int i, k;
-  
-  if (d == NULL)
-    return;
-
-  for (i = 0; i < d->num_tracks; i++)
-    if (d->tracks[i] != NULL) {
-      if (d->tracks[i]->private_data != NULL)
-        free(d->tracks[i]->private_data);
-      if (d->tracks[i]->language != NULL)
-        free(d->tracks[i]->language);
-      for (k = 0; k < (int)d->tracks[i]->c_encodings->size(); k++) {
-        safefree((*d->tracks[i]->c_encodings)[k].comp_settings);
-        safefree((*d->tracks[i]->c_encodings)[k].enc_keyid);
-        safefree((*d->tracks[i]->c_encodings)[k].sig_keyid);
-        safefree((*d->tracks[i]->c_encodings)[k].signature);
-      }
-      delete d->tracks[i]->c_encodings;
-      free(d->tracks[i]);
-    }
-
-  for (i = 0; i < d->num_indexes; i++)
-    free(d->index[i].entries);
-  free(d->index);
-
-  for (i = 0; i <= SUB_MAX_TEXT; i++)
-    safefree(d->subs.text[i]);
-
-  if (d->es != NULL)
-    delete d->es;
-  if (d->saved_l1 != NULL)
-    delete d->saved_l1;
-  if (d->in != NULL)
-    delete d->in;
-  if (d->segment != NULL)
-    delete d->segment;
-  if (d->chapters != NULL)
-    delete d->chapters;
-
-  free(d);
-}
-
-static void add_index_entry(mkv_demuxer_t *d, uint32_t tnum, uint64_t filepos,
-                            uint64_t timecode, int is_key) {
-  int i, found;
-  mkv_index_entry_t *entry;
-
-  for (i = 0, found = 0; i < d->num_indexes; i++)
-    if (d->index[i].tnum == tnum) {
-      found = 1;
-      break;
-    }
-
-  if (!found) {
-    d->index = (mkv_track_index_t *)realloc(d->index, (d->num_indexes + 1) *
-                                            sizeof(mkv_track_index_t));
-    if (d->index == NULL)
-      return;
-    i = d->num_indexes;
-    memset(&d->index[i], 0, sizeof(mkv_track_index_t));
-    d->index[i].tnum = tnum;
-    d->num_indexes++;
-  }
-
-  d->index[i].entries =
-    (mkv_index_entry_t *)realloc(d->index[i].entries,
-                                 (d->index[i].num_entries + 1) *
-                                 sizeof(mkv_index_entry_t));
-  if (d->index[i].entries == NULL)
-    return;
-  entry = &d->index[i].entries[d->index[i].num_entries];
-  entry->filepos = filepos;
-  entry->timecode = timecode;
-  entry->is_key = is_key;
-  d->index[i].num_entries++;
-}
-
-static void add_cluster_position(mkv_demuxer_t *mkv_d, int64_t position) {
-  mkv_d->cluster_positions = (int64_t *)realloc(mkv_d->cluster_positions,
-                                                (mkv_d->num_cluster_pos + 1) *
-                                                sizeof(int64_t));
-  if (mkv_d->cluster_positions != NULL) {
-    mkv_d->cluster_positions[mkv_d->num_cluster_pos] = position;
-    mkv_d->num_cluster_pos++;
-  } else
-    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 *> \
-  (((EbmlMaster *)p)->FindFirstElt(c::ClassInfos, false)))
-#define FINDNEXT(p, c, e) (static_cast<c *> \
-  (((EbmlMaster *)p)->FindNextElt(*e, false)))
-
-static void parse_cues(mkv_demuxer_t *mkv_d, uint64_t pos) {
-  EbmlElement *l2 = NULL;
-  EbmlStream *es;
-  KaxCues *cues;
-  KaxCuePoint *cpoint;
-  KaxCueTime *ctime;
-  KaxCueClusterPosition *ccpos;
-  KaxCueTrack *ctrack;
-  KaxCueTrackPositions *ctrackpos;
-  int upper_lvl_el, i, k;
-  uint64_t tc_scale, filepos = 0, timecode = 0;
-  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;
-
-  mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] /---- [ parsing cues ] -----------\n");
-
-  cues = (KaxCues *)es->FindNextElement(mkv_d->segment->Generic().Context,
-                                        upper_lvl_el, 0xFFFFFFFFL, true, 1);
-  if (cues == NULL)
-    return;
-
-  if (!(EbmlId(*cues) == KaxCues::ClassInfos.GlobalId)) {
-    mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] No KaxCues element found but %s.\n"
-           "[mkv] \\---- [ parsing cues ] -----------\n",
-           cues->Generic().DebugName);
-    
-    return;
-  }
-
-  mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |+ found cues\n");
-
-  cues->Read(*es, KaxCues::ClassInfos.Context, upper_lvl_el, l2, true);
-
-  cpoint = FINDFIRST(cues, KaxCuePoint);
-
-  while (cpoint != NULL) {
-    mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv] | + found cue point\n");
-
-    ctime = FINDFIRST(cpoint, KaxCueTime);
-    if (ctime == NULL) {
-      cpoint = FINDNEXT(cues, KaxCuePoint, cpoint);
-      continue;
-    }
-      
-    timecode = uint64(*ctime) * tc_scale / 1000000 - mkv_d->first_tc;
-    mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv] |  + found cue time: %.3fs\n",
-           (float)timecode / 1000.0);
-
-    ctrackpos = FINDFIRST(cpoint, KaxCueTrackPositions);
-
-    while (ctrackpos != NULL) {
-      ctrack = FINDFIRST(ctrackpos, KaxCueTrack);
-
-      if (ctrack == NULL) {
-        ctrackpos = FINDNEXT(cpoint, KaxCueTrackPositions, ctrackpos);
-        continue;
-      }
-
-      tnum = uint32(*ctrack);
-      mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv] |   + found cue track: %u\n", tnum);
-
-      ccpos = FINDFIRST(ctrackpos, KaxCueClusterPosition);
-      if (ccpos == NULL) {
-        ctrackpos = FINDNEXT(cpoint, KaxCueTrackPositions, ctrackpos);
-        continue;
-      }
-
-      filepos = mkv_d->segment->GetGlobalPosition(uint64_t(*ccpos));
-      mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv] |   + found cue cluster "
-             "position: %llu\n", filepos);
-
-      add_index_entry(mkv_d, tnum, filepos, timecode, 1);
-     
-      ctrackpos = FINDNEXT(cpoint, KaxCueTrackPositions, ctrackpos);
-    }
-
-    cpoint = FINDNEXT(cues, KaxCuePoint, cpoint);
-  }
-
-  delete cues;
-
-  // Debug: dump the index
-  for (i = 0; i < mkv_d->num_indexes; i++) {
-    mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv] Index for track %u contains %u "
-           "entries.\n", mkv_d->index[i].tnum, mkv_d->index[i].num_entries);
-    for (k = 0; k < mkv_d->index[i].num_entries; k++) {
-      entry = &mkv_d->index[i].entries[k];
-      mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv]   %d: timecode %llu, filepos %llu, "
-             "is key: %s\n", k, entry->timecode, entry->filepos,
-             entry->is_key ? "yes" : "no");
-    }
-  }
-
-  mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] \\---- [ parsing cues ] -----------\n");
-
-  mkv_d->cues_found = 1;
-}
-
-static void parse_chapters(mkv_demuxer_t *mkv_d, uint64_t pos) {
-  EbmlElement *l2 = NULL;
-  EbmlStream *es;
-  KaxChapters *kchapters;
-  KaxEditionEntry *keentry;
-  KaxChapterAtom *kcatom;
-  KaxChapterTimeStart *kctstart;
-  KaxChapterTimeEnd *kctend;
-  int upper_lvl_el, i, k;
-  mkv_chapter_t chapter;
-
-  if (mkv_d->chapters != NULL)
-    return;
-
-  es = mkv_d->es;
-  upper_lvl_el = 0;
-
-  mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] /---- [ parsing chapters ] ---------\n");
-
-  mkv_d->in->setFilePointer(pos);
-
-  kchapters =
-    (KaxChapters *)es->FindNextElement(mkv_d->segment->Generic().Context,
-                                       upper_lvl_el, 0xFFFFFFFFL, true, 1);
-  if (kchapters == NULL)
-    return;
-
-  if (!(EbmlId(*kchapters) == KaxChapters::ClassInfos.GlobalId)) {
-    mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] No KaxChapters element found but %s.\n"
-           "[mkv] \\---- [ parsing chapters ] ---------\n",
-           kchapters->Generic().DebugName);
-    
-    return;
-  }
-
-  mkv_d->chapters = new vector<mkv_chapter_t>;
-  kchapters->Read(*es, KaxChapters::ClassInfos.Context, upper_lvl_el, l2,
-                  true);
-
-  for (i = 0; i < (int)kchapters->ListSize(); i++) {
-    keentry = (KaxEditionEntry *)(*kchapters)[i];
-    if (EbmlId(*keentry) == KaxEditionEntry::ClassInfos.GlobalId) {
-      for (k = 0; k < (int)keentry->ListSize(); k++) {
-        kcatom = (KaxChapterAtom *)(*keentry)[k];
-        if (EbmlId(*kcatom) == KaxChapterAtom::ClassInfos.GlobalId) {
-          chapter.start = 0;
-          chapter.end = 0;
-          kctstart = FINDFIRST(kcatom, KaxChapterTimeStart);
-          if (kctstart != NULL)
-            chapter.start = uint64(*kctstart) / 1000000;
-          kctend = FINDFIRST(kcatom, KaxChapterTimeEnd);
-          if (kctend != NULL)
-            chapter.end = uint64(*kctend) / 1000000;
-          mkv_d->chapters->push_back(chapter);
-          mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Chapter %u from %02d:%02d:%02d."
-                 "%03d to %02d:%02d:%02d.%03d\n", mkv_d->chapters->size(),
-                 (int)(chapter.start / 60 / 60 / 1000),
-                 (int)((chapter.start / 60 / 1000) % 60),
-                 (int)((chapter.start / 1000) % 60),
-                 (int)(chapter.start % 1000),
-                 (int)(chapter.end / 60 / 60 / 1000),
-                 (int)((chapter.end / 60 / 1000) % 60),
-                 (int)((chapter.end / 1000) % 60),
-                 (int)(chapter.end % 1000));
-        }
-      }
-    }
-  }
-
-  mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] \\---- [ parsing chapters ] ---------\n");
-  delete kchapters;
-}
-
-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;
-  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);
-      else if (*id == KaxChapters::ClassInfos.GlobalId)
-        parse_chapters(mkv_d, seek_pos);
-    }
-
-    if (id != NULL)
-      delete id;
-  }
-
-  delete kseekhead;
-
-  mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] \\---- [ parsing seek head ] ---------\n");
-}
-
-#define AAC_SYNC_EXTENSION_TYPE 0x02b7
-static int aac_get_sample_rate_index(uint32_t sample_rate) {
-  if (92017 <= sample_rate)
-    return 0;
-  else if (75132 <= sample_rate)
-    return 1;
-  else if (55426 <= sample_rate)
-    return 2;
-  else if (46009 <= sample_rate)
-    return 3;
-  else if (37566 <= sample_rate)
-    return 4;
-  else if (27713 <= sample_rate)
-    return 5;
-  else if (23004 <= sample_rate)
-    return 6;
-  else if (18783 <= sample_rate)
-    return 7;
-  else if (13856 <= sample_rate)
-    return 8;
-  else if (11502 <= sample_rate)
-    return 9;
-  else if (9391 <= sample_rate)
-    return 10;
-  else
-    return 11;
-}
-
-extern "C" void demux_mkv_seek(demuxer_t *demuxer, float rel_seek_secs,
-                               int flags);
-
-extern "C" int demux_mkv_open(demuxer_t *demuxer) {
-  unsigned char signature[4];
-  stream_t *s;
-  demux_packet_t *dp;
-  mkv_demuxer_t *mkv_d;
-  int upper_lvl_el, exit_loop, i, vid, sid, aid;
-  // Elements for different levels
-  EbmlElement *l0 = NULL, *l1 = NULL, *l2 = NULL;
-  EbmlStream *es;
-  mkv_track_t *track;
-  sh_audio_t *sh_a;
-  sh_video_t *sh_v;
-  vector<uint64_t> seekheads_to_parse;
-  vector<uint64_t> cues_to_parse;
-  int64_t current_pos;
-  qt_image_description_t *idesc;
-
-#ifdef USE_ICONV
-  subcp_open();
-#endif
-
-  s = demuxer->stream;
-  stream_seek(s, s->start_pos);
-  memset(signature, 0, 4);
-  stream_read(s, (char *)signature, 4);
-  if ((signature[0] != 0x1A) || (signature[1] != 0x45) ||
-      (signature[2] != 0xDF) || (signature[3] != 0xA3))
-    return 0;
-  stream_seek(s, s->start_pos);
-  
-  try {
-    // structure for storing the demuxer's private data
-    mkv_d = (mkv_demuxer_t *)safemalloc(sizeof(mkv_demuxer_t));
-    memset(mkv_d, 0, sizeof(mkv_demuxer_t));
-    mkv_d->duration = -1.0;
-    
-    // Create the interface between MPlayer's IO system and
-    // libmatroska's IO system.
-    mkv_d->in = new mpstream_io_callback(demuxer->stream);
-    if (mkv_d->in == NULL) {
-      free_mkv_demuxer(mkv_d);
-      return 0;
-    }
-    mpstream_io_callback &io = *static_cast<mpstream_io_callback *>(mkv_d->in);
-    mkv_d->es = new EbmlStream(io);
-    if (mkv_d->es == NULL) {
-      free_mkv_demuxer(mkv_d);
-      return 0;
-    }
-    es = mkv_d->es;
-    
-    // Find the EbmlHead element. Must be the first one.
-    l0 = es->FindNextID(EbmlHead::ClassInfos, 0xFFFFFFFFFFFFFFFFULL);
-    if (l0 == NULL) {
-      mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] no head found\n");
-      free_mkv_demuxer(mkv_d);
-      return 0;
-    }
-    // Don't verify its data for now.
-    l0->SkipData(static_cast<EbmlStream &>(*es), l0->Generic().Context);
-    delete l0;
-    mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Found the head...\n");
-    
-    // Next element must be a segment
-    l0 = es->FindNextID(KaxSegment::ClassInfos, 0xFFFFFFFFFFFFFFFFULL);
-    if (l0 == NULL) {
-      mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] but no segment :(\n");
-      free_mkv_demuxer(mkv_d);
-      return 0;
-    }
-    if (!(EbmlId(*l0) == KaxSegment::ClassInfos.GlobalId)) {
-      mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] but no segment :(\n");
-      free_mkv_demuxer(mkv_d);
-      return 0;
-    }
-    mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] + a segment...\n");
-    
-    mkv_d->segment = (KaxSegment *)l0;
-    mkv_d->tc_scale = MKVD_TIMECODESCALE;
-    mkv_d->parsed_seekheads = new vector<uint64_t>;
-    mkv_d->parsed_cues = new vector<uint64_t>;
-
-    vid = 0;
-    aid = 0;
-    sid = 0;
-
-    upper_lvl_el = 0;
-    exit_loop = 0;
-    // We've got our segment, so let's find the tracks
-    l1 = es->FindNextElement(l0->Generic().Context, upper_lvl_el, 0xFFFFFFFFL,
-                             true, 1);
-    while ((l1 != NULL) && (upper_lvl_el <= 0)) {
-
-      if (EbmlId(*l1) == KaxInfo::ClassInfos.GlobalId) {
-        // General info about this Matroska file
-        KaxTimecodeScale *ktc_scale;
-        KaxDuration *kduration;
-
-        mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |+ segment information...\n");
-
-        l1->Read(*es, KaxInfo::ClassInfos.Context, upper_lvl_el, l2, true);
-
-        ktc_scale = FINDFIRST(l1, KaxTimecodeScale);
-        if (ktc_scale != NULL) {
-          mkv_d->tc_scale = uint64(*ktc_scale);
-          mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + timecode scale: %llu\n",
-                 mkv_d->tc_scale);
-        } else
-          mkv_d->tc_scale = MKVD_TIMECODESCALE;
-
-        kduration = FINDFIRST(l1, KaxDuration);
-        if (kduration != NULL) {
-          mkv_d->duration = float(*kduration) * mkv_d->tc_scale / 1000000000.0;
-          mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + duration: %.3fs\n",
-                 mkv_d->duration);
-        }
-
-        l1->SkipData(*es, l1->Generic().Context);
-
-      } else if (EbmlId(*l1) == KaxTracks::ClassInfos.GlobalId) {
-        // Yep, we've found our KaxTracks element. Now find all tracks
-        // contained in this segment.
-
-        KaxTrackEntry *ktentry;
-
-        mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |+ segment tracks...\n");
-
-        l1->Read(*es, KaxTracks::ClassInfos.Context, upper_lvl_el, l2, true);
-
-        ktentry = FINDFIRST(l1, KaxTrackEntry);
-        while (ktentry != NULL) {
-          // We actually found a track entry :) We're happy now.
-
-          KaxTrackNumber *ktnum;
-          KaxTrackDefaultDuration *kdefdur;
-          KaxTrackType *kttype;
-          KaxTrackAudio *ktaudio;
-          KaxTrackVideo *ktvideo;
-          KaxCodecID *kcodecid;
-          KaxCodecPrivate *kcodecpriv;
-          KaxTrackFlagDefault *ktfdefault;
-          KaxTrackLanguage *ktlanguage;
-#if LIBMATROSKA_VERSION >= 000503
-          KaxContentEncodings *kcencodings;
-          int kcenc_idx;
-          vector<mkv_content_encoding_t>::iterator ce_ins_it;
-#endif
-
-          mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + a track...\n");
-            
-          track = new_mkv_track(mkv_d);
-          if (track == NULL)
-            return 0;
-
-          ktnum = FINDFIRST(ktentry, KaxTrackNumber);
-          if (ktnum != NULL) {
-            mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |  + Track number: %u\n",
-                   uint32(*ktnum));
-            track->tnum = uint32(*ktnum);
-            if (find_duplicate_track_by_num(mkv_d, track->tnum, track) != NULL)
-              mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] |  + WARNING: There's "
-                     "more than one track with the number %u.\n",
-                     track->tnum);
-          }
-
-          kdefdur = FINDFIRST(ktentry, KaxTrackDefaultDuration);
-          if (kdefdur != NULL) {
-            if (uint64(*kdefdur) == 0)
-              mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |  + Default duration: 0");
-            else {
-              track->v_frate = 1000000000.0 / (float)uint64(*kdefdur);
-              mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |  + Default duration: "
-                     "%.3fms ( = %.3f fps)\n",
-                     (float)uint64(*kdefdur) / 1000000.0, track->v_frate);
-            }
-            track->default_duration = (float)uint64(*kdefdur) / 1000000000.0;
-          }
-
-          kttype = FINDFIRST(ktentry, KaxTrackType);
-          if (kttype != NULL) {
-            mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |  + Track type: ");
-
-            switch (uint8(*kttype)) {
-              case track_audio:
-                mp_msg(MSGT_DEMUX, MSGL_V, "Audio\n");
-                track->type = 'a';
-                track->xid = aid;
-                aid++;
-                break;
-              case track_video:
-                mp_msg(MSGT_DEMUX, MSGL_V, "Video\n");
-                track->type = 'v';
-                track->xid = vid;
-                vid++;
-                break;
-              case track_subtitle:
-                mp_msg(MSGT_DEMUX, MSGL_V, "Subtitle\n");
-                track->type = 's';
-                track->xid = sid;
-                sid++;
-                break;
-              default:
-                mp_msg(MSGT_DEMUX, MSGL_V, "unknown\n");
-                track->type = '?';
-                break;
-            }
-          }
-
-          ktaudio = FINDFIRST(ktentry, KaxTrackAudio);
-          if (ktaudio != NULL) {
-            KaxAudioSamplingFreq *ka_sfreq;
-            KaxAudioChannels *ka_channels;
-            KaxAudioBitDepth *ka_bitdepth;
-
-            mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |  + Audio track\n");
-
-            ka_sfreq = FINDFIRST(ktaudio, KaxAudioSamplingFreq);
-            if (ka_sfreq != NULL) {
-              track->a_sfreq = float(*ka_sfreq);
-              mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |   + Sampling "
-                     "frequency: %f\n", track->a_sfreq);
-            } else
-              track->a_sfreq = 8000.0;
-
-            ka_channels = FINDFIRST(ktaudio, KaxAudioChannels);
-            if (ka_channels != NULL) {
-              track->a_channels = uint8(*ka_channels);
-              mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |   + Channels: %u\n",
-                     track->a_channels);
-            } else
-              track->a_channels = 1;
-
-            ka_bitdepth = FINDFIRST(ktaudio, KaxAudioBitDepth);
-            if (ka_bitdepth != NULL) {
-              track->a_bps = uint8(*ka_bitdepth);
-              mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |   + Bit depth: %u\n",
-                     track->a_bps);
-            }
-
-          }
-
-          ktvideo = FINDFIRST(ktentry, KaxTrackVideo);
-          if (ktvideo != NULL) {
-            KaxVideoPixelWidth *kv_pwidth;
-            KaxVideoPixelHeight *kv_pheight;
-            KaxVideoDisplayWidth *kv_dwidth;
-            KaxVideoDisplayHeight *kv_dheight;
-            KaxVideoFrameRate *kv_frate;
-
-            kv_pwidth = FINDFIRST(ktvideo, KaxVideoPixelWidth);
-            if (kv_pwidth != NULL) {
-              track->v_width = uint16(*kv_pwidth);
-              mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |   + Pixel width: %u\n",
-                     track->v_width);
-            }
-
-            kv_pheight = FINDFIRST(ktvideo, KaxVideoPixelHeight);
-            if (kv_pheight != NULL) {
-              track->v_height = uint16(*kv_pheight);
-              mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |   + Pixel height: %u\n",
-                     track->v_height);
-            }
-
-            kv_dwidth = FINDFIRST(ktvideo, KaxVideoDisplayWidth);
-            if (kv_dwidth != NULL) {
-              track->v_dwidth = uint16(*kv_dwidth);
-              mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |   + Display width: %u\n",
-                     track->v_dwidth);
-            }
-
-            kv_dheight = FINDFIRST(ktvideo, KaxVideoDisplayHeight);
-            if (kv_dheight != NULL) {
-              track->v_dheight = uint16(*kv_dheight);
-              mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |   + Display height: %u\n",
-                     track->v_dheight);
-            }
-
-            // For older files.
-            kv_frate = FINDFIRST(ktvideo, KaxVideoFrameRate);
-            if (kv_frate != NULL) {
-              track->v_frate = float(*kv_frate);
-              mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |   + Frame rate: %f\n",
-                     track->v_frate);
-            }
-
-          }
-
-          kcodecid = FINDFIRST(ktentry, KaxCodecID);
-          if (kcodecid != NULL) {
-            mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |  + Codec ID: %s\n",
-                   string(*kcodecid).c_str());
-            track->codec_id = strdup(string(*kcodecid).c_str());
-          }
-
-          kcodecpriv = FINDFIRST(ktentry, KaxCodecPrivate);
-          if (kcodecpriv != NULL) {
-            mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |  + CodecPrivate, length "
-                   "%llu\n", kcodecpriv->GetSize());
-            track->private_size = kcodecpriv->GetSize();
-            if (track->private_size > 0)
-              track->private_data = safememdup(kcodecpriv->GetBuffer(),
-                                               track->private_size);
-          }
-
-          ktfdefault = FINDFIRST(ktentry, KaxTrackFlagDefault);
-          if (ktfdefault != NULL) {
-            track->default_track = uint32(*ktfdefault);
-            mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |  + Default flag: %u\n",
-                   track->default_track);
-          }
-
-          ktlanguage = FINDFIRST(ktentry, KaxTrackLanguage);
-          if (ktlanguage != NULL) {
-            mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |  + Language: %s\n",
-                   string(*ktlanguage).c_str());
-            if (track->language != NULL)
-              free(track->language);
-            track->language = strdup(string(*ktlanguage).c_str());
-          }
-
-#if LIBMATROSKA_VERSION >= 000503
-          kcencodings = FINDFIRST(ktentry, KaxContentEncodings);
-          if (kcencodings != NULL) {
-            for (kcenc_idx = 0; kcenc_idx < (int)kcencodings->ListSize();
-                 kcenc_idx++) {
-              EbmlElement *l3;
-
-              l3 = (*kcencodings)[kcenc_idx];
-              if (EbmlId(*l3) == KaxContentEncoding::ClassInfos.GlobalId) {
-                KaxContentEncoding *kcenc;
-                KaxContentEncodingOrder *ce_order;
-                KaxContentEncodingType *ce_type;
-                KaxContentEncodingScope *ce_scope;
-                KaxContentCompression *ce_comp;
-                KaxContentEncryption *ce_enc;
-                mkv_content_encoding_t enc;
-
-                memset(&enc, 0, sizeof(mkv_content_encoding_t));
-                kcenc = static_cast<KaxContentEncoding *>(l3);
-
-                ce_order = FINDFIRST(kcenc, KaxContentEncodingOrder);
-                if (ce_order != NULL)
-                  enc.order = uint32(*ce_order);
-
-                ce_type = FINDFIRST(kcenc, KaxContentEncodingType);
-                if (ce_type != NULL)
-                  enc.type = uint32(*ce_type);
-
-                ce_scope = FINDFIRST(kcenc, KaxContentEncodingScope);
-                if (ce_scope != NULL)
-                  enc.scope = uint32(*ce_scope);
-                else
-                  enc.scope = 1;
-
-                ce_comp = FINDFIRST(kcenc, KaxContentCompression);
-                if (ce_comp != NULL) {
-                  KaxContentCompAlgo *cc_algo;
-                  KaxContentCompSettings *cc_settings;
-
-                  cc_algo = FINDFIRST(ce_comp, KaxContentCompAlgo);
-                  if (cc_algo != NULL)
-                    enc.comp_algo = uint32(*cc_algo);
-
-                  cc_settings = FINDFIRST(ce_comp, KaxContentCompSettings);
-                  if (cc_settings != NULL) {
-                    enc.comp_settings =
-                      (unsigned char *)safememdup(&binary(*cc_settings),
-                                                  cc_settings->GetSize());
-                    enc.comp_settings_len = cc_settings->GetSize();
-                  }
-                }
-
-                ce_enc = FINDFIRST(kcenc, KaxContentEncryption);
-                if (ce_enc != NULL) {
-                  KaxContentEncAlgo *ce_ealgo;
-                  KaxContentEncKeyID *ce_ekeyid;
-                  KaxContentSigAlgo *ce_salgo;
-                  KaxContentSigHashAlgo *ce_shalgo;
-                  KaxContentSigKeyID *ce_skeyid;
-                  KaxContentSignature *ce_signature;
-
-                  ce_ealgo = FINDFIRST(ce_enc, KaxContentEncAlgo);
-                  if (ce_ealgo != NULL)
-                    enc.enc_algo = uint32(*ce_ealgo);
-
-                  ce_ekeyid = FINDFIRST(ce_enc, KaxContentEncKeyID);
-                  if (ce_ekeyid != NULL) {
-                    enc.enc_keyid =
-                      (unsigned char *)safememdup(&binary(*ce_ekeyid),
-                                                  ce_ekeyid->GetSize());
-                    enc.enc_keyid_len = ce_ekeyid->GetSize();
-                  }
-
-                  ce_salgo = FINDFIRST(ce_enc, KaxContentSigAlgo);
-                  if (ce_salgo != NULL)
-                    enc.enc_algo = uint32(*ce_salgo);
-
-                  ce_shalgo = FINDFIRST(ce_enc, KaxContentSigHashAlgo);
-                  if (ce_shalgo != NULL)
-                    enc.enc_algo = uint32(*ce_shalgo);
-
-                  ce_skeyid = FINDFIRST(ce_enc, KaxContentSigKeyID);
-                  if (ce_skeyid != NULL) {
-                    enc.sig_keyid =
-                      (unsigned char *)safememdup(&binary(*ce_skeyid),
-                                                  ce_skeyid->GetSize());
-                    enc.sig_keyid_len = ce_skeyid->GetSize();
-                  }
-
-                  ce_signature = FINDFIRST(ce_enc, KaxContentSignature);
-                  if (ce_signature != NULL) {
-                    enc.signature =
-                      (unsigned char *)safememdup(&binary(*ce_signature),
-                                                  ce_signature->GetSize());
-                    enc.signature_len = ce_signature->GetSize();
-                  }
-
-                }
-
-                ce_ins_it = track->c_encodings->begin();
-                while ((ce_ins_it != track->c_encodings->end()) &&
-                       (enc.order <= (*ce_ins_it).order))
-                  ce_ins_it++;
-                track->c_encodings->insert(ce_ins_it, enc);
-              }
-            }
-          }
-
-#endif
-          ktentry = FINDNEXT(l1, KaxTrackEntry, ktentry);
-        } // while (ktentry != NULL)
-
-        l1->SkipData(*es, l1->Generic().Context);
-
-      } else if (EbmlId(*l1) == KaxSeekHead::ClassInfos.GlobalId) {
-        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 (!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) == KaxChapters::ClassInfos.GlobalId) {
-        parse_chapters(mkv_d, l1->GetElementPosition());
-        l1->SkipData(*es, l1->Generic().Context);
-
-      } else if (EbmlId(*l1) == KaxCluster::ClassInfos.GlobalId) {
-        mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |+ found cluster, headers are "
-               "parsed completely :)\n");
-        add_cluster_position(mkv_d, l1->GetElementPosition());
-        mkv_d->saved_l1 = l1;
-        exit_loop = 1;
-
-      } else
-        l1->SkipData(*es, l1->Generic().Context);
-      
-      if (!in_parent(l0)) {
-        delete l1;
-        break;
-      }
-
-      if (upper_lvl_el > 0) {
-        upper_lvl_el--;
-        if (upper_lvl_el > 0)
-          break;
-        delete l1;
-        l1 = l2;
-        continue;
-
-      } else if (upper_lvl_el < 0) {
-        upper_lvl_el++;
-        if (upper_lvl_el < 0)
-          break;
-
-      }
-
-      if (exit_loop)      // we've found the first cluster, so get out
-        break;
-
-      l1->SkipData(*es, l1->Generic().Context);
-      delete l1;
-      l1 = es->FindNextElement(l0->Generic().Context, upper_lvl_el,
-                               0xFFFFFFFFL, true);
-
-    } // while (l1 != NULL)
-
-    if (!exit_loop) {
-      free_mkv_demuxer(mkv_d);
-      return 0;
-    }
-
-    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);
-    if ((l2 != NULL) && !upper_lvl_el &&
-        (EbmlId(*l2) == KaxClusterTimecode::ClassInfos.GlobalId)) {
-      KaxClusterTimecode &ctc = *static_cast<KaxClusterTimecode *>(l2);
-      ctc.ReadData(es->I_O());
-      mkv_d->first_tc = uint64(ctc) * mkv_d->tc_scale / 1000000;
-      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);
-
-  } catch (exception &ex) {
-    mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] caught exception\n");
-    return 0;
-  }
-
-  if (!check_track_information(mkv_d)) {
-    free_mkv_demuxer(mkv_d);
-    return 0;
-  }
-
-  track = NULL;
-  if (demuxer->video->id == -1) { // Automatically select a video track.
-    // Search for a video track that has the 'default' flag set.
-    for (i = 0; i < mkv_d->num_tracks; i++)
-      if ((mkv_d->tracks[i]->type == 'v') && mkv_d->tracks[i]->ok &&
-          mkv_d->tracks[i]->default_track) {
-        track = mkv_d->tracks[i];
-        break;
-      }
-
-    if (track == NULL)
-      // No track has the 'default' flag set - let's take the first video
-      // track.
-      for (i = 0; i < mkv_d->num_tracks; i++)
-        if ((mkv_d->tracks[i]->type == 'v') && mkv_d->tracks[i]->ok) {
-          track = mkv_d->tracks[i];
-          break;
-        }
-  } else if (demuxer->video->id != -2) // -2 = no video at all
-    track = find_track_by_num(mkv_d, demuxer->video->id, 'v');
-
-  if (track) {
-    BITMAPINFOHEADER *bih;
-
-    idesc = NULL;
-
-    if (track->ms_compat) {         // MS compatibility mode
-      BITMAPINFOHEADER *src;
-      src = (BITMAPINFOHEADER *)track->private_data;
-      bih = (BITMAPINFOHEADER *)safemalloc(track->private_size);
-      memset(bih, 0, track->private_size);
-      bih->biSize = get_uint32(&src->biSize);
-      bih->biWidth = get_uint32(&src->biWidth);
-      bih->biHeight = get_uint32(&src->biHeight);
-      bih->biPlanes = get_uint16(&src->biPlanes);
-      bih->biBitCount = get_uint16(&src->biBitCount);
-      bih->biCompression = get_uint32(&src->biCompression);
-      bih->biSizeImage = get_uint32(&src->biSizeImage);
-      bih->biXPelsPerMeter = get_uint32(&src->biXPelsPerMeter);
-      bih->biYPelsPerMeter = get_uint32(&src->biYPelsPerMeter);
-      bih->biClrUsed = get_uint32(&src->biClrUsed);
-      bih->biClrImportant = get_uint32(&src->biClrImportant);
-      memcpy((char *)bih + sizeof(BITMAPINFOHEADER),
-             (char *)src + sizeof(BITMAPINFOHEADER),
-             track->private_size - sizeof(BITMAPINFOHEADER));
-
-    } else {
-      bih = (BITMAPINFOHEADER *)safemalloc(sizeof(BITMAPINFOHEADER));
-      memset(bih, 0, sizeof(BITMAPINFOHEADER));
-      bih->biSize = sizeof(BITMAPINFOHEADER);
-      bih->biWidth = track->v_width;
-      bih->biHeight = track->v_height;
-      bih->biBitCount = 24;
-      bih->biSizeImage = bih->biWidth * bih->biHeight * bih->biBitCount / 8;
-
-      if ((track->private_size >= sizeof(real_video_props_t)) &&
-          (!strcmp(track->codec_id, MKV_V_REALV10) ||
-           !strcmp(track->codec_id, MKV_V_REALV20) ||
-           !strcmp(track->codec_id, MKV_V_REALV30) ||
-           !strcmp(track->codec_id, MKV_V_REALV40))) {
-        unsigned char *dst, *src;
-        real_video_props_t *rvp;
-        uint32_t type2;
-
-        rvp = (real_video_props_t *)track->private_data;
-        src = (unsigned char *)(rvp + 1);
-
-        bih = (BITMAPINFOHEADER *)realloc(bih, sizeof(BITMAPINFOHEADER) + 12);
-        bih->biSize = 48;
-        bih->biPlanes = 1;
-        type2 = get_uint32_be(&rvp->type2);
-        if ((type2 == 0x10003000) || (type2 == 0x10003001))
-          bih->biCompression = mmioFOURCC('R', 'V', '1', '3');
-        else
-          bih->biCompression = mmioFOURCC('R', 'V', track->codec_id[9], '0');
-        dst = (unsigned char *)(bih + 1);
-        ((unsigned int *)dst)[0] = get_uint32_be(&rvp->type1);
-        ((unsigned int *)dst)[1] = type2;
-
-		    if ((bih->biCompression <= 0x30335652) &&
-            (type2 >= 0x20200002)) {
-          // read secondary WxH for the cmsg24[] (see vd_realvid.c)
-          ((unsigned short *)(bih + 1))[4] = 4 * (unsigned short)src[0];
-          ((unsigned short *)(bih + 1))[5] = 4 * (unsigned short)src[1];
-        } else
-          memset(&dst[8], 0, 4);
-        track->realmedia = true;
-
-#if defined(USE_QTX_CODECS)
-      } else if ((track->private_size >= sizeof(qt_image_description_t)) &&
-                 (!strcmp(track->codec_id, MKV_V_QUICKTIME))) {
-        idesc = (qt_image_description_t *)track->private_data;
-        idesc->id_size = get_uint32_be(&idesc->id_size);
-        idesc->codec_type = get_uint32(&idesc->codec_type);
-        idesc->version = get_uint16_be(&idesc->version);
-        idesc->revision = get_uint16_be(&idesc->revision);
-        idesc->vendor = get_uint32_be(&idesc->vendor);
-        idesc->temporal_quality = get_uint32_be(&idesc->temporal_quality);
-        idesc->spatial_quality = get_uint32_be(&idesc->spatial_quality);
-        idesc->width = get_uint16_be(&idesc->width);
-        idesc->height = get_uint16_be(&idesc->height);
-        idesc->horizontal_resolution =
-          get_uint32_be(&idesc->horizontal_resolution);
-        idesc->vertical_resolution =
-          get_uint32_be(&idesc->vertical_resolution);
-        idesc->data_size = get_uint32_be(&idesc->data_size);
-        idesc->frame_count = get_uint16_be(&idesc->frame_count);
-        idesc->depth = get_uint16_be(&idesc->depth);
-        idesc->color_table_id = get_uint16_be(&idesc->color_table_id);
-        bih->biPlanes = 1;
-        bih->biCompression = idesc->codec_type;
-#endif // defined(USE_QTX_CODECS)
-
-      } else {
-        mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Unknown/unsupported CodecID "
-               "(%s) or missing/bad CodecPrivate data (track %u).\n",
-               track->codec_id, track->tnum);
-        demuxer->video->id = -2;
-      }
-    }
-
-    if (demuxer->video->id != -2) {
-      mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] Will play video track %u\n",
-             track->tnum);
-
-      sh_v = new_sh_video(demuxer, track->tnum);
-      sh_v->bih = bih;
-      sh_v->format = sh_v->bih->biCompression;
-      if (track->v_frate == 0.0)
-        track->v_frate = 25.0;
-      sh_v->fps = track->v_frate;
-      sh_v->frametime = 1 / track->v_frate;
-      if (!track->realmedia) {
-        sh_v->disp_w = track->v_width;
-        sh_v->disp_h = track->v_height;
-        sh_v->aspect = (float)track->v_dwidth / (float)track->v_dheight;
-      } else {
-        // vd_realvid.c will set aspect to disp_w/disp_h and rederive
-        // disp_w and disp_h from the RealVideo stream contents returned
-        // by the Real DLLs. If DisplayWidth/DisplayHeight was not set in
-        // the Matroska file then it has already been set to PixelWidth/Height
-        // by check_track_information.
-        sh_v->disp_w = track->v_dwidth;
-        sh_v->disp_h = track->v_dheight;
-      }
-      if (idesc != NULL)
-        sh_v->ImageDesc = idesc;
-      mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Aspect: %f\n", sh_v->aspect);
-
-      demuxer->video->id = track->tnum;
-      demuxer->video->sh = sh_v;
-      sh_v->ds = demuxer->video;
-
-      mkv_d->video = track;
-    } else
-      free(bih);
-
-  } else {
-    mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] No video track found/wanted.\n");
-    demuxer->video->id = -2;
-  }
-
-  track = NULL;
-  if (demuxer->audio->id == -1) { // Automatically select an audio track.
-    // check if the user specified an audio language
-    if (audio_lang != NULL) {
-      track = find_track_by_language(mkv_d, audio_lang, NULL, 'a');
-    }
-    if (track == NULL)
-      // no audio language specified, or language not found
-      // Search for an audio track that has the 'default' flag set.
-      for (i = 0; i < mkv_d->num_tracks; i++)
-        if ((mkv_d->tracks[i]->type == 'a') && mkv_d->tracks[i]->ok &&
-            mkv_d->tracks[i]->default_track) {
-          track = mkv_d->tracks[i];
-          break;
-        }
-
-    if (track == NULL)
-      // No track has the 'default' flag set - let's take the first audio
-      // track.
-      for (i = 0; i < mkv_d->num_tracks; i++)
-        if ((mkv_d->tracks[i]->type == 'a') && mkv_d->tracks[i]->ok) {
-          track = mkv_d->tracks[i];
-          break;
-        }
-  } else if (demuxer->audio->id != -2) // -2 = no audio at all
-    track = find_track_by_num(mkv_d, demuxer->audio->id, 'a');
-
-  if (track) {
-    mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] Will play audio track %u\n",
-           track->tnum);
-    sh_a = new_sh_audio(demuxer, track->tnum);
-
-    demuxer->audio->id = track->tnum;
-    demuxer->audio->sh = sh_a;
-    sh_a->ds = demuxer->audio;
-
-    mkv_d->audio = track;
-
-    if (track->ms_compat)
-      sh_a->wf = (WAVEFORMATEX *)safememdup(track->private_data,
-                                            track->private_size);
-    else {
-      sh_a->wf = (WAVEFORMATEX *)safemalloc(sizeof(WAVEFORMATEX));
-      memset(sh_a->wf, 0, sizeof(WAVEFORMATEX));
-    }
-    sh_a->format = track->a_formattag;
-    sh_a->wf->wFormatTag = track->a_formattag;
-    sh_a->channels = track->a_channels;
-    sh_a->wf->nChannels = track->a_channels;
-    sh_a->samplerate = (uint32_t)track->a_sfreq;
-    sh_a->wf->nSamplesPerSec = (uint32_t)track->a_sfreq;
-    sh_a->samplesize = track->a_bps / 8;
-    if (!strcmp(track->codec_id, MKV_A_MP3) ||
-        !strcmp(track->codec_id, MKV_A_MP2)) {
-      sh_a->wf->nAvgBytesPerSec = 16000;
-      sh_a->wf->nBlockAlign = 1152;
-      sh_a->wf->wBitsPerSample = 0;
-      sh_a->samplesize = 0;
-
-    } else if (!strncmp(track->codec_id, MKV_A_AC3, strlen(MKV_A_AC3))) {
-      sh_a->wf->nAvgBytesPerSec = 16000;
-      sh_a->wf->nBlockAlign = 1536;
-      sh_a->wf->wBitsPerSample = 0;
-      sh_a->samplesize = 0;
-
-    } else if (!strcmp(track->codec_id, MKV_A_PCM) ||
-               !strcmp(track->codec_id, MKV_A_PCM_BE)) {
-      sh_a->wf->nAvgBytesPerSec = sh_a->channels * sh_a->samplerate * 2;
-      sh_a->wf->nBlockAlign = sh_a->wf->nAvgBytesPerSec;
-      sh_a->wf->wBitsPerSample = track->a_bps;
-      if (!strcmp(track->codec_id, MKV_A_PCM_BE))
-        sh_a->format = mmioFOURCC('t', 'w', 'o', 's');
-
-    } else if (!strcmp(track->codec_id, MKV_A_QDMC) ||
-               !strcmp(track->codec_id, MKV_A_QDMC2)) {
-      sh_a->wf->wBitsPerSample = track->a_bps;
-      sh_a->wf->nAvgBytesPerSec = 16000;
-      sh_a->wf->nBlockAlign = 1486;
-      track->fix_i_bps = true;
-      track->qt_last_a_pts = 0.0;
-      if (track->private_data != NULL) {
-        sh_a->codecdata = (unsigned char *)safememdup(track->private_data,
-                                                      track->private_size);
-        sh_a->codecdata_len = track->private_size;
-      }
-      if (!strcmp(track->codec_id, MKV_A_QDMC))
-        sh_a->format = mmioFOURCC('Q', 'D', 'M', 'C');
-      else
-        sh_a->format = mmioFOURCC('Q', 'D', 'M', '2');
-
-    } else if (track->a_formattag == mmioFOURCC('M', 'P', '4', 'A')) {
-      int profile, srate_idx;
-
-      sh_a->wf->nAvgBytesPerSec = 16000;
-      sh_a->wf->nBlockAlign = 1024;
-      sh_a->wf->wBitsPerSample = 0;
-      sh_a->samplesize = 0;
-
-      // Recreate the 'private data' which faad2 uses in its initialization.
-      srate_idx = aac_get_sample_rate_index(sh_a->samplerate);
-      if (!strncmp(&track->codec_id[12], "MAIN", 4))
-        profile = 0;
-      else if (!strncmp(&track->codec_id[12], "LC", 2))
-        profile = 1;
-      else if (!strncmp(&track->codec_id[12], "SSR", 3))
-        profile = 2;
-      else
-        profile = 3;
-      sh_a->codecdata = (unsigned char *)safemalloc(5);
-      sh_a->codecdata[0] = ((profile + 1) << 3) | ((srate_idx & 0xe) >> 1);
-      sh_a->codecdata[1] = ((srate_idx & 0x1) << 7) |
-        (track->a_channels << 3);
-
-      if (strstr(track->codec_id, "SBR") != NULL) {
-        // HE-AAC (aka SBR AAC)
-        sh_a->codecdata_len = 5;
-
-        sh_a->samplerate *= 2;
-        sh_a->wf->nSamplesPerSec *= 2;
-        srate_idx = aac_get_sample_rate_index(sh_a->samplerate);
-        sh_a->codecdata[2] = AAC_SYNC_EXTENSION_TYPE >> 3;
-        sh_a->codecdata[3] = ((AAC_SYNC_EXTENSION_TYPE & 0x07) << 5) | 5;
-        sh_a->codecdata[4] = (1 << 7) | (srate_idx << 3);
-        track->default_duration = 1024.0 / (float)(sh_a->samplerate / 2);
-
-      } else {
-        sh_a->codecdata_len = 2;
-        track->default_duration = 1024.0 / (float)sh_a->samplerate;
-      }
-
-    } else if (!strcmp(track->codec_id, MKV_A_VORBIS)) {
-      for (i = 0; i < 3; i++) {
-        dp = new_demux_packet(track->header_sizes[i]);
-        memcpy(dp->buffer, track->headers[i], track->header_sizes[i]);
-        dp->pts = 0;
-        dp->flags = 0;
-        ds_add_packet(demuxer->audio, dp);
-      }
-
-    } else if ((track->private_size >= sizeof(real_audio_v4_props_t)) &&
-               !strncmp(track->codec_id, MKV_A_REALATRC, 7)) {
-      // Common initialization for all RealAudio codecs
-      real_audio_v4_props_t *ra4p;
-      real_audio_v5_props_t *ra5p;
-      unsigned char *src;
-      int codecdata_length, version;
-
-      ra4p = (real_audio_v4_props_t *)track->private_data;
-      ra5p = (real_audio_v5_props_t *)track->private_data;
-
-      sh_a->wf->wBitsPerSample = sh_a->samplesize * 8;
-      sh_a->wf->nAvgBytesPerSec = 0; // FIXME !?
-      sh_a->wf->nBlockAlign = get_uint16_be(&ra4p->frame_size);
-
-      version = get_uint16_be(&ra4p->version1);
-
-      if (version == 4) {
-        src = (unsigned char *)(ra4p + 1);
-        src += src[0] + 1;
-        src += src[0] + 1;
-      } else
-        src = (unsigned char *)(ra5p + 1);
-
-      src += 3;
-      if (version == 5)
-        src++;
-      codecdata_length = get_uint32_be(src);
-      src += 4;
-      sh_a->wf->cbSize = 10 + codecdata_length;
-      sh_a->wf = (WAVEFORMATEX *)realloc(sh_a->wf, sizeof(WAVEFORMATEX) +
-                                         sh_a->wf->cbSize);
-      ((short *)(sh_a->wf + 1))[0] = get_uint16_be(&ra4p->sub_packet_size);
-      ((short *)(sh_a->wf + 1))[1] = get_uint16_be(&ra4p->sub_packet_h);
-      ((short *)(sh_a->wf + 1))[2] = get_uint16_be(&ra4p->flavor);
-      ((short *)(sh_a->wf + 1))[3] = get_uint32_be(&ra4p->coded_frame_size);
-      ((short *)(sh_a->wf + 1))[4] = codecdata_length;
-      memcpy(((char *)(sh_a->wf + 1)) + 10, src, codecdata_length);
-
-      track->realmedia = true;
-
-    } else if (!strcmp(track->codec_id, MKV_A_FLAC) ||
-               (track->a_formattag == 0xf1ac)) {
-      unsigned char *ptr;
-      int size;
-      free(sh_a->wf);
-      sh_a->wf = NULL;
-
-      if (track->a_formattag == mmioFOURCC('f', 'L', 'a', 'C')) {
-        ptr = (unsigned char *)track->private_data;
-        size = track->private_size;
-      } else {
-        sh_a->format = mmioFOURCC('f', 'L', 'a', 'C');
-        ptr = (unsigned char *)track->private_data + sizeof(WAVEFORMATEX);
-        size = track->private_size - sizeof(WAVEFORMATEX);
-      }
-      if ((size < 4) || (ptr[0] != 'f') || (ptr[1] != 'L') ||
-          (ptr[2] != 'a') || (ptr[3] != 'C')) {
-        dp = new_demux_packet(4);
-        memcpy(dp->buffer, "fLaC", 4);
-        dp->pts = 0;
-        dp->flags = 0;
-        ds_add_packet(demuxer->audio, dp);
-      }
-      dp = new_demux_packet(size);
-      memcpy(dp->buffer, ptr, size);
-      dp->pts = 0;
-      dp->flags = 0;
-      ds_add_packet(demuxer->audio, dp);
-    }
-
-  } else {
-    mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] No audio track found/wanted.\n");
-    demuxer->audio->id = -2;
-  }
-
-  // DO NOT automatically select a subtitle track and behave like DVD
-  // playback: only show subtitles if the user explicitely wants them.
-  track = NULL;
-  if (demuxer->sub->id >= 0)
-    track = find_track_by_num(mkv_d, demuxer->sub->id, 's');
-  else if (dvdsub_lang != NULL)
-    track = find_track_by_language(mkv_d, dvdsub_lang, NULL);
-  if (track) {
-    if (!strcmp(track->codec_id, MKV_S_VOBSUB)) {
-      mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] Will display subtitle track %u\n",
-             track->tnum);
-      mkv_d->subs_track = track;
-      mkv_d->subtitle_type = MKV_SUBTYPE_VOBSUB;
-      demuxer->sub->sh = (mkv_sh_sub_t *)safememdup(&track->sh_sub,
-                                                    sizeof(mkv_sh_sub_t));
-      demuxer->sub->id = track->xid;
-
-    } else if (strcmp(track->codec_id, MKV_S_TEXTASCII) &&
-               strcmp(track->codec_id, MKV_S_TEXTUTF8) && 
-               strcmp(track->codec_id, MKV_S_TEXTSSA) &&
-               strcmp(track->codec_id, "S_SSA") &&
-               strcmp(track->codec_id, "S_ASS") &&
-               strcmp(track->codec_id, "S_TEXT/ASS"))
-      mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] Subtitle type '%s' is not "
-             "supported. Track will not be displayed.\n", track->codec_id);
-    else {
-      mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] Will display subtitle track %u\n",
-             track->tnum);
-      mkv_d->subs_track = track;
-      if (!mkv_d->subs.text[0]) {
-        for (i = 0; i <= SUB_MAX_TEXT; i++)
-          mkv_d->subs.text[i] = (char *)safemalloc(256);
-
-        if (!strcmp(track->codec_id, MKV_S_TEXTUTF8))
-          sub_utf8 = 1;       // Force UTF-8 conversion.
-        if (!strcmp(track->codec_id, MKV_S_TEXTSSA) ||
-            !strcmp(track->codec_id, "S_SSA") ||
-            !strcmp(track->codec_id, "S_ASS") ||
-            !strcmp(track->codec_id, "S_TEXT/ASS")) {
-          mkv_d->subtitle_type = MKV_SUBTYPE_SSA;
-          sub_utf8 = 1;
-        } else
-          mkv_d->subtitle_type = MKV_SUBTYPE_TEXT;
-      } else
-        mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] File does not contain a "
-               "subtitle track with the id %u.\n", demuxer->sub->id);
-      demuxer->sub->sh = NULL;
-    }
-  }
-
-  demuxer->priv = mkv_d;
-
-  if (mkv_d->chapters != NULL) {
-    for (i = 0; i < (int)mkv_d->chapters->size(); i++) {
-      (*mkv_d->chapters)[i].start -= mkv_d->first_tc;
-      (*mkv_d->chapters)[i].end -= mkv_d->first_tc;
-    }
-    if ((dvd_last_chapter > 0) &&
-        (dvd_last_chapter <= (int)mkv_d->chapters->size())) {
-      if ((*mkv_d->chapters)[dvd_last_chapter - 1].end != 0)
-        mkv_d->stop_timecode = (*mkv_d->chapters)[dvd_last_chapter - 1].end;
-      else if ((dvd_last_chapter + 1) <= (int)mkv_d->chapters->size())
-        mkv_d->stop_timecode = (*mkv_d->chapters)[dvd_last_chapter].start;
-    }
-  }
-
-  if (s->end_pos == 0)
-    demuxer->seekable = 0;
-  else {
-    demuxer->movi_start = s->start_pos;
-    demuxer->movi_end = s->end_pos;
-    demuxer->seekable = 1;
-    if ((dvd_chapter != 1) && (mkv_d->chapters != NULL) &&
-        (dvd_chapter <= (int)mkv_d->chapters->size()))
-      demux_mkv_seek(demuxer, (float)(*mkv_d->chapters)[dvd_chapter - 1].start
-                     / 1000.0, 1);
-  }
-
-  return 1;
-}
-
-// Taken from demux_real.c. Thanks to the original developpers :)
-#define SKIP_BITS(n) buffer <<= n
-#define SHOW_BITS(n) ((buffer) >> (32 - (n)))
-
-static float real_fix_timestamp(mkv_track_t *track, unsigned char *s,
-                                int timestamp) {
-  float v_pts;
-  uint32_t buffer = (s[0] << 24) + (s[1] << 16) + (s[2] << 8) + s[3];
-  int kf = timestamp;
-  int pict_type;
-  int orig_kf;
-
-  if (!strcmp(track->codec_id, MKV_V_REALV30) ||
-      !strcmp(track->codec_id, MKV_V_REALV40)) {
-
-    if (!strcmp(track->codec_id, MKV_V_REALV30)) {
-      SKIP_BITS(3);
-      pict_type = SHOW_BITS(2);
-      SKIP_BITS(2 + 7);
-    }else{
-      SKIP_BITS(1);
-      pict_type = SHOW_BITS(2);
-      SKIP_BITS(2 + 7 + 3);
-    }
-    kf = SHOW_BITS(13);         // kf= 2*SHOW_BITS(12);
-    orig_kf = kf;
-    if (pict_type <= 1) {
-      // I frame, sync timestamps:
-      track->rv_kf_base = timestamp - kf;
-      mp_msg(MSGT_DEMUX, MSGL_V, "\nTS: base=%08X\n", track->rv_kf_base);
-      kf = timestamp;
-    } else {
-      // P/B frame, merge timestamps:
-      int tmp = timestamp - track->rv_kf_base;
-      kf |= tmp & (~0x1fff);    // combine with packet timestamp
-      if (kf < (tmp - 4096))    // workaround wrap-around problems
-        kf += 8192;
-      else if (kf > (tmp + 4096))
-        kf -= 8192;
-      kf += track->rv_kf_base;
-    }
-    if (pict_type != 3) {       // P || I  frame -> swap timestamps
-      int tmp = kf;
-      kf = track->rv_kf_pts;
-      track->rv_kf_pts = tmp;
-    }
-    mp_msg(MSGT_DEMUX, MSGL_V, "\nTS: %08X -> %08X (%04X) %d %02X %02X %02X "
-           "%02X %5d\n", timestamp, kf, orig_kf, pict_type, s[0], s[1], s[2],
-           s[3], kf - (int)(1000.0 * track->rv_pts));
-  }
-  v_pts = kf * 0.001f;
-  track->rv_pts = v_pts;
-
-  return v_pts;
-}
-
-static void handle_realvideo(demuxer_t *demuxer, unsigned char *data,
-                             uint32_t size, bool keyframe, int &found_data) {
-  dp_hdr_t *hdr;
-  int chunks, isize;
-  mkv_demuxer_t *mkv_d;
-  demux_stream_t *ds;
-  demux_packet_t *dp;
-
-  mkv_d = (mkv_demuxer_t *)demuxer->priv;
-  ds = demuxer->video;
-  chunks = data[0];
-  isize = size - 1 - (chunks + 1) * 8;
-  dp = new_demux_packet(sizeof(dp_hdr_t) + isize + 8 * (chunks + 1));
-  memcpy(&dp->buffer[sizeof(dp_hdr_t)], &data[1 + (chunks + 1) * 8], isize);
-  memcpy(&dp->buffer[sizeof(dp_hdr_t) + isize], &data[1], (chunks + 1) * 8);
-  hdr = (dp_hdr_t *)dp->buffer;
-  hdr->len = isize;
-  hdr->chunks = chunks;
-  hdr->timestamp = (int)(mkv_d->last_pts * 1000);
-  hdr->chunktab = sizeof(dp_hdr_t) + isize;
-
-  dp->len = sizeof(dp_hdr_t) + isize + 8 * (chunks + 1);
-  if (mkv_d->v_skip_to_keyframe) {
-    dp->pts = mkv_d->last_pts;
-    mkv_d->video->rv_kf_base = 0;
-    mkv_d->video->rv_kf_pts = hdr->timestamp;
-  } else
-    dp->pts = real_fix_timestamp(mkv_d->video, &dp->buffer[sizeof(dp_hdr_t)],
-                                 hdr->timestamp);
-  dp->pos = demuxer->filepos;
-  dp->flags = keyframe ? 0x10 : 0;
-
-  ds_add_packet(ds, dp);
-
-  found_data++;
-}
-
-static void handle_realaudio(demuxer_t *demuxer, unsigned char *data,
-                             uint32_t size, bool keyframe, int &found_data) {
-  mkv_demuxer_t *mkv_d;
-  demux_packet_t *dp;
-
-  mkv_d = (mkv_demuxer_t *)demuxer->priv;
-
-  dp = new_demux_packet(size);
-  memcpy(dp->buffer, data, size);
-  if ((mkv_d->audio->ra_pts == mkv_d->last_pts) &&
-      !mkv_d->a_skip_to_keyframe)
-    dp->pts = 0;
-  else
-    dp->pts = mkv_d->last_pts;
-  mkv_d->audio->ra_pts = mkv_d->last_pts;
-
-  dp->pos = demuxer->filepos;
-  dp->flags = keyframe ? 0x10 : 0;
-
-  ds_add_packet(demuxer->audio, dp);
-
-  found_data++;
-}
-
-extern "C" int demux_mkv_fill_buffer(demuxer_t *d) {
-  demux_packet_t *dp;
-  demux_stream_t *ds;
-  mkv_demuxer_t *mkv_d;
-  mkv_track_t *t = NULL;
-  int upper_lvl_el, exit_loop, found_data, i, linei, sl;
-  char *texttmp;
-  // Elements for different levels
-  EbmlElement *l0 = NULL, *l1 = NULL, *l2 = NULL, *l3 = NULL;
-  EbmlStream *es;
-  KaxBlock *block;
-  int64_t block_duration, block_bref, block_fref;
-  bool use_this_block, lines_cut;
-  float current_pts;
-
-  mkv_d = (mkv_demuxer_t *)d->priv;
-  es = mkv_d->es;
-  l0 = mkv_d->segment;
-
-  // End of stream
-  if (mkv_d->saved_l1 == NULL)
-    return 0;
-
-  exit_loop = 0;
-  upper_lvl_el = 0;
-  l1 = mkv_d->saved_l1;
-  mkv_d->saved_l1 = NULL;
-  found_data = 0;
-  try {
-    // The idea is not to handle a complete KaxCluster with each call to
-    // demux_mkv_fill_buffer because those might be rather big.
-    while ((l1 != NULL) && (upper_lvl_el <= 0)) {
-
-      if (EbmlId(*l1) == KaxCluster::ClassInfos.GlobalId) {
-        mkv_d->cluster = (KaxCluster *)l1;
-        if (found_data) {
-          mkv_d->saved_l1 = l1;
-          break;
-        }
-
-        if (mkv_d->saved_l2 != NULL) {
-          l2 = mkv_d->saved_l2;
-          mkv_d->saved_l2 = NULL;
-        } else
-          l2 = es->FindNextElement(l1->Generic().Context, upper_lvl_el,
-                                   0xFFFFFFFFL, true, 1);
-        while ((l2 != NULL) && (upper_lvl_el <= 0)) {
-
-          // Handle at least one data packets in one call to
-          // demux_mkv_fill_buffer - but abort if we have found that.
-          if (found_data >= 1) {
-            mkv_d->saved_l2 = l2;
-            mkv_d->saved_l1 = l1;
-            exit_loop = 1;
-            break;
-          }
-
-          if (EbmlId(*l2) == KaxClusterTimecode::ClassInfos.GlobalId) {
-            KaxClusterTimecode &ctc = *static_cast<KaxClusterTimecode *>(l2);
-            ctc.ReadData(es->I_O());
-            mkv_d->cluster_tc = uint64(ctc);
-#if LIBEBML_VERSION >= 000404
-            mkv_d->cluster->InitTimecode(mkv_d->cluster_tc, mkv_d->tc_scale);
-#else
-            mkv_d->cluster->InitTimecode(mkv_d->cluster_tc);
-#endif // LIBEBML_VERSION
-
-          } else if (EbmlId(*l2) == KaxBlockGroup::ClassInfos.GlobalId) {
-
-            KaxBlockDuration *kbdur;
-            KaxReferenceBlock *krefblock;
-            KaxBlock *kblock;
-
-            block = NULL;
-            block_duration = -1;
-            block_bref = 0;
-            block_fref = 0;
-
-            l2->Read(*es, KaxBlockGroup::ClassInfos.Context, upper_lvl_el, l3,
-                     true);
-
-            kbdur = FINDFIRST(l2, KaxBlockDuration);
-            if (kbdur != NULL)
-              block_duration = uint64(*kbdur);
-
-            kblock = FINDFIRST(l2, KaxBlock);
-            if (kblock != NULL) {
-              kblock->SetParent(*mkv_d->cluster);
-              if ((mkv_d->stop_timecode > 0) &&
-                  ((kblock->GlobalTimecode() / 1000000 - mkv_d->first_tc) >=
-                   mkv_d->stop_timecode)) {
-                delete l2;
-                return 0;
-              }
-            }
-
-            krefblock = FINDFIRST(l2, KaxReferenceBlock);
-            while (krefblock != NULL) {
-              if (int64(*krefblock) < 0)
-                block_bref = int64(*krefblock);
-              else
-                block_fref = int64(*krefblock);
-
-              krefblock = FINDNEXT(l2, KaxReferenceBlock, krefblock);
-            }
-
-            if (kblock != NULL) {
-              // Clear the subtitles if they're obsolete now.
-              lines_cut = false;
-              for (linei = 0; linei < mkv_d->subs.lines; linei++) {
-                if (mkv_d->clear_subs_at[linei] <=
-                    (kblock->GlobalTimecode() / 1000000 - mkv_d->first_tc)) {
-                  sl = linei; 
-                  texttmp = mkv_d->subs.text[sl];
-                  while (sl < mkv_d->subs.lines) {
-                    mkv_d->subs.text[sl] = mkv_d->subs.text[sl + 1];
-                    mkv_d->clear_subs_at[sl] = mkv_d->clear_subs_at[sl + 1];
-                    sl++;
-                  }
-                  mkv_d->subs.text[sl] = texttmp;
-                  mkv_d->subs.lines--;
-                  linei--;
-                  lines_cut = true;
-                }
-                if (lines_cut) {
-                  vo_sub = &mkv_d->subs;
-                  vo_osd_changed(OSDTYPE_SUBTITLE);
-                }
-              }
-
-              ds = NULL;
-              if ((mkv_d->video != NULL) &&
-                  (mkv_d->video->tnum == kblock->TrackNum())) {
-                ds = d->video;
-                t = mkv_d->video;
-              } else if ((mkv_d->audio != NULL) && 
-                         (mkv_d->audio->tnum == kblock->TrackNum())) {
-                ds = d->audio;
-                t = mkv_d->audio;
-              } else if ((mkv_d->subs_track != NULL) && 
-                         (mkv_d->subs_track->tnum == kblock->TrackNum())) {
-                ds = d->sub;
-                t = mkv_d->subs_track;
-              }
-
-              use_this_block = true;
-
-              current_pts = (float)(kblock->GlobalTimecode() / 1000000.0 -
-                                    mkv_d->first_tc) / 1000.0;
-              if (current_pts < 0.0)
-                current_pts = 0.0;
-
-              if (ds == d->audio) {
-                if (mkv_d->a_skip_to_keyframe &&       
-                    (block_bref != 0))
-                  use_this_block = false;
-                
-                else if (mkv_d->v_skip_to_keyframe)
-                  use_this_block = false;
-
-                if (mkv_d->audio->fix_i_bps && use_this_block) {
-                  uint32_t i, sum;
-                  sh_audio_t *sh;
-
-                  for (i = 0, sum = 0; i < kblock->NumberFrames(); i++) {
-                    DataBuffer &data = kblock->GetBuffer(i);
-                    sum += data.Size();
-                  }
-                  sh = (sh_audio_t *)ds->sh;
-                  if (block_duration != -1) {
-                    sh->i_bps = sum * 1000 / block_duration;
-                    mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Changed i_bps to %d.\n",
-                           sh->i_bps);
-                    mkv_d->audio->fix_i_bps = false;
-                  } else if (mkv_d->audio->qt_last_a_pts == 0.0)
-                    mkv_d->audio->qt_last_a_pts = current_pts;
-                  else if (mkv_d->audio->qt_last_a_pts != current_pts) {
-                    sh->i_bps = (int)(sum / (current_pts -
-                                             mkv_d->audio->qt_last_a_pts));
-                    mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Changed i_bps to %d.\n",
-                           sh->i_bps);
-                    mkv_d->audio->fix_i_bps = false;
-                  }
-                }
-
-              } else if ((current_pts * 1000) < mkv_d->skip_to_timecode)
-                use_this_block = false;
-
-              else if (ds == d->video) {
-                if (mkv_d->v_skip_to_keyframe &&
-                    (block_bref != 0))
-                  use_this_block = false;
-                
-              } else if ((mkv_d->subs_track != NULL) &&
-                         (mkv_d->subs_track->tnum == kblock->TrackNum())) {
-                if (mkv_d->subtitle_type != MKV_SUBTYPE_VOBSUB) {
-                  if (!mkv_d->v_skip_to_keyframe)
-                    handle_subtitles(d, kblock, block_duration);
-                  use_this_block = false;
-                }
-
-              } else
-                use_this_block = false;
-
-              if (use_this_block) {
-                mkv_d->last_pts = current_pts;
-                ds->pts = current_pts;
-                d->filepos = mkv_d->in->getFilePointer();
-                mkv_d->last_filepos = d->filepos;
-
-                for (i = 0; i < (int)kblock->NumberFrames(); i++) {
-                  unsigned char *re_buffer;
-                  uint32_t re_size;
-                  bool re_modified;
-                  DataBuffer &data = kblock->GetBuffer(i);
-
-                  re_buffer = data.Buffer();
-                  re_size = data.Size();
-                  re_modified = reverse_encodings(t, re_buffer, re_size, 1);
-
-                  if ((ds == d->video) && mkv_d->video->realmedia)
-                    handle_realvideo(d, re_buffer, re_size, block_bref == 0,
-                                     found_data);
-
-                  else if ((ds == d->audio) && mkv_d->audio->realmedia)
-                    handle_realaudio(d, re_buffer, re_size, block_bref == 0,
-                                     found_data);
-
-                  else {
-                    dp = new_demux_packet(re_size);
-                    memcpy(dp->buffer, re_buffer, re_size);
-                    dp->flags = block_bref == 0 ? 1 : 0;
-                    dp->pts = mkv_d->last_pts + i * t->default_duration;
-                    ds_add_packet(ds, dp);
-                    found_data++;
-                  }
-                  if (re_modified)
-                    safefree(re_buffer);
-                }
-                if (ds == d->video) {
-                  mkv_d->v_skip_to_keyframe = false;
-                  mkv_d->skip_to_timecode = 0;
-                } else if (ds == d->audio)
-                  mkv_d->a_skip_to_keyframe = false;
-              }
-
-              delete block;
-            } // kblock != NULL
-
-          } else
-            l2->SkipData(*es, l2->Generic().Context);
-
-          if (!in_parent(l1)) {
-            delete l2;
-            break;
-          }
-
-          if (upper_lvl_el > 0) {
-            upper_lvl_el--;
-            if (upper_lvl_el > 0)
-              break;
-            delete l2;
-            l2 = l3;
-            continue;
-
-          } else if (upper_lvl_el < 0) {
-            upper_lvl_el++;
-            if (upper_lvl_el < 0)
-              break;
-
-          }
-
-          l2->SkipData(*es, l2->Generic().Context);
-          delete l2;
-          l2 = es->FindNextElement(l1->Generic().Context, upper_lvl_el,
-                                   0xFFFFFFFFL, true);
-
-        } // while (l2 != NULL)
-
-      } else if (EbmlId(*l1) == KaxCues::ClassInfos.GlobalId)
-        return 0;
-      else
-        l1->SkipData(*es, l1->Generic().Context);
-
-      if (!in_parent(l0)) {
-        delete l1;
-        break;
-      }
-
-      if (upper_lvl_el > 0) {
-        upper_lvl_el--;
-        if (upper_lvl_el > 0)
-          break;
-        delete l1;
-        l1 = l2;
-        continue;
-
-      } else if (upper_lvl_el < 0) {
-        upper_lvl_el++;
-        if (upper_lvl_el < 0)
-          break;
-
-      }
-
-      if (exit_loop)
-        break;
-
-      l1->SkipData(*es, l1->Generic().Context);
-      delete l1;
-      l1 = es->FindNextElement(l0->Generic().Context, upper_lvl_el,
-                               0xFFFFFFFFL, true);
-
-    } // while (l1 != NULL)
-  } catch (exception ex) {
-    mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] exception caught\n");
-    return 0;
-  }
-
-  if (found_data)
-    return 1;
-
-  return 0;
-}
-
-extern "C" void resync_audio_stream(sh_audio_t *sh_audio);
-
-extern "C" void demux_mkv_seek(demuxer_t *demuxer, float rel_seek_secs,
-                               int flags) {
-  int i, k, upper_lvl_el;
-  mkv_demuxer_t *mkv_d = (mkv_demuxer_t *)demuxer->priv;
-  int64_t target_timecode, target_filepos = 0, min_diff, diff, current_pos;
-  int64_t cluster_pos;
-  mkv_track_index_t *index;
-  mkv_index_entry_t *entry;
-  EbmlElement *l1;
-
-  mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] SEEK, relss: %.3f, flags: %d\n",
-         rel_seek_secs, flags);
-
-  if (!mkv_d->cues_found && !mkv_d->cues_searched) {
-    // We've not found an index so far. So let's skip over all level 1
-    // elements until we either hit another segment, the end of the file
-    // or - suprise - some cues.
-    current_pos = mkv_d->in->getFilePointer();
-
-    // Skip the data but do not delete the element! This is our current
-    // cluster, and we need it later on in demux_mkv_fill_buffer.
-    l1 = mkv_d->saved_l1;
-    l1->SkipData(static_cast<EbmlStream &>(*mkv_d->es), l1->Generic().Context);
-    l1 = mkv_d->es->FindNextElement(mkv_d->segment->Generic().Context,
-                                    upper_lvl_el, 0xFFFFFFFFL, true, 1);
-    while (l1 != NULL) {
-      if (upper_lvl_el)
-        break;
-
-      if (EbmlId(*l1) == KaxCues::ClassInfos.GlobalId) {
-        parse_cues(mkv_d, l1->GetElementPosition());
-        delete l1;
-        break;
-      } else {
-        if (EbmlId(*l1) == KaxCluster::ClassInfos.GlobalId)
-          add_cluster_position(mkv_d, l1->GetElementPosition());
-        l1->SkipData(static_cast<EbmlStream &>(*mkv_d->es),
-                     l1->Generic().Context);
-        delete l1;
-        l1 = mkv_d->es->FindNextElement(mkv_d->segment->Generic().Context,
-                                        upper_lvl_el, 0xFFFFFFFFL, true, 1);
-      }
-    }
-
-    if (demuxer->stream->eof)
-      stream_reset(demuxer->stream);
-    mkv_d->in->setFilePointer(current_pos);
-
-    mkv_d->cues_searched = 1;
-  }
-
-  if (!(flags & 2)) {           // Time in secs
-    if (flags & 1)              // Absolute seek
-      target_timecode = 0;
-    else                        // Relative seek
-      target_timecode = (int64_t)(mkv_d->last_pts * 1000.0);
-    target_timecode += (int64_t)(rel_seek_secs * 1000.0);
-    if (target_timecode < 0)
-      target_timecode = 0;
-
-    min_diff = 0xFFFFFFFL;
-
-    // Let's find the entry in the index with the smallest difference
-    // to the wanted timecode.
-    entry = NULL;
-    for (i = 0; i < mkv_d->num_indexes; i++)
-      if (mkv_d->index[i].tnum == mkv_d->video->tnum) {
-        index = &mkv_d->index[i];
-        for (k = 0; k < index->num_entries; k++) {
-          if (!index->entries[k].is_key)
-            continue;
-          diff = target_timecode - (int64_t)index->entries[k].timecode;
-          if (((flags & 1) || (target_timecode <= (mkv_d->last_pts * 1000))) &&
-              (diff >= 0) && (diff < min_diff)) {
-            min_diff = diff;
-            entry = &index->entries[k];
-            mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] seek BACK, solution: last_pts: "
-                   "%d, target: %d, diff: %d, entry->timecode: %d, PREV diff: "
-                   "%d, k: %d\n", (int)(mkv_d->last_pts * 1000),
-                   (int)target_timecode, (int)diff, (int)entry->timecode,
-                   k > 0 ? (int)(index->entries[k - 1].timecode -
-                                 target_timecode) : 0, k);
-                   
-          } else if ((target_timecode > (mkv_d->last_pts * 1000)) &&
-                     (diff < 0) && (-diff < min_diff)) {
-            min_diff = -diff;
-            entry = &index->entries[k];
-            mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] seek FORW, solution: last_pts: "
-                   "%d, target: %d, diff: %d, entry->timecode: %d, NEXT diff: "
-                   "%d, k: %d\n", (int)(mkv_d->last_pts * 1000),
-                   (int)target_timecode, (int)diff, (int)entry->timecode,
-                   k < index->num_entries ?
-                   (int)(index->entries[k + 1].timecode - target_timecode) :
-                   0, k);
-          }
-        }
-        break;
-      }
-
-    if (mkv_d->saved_l1 != NULL)
-      delete mkv_d->saved_l1;
-
-    if (mkv_d->saved_l2 != NULL) {
-      delete mkv_d->saved_l2;
-      mkv_d->saved_l2 = NULL;
-    }
-
-    if (entry != NULL) {        // We've found an entry.
-      mkv_d->in->setFilePointer(entry->filepos);
-      upper_lvl_el = 0;
-      mkv_d->saved_l1 =
-        mkv_d->es->FindNextElement(mkv_d->segment->Generic().Context,
-                                   upper_lvl_el, 0xFFFFFFFFL, true, 1);
-    } else {                    // We've not found an entry --> no index?
-      target_filepos = (int64_t)(target_timecode * mkv_d->last_filepos /
-        (mkv_d->last_pts * 1000.0));
-      mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] No index entry found. Calculated "
-             "filepos %lld. Old timecode %lld.\n", target_filepos,
-             (int64_t)(mkv_d->last_pts * 1000.0));
-      // Let's find the nearest cluster so that libebml does not have to
-      // do so much work.
-      cluster_pos = 0;
-      min_diff = 0x0FFFFFFFL;
-      for (i = 0; i < mkv_d->num_cluster_pos; i++) {
-        diff = mkv_d->cluster_positions[i] - target_filepos;
-        if (rel_seek_secs < 0) {
-          if ((diff > 0) && (diff < min_diff)) {
-            cluster_pos = mkv_d->cluster_positions[i];
-            min_diff = diff;
-          }
-        } else if ((diff < 0 ? -1 * diff : diff) < min_diff) {
-          cluster_pos = mkv_d->cluster_positions[i];
-          min_diff = diff < 0 ? -1 * diff : diff;
-        }
-      }
-      if (min_diff != 0x0FFFFFFFL) {
-        target_filepos = cluster_pos;
-        mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] New target_filepos because of "
-               "cluster: %lld.\n", target_filepos);
-      }
-      if (target_filepos >= demuxer->movi_end)
-        return;
-      mkv_d->in->setFilePointer(target_filepos);
-      upper_lvl_el = 0;
-      mkv_d->saved_l1 =
-        mkv_d->es->FindNextElement(mkv_d->segment->Generic().Context,
-                                   upper_lvl_el, 0xFFFFFFFFL, true, 1);
-      mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] seek result: target_timecode %lld, "
-             "did not find an entry. Calculated target_filspos: %lld\n",
-             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" :
-             mkv_d->saved_l1->Generic().DebugName);
-    }
-
-    if (mkv_d->video != NULL)
-      mkv_d->v_skip_to_keyframe = true;
-    if (rel_seek_secs > 0.0)
-      mkv_d->skip_to_timecode = target_timecode;
-
-    mkv_d->a_skip_to_keyframe = true;
-
-    demux_mkv_fill_buffer(demuxer);
-    mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] New timecode: %lld\n",
-           (int64_t)(mkv_d->last_pts * 1000.0));
-
-    mkv_d->subs.lines = 0;
-    vo_sub = &mkv_d->subs;
-    vo_osd_changed(OSDTYPE_SUBTITLE);
-
-    if(demuxer->audio->sh != NULL)
-      resync_audio_stream((sh_audio_t *)demuxer->audio->sh); 
-
-  } else
-    mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] seek unsupported flags\n");
-
-}
-
-extern "C" void demux_close_mkv(demuxer_t *demuxer) {
-  mkv_demuxer_t *mkv_d = (mkv_demuxer_t *)demuxer->priv;
-
-  free_mkv_demuxer(mkv_d);
-
-#ifdef USE_ICONV
-  subcp_close();
-#endif
-}
-
-extern "C" int demux_mkv_control(demuxer_t *demuxer, int cmd, void *arg) {
-  mkv_demuxer_t *mkv_d = (mkv_demuxer_t *)demuxer->priv;
-  
-  switch (cmd) {
-    case DEMUXER_CTRL_GET_TIME_LENGTH:
-      if (mkv_d->duration == -1.0)
-        return DEMUXER_CTRL_DONTKNOW;
-
-      *((unsigned long *)arg) = (unsigned long)mkv_d->duration;
-      return DEMUXER_CTRL_OK;
-
-    case DEMUXER_CTRL_GET_PERCENT_POS:
-      if (mkv_d->duration == -1.0) {
-        if (demuxer->movi_start == demuxer->movi_end)
-          return DEMUXER_CTRL_DONTKNOW;
-
-        *((int *)arg) =
-          (int)((demuxer->filepos - demuxer->movi_start) /
-                ((demuxer->movi_end - demuxer->movi_start) / 100));
-        return DEMUXER_CTRL_OK;
-      }
-
-      *((int *)arg) = (int)(100 * mkv_d->last_pts / mkv_d->duration);
-      return DEMUXER_CTRL_OK; 
-
-    default:
-      return DEMUXER_CTRL_NOTIMPL;
-  }
-}
-
-#endif /* HAVE_MATROSKA */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmpdemux/demux_mkv_old.cpp	Fri Jan 23 21:34:28 2004 +0000
@@ -0,0 +1,3182 @@
+// Matroska demuxer
+// written by Moritz Bunkus <moritz@bunkus.org>
+// License: GPL of course ;)
+
+// $Id$
+
+extern "C" {
+#include "config.h"
+}
+
+#ifdef HAVE_MATROSKA
+
+#include <vector>
+
+#include <ebml/EbmlHead.h>
+#include <ebml/EbmlSubHead.h>
+#include <ebml/EbmlStream.h>
+#include <ebml/EbmlContexts.h>
+#include <ebml/EbmlVersion.h>
+#include <ebml/StdIOCallback.h>
+
+#include <matroska/KaxVersion.h>
+
+#include <matroska/KaxAttachments.h>
+#include <matroska/KaxBlock.h>
+#include <matroska/KaxBlockData.h>
+#include <matroska/KaxChapters.h>
+#include <matroska/KaxCluster.h>
+#include <matroska/KaxClusterData.h>
+#if LIBMATROSKA_VERSION >= 000503
+#include <matroska/KaxContentEncoding.h>
+#endif
+#include <matroska/KaxContexts.h>
+#include <matroska/KaxCues.h>
+#include <matroska/KaxCuesData.h>
+#include <matroska/KaxInfo.h>
+#include <matroska/KaxInfoData.h>
+#include <matroska/KaxSeekHead.h>
+#include <matroska/KaxSegment.h>
+#include <matroska/KaxTracks.h>
+#include <matroska/KaxTrackAudio.h>
+#include <matroska/KaxTrackVideo.h>
+#include <matroska/KaxTrackEntryData.h>
+#include <matroska/FileKax.h>
+
+extern "C" {
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_ZLIB
+#include <zlib.h>
+#endif
+
+#include "../mp_msg.h"
+#include "../help_mp.h"
+#include "stream.h"
+#include "demuxer.h"
+#include "stheader.h"
+
+#include "../subreader.h"
+#include "../libvo/sub.h"
+
+}
+
+#include "matroska.h"
+
+using namespace libebml;
+using namespace libmatroska;
+using namespace std;
+
+#if LIBEBML_VERSION < 000500
+#error libebml version too old - need at least 0.5.0
+#endif
+
+// for e.g. "-slang ger"
+extern char *dvdsub_lang;
+extern char *audio_lang;
+// for "-chapter x-y"
+extern int dvd_chapter;
+extern int dvd_last_chapter;
+
+// default values for Matroska elements
+#define MKVD_TIMECODESCALE 1000000 // 1000000 = 1ms
+
+#define MKV_SUBTYPE_TEXT                  1
+#define MKV_SUBTYPE_SSA                   2
+#define MKV_SUBTYPE_VOBSUB                3
+
+#define MKV_SUBCOMPRESSION_NONE           0
+#define MKV_SUBCOMPRESSION_ZLIB           1
+
+#define safefree(m) { if (m != NULL) free(m); }
+void *safemalloc(int bytes) {
+  void *dst;
+
+  dst = malloc(bytes);
+  if (dst == NULL) {
+    mp_msg(MSGT_DEMUX, MSGL_FATAL, "[mkv] Could not allocate %d bytes of "
+          "memory.\n", bytes);
+    exit(1);
+  }
+
+  return dst;
+}
+
+void *safememdup(const void *src, int bytes) {
+  void *dst;
+
+  dst = safemalloc(bytes);
+  memcpy(dst, src, bytes);
+
+  return dst;
+}
+
+class mpstream_io_callback: public IOCallback {
+  private:
+    stream_t *s;
+  public:
+    mpstream_io_callback(stream_t *stream);
+
+    virtual uint32 read(void *buffer, size_t size);
+    virtual void setFilePointer(int64 offset, seek_mode mode = seek_beginning);
+    virtual size_t write(const void *buffer, size_t size);
+    virtual uint64 getFilePointer();
+    virtual void close();
+};
+
+mpstream_io_callback::mpstream_io_callback(stream_t *stream) {
+  s = stream;
+}
+
+uint32 mpstream_io_callback::read(void *buffer, size_t size) {
+  uint32_t result;
+
+  result = stream_read(s, (char *)buffer, size);
+
+  return result;
+}
+
+void mpstream_io_callback::setFilePointer(int64 offset, seek_mode mode) {
+  int64 new_pos;
+  
+  if (mode == seek_beginning)
+    new_pos = offset + s->start_pos;
+  else if (mode == seek_end)
+    new_pos = s->end_pos - offset;
+  else
+    new_pos = s->pos + offset;
+
+  if (new_pos > s->end_pos) {
+    mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] seek warning: new_pos %lld > end_pos "
+           "%lld\n", new_pos, s->end_pos);
+    return;
+  }
+
+  stream_seek(s, new_pos);
+}
+
+size_t mpstream_io_callback::write(const void */*buffer*/, size_t /*size*/) {
+  return 0;
+}
+
+uint64 mpstream_io_callback::getFilePointer() {
+  return s->pos - s->buf_len + s->buf_pos;
+}
+
+void mpstream_io_callback::close() {
+}
+
+typedef struct mkv_index_entry {
+  uint64_t timecode, filepos;
+  int is_key;
+} mkv_index_entry_t;
+
+typedef struct mkv_track_index {
+  uint32_t tnum;
+  int num_entries;
+  mkv_index_entry_t *entries;
+} mkv_track_index_t;
+
+typedef struct {
+  uint32_t order, type, scope;
+  uint32_t comp_algo;
+  unsigned char *comp_settings;
+  uint32_t comp_settings_len;
+  uint32_t enc_algo, sig_algo, sig_hash_algo;
+  unsigned char *enc_keyid, *sig_keyid, *signature;
+  uint32_t enc_keyid_len, sig_keyid_len, signature_len;
+} mkv_content_encoding_t;
+
+typedef struct {
+  int64_t start, end;
+} mkv_chapter_t;
+
+typedef struct mkv_track {
+  uint32_t tnum, xid;
+  
+  char *codec_id;
+  int ms_compat;
+  char *language;
+
+  char type; // 'v' = video, 'a' = audio, 's' = subs
+  
+  char v_fourcc[5];
+  uint32_t v_width, v_height, v_dwidth, v_dheight;
+  float v_frate;
+
+  uint32_t a_formattag;
+  uint32_t a_channels, a_bps;
+  float a_sfreq;
+
+  float default_duration;
+
+  int default_track;
+
+  void *private_data;
+  unsigned int private_size;
+
+  // For Vorbis audio
+  unsigned char *headers[3];
+  uint32_t header_sizes[3];
+
+  int ok;
+
+  // Stuff for RealMedia
+  bool realmedia;
+  demux_packet_t *rm_dp;
+  int rm_seqnum, rv_kf_base, rv_kf_pts;
+  float rv_pts;                 // previous video timestamp
+  float ra_pts;                 // previous audio timestamp
+
+  // Stuff for QuickTime
+  bool fix_i_bps;
+  float qt_last_a_pts;
+
+  // Stuff for VobSubs
+  mkv_sh_sub_t sh_sub;
+
+  // Generic content encoding support.
+  vector<mkv_content_encoding_t> *c_encodings;
+} mkv_track_t;
+
+typedef struct mkv_demuxer {
+  float duration, last_pts;
+  uint64_t last_filepos;
+
+  mkv_track_t **tracks;
+  int num_tracks;
+  mkv_track_t *video, *audio, *subs_track;
+
+  uint64_t tc_scale, cluster_tc, first_tc;
+
+  mpstream_io_callback *in;
+
+  uint64_t clear_subs_at[SUB_MAX_TEXT];
+
+  subtitle subs;
+  int subtitle_type;
+
+  EbmlStream *es;
+  EbmlElement *saved_l1, *saved_l2;
+  KaxSegment *segment;
+  KaxCluster *cluster;
+
+  mkv_track_index_t *index;
+  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;
+
+  vector<mkv_chapter_t> *chapters; // No support for nested chapters atm.
+  uint64_t stop_timecode;
+} mkv_demuxer_t;
+
+typedef struct {
+  uint32_t chunks;              // number of chunks
+  uint32_t timestamp;           // timestamp from packet header
+  uint32_t len;                 // length of actual data
+  uint32_t chunktab;            // offset to chunk offset array
+} dp_hdr_t;
+
+#if __GNUC__ == 2
+#pragma pack(2)
+#else
+#pragma pack(push,2)
+#endif
+
+typedef struct {
+  uint32_t size;
+  uint32_t fourcc1;
+  uint32_t fourcc2;
+  uint16_t width;
+  uint16_t height;
+  uint16_t bpp;
+  uint32_t unknown1;
+  uint32_t fps;
+  uint32_t type1;
+  uint32_t type2;
+} real_video_props_t;
+
+typedef struct {
+  uint32_t fourcc1;             // '.', 'r', 'a', 0xfd
+  uint16_t version1;            // 4 or 5
+  uint16_t unknown1;            // 00 000
+  uint32_t fourcc2;             // .ra4 or .ra5
+  uint32_t unknown2;            // ???
+  uint16_t version2;            // 4 or 5
+  uint32_t header_size;         // == 0x4e
+  uint16_t flavor;              // codec flavor id
+  uint32_t coded_frame_size;    // coded frame size
+  uint32_t unknown3;            // big number
+  uint32_t unknown4;            // bigger number
+  uint32_t unknown5;            // yet another number
+  uint16_t sub_packet_h;
+  uint16_t frame_size;
+  uint16_t sub_packet_size;
+  uint16_t unknown6;            // 00 00
+  uint16_t sample_rate;
+  uint16_t unknown8;            // 0
+  uint16_t sample_size;
+  uint16_t channels;
+} real_audio_v4_props_t;
+
+typedef struct {
+  uint32_t fourcc1;             // '.', 'r', 'a', 0xfd
+  uint16_t version1;            // 4 or 5
+  uint16_t unknown1;            // 00 000
+  uint32_t fourcc2;             // .ra4 or .ra5
+  uint32_t unknown2;            // ???
+  uint16_t version2;            // 4 or 5
+  uint32_t header_size;         // == 0x4e
+  uint16_t flavor;              // codec flavor id
+  uint32_t coded_frame_size;    // coded frame size
+  uint32_t unknown3;            // big number
+  uint32_t unknown4;            // bigger number
+  uint32_t unknown5;            // yet another number
+  uint16_t sub_packet_h;
+  uint16_t frame_size;
+  uint16_t sub_packet_size;
+  uint16_t unknown6;            // 00 00
+  uint8_t unknown7[6];          // 0, srate, 0
+  uint16_t sample_rate;
+  uint16_t unknown8;            // 0
+  uint16_t sample_size;
+  uint16_t channels;
+  uint32_t genr;                // "genr"
+  uint32_t fourcc3;             // fourcc
+} real_audio_v5_props_t;
+
+// I have to (re)define this struct here because g++ will not compile
+// components.h from the qtsdk if I include it.
+typedef struct {
+  uint32_t id_size;
+  uint32_t codec_type;
+  uint32_t reserved1;
+  uint16_t reserved2;
+  uint16_t data_reference_index;
+  uint16_t version;
+  uint16_t revision;
+  uint32_t vendor;
+  uint32_t temporal_quality;
+  uint32_t spatial_quality;
+  uint16_t width;
+  uint16_t height;
+  uint32_t horizontal_resolution; // 32bit fixed-point number
+  uint32_t vertical_resolution; // 32bit fixed-point number
+  uint32_t data_size;
+  uint16_t frame_count;
+  char compressor_name[32];
+  uint16_t depth;
+  uint16_t color_table_id;
+} qt_image_description_t;
+
+#if __GNUC__ == 2
+#pragma pack()
+#else
+#pragma pack(pop)
+#endif
+
+static uint16_t get_uint16(const void *buf) {
+  uint16_t      ret;
+  unsigned char *tmp;
+
+  tmp = (unsigned char *) buf;
+
+  ret = tmp[1] & 0xff;
+  ret = (ret << 8) + (tmp[0] & 0xff);
+
+  return ret;
+}
+
+static uint32_t get_uint32(const void *buf) {
+  uint32_t      ret;
+  unsigned char *tmp;
+
+  tmp = (unsigned char *) buf;
+
+  ret = tmp[3] & 0xff;
+  ret = (ret << 8) + (tmp[2] & 0xff);
+  ret = (ret << 8) + (tmp[1] & 0xff);
+  ret = (ret << 8) + (tmp[0] & 0xff);
+
+  return ret;
+}
+
+static uint16_t get_uint16_be(const void *buf) {
+  uint16_t ret;
+  unsigned char *tmp;
+
+  tmp = (unsigned char *) buf;
+
+  ret = tmp[0] & 0xff;
+  ret = (ret << 8) + (tmp[1] & 0xff);
+
+  return ret;
+}
+
+static uint32_t get_uint32_be(const void *buf) {
+  uint32_t ret;
+  unsigned char *tmp;
+
+  tmp = (unsigned char *) buf;
+
+  ret = tmp[0] & 0xff;
+  ret = (ret << 8) + (tmp[1] & 0xff);
+  ret = (ret << 8) + (tmp[2] & 0xff);
+  ret = (ret << 8) + (tmp[3] & 0xff);
+
+  return ret;
+}
+
+unsigned char read_char(unsigned char *p, int &pos, int size) {
+  if ((pos + 1) > size)
+    throw exception();
+  pos++;
+  return p[pos - 1];
+}
+
+unsigned short read_word(unsigned char *p, int &pos, int size) {
+  unsigned short v;
+
+  if ((pos + 2) > size)
+    throw exception();
+  v = p[pos];
+  v = (v << 8) | (p[pos + 1] & 0xff);
+  pos += 2;
+  return v;
+}
+
+unsigned int read_dword(unsigned char *p, int &pos, int size) {
+  unsigned int v;
+
+  if ((pos + 4) > size)
+    throw exception();
+  v = p[pos];
+  v = (v << 8) | (p[pos + 1] & 0xff);
+  v = (v << 8) | (p[pos + 2] & 0xff);
+  v = (v << 8) | (p[pos + 3] & 0xff);
+  pos += 4;
+  return v;
+}
+
+static void
+finish_text_sub_handling(mkv_demuxer_t *mkv_d, KaxBlock *block,
+                         int64_t duration, int first_line) {
+  int i;
+
+#ifdef USE_ICONV
+  subcp_recode1(&mkv_d->subs);
+#endif
+
+  vo_sub = &mkv_d->subs;
+  vo_osd_changed(OSDTYPE_SUBTITLE);
+
+  for (i = first_line; i <= (mkv_d->subs.lines - 1); i++)
+    mkv_d->clear_subs_at[i] =  block->GlobalTimecode() / 1000000 -
+      mkv_d->first_tc + duration;
+}
+
+static void handle_subtitles(demuxer_t *d, KaxBlock *block, int64_t duration) {
+  mkv_demuxer_t *mkv_d = (mkv_demuxer_t *)d->priv;
+  int len, line, state, i, first_line;
+  char *s1, *s2, *buffer;
+
+  if (duration == -1) {
+    mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Warning: No KaxBlockDuration "
+           "element for subtitle track found.\n");
+    return;
+  }
+
+  DataBuffer &data = block->GetBuffer(0);
+  len = data.Size();
+
+  buffer = (char *)data.Buffer();
+  s1 = buffer;
+
+  while (((*s1 == '\n') || (*s1 == '\r')) &&
+         ((unsigned int)(s1 - buffer) <= data.Size()))
+    s1++;
+
+  line = 0;
+  mkv_d->subs.lines++;
+  if (mkv_d->subs.lines > SUB_MAX_TEXT) {
+  	mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Warning: too many sublines to "
+           "render, skipping\n");
+  	mkv_d->subs.lines = SUB_MAX_TEXT;
+  	return;
+  }
+  first_line = mkv_d->subs.lines - 1;
+  s2 = mkv_d->subs.text[mkv_d->subs.lines - 1];
+  state = 0;
+
+  if (mkv_d->subtitle_type == MKV_SUBTYPE_SSA) {
+    /* Matroska's SSA format does not have timecodes embedded into 
+       the SAA line. Timescodes are encoded into the blocks timecode
+       and duration. */
+
+    /* Find text section. */
+    for (i = 0; (i < 8) && (*s1 != 0); s1++)
+      if (*s1 == ',')
+        i++;
+
+    if (*s1 == 0) {             // Broken line?
+      mkv_d->subs.lines--;
+      return;
+    }
+
+    /* Load text. */
+    while ((unsigned int)(s1 - buffer) < data.Size()) {
+      if (*s1 == '{')
+        state = 1;
+      else if ((*s1 == '}') && (state == 1))
+        state = 2;
+
+      if (state == 0) {
+        *s2 = *s1;
+        s2++;
+        if ((s2 - mkv_d->subs.text[mkv_d->subs.lines - 1]) >= 255)
+          break;
+      }
+      s1++;
+      
+      /* Newline */
+      if ((*s1 == '\\') && ((unsigned int)(s1 + 1 - buffer) < data.Size()) &&
+          ((*(s1 + 1) == 'N') || (*(s1 + 1) == 'n'))) {
+        *s2 = 0;
+        mkv_d->subs.lines++;
+        if (mkv_d->subs.lines > SUB_MAX_TEXT) {
+          mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Warning: too many sublines to "
+                 "render, skipping\n");
+          mkv_d->subs.lines = SUB_MAX_TEXT;
+          finish_text_sub_handling(mkv_d, block, duration, first_line);
+          return;
+        }
+        s2 = mkv_d->subs.text[mkv_d->subs.lines - 1];
+        s1 += 2;
+      }
+
+      if (state == 2)
+        state = 0;
+    }
+    *s2 = 0;
+
+  } else {
+    while ((unsigned int)(s1 - buffer) != data.Size()) {
+      if ((*s1 == '\n') || (*s1 == '\r')) {
+        if (state == 0) {       // normal char --> newline
+          if (mkv_d->subs.lines == SUB_MAX_TEXT)
+            break;
+          *s2 = 0;
+          mkv_d->clear_subs_at[mkv_d->subs.lines - 1]= 
+            block->GlobalTimecode() / 1000000 - mkv_d->first_tc + duration;
+          s2 = mkv_d->subs.text[mkv_d->subs.lines];
+          mkv_d->subs.lines++;
+          state = 1;
+        }
+      } else if (*s1 == '<')    // skip HTML tags
+        state = 2;
+      else if (*s1 == '>')
+        state = 0;
+      else if (state != 2) {      // normal character
+        state = 0;
+        if ((s2 - mkv_d->subs.text[mkv_d->subs.lines - 1]) < 255) {
+          *s2 = *s1;
+          s2++;
+        }
+      }
+      s1++;
+    }
+
+    *s2 = 0;
+  }
+
+  finish_text_sub_handling(mkv_d, block, duration, first_line);
+}
+
+static mkv_track_t *new_mkv_track(mkv_demuxer_t *d) {
+  mkv_track_t *t;
+  
+  t = (mkv_track_t *)safemalloc(sizeof(mkv_track_t));
+  memset(t, 0, sizeof(mkv_track_t));
+  d->tracks = (mkv_track_t **)realloc(d->tracks, (d->num_tracks + 1) *
+                                      sizeof(mkv_track_t *));
+  if (d->tracks == NULL)
+    return NULL;
+  d->tracks[d->num_tracks] = t;
+  d->num_tracks++;
+
+  // Set default values.
+  t->default_track = 1;
+  t->a_sfreq = 8000.0;
+  t->a_channels = 1;
+  t->language = strdup("eng");
+
+  t->c_encodings = new vector<mkv_content_encoding_t>;
+  
+  return t;
+}
+
+static mkv_track_t *find_track_by_num(mkv_demuxer_t *d, uint32_t n,
+                                      char track_type) {
+  int i;
+
+  for (i = 0; i < d->num_tracks; i++)
+    if ((d->tracks[i] != NULL) && (d->tracks[i]->type == track_type) &&
+        (d->tracks[i]->xid == n))
+      return d->tracks[i];
+  
+  return NULL;
+}
+
+static mkv_track_t *find_duplicate_track_by_num(mkv_demuxer_t *d, uint32_t n,
+                                                mkv_track_t *c) {
+  int i;
+  
+  for (i = 0; i < d->num_tracks; i++)
+    if ((d->tracks[i] != NULL) && (d->tracks[i]->tnum == n) &&
+        (d->tracks[i] != c))
+      return d->tracks[i];
+  
+  return NULL;
+}
+
+static mkv_track_t *find_track_by_language(mkv_demuxer_t *d, char *language,
+                                           mkv_track_t *c, char type = 's') {
+  int i;
+  
+  for (i = 0; i < d->num_tracks; i++)
+    if ((d->tracks[i] != NULL) && (d->tracks[i] != c) &&
+        (d->tracks[i]->language != NULL) &&
+        !strcmp(d->tracks[i]->language, language) &&
+        (d->tracks[i]->type == type))
+      return d->tracks[i];
+  
+  return NULL;
+}
+
+static bool mkv_parse_idx(mkv_track_t *t) {
+  uint32_t i, p, things_found;
+  int idx;
+  string line, s1, s2;
+  char *src;
+
+  if ((t->private_data == NULL) || (t->private_size < 1))
+    return false;
+
+  things_found = 0;
+  i = 0;
+  src = (char *)t->private_data;
+  do {
+    line = "";
+    while ((i < t->private_size) && (src[i] != '\n') && (src[i] != '\r')) {
+      if (!isspace(src[i]))
+        line += src[i];
+      i++;
+    }
+    while ((i < t->private_size) && ((src[i] == '\n') || (src[i] == '\r')))
+      i++;
+
+    if (!strncasecmp(line.c_str(), "size:", 5)) {
+      s1 = line.substr(5);
+      idx = s1.find('x');
+      if (idx >= 0) {
+        s2 = s1.substr(idx + 1);
+        s1.erase(idx);
+        t->sh_sub.width = strtol(s1.c_str(), NULL, 10);
+        t->sh_sub.height = strtol(s2.c_str(), NULL, 10);
+        things_found |= 1;
+        mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] VobSub IDX parser: size: %d x %d\n",
+               t->sh_sub.width, t->sh_sub.height);
+      }
+
+    } else if (!strncasecmp(line.c_str(), "palette:", 8)) {
+      s1 = line.substr(8);
+      for (p = 0; p < 15; p++) {
+        idx = s1.find(',');
+        if (idx < 0)
+          break;
+        s2 = s1.substr(0, idx);
+        s1.erase(0, idx + 1);
+        t->sh_sub.palette[p] = (unsigned int)strtol(s2.c_str(), NULL, 16);
+      }
+      if (idx >= 0) {
+        t->sh_sub.palette[15] = (unsigned int)strtol(s1.c_str(), NULL, 16);
+        things_found |= 2;
+        mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] VobSub IDX parser: palette: 0x%06x "
+               "0x%06x 0x%06x 0x%06x 0x%06x 0x%06x 0x%06x 0x%06x 0x%06x "
+               "0x%06x 0x%06x 0x%06x 0x%06x 0x%06x 0x%06x 0x%06x\n",
+               t->sh_sub.palette[0], t->sh_sub.palette[1],
+               t->sh_sub.palette[2], t->sh_sub.palette[3],
+               t->sh_sub.palette[4], t->sh_sub.palette[5],
+               t->sh_sub.palette[6], t->sh_sub.palette[7],
+               t->sh_sub.palette[8], t->sh_sub.palette[9],
+               t->sh_sub.palette[10], t->sh_sub.palette[11],
+               t->sh_sub.palette[12], t->sh_sub.palette[13],
+               t->sh_sub.palette[14], t->sh_sub.palette[15]);
+      }
+    }
+
+  } while ((i != t->private_size) && (things_found != 3));
+  t->sh_sub.type = 'v';
+
+  return (things_found == 3);
+}
+
+static bool reverse_encodings(mkv_track_t *track, unsigned char *&data,
+                              uint32_t &size, uint32_t type) {
+  int new_size, n;
+  unsigned char *new_data, *old_data;
+  bool modified;
+  vector<mkv_content_encoding_t>::iterator ce;
+
+  if (track->c_encodings->size() == 0)
+    return false;
+
+  new_data = data;
+  new_size = size;
+  modified = false;
+  for (ce = track->c_encodings->begin(); ce < track->c_encodings->end();
+       ce++) {
+    if ((ce->scope & type) == 0)
+      continue;
+
+#ifdef HAVE_ZLIB
+    if (ce->comp_algo == 0) {
+      int result;
+      z_stream zstream;
+
+      old_data = new_data;
+
+      zstream.zalloc = (alloc_func)0;
+      zstream.zfree = (free_func)0;
+      zstream.opaque = (voidpf)0;
+      result = inflateInit(&zstream);
+      if (result != Z_OK) {
+        mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Zlib initialization failed. "
+              "Result: %d\n", result);
+        safefree(new_data);
+        data = old_data;
+        size = new_size;
+        return modified;
+      }
+      zstream.next_in = (Bytef *)old_data;
+      zstream.avail_in = new_size;
+
+      n = 0;
+      new_data = NULL;
+      do {
+        n++;
+        new_data = (unsigned char *)realloc(new_data, n * 4000);
+        zstream.next_out = (Bytef *)&new_data[(n - 1) * 4000];
+        zstream.avail_out = 4000;
+        result = inflate(&zstream, Z_NO_FLUSH);
+        if ((result != Z_OK) && (result != Z_STREAM_END)) {
+          mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Zlib decompression failed. "
+                 "Result: %d \n", result);
+          safefree(new_data);
+          data = old_data;
+          size = new_size;
+          inflateEnd(&zstream);
+          return modified;
+        }
+      } while ((zstream.avail_out == 0) &&
+               (zstream.avail_in != 0) && (result != Z_STREAM_END));
+
+      mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv] zlib decompression: from %d to "
+            "%d \n", (int)new_size, (int)zstream.total_out);
+      new_size = zstream.total_out;
+      inflateEnd(&zstream);
+
+      if (modified)
+        safefree(old_data);
+      modified = true;
+    }
+#endif
+  }
+
+  data = new_data;
+  size = new_size;
+
+  return modified;
+}
+
+static int check_track_information(mkv_demuxer_t *d) {
+  int i, track_num;
+  unsigned char *c;
+  uint32_t u, offset, length;
+  mkv_track_t *t;
+  mkv_content_encoding_t *ce;
+  BITMAPINFOHEADER *bih;
+  WAVEFORMATEX *wfe;
+  
+  for (track_num = 0; track_num < d->num_tracks; track_num++) {
+    t = d->tracks[track_num];
+    
+    t->ok = 1;
+    for (i = 0; i < (int)t->c_encodings->size(); i++) {
+      ce = &(*t->c_encodings)[i];
+
+      if (ce->type == 1) {
+        mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Track number %u has been "
+              "encrypted and decryption has not yet been implemented. "
+              "Skipping track.\n", t->tnum);
+        t->ok = 0;
+        break;
+      }
+
+      if (ce->type != 0) {
+        mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Unknown content encoding type %u "
+              "for track %u. Skipping track.\n", ce->type, t->tnum);
+        t->ok = 0;
+        break;
+      }
+
+      if (ce->comp_algo == 0) {
+#if !defined(HAVE_ZLIB)
+        mp_msg(MSGT_DEMUX, MSGL_WARN, "Track %u was compressed with zlib but "
+              "mplayer has not been compiled with support for zlib "
+              "compression. Skipping track.\n", t->tnum);
+        t->ok = 0;
+        break;
+#endif
+      } else {
+        mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Track %u has been compressed "
+               "with an unknown/unsupported compression algorithm (%u). "
+               "Skipping track.\n", t->tnum, ce->comp_algo);
+        t->ok = 0;
+        break;
+      }
+    }
+
+    if (!t->ok)
+      continue;
+    t->ok = 0;
+
+    if (t->private_data != NULL) {
+      c = (unsigned char *)t->private_data;
+      length = t->private_size;
+      if (reverse_encodings(t, c, length, 2)) {
+        safefree(t->private_data);
+        t->private_data = c;
+        t->private_size = length;
+      }
+    }
+
+    switch (t->type) {
+      case 'v':                 // video track
+        if (t->codec_id == NULL)
+          continue;
+        if (!strcmp(t->codec_id, MKV_V_MSCOMP)) {
+          if ((t->private_data == NULL) ||
+              (t->private_size < sizeof(BITMAPINFOHEADER))) {
+            mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] WARNING: CodecID for track "
+                   "%u is '" MKV_V_MSCOMP "', but there was no "
+                   "BITMAPINFOHEADER struct present. Therefore we don't have "
+                   "a FourCC to identify the video codec used.\n", t->tnum);
+            continue;
+          } else {
+            t->ms_compat = 1;
+
+            bih = (BITMAPINFOHEADER *)t->private_data;
+
+            u = get_uint32(&bih->biWidth);
+            if (t->v_width != u) {
+              mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] WARNING: (MS "
+                     "compatibility mode, track %u) "
+                     "Matrosa says video width is %u, but the "
+                     "BITMAPINFOHEADER says %u.\n", t->tnum, t->v_width, u);
+              if (t->v_width == 0)
+                t->v_width = u;
+            }
+
+            u = get_uint32(&bih->biHeight);
+            if (t->v_height != u) {
+              mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] WARNING: (MS compatibility "
+                     "mode, track %u) "
+                     "Matrosa video height is %u, but the BITMAPINFOHEADER "
+                     "says %u.\n", t->tnum, t->v_height, u);
+              if (t->v_height == 0)
+                t->v_height = u;
+            }
+
+            memcpy(t->v_fourcc, &bih->biCompression, 4);
+          }
+        }
+
+        if (t->v_width == 0) {
+          mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] The width for track %u was "
+                 "not set.\n", t->tnum);
+          continue;
+        }
+        if (t->v_height == 0) {
+          mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] The height for track %u was "
+                 "not set.\n", t->tnum);
+          continue;
+        }
+
+        if (t->v_dwidth == 0)
+          t->v_dwidth = t->v_width;
+        if (t->v_dheight == 0)
+          t->v_dheight = t->v_height;
+
+        // This track seems to be ok.
+        t->ok = 1;
+        mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] Track ID %u: video (%s), "
+               "-vid %u\n", t->tnum, t->codec_id, t->xid);
+
+        break;
+
+      case 'a':                 // audio track
+        if (t->codec_id == NULL)
+          continue;
+        if (!strcmp(t->codec_id, MKV_A_ACM)) {
+          if ((t->private_data == NULL) ||
+              (t->private_size < sizeof(WAVEFORMATEX))) {
+            mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] WARNING: CodecID for track "
+                   "%u is '" MKV_A_ACM "', "
+                   "but there was no WAVEFORMATEX struct present. "
+                   "Therefore we don't have a format ID to identify the audio "
+                   "codec used.\n", t->tnum);
+            continue;
+          } else {
+            t->ms_compat = 1;
+
+            wfe = (WAVEFORMATEX *)t->private_data;
+            u = get_uint32(&wfe->nSamplesPerSec);
+            if (((uint32_t)t->a_sfreq) != u) {
+              mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] WARNING: (MS compatibility "
+                     "mode for track %u) "
+                     "Matroska says that there are %u samples per second, "
+                     "but WAVEFORMATEX says that there are %u.\n", t->tnum,
+                     (uint32_t)t->a_sfreq, u);
+              if (t->a_sfreq == 0.0)
+                t->a_sfreq = (float)u;
+            }
+
+            u = get_uint16(&wfe->nChannels);
+            if (t->a_channels != u) {
+              mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] WARNING: (MS "
+                     "compatibility mode for track %u) "
+                     "Matroska says that there are %u channels, but the "
+                     "WAVEFORMATEX says that there are %u.\n", t->tnum,
+                     t->a_channels, u);
+              if (t->a_channels == 0)
+                t->a_channels = u;
+            }
+
+            u = get_uint16(&wfe->wBitsPerSample);
+            if (t->a_bps != u) {
+              mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] WARNING: (MS "
+                     "compatibility mode for track %u) "
+                     "Matroska says that there are %u bits per sample, "
+                     "but the WAVEFORMATEX says that there are %u.\n", t->tnum,
+                     t->a_bps, u);
+              if (t->a_bps == 0)
+                t->a_bps = u;
+            }
+            
+            t->a_formattag = get_uint16(&wfe->wFormatTag);
+          }
+        } else {
+          if (!strcmp(t->codec_id, MKV_A_MP3) ||
+              !strcmp(t->codec_id, MKV_A_MP2))
+            t->a_formattag = 0x0055;
+          else if (!strncmp(t->codec_id, MKV_A_AC3, strlen(MKV_A_AC3)))
+            t->a_formattag = 0x2000;
+          else if (!strcmp(t->codec_id, MKV_A_DTS))
+            // uses same format tag as AC3, only supported with -hwac3
+            t->a_formattag = 0x2000;
+          else if (!strcmp(t->codec_id, MKV_A_PCM) ||
+                   !strcmp(t->codec_id, MKV_A_PCM_BE))
+            t->a_formattag = 0x0001;
+          else if (!strcmp(t->codec_id, MKV_A_AAC_2MAIN) ||
+                   !strncmp(t->codec_id, MKV_A_AAC_2LC,
+                            strlen(MKV_A_AAC_2LC)) ||
+                   !strcmp(t->codec_id, MKV_A_AAC_2SSR) ||
+                   !strcmp(t->codec_id, MKV_A_AAC_4MAIN) ||
+                   !strncmp(t->codec_id, MKV_A_AAC_4LC,
+                            strlen(MKV_A_AAC_4LC)) ||
+                   !strcmp(t->codec_id, MKV_A_AAC_4SSR) ||
+                   !strcmp(t->codec_id, MKV_A_AAC_4LTP))
+            t->a_formattag = mmioFOURCC('M', 'P', '4', 'A');
+          else if (!strcmp(t->codec_id, MKV_A_VORBIS)) {
+            if (t->private_data == NULL) {
+              mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] WARNING: CodecID for "
+                     "track %u is '" MKV_A_VORBIS
+                     "', but there are no header packets present.", t->tnum);
+              continue;
+            }
+
+            c = (unsigned char *)t->private_data;
+            if (c[0] != 2) {
+              mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Vorbis track does not "
+                     "contain valid headers.\n");
+              continue;
+            }
+
+            offset = 1;
+            for (i = 0; i < 2; i++) {
+              length = 0;
+              while ((c[offset] == (unsigned char )255) &&
+                     (length < t->private_size)) {
+                length += 255;
+                offset++;
+              }
+              if (offset >= (t->private_size - 1)) {
+                mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Vorbis track does not "
+                       "contain valid headers.\n");
+                continue;
+              }
+              length += c[offset];
+              offset++;
+              t->header_sizes[i] = length;
+            }
+
+            t->headers[0] = &c[offset];
+            t->headers[1] = &c[offset + t->header_sizes[0]];
+            t->headers[2] = &c[offset + t->header_sizes[0] +
+                               t->header_sizes[1]];
+            t->header_sizes[2] = t->private_size - offset -
+              t->header_sizes[0] - t->header_sizes[1];
+
+            t->a_formattag = 0xFFFE;
+          } else if (!strcmp(t->codec_id, MKV_A_QDMC) ||
+                     !strcmp(t->codec_id, MKV_A_QDMC2)) {
+            ;
+          } else if (!strcmp(t->codec_id, MKV_A_FLAC)) {
+            if ((t->private_data == NULL) || (t->private_size == 0)) {
+              mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] FLAC track does not "
+                     "contain valid headers.\n");
+              continue;
+            }
+            t->a_formattag = mmioFOURCC('f', 'L', 'a', 'C');
+          } else if (t->private_size >= sizeof(real_audio_v4_props_t)) {
+            if (!strcmp(t->codec_id, MKV_A_REAL28))
+              t->a_formattag = mmioFOURCC('2', '8', '_', '8');
+            else if (!strcmp(t->codec_id, MKV_A_REALATRC))
+              t->a_formattag = mmioFOURCC('a', 't', 'r', 'c');
+            else if (!strcmp(t->codec_id, MKV_A_REALCOOK))
+              t->a_formattag = mmioFOURCC('c', 'o', 'o', 'k');
+            else if (!strcmp(t->codec_id, MKV_A_REALDNET))
+              t->a_formattag = mmioFOURCC('d', 'n', 'e', 't');
+            else if (!strcmp(t->codec_id, MKV_A_REALSIPR))
+              t->a_formattag = mmioFOURCC('s', 'i', 'p', 'r');
+          } else {
+            mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Unknown/unsupported audio "
+                   "codec ID '%s' for track %u or missing/faulty private "
+                   "codec data.\n", t->codec_id, t->tnum);
+            continue;
+          }
+        }
+
+        if (t->a_sfreq == 0.0) {
+          mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] The sampling frequency was not "
+                 "set for track %u.\n", t->tnum);
+          continue;
+        }
+
+        if (t->a_channels == 0) {
+          mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] The number of channels was not "
+                 "set for track %u.\n", t->tnum);
+          continue;
+        }
+
+        // This track seems to be ok.
+        t->ok = 1;
+        mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] Track ID %u: audio (%s), -aid "
+               "%u%s%s\n", t->tnum, t->codec_id, t->xid,
+               t->language != NULL ? ", -alang " : "",
+               t->language != NULL ? t->language : "");
+        break;
+
+      case 's':
+        if (!strcmp(t->codec_id, MKV_S_VOBSUB)) {
+          if (mkv_parse_idx(t)) {
+            t->ok = 1;
+            mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] Track ID %u: subtitles (%s), "
+                   "-sid %u%s%s\n", t->tnum, t->codec_id,
+                   t->xid, t->language != NULL ? ", -slang " : "",
+                   t->language != NULL ? t->language : "");
+          }
+
+        } else {                // Text subtitles do not need any data
+          t->ok = 1;            // except the CodecID.
+          mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] Track ID %u: subtitles (%s), "
+                 "-sid %u%s%s\n", t->tnum, t->codec_id, t->xid,
+                 t->language != NULL ? ", -slang " : "",
+                 t->language != NULL ? t->language : "");
+        }
+        break;
+
+      default:                  // unknown track type!? error in demuxer...
+        mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] Error in demux_mkv.cpp: unknown "
+               "demuxer type for track %u: '%c'\n", t->tnum, t->type);
+        continue;
+    }
+
+    if (t->ok)
+      mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Track %u seems to be ok.\n", t->tnum);
+  }
+
+  return 1;
+}
+
+static void free_mkv_demuxer(mkv_demuxer_t *d) {
+  int i, k;
+  
+  if (d == NULL)
+    return;
+
+  for (i = 0; i < d->num_tracks; i++)
+    if (d->tracks[i] != NULL) {
+      if (d->tracks[i]->private_data != NULL)
+        free(d->tracks[i]->private_data);
+      if (d->tracks[i]->language != NULL)
+        free(d->tracks[i]->language);
+      for (k = 0; k < (int)d->tracks[i]->c_encodings->size(); k++) {
+        safefree((*d->tracks[i]->c_encodings)[k].comp_settings);
+        safefree((*d->tracks[i]->c_encodings)[k].enc_keyid);
+        safefree((*d->tracks[i]->c_encodings)[k].sig_keyid);
+        safefree((*d->tracks[i]->c_encodings)[k].signature);
+      }
+      delete d->tracks[i]->c_encodings;
+      free(d->tracks[i]);
+    }
+
+  for (i = 0; i < d->num_indexes; i++)
+    free(d->index[i].entries);
+  free(d->index);
+
+  for (i = 0; i <= SUB_MAX_TEXT; i++)
+    safefree(d->subs.text[i]);
+
+  if (d->es != NULL)
+    delete d->es;
+  if (d->saved_l1 != NULL)
+    delete d->saved_l1;
+  if (d->in != NULL)
+    delete d->in;
+  if (d->segment != NULL)
+    delete d->segment;
+  if (d->chapters != NULL)
+    delete d->chapters;
+
+  free(d);
+}
+
+static void add_index_entry(mkv_demuxer_t *d, uint32_t tnum, uint64_t filepos,
+                            uint64_t timecode, int is_key) {
+  int i, found;
+  mkv_index_entry_t *entry;
+
+  for (i = 0, found = 0; i < d->num_indexes; i++)
+    if (d->index[i].tnum == tnum) {
+      found = 1;
+      break;
+    }
+
+  if (!found) {
+    d->index = (mkv_track_index_t *)realloc(d->index, (d->num_indexes + 1) *
+                                            sizeof(mkv_track_index_t));
+    if (d->index == NULL)
+      return;
+    i = d->num_indexes;
+    memset(&d->index[i], 0, sizeof(mkv_track_index_t));
+    d->index[i].tnum = tnum;
+    d->num_indexes++;
+  }
+
+  d->index[i].entries =
+    (mkv_index_entry_t *)realloc(d->index[i].entries,
+                                 (d->index[i].num_entries + 1) *
+                                 sizeof(mkv_index_entry_t));
+  if (d->index[i].entries == NULL)
+    return;
+  entry = &d->index[i].entries[d->index[i].num_entries];
+  entry->filepos = filepos;
+  entry->timecode = timecode;
+  entry->is_key = is_key;
+  d->index[i].num_entries++;
+}
+
+static void add_cluster_position(mkv_demuxer_t *mkv_d, int64_t position) {
+  mkv_d->cluster_positions = (int64_t *)realloc(mkv_d->cluster_positions,
+                                                (mkv_d->num_cluster_pos + 1) *
+                                                sizeof(int64_t));
+  if (mkv_d->cluster_positions != NULL) {
+    mkv_d->cluster_positions[mkv_d->num_cluster_pos] = position;
+    mkv_d->num_cluster_pos++;
+  } else
+    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 *> \
+  (((EbmlMaster *)p)->FindFirstElt(c::ClassInfos, false)))
+#define FINDNEXT(p, c, e) (static_cast<c *> \
+  (((EbmlMaster *)p)->FindNextElt(*e, false)))
+
+static void parse_cues(mkv_demuxer_t *mkv_d, uint64_t pos) {
+  EbmlElement *l2 = NULL;
+  EbmlStream *es;
+  KaxCues *cues;
+  KaxCuePoint *cpoint;
+  KaxCueTime *ctime;
+  KaxCueClusterPosition *ccpos;
+  KaxCueTrack *ctrack;
+  KaxCueTrackPositions *ctrackpos;
+  int upper_lvl_el, i, k;
+  uint64_t tc_scale, filepos = 0, timecode = 0;
+  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;
+
+  mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] /---- [ parsing cues ] -----------\n");
+
+  cues = (KaxCues *)es->FindNextElement(mkv_d->segment->Generic().Context,
+                                        upper_lvl_el, 0xFFFFFFFFL, true, 1);
+  if (cues == NULL)
+    return;
+
+  if (!(EbmlId(*cues) == KaxCues::ClassInfos.GlobalId)) {
+    mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] No KaxCues element found but %s.\n"
+           "[mkv] \\---- [ parsing cues ] -----------\n",
+           cues->Generic().DebugName);
+    
+    return;
+  }
+
+  mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |+ found cues\n");
+
+  cues->Read(*es, KaxCues::ClassInfos.Context, upper_lvl_el, l2, true);
+
+  cpoint = FINDFIRST(cues, KaxCuePoint);
+
+  while (cpoint != NULL) {
+    mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv] | + found cue point\n");
+
+    ctime = FINDFIRST(cpoint, KaxCueTime);
+    if (ctime == NULL) {
+      cpoint = FINDNEXT(cues, KaxCuePoint, cpoint);
+      continue;
+    }
+      
+    timecode = uint64(*ctime) * tc_scale / 1000000 - mkv_d->first_tc;
+    mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv] |  + found cue time: %.3fs\n",
+           (float)timecode / 1000.0);
+
+    ctrackpos = FINDFIRST(cpoint, KaxCueTrackPositions);
+
+    while (ctrackpos != NULL) {
+      ctrack = FINDFIRST(ctrackpos, KaxCueTrack);
+
+      if (ctrack == NULL) {
+        ctrackpos = FINDNEXT(cpoint, KaxCueTrackPositions, ctrackpos);
+        continue;
+      }
+
+      tnum = uint32(*ctrack);
+      mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv] |   + found cue track: %u\n", tnum);
+
+      ccpos = FINDFIRST(ctrackpos, KaxCueClusterPosition);
+      if (ccpos == NULL) {
+        ctrackpos = FINDNEXT(cpoint, KaxCueTrackPositions, ctrackpos);
+        continue;
+      }
+
+      filepos = mkv_d->segment->GetGlobalPosition(uint64_t(*ccpos));
+      mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv] |   + found cue cluster "
+             "position: %llu\n", filepos);
+
+      add_index_entry(mkv_d, tnum, filepos, timecode, 1);
+     
+      ctrackpos = FINDNEXT(cpoint, KaxCueTrackPositions, ctrackpos);
+    }
+
+    cpoint = FINDNEXT(cues, KaxCuePoint, cpoint);
+  }
+
+  delete cues;
+
+  // Debug: dump the index
+  for (i = 0; i < mkv_d->num_indexes; i++) {
+    mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv] Index for track %u contains %u "
+           "entries.\n", mkv_d->index[i].tnum, mkv_d->index[i].num_entries);
+    for (k = 0; k < mkv_d->index[i].num_entries; k++) {
+      entry = &mkv_d->index[i].entries[k];
+      mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv]   %d: timecode %llu, filepos %llu, "
+             "is key: %s\n", k, entry->timecode, entry->filepos,
+             entry->is_key ? "yes" : "no");
+    }
+  }
+
+  mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] \\---- [ parsing cues ] -----------\n");
+
+  mkv_d->cues_found = 1;
+}
+
+static void parse_chapters(mkv_demuxer_t *mkv_d, uint64_t pos) {
+  EbmlElement *l2 = NULL;
+  EbmlStream *es;
+  KaxChapters *kchapters;
+  KaxEditionEntry *keentry;
+  KaxChapterAtom *kcatom;
+  KaxChapterTimeStart *kctstart;
+  KaxChapterTimeEnd *kctend;
+  int upper_lvl_el, i, k;
+  mkv_chapter_t chapter;
+
+  if (mkv_d->chapters != NULL)
+    return;
+
+  es = mkv_d->es;
+  upper_lvl_el = 0;
+
+  mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] /---- [ parsing chapters ] ---------\n");
+
+  mkv_d->in->setFilePointer(pos);
+
+  kchapters =
+    (KaxChapters *)es->FindNextElement(mkv_d->segment->Generic().Context,
+                                       upper_lvl_el, 0xFFFFFFFFL, true, 1);
+  if (kchapters == NULL)
+    return;
+
+  if (!(EbmlId(*kchapters) == KaxChapters::ClassInfos.GlobalId)) {
+    mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] No KaxChapters element found but %s.\n"
+           "[mkv] \\---- [ parsing chapters ] ---------\n",
+           kchapters->Generic().DebugName);
+    
+    return;
+  }
+
+  mkv_d->chapters = new vector<mkv_chapter_t>;
+  kchapters->Read(*es, KaxChapters::ClassInfos.Context, upper_lvl_el, l2,
+                  true);
+
+  for (i = 0; i < (int)kchapters->ListSize(); i++) {
+    keentry = (KaxEditionEntry *)(*kchapters)[i];
+    if (EbmlId(*keentry) == KaxEditionEntry::ClassInfos.GlobalId) {
+      for (k = 0; k < (int)keentry->ListSize(); k++) {
+        kcatom = (KaxChapterAtom *)(*keentry)[k];
+        if (EbmlId(*kcatom) == KaxChapterAtom::ClassInfos.GlobalId) {
+          chapter.start = 0;
+          chapter.end = 0;
+          kctstart = FINDFIRST(kcatom, KaxChapterTimeStart);
+          if (kctstart != NULL)
+            chapter.start = uint64(*kctstart) / 1000000;
+          kctend = FINDFIRST(kcatom, KaxChapterTimeEnd);
+          if (kctend != NULL)
+            chapter.end = uint64(*kctend) / 1000000;
+          mkv_d->chapters->push_back(chapter);
+          mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Chapter %u from %02d:%02d:%02d."
+                 "%03d to %02d:%02d:%02d.%03d\n", mkv_d->chapters->size(),
+                 (int)(chapter.start / 60 / 60 / 1000),
+                 (int)((chapter.start / 60 / 1000) % 60),
+                 (int)((chapter.start / 1000) % 60),
+                 (int)(chapter.start % 1000),
+                 (int)(chapter.end / 60 / 60 / 1000),
+                 (int)((chapter.end / 60 / 1000) % 60),
+                 (int)((chapter.end / 1000) % 60),
+                 (int)(chapter.end % 1000));
+        }
+      }
+    }
+  }
+
+  mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] \\---- [ parsing chapters ] ---------\n");
+  delete kchapters;
+}
+
+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;
+  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);
+      else if (*id == KaxChapters::ClassInfos.GlobalId)
+        parse_chapters(mkv_d, seek_pos);
+    }
+
+    if (id != NULL)
+      delete id;
+  }
+
+  delete kseekhead;
+
+  mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] \\---- [ parsing seek head ] ---------\n");
+}
+
+#define AAC_SYNC_EXTENSION_TYPE 0x02b7
+static int aac_get_sample_rate_index(uint32_t sample_rate) {
+  if (92017 <= sample_rate)
+    return 0;
+  else if (75132 <= sample_rate)
+    return 1;
+  else if (55426 <= sample_rate)
+    return 2;
+  else if (46009 <= sample_rate)
+    return 3;
+  else if (37566 <= sample_rate)
+    return 4;
+  else if (27713 <= sample_rate)
+    return 5;
+  else if (23004 <= sample_rate)
+    return 6;
+  else if (18783 <= sample_rate)
+    return 7;
+  else if (13856 <= sample_rate)
+    return 8;
+  else if (11502 <= sample_rate)
+    return 9;
+  else if (9391 <= sample_rate)
+    return 10;
+  else
+    return 11;
+}
+
+extern "C" void demux_mkv_seek(demuxer_t *demuxer, float rel_seek_secs,
+                               int flags);
+
+extern "C" int demux_mkv_open(demuxer_t *demuxer) {
+  unsigned char signature[4];
+  stream_t *s;
+  demux_packet_t *dp;
+  mkv_demuxer_t *mkv_d;
+  int upper_lvl_el, exit_loop, i, vid, sid, aid;
+  // Elements for different levels
+  EbmlElement *l0 = NULL, *l1 = NULL, *l2 = NULL;
+  EbmlStream *es;
+  mkv_track_t *track;
+  sh_audio_t *sh_a;
+  sh_video_t *sh_v;
+  vector<uint64_t> seekheads_to_parse;
+  vector<uint64_t> cues_to_parse;
+  int64_t current_pos;
+  qt_image_description_t *idesc;
+
+#ifdef USE_ICONV
+  subcp_open();
+#endif
+
+  s = demuxer->stream;
+  stream_seek(s, s->start_pos);
+  memset(signature, 0, 4);
+  stream_read(s, (char *)signature, 4);
+  if ((signature[0] != 0x1A) || (signature[1] != 0x45) ||
+      (signature[2] != 0xDF) || (signature[3] != 0xA3))
+    return 0;
+  stream_seek(s, s->start_pos);
+  
+  try {
+    // structure for storing the demuxer's private data
+    mkv_d = (mkv_demuxer_t *)safemalloc(sizeof(mkv_demuxer_t));
+    memset(mkv_d, 0, sizeof(mkv_demuxer_t));
+    mkv_d->duration = -1.0;
+    
+    // Create the interface between MPlayer's IO system and
+    // libmatroska's IO system.
+    mkv_d->in = new mpstream_io_callback(demuxer->stream);
+    if (mkv_d->in == NULL) {
+      free_mkv_demuxer(mkv_d);
+      return 0;
+    }
+    mpstream_io_callback &io = *static_cast<mpstream_io_callback *>(mkv_d->in);
+    mkv_d->es = new EbmlStream(io);
+    if (mkv_d->es == NULL) {
+      free_mkv_demuxer(mkv_d);
+      return 0;
+    }
+    es = mkv_d->es;
+    
+    // Find the EbmlHead element. Must be the first one.
+    l0 = es->FindNextID(EbmlHead::ClassInfos, 0xFFFFFFFFFFFFFFFFULL);
+    if (l0 == NULL) {
+      mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] no head found\n");
+      free_mkv_demuxer(mkv_d);
+      return 0;
+    }
+    // Don't verify its data for now.
+    l0->SkipData(static_cast<EbmlStream &>(*es), l0->Generic().Context);
+    delete l0;
+    mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Found the head...\n");
+    
+    // Next element must be a segment
+    l0 = es->FindNextID(KaxSegment::ClassInfos, 0xFFFFFFFFFFFFFFFFULL);
+    if (l0 == NULL) {
+      mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] but no segment :(\n");
+      free_mkv_demuxer(mkv_d);
+      return 0;
+    }
+    if (!(EbmlId(*l0) == KaxSegment::ClassInfos.GlobalId)) {
+      mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] but no segment :(\n");
+      free_mkv_demuxer(mkv_d);
+      return 0;
+    }
+    mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] + a segment...\n");
+    
+    mkv_d->segment = (KaxSegment *)l0;
+    mkv_d->tc_scale = MKVD_TIMECODESCALE;
+    mkv_d->parsed_seekheads = new vector<uint64_t>;
+    mkv_d->parsed_cues = new vector<uint64_t>;
+
+    vid = 0;
+    aid = 0;
+    sid = 0;
+
+    upper_lvl_el = 0;
+    exit_loop = 0;
+    // We've got our segment, so let's find the tracks
+    l1 = es->FindNextElement(l0->Generic().Context, upper_lvl_el, 0xFFFFFFFFL,
+                             true, 1);
+    while ((l1 != NULL) && (upper_lvl_el <= 0)) {
+
+      if (EbmlId(*l1) == KaxInfo::ClassInfos.GlobalId) {
+        // General info about this Matroska file
+        KaxTimecodeScale *ktc_scale;
+        KaxDuration *kduration;
+
+        mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |+ segment information...\n");
+
+        l1->Read(*es, KaxInfo::ClassInfos.Context, upper_lvl_el, l2, true);
+
+        ktc_scale = FINDFIRST(l1, KaxTimecodeScale);
+        if (ktc_scale != NULL) {
+          mkv_d->tc_scale = uint64(*ktc_scale);
+          mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + timecode scale: %llu\n",
+                 mkv_d->tc_scale);
+        } else
+          mkv_d->tc_scale = MKVD_TIMECODESCALE;
+
+        kduration = FINDFIRST(l1, KaxDuration);
+        if (kduration != NULL) {
+          mkv_d->duration = float(*kduration) * mkv_d->tc_scale / 1000000000.0;
+          mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + duration: %.3fs\n",
+                 mkv_d->duration);
+        }
+
+        l1->SkipData(*es, l1->Generic().Context);
+
+      } else if (EbmlId(*l1) == KaxTracks::ClassInfos.GlobalId) {
+        // Yep, we've found our KaxTracks element. Now find all tracks
+        // contained in this segment.
+
+        KaxTrackEntry *ktentry;
+
+        mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |+ segment tracks...\n");
+
+        l1->Read(*es, KaxTracks::ClassInfos.Context, upper_lvl_el, l2, true);
+
+        ktentry = FINDFIRST(l1, KaxTrackEntry);
+        while (ktentry != NULL) {
+          // We actually found a track entry :) We're happy now.
+
+          KaxTrackNumber *ktnum;
+          KaxTrackDefaultDuration *kdefdur;
+          KaxTrackType *kttype;
+          KaxTrackAudio *ktaudio;
+          KaxTrackVideo *ktvideo;
+          KaxCodecID *kcodecid;
+          KaxCodecPrivate *kcodecpriv;
+          KaxTrackFlagDefault *ktfdefault;
+          KaxTrackLanguage *ktlanguage;
+#if LIBMATROSKA_VERSION >= 000503
+          KaxContentEncodings *kcencodings;
+          int kcenc_idx;
+          vector<mkv_content_encoding_t>::iterator ce_ins_it;
+#endif
+
+          mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + a track...\n");
+            
+          track = new_mkv_track(mkv_d);
+          if (track == NULL)
+            return 0;
+
+          ktnum = FINDFIRST(ktentry, KaxTrackNumber);
+          if (ktnum != NULL) {
+            mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |  + Track number: %u\n",
+                   uint32(*ktnum));
+            track->tnum = uint32(*ktnum);
+            if (find_duplicate_track_by_num(mkv_d, track->tnum, track) != NULL)
+              mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] |  + WARNING: There's "
+                     "more than one track with the number %u.\n",
+                     track->tnum);
+          }
+
+          kdefdur = FINDFIRST(ktentry, KaxTrackDefaultDuration);
+          if (kdefdur != NULL) {
+            if (uint64(*kdefdur) == 0)
+              mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |  + Default duration: 0");
+            else {
+              track->v_frate = 1000000000.0 / (float)uint64(*kdefdur);
+              mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |  + Default duration: "
+                     "%.3fms ( = %.3f fps)\n",
+                     (float)uint64(*kdefdur) / 1000000.0, track->v_frate);
+            }
+            track->default_duration = (float)uint64(*kdefdur) / 1000000000.0;
+          }
+
+          kttype = FINDFIRST(ktentry, KaxTrackType);
+          if (kttype != NULL) {
+            mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |  + Track type: ");
+
+            switch (uint8(*kttype)) {
+              case track_audio:
+                mp_msg(MSGT_DEMUX, MSGL_V, "Audio\n");
+                track->type = 'a';
+                track->xid = aid;
+                aid++;
+                break;
+              case track_video:
+                mp_msg(MSGT_DEMUX, MSGL_V, "Video\n");
+                track->type = 'v';
+                track->xid = vid;
+                vid++;
+                break;
+              case track_subtitle:
+                mp_msg(MSGT_DEMUX, MSGL_V, "Subtitle\n");
+                track->type = 's';
+                track->xid = sid;
+                sid++;
+                break;
+              default:
+                mp_msg(MSGT_DEMUX, MSGL_V, "unknown\n");
+                track->type = '?';
+                break;
+            }
+          }
+
+          ktaudio = FINDFIRST(ktentry, KaxTrackAudio);
+          if (ktaudio != NULL) {
+            KaxAudioSamplingFreq *ka_sfreq;
+            KaxAudioChannels *ka_channels;
+            KaxAudioBitDepth *ka_bitdepth;
+
+            mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |  + Audio track\n");
+
+            ka_sfreq = FINDFIRST(ktaudio, KaxAudioSamplingFreq);
+            if (ka_sfreq != NULL) {
+              track->a_sfreq = float(*ka_sfreq);
+              mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |   + Sampling "
+                     "frequency: %f\n", track->a_sfreq);
+            } else
+              track->a_sfreq = 8000.0;
+
+            ka_channels = FINDFIRST(ktaudio, KaxAudioChannels);
+            if (ka_channels != NULL) {
+              track->a_channels = uint8(*ka_channels);
+              mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |   + Channels: %u\n",
+                     track->a_channels);
+            } else
+              track->a_channels = 1;
+
+            ka_bitdepth = FINDFIRST(ktaudio, KaxAudioBitDepth);
+            if (ka_bitdepth != NULL) {
+              track->a_bps = uint8(*ka_bitdepth);
+              mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |   + Bit depth: %u\n",
+                     track->a_bps);
+            }
+
+          }
+
+          ktvideo = FINDFIRST(ktentry, KaxTrackVideo);
+          if (ktvideo != NULL) {
+            KaxVideoPixelWidth *kv_pwidth;
+            KaxVideoPixelHeight *kv_pheight;
+            KaxVideoDisplayWidth *kv_dwidth;
+            KaxVideoDisplayHeight *kv_dheight;
+            KaxVideoFrameRate *kv_frate;
+
+            kv_pwidth = FINDFIRST(ktvideo, KaxVideoPixelWidth);
+            if (kv_pwidth != NULL) {
+              track->v_width = uint16(*kv_pwidth);
+              mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |   + Pixel width: %u\n",
+                     track->v_width);
+            }
+
+            kv_pheight = FINDFIRST(ktvideo, KaxVideoPixelHeight);
+            if (kv_pheight != NULL) {
+              track->v_height = uint16(*kv_pheight);
+              mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |   + Pixel height: %u\n",
+                     track->v_height);
+            }
+
+            kv_dwidth = FINDFIRST(ktvideo, KaxVideoDisplayWidth);
+            if (kv_dwidth != NULL) {
+              track->v_dwidth = uint16(*kv_dwidth);
+              mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |   + Display width: %u\n",
+                     track->v_dwidth);
+            }
+
+            kv_dheight = FINDFIRST(ktvideo, KaxVideoDisplayHeight);
+            if (kv_dheight != NULL) {
+              track->v_dheight = uint16(*kv_dheight);
+              mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |   + Display height: %u\n",
+                     track->v_dheight);
+            }
+
+            // For older files.
+            kv_frate = FINDFIRST(ktvideo, KaxVideoFrameRate);
+            if (kv_frate != NULL) {
+              track->v_frate = float(*kv_frate);
+              mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |   + Frame rate: %f\n",
+                     track->v_frate);
+            }
+
+          }
+
+          kcodecid = FINDFIRST(ktentry, KaxCodecID);
+          if (kcodecid != NULL) {
+            mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |  + Codec ID: %s\n",
+                   string(*kcodecid).c_str());
+            track->codec_id = strdup(string(*kcodecid).c_str());
+          }
+
+          kcodecpriv = FINDFIRST(ktentry, KaxCodecPrivate);
+          if (kcodecpriv != NULL) {
+            mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |  + CodecPrivate, length "
+                   "%llu\n", kcodecpriv->GetSize());
+            track->private_size = kcodecpriv->GetSize();
+            if (track->private_size > 0)
+              track->private_data = safememdup(kcodecpriv->GetBuffer(),
+                                               track->private_size);
+          }
+
+          ktfdefault = FINDFIRST(ktentry, KaxTrackFlagDefault);
+          if (ktfdefault != NULL) {
+            track->default_track = uint32(*ktfdefault);
+            mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |  + Default flag: %u\n",
+                   track->default_track);
+          }
+
+          ktlanguage = FINDFIRST(ktentry, KaxTrackLanguage);
+          if (ktlanguage != NULL) {
+            mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |  + Language: %s\n",
+                   string(*ktlanguage).c_str());
+            if (track->language != NULL)
+              free(track->language);
+            track->language = strdup(string(*ktlanguage).c_str());
+          }
+
+#if LIBMATROSKA_VERSION >= 000503
+          kcencodings = FINDFIRST(ktentry, KaxContentEncodings);
+          if (kcencodings != NULL) {
+            for (kcenc_idx = 0; kcenc_idx < (int)kcencodings->ListSize();
+                 kcenc_idx++) {
+              EbmlElement *l3;
+
+              l3 = (*kcencodings)[kcenc_idx];
+              if (EbmlId(*l3) == KaxContentEncoding::ClassInfos.GlobalId) {
+                KaxContentEncoding *kcenc;
+                KaxContentEncodingOrder *ce_order;
+                KaxContentEncodingType *ce_type;
+                KaxContentEncodingScope *ce_scope;
+                KaxContentCompression *ce_comp;
+                KaxContentEncryption *ce_enc;
+                mkv_content_encoding_t enc;
+
+                memset(&enc, 0, sizeof(mkv_content_encoding_t));
+                kcenc = static_cast<KaxContentEncoding *>(l3);
+
+                ce_order = FINDFIRST(kcenc, KaxContentEncodingOrder);
+                if (ce_order != NULL)
+                  enc.order = uint32(*ce_order);
+
+                ce_type = FINDFIRST(kcenc, KaxContentEncodingType);
+                if (ce_type != NULL)
+                  enc.type = uint32(*ce_type);
+
+                ce_scope = FINDFIRST(kcenc, KaxContentEncodingScope);
+                if (ce_scope != NULL)
+                  enc.scope = uint32(*ce_scope);
+                else
+                  enc.scope = 1;
+
+                ce_comp = FINDFIRST(kcenc, KaxContentCompression);
+                if (ce_comp != NULL) {
+                  KaxContentCompAlgo *cc_algo;
+                  KaxContentCompSettings *cc_settings;
+
+                  cc_algo = FINDFIRST(ce_comp, KaxContentCompAlgo);
+                  if (cc_algo != NULL)
+                    enc.comp_algo = uint32(*cc_algo);
+
+                  cc_settings = FINDFIRST(ce_comp, KaxContentCompSettings);
+                  if (cc_settings != NULL) {
+                    enc.comp_settings =
+                      (unsigned char *)safememdup(&binary(*cc_settings),
+                                                  cc_settings->GetSize());
+                    enc.comp_settings_len = cc_settings->GetSize();
+                  }
+                }
+
+                ce_enc = FINDFIRST(kcenc, KaxContentEncryption);
+                if (ce_enc != NULL) {
+                  KaxContentEncAlgo *ce_ealgo;
+                  KaxContentEncKeyID *ce_ekeyid;
+                  KaxContentSigAlgo *ce_salgo;
+                  KaxContentSigHashAlgo *ce_shalgo;
+                  KaxContentSigKeyID *ce_skeyid;
+                  KaxContentSignature *ce_signature;
+
+                  ce_ealgo = FINDFIRST(ce_enc, KaxContentEncAlgo);
+                  if (ce_ealgo != NULL)
+                    enc.enc_algo = uint32(*ce_ealgo);
+
+                  ce_ekeyid = FINDFIRST(ce_enc, KaxContentEncKeyID);
+                  if (ce_ekeyid != NULL) {
+                    enc.enc_keyid =
+                      (unsigned char *)safememdup(&binary(*ce_ekeyid),
+                                                  ce_ekeyid->GetSize());
+                    enc.enc_keyid_len = ce_ekeyid->GetSize();
+                  }
+
+                  ce_salgo = FINDFIRST(ce_enc, KaxContentSigAlgo);
+                  if (ce_salgo != NULL)
+                    enc.enc_algo = uint32(*ce_salgo);
+
+                  ce_shalgo = FINDFIRST(ce_enc, KaxContentSigHashAlgo);
+                  if (ce_shalgo != NULL)
+                    enc.enc_algo = uint32(*ce_shalgo);
+
+                  ce_skeyid = FINDFIRST(ce_enc, KaxContentSigKeyID);
+                  if (ce_skeyid != NULL) {
+                    enc.sig_keyid =
+                      (unsigned char *)safememdup(&binary(*ce_skeyid),
+                                                  ce_skeyid->GetSize());
+                    enc.sig_keyid_len = ce_skeyid->GetSize();
+                  }
+
+                  ce_signature = FINDFIRST(ce_enc, KaxContentSignature);
+                  if (ce_signature != NULL) {
+                    enc.signature =
+                      (unsigned char *)safememdup(&binary(*ce_signature),
+                                                  ce_signature->GetSize());
+                    enc.signature_len = ce_signature->GetSize();
+                  }
+
+                }
+
+                ce_ins_it = track->c_encodings->begin();
+                while ((ce_ins_it != track->c_encodings->end()) &&
+                       (enc.order <= (*ce_ins_it).order))
+                  ce_ins_it++;
+                track->c_encodings->insert(ce_ins_it, enc);
+              }
+            }
+          }
+
+#endif
+          ktentry = FINDNEXT(l1, KaxTrackEntry, ktentry);
+        } // while (ktentry != NULL)
+
+        l1->SkipData(*es, l1->Generic().Context);
+
+      } else if (EbmlId(*l1) == KaxSeekHead::ClassInfos.GlobalId) {
+        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 (!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) == KaxChapters::ClassInfos.GlobalId) {
+        parse_chapters(mkv_d, l1->GetElementPosition());
+        l1->SkipData(*es, l1->Generic().Context);
+
+      } else if (EbmlId(*l1) == KaxCluster::ClassInfos.GlobalId) {
+        mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |+ found cluster, headers are "
+               "parsed completely :)\n");
+        add_cluster_position(mkv_d, l1->GetElementPosition());
+        mkv_d->saved_l1 = l1;
+        exit_loop = 1;
+
+      } else
+        l1->SkipData(*es, l1->Generic().Context);
+      
+      if (!in_parent(l0)) {
+        delete l1;
+        break;
+      }
+
+      if (upper_lvl_el > 0) {
+        upper_lvl_el--;
+        if (upper_lvl_el > 0)
+          break;
+        delete l1;
+        l1 = l2;
+        continue;
+
+      } else if (upper_lvl_el < 0) {
+        upper_lvl_el++;
+        if (upper_lvl_el < 0)
+          break;
+
+      }
+
+      if (exit_loop)      // we've found the first cluster, so get out
+        break;
+
+      l1->SkipData(*es, l1->Generic().Context);
+      delete l1;
+      l1 = es->FindNextElement(l0->Generic().Context, upper_lvl_el,
+                               0xFFFFFFFFL, true);
+
+    } // while (l1 != NULL)
+
+    if (!exit_loop) {
+      free_mkv_demuxer(mkv_d);
+      return 0;
+    }
+
+    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);
+    if ((l2 != NULL) && !upper_lvl_el &&
+        (EbmlId(*l2) == KaxClusterTimecode::ClassInfos.GlobalId)) {
+      KaxClusterTimecode &ctc = *static_cast<KaxClusterTimecode *>(l2);
+      ctc.ReadData(es->I_O());
+      mkv_d->first_tc = uint64(ctc) * mkv_d->tc_scale / 1000000;
+      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);
+
+  } catch (exception &ex) {
+    mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] caught exception\n");
+    return 0;
+  }
+
+  if (!check_track_information(mkv_d)) {
+    free_mkv_demuxer(mkv_d);
+    return 0;
+  }
+
+  track = NULL;
+  if (demuxer->video->id == -1) { // Automatically select a video track.
+    // Search for a video track that has the 'default' flag set.
+    for (i = 0; i < mkv_d->num_tracks; i++)
+      if ((mkv_d->tracks[i]->type == 'v') && mkv_d->tracks[i]->ok &&
+          mkv_d->tracks[i]->default_track) {
+        track = mkv_d->tracks[i];
+        break;
+      }
+
+    if (track == NULL)
+      // No track has the 'default' flag set - let's take the first video
+      // track.
+      for (i = 0; i < mkv_d->num_tracks; i++)
+        if ((mkv_d->tracks[i]->type == 'v') && mkv_d->tracks[i]->ok) {
+          track = mkv_d->tracks[i];
+          break;
+        }
+  } else if (demuxer->video->id != -2) // -2 = no video at all
+    track = find_track_by_num(mkv_d, demuxer->video->id, 'v');
+
+  if (track) {
+    BITMAPINFOHEADER *bih;
+
+    idesc = NULL;
+
+    if (track->ms_compat) {         // MS compatibility mode
+      BITMAPINFOHEADER *src;
+      src = (BITMAPINFOHEADER *)track->private_data;
+      bih = (BITMAPINFOHEADER *)safemalloc(track->private_size);
+      memset(bih, 0, track->private_size);
+      bih->biSize = get_uint32(&src->biSize);
+      bih->biWidth = get_uint32(&src->biWidth);
+      bih->biHeight = get_uint32(&src->biHeight);
+      bih->biPlanes = get_uint16(&src->biPlanes);
+      bih->biBitCount = get_uint16(&src->biBitCount);
+      bih->biCompression = get_uint32(&src->biCompression);
+      bih->biSizeImage = get_uint32(&src->biSizeImage);
+      bih->biXPelsPerMeter = get_uint32(&src->biXPelsPerMeter);
+      bih->biYPelsPerMeter = get_uint32(&src->biYPelsPerMeter);
+      bih->biClrUsed = get_uint32(&src->biClrUsed);
+      bih->biClrImportant = get_uint32(&src->biClrImportant);
+      memcpy((char *)bih + sizeof(BITMAPINFOHEADER),
+             (char *)src + sizeof(BITMAPINFOHEADER),
+             track->private_size - sizeof(BITMAPINFOHEADER));
+
+    } else {
+      bih = (BITMAPINFOHEADER *)safemalloc(sizeof(BITMAPINFOHEADER));
+      memset(bih, 0, sizeof(BITMAPINFOHEADER));
+      bih->biSize = sizeof(BITMAPINFOHEADER);
+      bih->biWidth = track->v_width;
+      bih->biHeight = track->v_height;
+      bih->biBitCount = 24;
+      bih->biSizeImage = bih->biWidth * bih->biHeight * bih->biBitCount / 8;
+
+      if ((track->private_size >= sizeof(real_video_props_t)) &&
+          (!strcmp(track->codec_id, MKV_V_REALV10) ||
+           !strcmp(track->codec_id, MKV_V_REALV20) ||
+           !strcmp(track->codec_id, MKV_V_REALV30) ||
+           !strcmp(track->codec_id, MKV_V_REALV40))) {
+        unsigned char *dst, *src;
+        real_video_props_t *rvp;
+        uint32_t type2;
+
+        rvp = (real_video_props_t *)track->private_data;
+        src = (unsigned char *)(rvp + 1);
+
+        bih = (BITMAPINFOHEADER *)realloc(bih, sizeof(BITMAPINFOHEADER) + 12);
+        bih->biSize = 48;
+        bih->biPlanes = 1;
+        type2 = get_uint32_be(&rvp->type2);
+        if ((type2 == 0x10003000) || (type2 == 0x10003001))
+          bih->biCompression = mmioFOURCC('R', 'V', '1', '3');
+        else
+          bih->biCompression = mmioFOURCC('R', 'V', track->codec_id[9], '0');
+        dst = (unsigned char *)(bih + 1);
+        ((unsigned int *)dst)[0] = get_uint32_be(&rvp->type1);
+        ((unsigned int *)dst)[1] = type2;
+
+		    if ((bih->biCompression <= 0x30335652) &&
+            (type2 >= 0x20200002)) {
+          // read secondary WxH for the cmsg24[] (see vd_realvid.c)
+          ((unsigned short *)(bih + 1))[4] = 4 * (unsigned short)src[0];
+          ((unsigned short *)(bih + 1))[5] = 4 * (unsigned short)src[1];
+        } else
+          memset(&dst[8], 0, 4);
+        track->realmedia = true;
+
+#if defined(USE_QTX_CODECS)
+      } else if ((track->private_size >= sizeof(qt_image_description_t)) &&
+                 (!strcmp(track->codec_id, MKV_V_QUICKTIME))) {
+        idesc = (qt_image_description_t *)track->private_data;
+        idesc->id_size = get_uint32_be(&idesc->id_size);
+        idesc->codec_type = get_uint32(&idesc->codec_type);
+        idesc->version = get_uint16_be(&idesc->version);
+        idesc->revision = get_uint16_be(&idesc->revision);
+        idesc->vendor = get_uint32_be(&idesc->vendor);
+        idesc->temporal_quality = get_uint32_be(&idesc->temporal_quality);
+        idesc->spatial_quality = get_uint32_be(&idesc->spatial_quality);
+        idesc->width = get_uint16_be(&idesc->width);
+        idesc->height = get_uint16_be(&idesc->height);
+        idesc->horizontal_resolution =
+          get_uint32_be(&idesc->horizontal_resolution);
+        idesc->vertical_resolution =
+          get_uint32_be(&idesc->vertical_resolution);
+        idesc->data_size = get_uint32_be(&idesc->data_size);
+        idesc->frame_count = get_uint16_be(&idesc->frame_count);
+        idesc->depth = get_uint16_be(&idesc->depth);
+        idesc->color_table_id = get_uint16_be(&idesc->color_table_id);
+        bih->biPlanes = 1;
+        bih->biCompression = idesc->codec_type;
+#endif // defined(USE_QTX_CODECS)
+
+      } else {
+        mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Unknown/unsupported CodecID "
+               "(%s) or missing/bad CodecPrivate data (track %u).\n",
+               track->codec_id, track->tnum);
+        demuxer->video->id = -2;
+      }
+    }
+
+    if (demuxer->video->id != -2) {
+      mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] Will play video track %u\n",
+             track->tnum);
+
+      sh_v = new_sh_video(demuxer, track->tnum);
+      sh_v->bih = bih;
+      sh_v->format = sh_v->bih->biCompression;
+      if (track->v_frate == 0.0)
+        track->v_frate = 25.0;
+      sh_v->fps = track->v_frate;
+      sh_v->frametime = 1 / track->v_frate;
+      if (!track->realmedia) {
+        sh_v->disp_w = track->v_width;
+        sh_v->disp_h = track->v_height;
+        sh_v->aspect = (float)track->v_dwidth / (float)track->v_dheight;
+      } else {
+        // vd_realvid.c will set aspect to disp_w/disp_h and rederive
+        // disp_w and disp_h from the RealVideo stream contents returned
+        // by the Real DLLs. If DisplayWidth/DisplayHeight was not set in
+        // the Matroska file then it has already been set to PixelWidth/Height
+        // by check_track_information.
+        sh_v->disp_w = track->v_dwidth;
+        sh_v->disp_h = track->v_dheight;
+      }
+      if (idesc != NULL)
+        sh_v->ImageDesc = idesc;
+      mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Aspect: %f\n", sh_v->aspect);
+
+      demuxer->video->id = track->tnum;
+      demuxer->video->sh = sh_v;
+      sh_v->ds = demuxer->video;
+
+      mkv_d->video = track;
+    } else
+      free(bih);
+
+  } else {
+    mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] No video track found/wanted.\n");
+    demuxer->video->id = -2;
+  }
+
+  track = NULL;
+  if (demuxer->audio->id == -1) { // Automatically select an audio track.
+    // check if the user specified an audio language
+    if (audio_lang != NULL) {
+      track = find_track_by_language(mkv_d, audio_lang, NULL, 'a');
+    }
+    if (track == NULL)
+      // no audio language specified, or language not found
+      // Search for an audio track that has the 'default' flag set.
+      for (i = 0; i < mkv_d->num_tracks; i++)
+        if ((mkv_d->tracks[i]->type == 'a') && mkv_d->tracks[i]->ok &&
+            mkv_d->tracks[i]->default_track) {
+          track = mkv_d->tracks[i];
+          break;
+        }
+
+    if (track == NULL)
+      // No track has the 'default' flag set - let's take the first audio
+      // track.
+      for (i = 0; i < mkv_d->num_tracks; i++)
+        if ((mkv_d->tracks[i]->type == 'a') && mkv_d->tracks[i]->ok) {
+          track = mkv_d->tracks[i];
+          break;
+        }
+  } else if (demuxer->audio->id != -2) // -2 = no audio at all
+    track = find_track_by_num(mkv_d, demuxer->audio->id, 'a');
+
+  if (track) {
+    mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] Will play audio track %u\n",
+           track->tnum);
+    sh_a = new_sh_audio(demuxer, track->tnum);
+
+    demuxer->audio->id = track->tnum;
+    demuxer->audio->sh = sh_a;
+    sh_a->ds = demuxer->audio;
+
+    mkv_d->audio = track;
+
+    if (track->ms_compat)
+      sh_a->wf = (WAVEFORMATEX *)safememdup(track->private_data,
+                                            track->private_size);
+    else {
+      sh_a->wf = (WAVEFORMATEX *)safemalloc(sizeof(WAVEFORMATEX));
+      memset(sh_a->wf, 0, sizeof(WAVEFORMATEX));
+    }
+    sh_a->format = track->a_formattag;
+    sh_a->wf->wFormatTag = track->a_formattag;
+    sh_a->channels = track->a_channels;
+    sh_a->wf->nChannels = track->a_channels;
+    sh_a->samplerate = (uint32_t)track->a_sfreq;
+    sh_a->wf->nSamplesPerSec = (uint32_t)track->a_sfreq;
+    sh_a->samplesize = track->a_bps / 8;
+    if (!strcmp(track->codec_id, MKV_A_MP3) ||
+        !strcmp(track->codec_id, MKV_A_MP2)) {
+      sh_a->wf->nAvgBytesPerSec = 16000;
+      sh_a->wf->nBlockAlign = 1152;
+      sh_a->wf->wBitsPerSample = 0;
+      sh_a->samplesize = 0;
+
+    } else if (!strncmp(track->codec_id, MKV_A_AC3, strlen(MKV_A_AC3))) {
+      sh_a->wf->nAvgBytesPerSec = 16000;
+      sh_a->wf->nBlockAlign = 1536;
+      sh_a->wf->wBitsPerSample = 0;
+      sh_a->samplesize = 0;
+
+    } else if (!strcmp(track->codec_id, MKV_A_PCM) ||
+               !strcmp(track->codec_id, MKV_A_PCM_BE)) {
+      sh_a->wf->nAvgBytesPerSec = sh_a->channels * sh_a->samplerate * 2;
+      sh_a->wf->nBlockAlign = sh_a->wf->nAvgBytesPerSec;
+      sh_a->wf->wBitsPerSample = track->a_bps;
+      if (!strcmp(track->codec_id, MKV_A_PCM_BE))
+        sh_a->format = mmioFOURCC('t', 'w', 'o', 's');
+
+    } else if (!strcmp(track->codec_id, MKV_A_QDMC) ||
+               !strcmp(track->codec_id, MKV_A_QDMC2)) {
+      sh_a->wf->wBitsPerSample = track->a_bps;
+      sh_a->wf->nAvgBytesPerSec = 16000;
+      sh_a->wf->nBlockAlign = 1486;
+      track->fix_i_bps = true;
+      track->qt_last_a_pts = 0.0;
+      if (track->private_data != NULL) {
+        sh_a->codecdata = (unsigned char *)safememdup(track->private_data,
+                                                      track->private_size);
+        sh_a->codecdata_len = track->private_size;
+      }
+      if (!strcmp(track->codec_id, MKV_A_QDMC))
+        sh_a->format = mmioFOURCC('Q', 'D', 'M', 'C');
+      else
+        sh_a->format = mmioFOURCC('Q', 'D', 'M', '2');
+
+    } else if (track->a_formattag == mmioFOURCC('M', 'P', '4', 'A')) {
+      int profile, srate_idx;
+
+      sh_a->wf->nAvgBytesPerSec = 16000;
+      sh_a->wf->nBlockAlign = 1024;
+      sh_a->wf->wBitsPerSample = 0;
+      sh_a->samplesize = 0;
+
+      // Recreate the 'private data' which faad2 uses in its initialization.
+      srate_idx = aac_get_sample_rate_index(sh_a->samplerate);
+      if (!strncmp(&track->codec_id[12], "MAIN", 4))
+        profile = 0;
+      else if (!strncmp(&track->codec_id[12], "LC", 2))
+        profile = 1;
+      else if (!strncmp(&track->codec_id[12], "SSR", 3))
+        profile = 2;
+      else
+        profile = 3;
+      sh_a->codecdata = (unsigned char *)safemalloc(5);
+      sh_a->codecdata[0] = ((profile + 1) << 3) | ((srate_idx & 0xe) >> 1);
+      sh_a->codecdata[1] = ((srate_idx & 0x1) << 7) |
+        (track->a_channels << 3);
+
+      if (strstr(track->codec_id, "SBR") != NULL) {
+        // HE-AAC (aka SBR AAC)
+        sh_a->codecdata_len = 5;
+
+        sh_a->samplerate *= 2;
+        sh_a->wf->nSamplesPerSec *= 2;
+        srate_idx = aac_get_sample_rate_index(sh_a->samplerate);
+        sh_a->codecdata[2] = AAC_SYNC_EXTENSION_TYPE >> 3;
+        sh_a->codecdata[3] = ((AAC_SYNC_EXTENSION_TYPE & 0x07) << 5) | 5;
+        sh_a->codecdata[4] = (1 << 7) | (srate_idx << 3);
+        track->default_duration = 1024.0 / (float)(sh_a->samplerate / 2);
+
+      } else {
+        sh_a->codecdata_len = 2;
+        track->default_duration = 1024.0 / (float)sh_a->samplerate;
+      }
+
+    } else if (!strcmp(track->codec_id, MKV_A_VORBIS)) {
+      for (i = 0; i < 3; i++) {
+        dp = new_demux_packet(track->header_sizes[i]);
+        memcpy(dp->buffer, track->headers[i], track->header_sizes[i]);
+        dp->pts = 0;
+        dp->flags = 0;
+        ds_add_packet(demuxer->audio, dp);
+      }
+
+    } else if ((track->private_size >= sizeof(real_audio_v4_props_t)) &&
+               !strncmp(track->codec_id, MKV_A_REALATRC, 7)) {
+      // Common initialization for all RealAudio codecs
+      real_audio_v4_props_t *ra4p;
+      real_audio_v5_props_t *ra5p;
+      unsigned char *src;
+      int codecdata_length, version;
+
+      ra4p = (real_audio_v4_props_t *)track->private_data;
+      ra5p = (real_audio_v5_props_t *)track->private_data;
+
+      sh_a->wf->wBitsPerSample = sh_a->samplesize * 8;
+      sh_a->wf->nAvgBytesPerSec = 0; // FIXME !?
+      sh_a->wf->nBlockAlign = get_uint16_be(&ra4p->frame_size);
+
+      version = get_uint16_be(&ra4p->version1);
+
+      if (version == 4) {
+        src = (unsigned char *)(ra4p + 1);
+        src += src[0] + 1;
+        src += src[0] + 1;
+      } else
+        src = (unsigned char *)(ra5p + 1);
+
+      src += 3;
+      if (version == 5)
+        src++;
+      codecdata_length = get_uint32_be(src);
+      src += 4;
+      sh_a->wf->cbSize = 10 + codecdata_length;
+      sh_a->wf = (WAVEFORMATEX *)realloc(sh_a->wf, sizeof(WAVEFORMATEX) +
+                                         sh_a->wf->cbSize);
+      ((short *)(sh_a->wf + 1))[0] = get_uint16_be(&ra4p->sub_packet_size);
+      ((short *)(sh_a->wf + 1))[1] = get_uint16_be(&ra4p->sub_packet_h);
+      ((short *)(sh_a->wf + 1))[2] = get_uint16_be(&ra4p->flavor);
+      ((short *)(sh_a->wf + 1))[3] = get_uint32_be(&ra4p->coded_frame_size);
+      ((short *)(sh_a->wf + 1))[4] = codecdata_length;
+      memcpy(((char *)(sh_a->wf + 1)) + 10, src, codecdata_length);
+
+      track->realmedia = true;
+
+    } else if (!strcmp(track->codec_id, MKV_A_FLAC) ||
+               (track->a_formattag == 0xf1ac)) {
+      unsigned char *ptr;
+      int size;
+      free(sh_a->wf);
+      sh_a->wf = NULL;
+
+      if (track->a_formattag == mmioFOURCC('f', 'L', 'a', 'C')) {
+        ptr = (unsigned char *)track->private_data;
+        size = track->private_size;
+      } else {
+        sh_a->format = mmioFOURCC('f', 'L', 'a', 'C');
+        ptr = (unsigned char *)track->private_data + sizeof(WAVEFORMATEX);
+        size = track->private_size - sizeof(WAVEFORMATEX);
+      }
+      if ((size < 4) || (ptr[0] != 'f') || (ptr[1] != 'L') ||
+          (ptr[2] != 'a') || (ptr[3] != 'C')) {
+        dp = new_demux_packet(4);
+        memcpy(dp->buffer, "fLaC", 4);
+        dp->pts = 0;
+        dp->flags = 0;
+        ds_add_packet(demuxer->audio, dp);
+      }
+      dp = new_demux_packet(size);
+      memcpy(dp->buffer, ptr, size);
+      dp->pts = 0;
+      dp->flags = 0;
+      ds_add_packet(demuxer->audio, dp);
+    }
+
+  } else {
+    mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] No audio track found/wanted.\n");
+    demuxer->audio->id = -2;
+  }
+
+  // DO NOT automatically select a subtitle track and behave like DVD
+  // playback: only show subtitles if the user explicitely wants them.
+  track = NULL;
+  if (demuxer->sub->id >= 0)
+    track = find_track_by_num(mkv_d, demuxer->sub->id, 's');
+  else if (dvdsub_lang != NULL)
+    track = find_track_by_language(mkv_d, dvdsub_lang, NULL);
+  if (track) {
+    if (!strcmp(track->codec_id, MKV_S_VOBSUB)) {
+      mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] Will display subtitle track %u\n",
+             track->tnum);
+      mkv_d->subs_track = track;
+      mkv_d->subtitle_type = MKV_SUBTYPE_VOBSUB;
+      demuxer->sub->sh = (mkv_sh_sub_t *)safememdup(&track->sh_sub,
+                                                    sizeof(mkv_sh_sub_t));
+      demuxer->sub->id = track->xid;
+
+    } else if (strcmp(track->codec_id, MKV_S_TEXTASCII) &&
+               strcmp(track->codec_id, MKV_S_TEXTUTF8) && 
+               strcmp(track->codec_id, MKV_S_TEXTSSA) &&
+               strcmp(track->codec_id, "S_SSA") &&
+               strcmp(track->codec_id, "S_ASS") &&
+               strcmp(track->codec_id, "S_TEXT/ASS"))
+      mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] Subtitle type '%s' is not "
+             "supported. Track will not be displayed.\n", track->codec_id);
+    else {
+      mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] Will display subtitle track %u\n",
+             track->tnum);
+      mkv_d->subs_track = track;
+      if (!mkv_d->subs.text[0]) {
+        for (i = 0; i <= SUB_MAX_TEXT; i++)
+          mkv_d->subs.text[i] = (char *)safemalloc(256);
+
+        if (!strcmp(track->codec_id, MKV_S_TEXTUTF8))
+          sub_utf8 = 1;       // Force UTF-8 conversion.
+        if (!strcmp(track->codec_id, MKV_S_TEXTSSA) ||
+            !strcmp(track->codec_id, "S_SSA") ||
+            !strcmp(track->codec_id, "S_ASS") ||
+            !strcmp(track->codec_id, "S_TEXT/ASS")) {
+          mkv_d->subtitle_type = MKV_SUBTYPE_SSA;
+          sub_utf8 = 1;
+        } else
+          mkv_d->subtitle_type = MKV_SUBTYPE_TEXT;
+      } else
+        mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] File does not contain a "
+               "subtitle track with the id %u.\n", demuxer->sub->id);
+      demuxer->sub->sh = NULL;
+    }
+  }
+
+  demuxer->priv = mkv_d;
+
+  if (mkv_d->chapters != NULL) {
+    for (i = 0; i < (int)mkv_d->chapters->size(); i++) {
+      (*mkv_d->chapters)[i].start -= mkv_d->first_tc;
+      (*mkv_d->chapters)[i].end -= mkv_d->first_tc;
+    }
+    if ((dvd_last_chapter > 0) &&
+        (dvd_last_chapter <= (int)mkv_d->chapters->size())) {
+      if ((*mkv_d->chapters)[dvd_last_chapter - 1].end != 0)
+        mkv_d->stop_timecode = (*mkv_d->chapters)[dvd_last_chapter - 1].end;
+      else if ((dvd_last_chapter + 1) <= (int)mkv_d->chapters->size())
+        mkv_d->stop_timecode = (*mkv_d->chapters)[dvd_last_chapter].start;
+    }
+  }
+
+  if (s->end_pos == 0)
+    demuxer->seekable = 0;
+  else {
+    demuxer->movi_start = s->start_pos;
+    demuxer->movi_end = s->end_pos;
+    demuxer->seekable = 1;
+    if ((dvd_chapter != 1) && (mkv_d->chapters != NULL) &&
+        (dvd_chapter <= (int)mkv_d->chapters->size()))
+      demux_mkv_seek(demuxer, (float)(*mkv_d->chapters)[dvd_chapter - 1].start
+                     / 1000.0, 1);
+  }
+
+  return 1;
+}
+
+// Taken from demux_real.c. Thanks to the original developpers :)
+#define SKIP_BITS(n) buffer <<= n
+#define SHOW_BITS(n) ((buffer) >> (32 - (n)))
+
+static float real_fix_timestamp(mkv_track_t *track, unsigned char *s,
+                                int timestamp) {
+  float v_pts;
+  uint32_t buffer = (s[0] << 24) + (s[1] << 16) + (s[2] << 8) + s[3];
+  int kf = timestamp;
+  int pict_type;
+  int orig_kf;
+
+  if (!strcmp(track->codec_id, MKV_V_REALV30) ||
+      !strcmp(track->codec_id, MKV_V_REALV40)) {
+
+    if (!strcmp(track->codec_id, MKV_V_REALV30)) {
+      SKIP_BITS(3);
+      pict_type = SHOW_BITS(2);
+      SKIP_BITS(2 + 7);
+    }else{
+      SKIP_BITS(1);
+      pict_type = SHOW_BITS(2);
+      SKIP_BITS(2 + 7 + 3);
+    }
+    kf = SHOW_BITS(13);         // kf= 2*SHOW_BITS(12);
+    orig_kf = kf;
+    if (pict_type <= 1) {
+      // I frame, sync timestamps:
+      track->rv_kf_base = timestamp - kf;
+      mp_msg(MSGT_DEMUX, MSGL_V, "\nTS: base=%08X\n", track->rv_kf_base);
+      kf = timestamp;
+    } else {
+      // P/B frame, merge timestamps:
+      int tmp = timestamp - track->rv_kf_base;
+      kf |= tmp & (~0x1fff);    // combine with packet timestamp
+      if (kf < (tmp - 4096))    // workaround wrap-around problems
+        kf += 8192;
+      else if (kf > (tmp + 4096))
+        kf -= 8192;
+      kf += track->rv_kf_base;
+    }
+    if (pict_type != 3) {       // P || I  frame -> swap timestamps
+      int tmp = kf;
+      kf = track->rv_kf_pts;
+      track->rv_kf_pts = tmp;
+    }
+    mp_msg(MSGT_DEMUX, MSGL_V, "\nTS: %08X -> %08X (%04X) %d %02X %02X %02X "
+           "%02X %5d\n", timestamp, kf, orig_kf, pict_type, s[0], s[1], s[2],
+           s[3], kf - (int)(1000.0 * track->rv_pts));
+  }
+  v_pts = kf * 0.001f;
+  track->rv_pts = v_pts;
+
+  return v_pts;
+}
+
+static void handle_realvideo(demuxer_t *demuxer, unsigned char *data,
+                             uint32_t size, bool keyframe, int &found_data) {
+  dp_hdr_t *hdr;
+  int chunks, isize;
+  mkv_demuxer_t *mkv_d;
+  demux_stream_t *ds;
+  demux_packet_t *dp;
+
+  mkv_d = (mkv_demuxer_t *)demuxer->priv;
+  ds = demuxer->video;
+  chunks = data[0];
+  isize = size - 1 - (chunks + 1) * 8;
+  dp = new_demux_packet(sizeof(dp_hdr_t) + isize + 8 * (chunks + 1));
+  memcpy(&dp->buffer[sizeof(dp_hdr_t)], &data[1 + (chunks + 1) * 8], isize);
+  memcpy(&dp->buffer[sizeof(dp_hdr_t) + isize], &data[1], (chunks + 1) * 8);
+  hdr = (dp_hdr_t *)dp->buffer;
+  hdr->len = isize;
+  hdr->chunks = chunks;
+  hdr->timestamp = (int)(mkv_d->last_pts * 1000);
+  hdr->chunktab = sizeof(dp_hdr_t) + isize;
+
+  dp->len = sizeof(dp_hdr_t) + isize + 8 * (chunks + 1);
+  if (mkv_d->v_skip_to_keyframe) {
+    dp->pts = mkv_d->last_pts;
+    mkv_d->video->rv_kf_base = 0;
+    mkv_d->video->rv_kf_pts = hdr->timestamp;
+  } else
+    dp->pts = real_fix_timestamp(mkv_d->video, &dp->buffer[sizeof(dp_hdr_t)],
+                                 hdr->timestamp);
+  dp->pos = demuxer->filepos;
+  dp->flags = keyframe ? 0x10 : 0;
+
+  ds_add_packet(ds, dp);
+
+  found_data++;
+}
+
+static void handle_realaudio(demuxer_t *demuxer, unsigned char *data,
+                             uint32_t size, bool keyframe, int &found_data) {
+  mkv_demuxer_t *mkv_d;
+  demux_packet_t *dp;
+
+  mkv_d = (mkv_demuxer_t *)demuxer->priv;
+
+  dp = new_demux_packet(size);
+  memcpy(dp->buffer, data, size);
+  if ((mkv_d->audio->ra_pts == mkv_d->last_pts) &&
+      !mkv_d->a_skip_to_keyframe)
+    dp->pts = 0;
+  else
+    dp->pts = mkv_d->last_pts;
+  mkv_d->audio->ra_pts = mkv_d->last_pts;
+
+  dp->pos = demuxer->filepos;
+  dp->flags = keyframe ? 0x10 : 0;
+
+  ds_add_packet(demuxer->audio, dp);
+
+  found_data++;
+}
+
+extern "C" int demux_mkv_fill_buffer(demuxer_t *d) {
+  demux_packet_t *dp;
+  demux_stream_t *ds;
+  mkv_demuxer_t *mkv_d;
+  mkv_track_t *t = NULL;
+  int upper_lvl_el, exit_loop, found_data, i, linei, sl;
+  char *texttmp;
+  // Elements for different levels
+  EbmlElement *l0 = NULL, *l1 = NULL, *l2 = NULL, *l3 = NULL;
+  EbmlStream *es;
+  KaxBlock *block;
+  int64_t block_duration, block_bref, block_fref;
+  bool use_this_block, lines_cut;
+  float current_pts;
+
+  mkv_d = (mkv_demuxer_t *)d->priv;
+  es = mkv_d->es;
+  l0 = mkv_d->segment;
+
+  // End of stream
+  if (mkv_d->saved_l1 == NULL)
+    return 0;
+
+  exit_loop = 0;
+  upper_lvl_el = 0;
+  l1 = mkv_d->saved_l1;
+  mkv_d->saved_l1 = NULL;
+  found_data = 0;
+  try {
+    // The idea is not to handle a complete KaxCluster with each call to
+    // demux_mkv_fill_buffer because those might be rather big.
+    while ((l1 != NULL) && (upper_lvl_el <= 0)) {
+
+      if (EbmlId(*l1) == KaxCluster::ClassInfos.GlobalId) {
+        mkv_d->cluster = (KaxCluster *)l1;
+        if (found_data) {
+          mkv_d->saved_l1 = l1;
+          break;
+        }
+
+        if (mkv_d->saved_l2 != NULL) {
+          l2 = mkv_d->saved_l2;
+          mkv_d->saved_l2 = NULL;
+        } else
+          l2 = es->FindNextElement(l1->Generic().Context, upper_lvl_el,
+                                   0xFFFFFFFFL, true, 1);
+        while ((l2 != NULL) && (upper_lvl_el <= 0)) {
+
+          // Handle at least one data packets in one call to
+          // demux_mkv_fill_buffer - but abort if we have found that.
+          if (found_data >= 1) {
+            mkv_d->saved_l2 = l2;
+            mkv_d->saved_l1 = l1;
+            exit_loop = 1;
+            break;
+          }
+
+          if (EbmlId(*l2) == KaxClusterTimecode::ClassInfos.GlobalId) {
+            KaxClusterTimecode &ctc = *static_cast<KaxClusterTimecode *>(l2);
+            ctc.ReadData(es->I_O());
+            mkv_d->cluster_tc = uint64(ctc);
+#if LIBEBML_VERSION >= 000404
+            mkv_d->cluster->InitTimecode(mkv_d->cluster_tc, mkv_d->tc_scale);
+#else
+            mkv_d->cluster->InitTimecode(mkv_d->cluster_tc);
+#endif // LIBEBML_VERSION
+
+          } else if (EbmlId(*l2) == KaxBlockGroup::ClassInfos.GlobalId) {
+
+            KaxBlockDuration *kbdur;
+            KaxReferenceBlock *krefblock;
+            KaxBlock *kblock;
+
+            block = NULL;
+            block_duration = -1;
+            block_bref = 0;
+            block_fref = 0;
+
+            l2->Read(*es, KaxBlockGroup::ClassInfos.Context, upper_lvl_el, l3,
+                     true);
+
+            kbdur = FINDFIRST(l2, KaxBlockDuration);
+            if (kbdur != NULL)
+              block_duration = uint64(*kbdur);
+
+            kblock = FINDFIRST(l2, KaxBlock);
+            if (kblock != NULL) {
+              kblock->SetParent(*mkv_d->cluster);
+              if ((mkv_d->stop_timecode > 0) &&
+                  ((kblock->GlobalTimecode() / 1000000 - mkv_d->first_tc) >=
+                   mkv_d->stop_timecode)) {
+                delete l2;
+                return 0;
+              }
+            }
+
+            krefblock = FINDFIRST(l2, KaxReferenceBlock);
+            while (krefblock != NULL) {
+              if (int64(*krefblock) < 0)
+                block_bref = int64(*krefblock);
+              else
+                block_fref = int64(*krefblock);
+
+              krefblock = FINDNEXT(l2, KaxReferenceBlock, krefblock);
+            }
+
+            if (kblock != NULL) {
+              // Clear the subtitles if they're obsolete now.
+              lines_cut = false;
+              for (linei = 0; linei < mkv_d->subs.lines; linei++) {
+                if (mkv_d->clear_subs_at[linei] <=
+                    (kblock->GlobalTimecode() / 1000000 - mkv_d->first_tc)) {
+                  sl = linei; 
+                  texttmp = mkv_d->subs.text[sl];
+                  while (sl < mkv_d->subs.lines) {
+                    mkv_d->subs.text[sl] = mkv_d->subs.text[sl + 1];
+                    mkv_d->clear_subs_at[sl] = mkv_d->clear_subs_at[sl + 1];
+                    sl++;
+                  }
+                  mkv_d->subs.text[sl] = texttmp;
+                  mkv_d->subs.lines--;
+                  linei--;
+                  lines_cut = true;
+                }
+                if (lines_cut) {
+                  vo_sub = &mkv_d->subs;
+                  vo_osd_changed(OSDTYPE_SUBTITLE);
+                }
+              }
+
+              ds = NULL;
+              if ((mkv_d->video != NULL) &&
+                  (mkv_d->video->tnum == kblock->TrackNum())) {
+                ds = d->video;
+                t = mkv_d->video;
+              } else if ((mkv_d->audio != NULL) && 
+                         (mkv_d->audio->tnum == kblock->TrackNum())) {
+                ds = d->audio;
+                t = mkv_d->audio;
+              } else if ((mkv_d->subs_track != NULL) && 
+                         (mkv_d->subs_track->tnum == kblock->TrackNum())) {
+                ds = d->sub;
+                t = mkv_d->subs_track;
+              }
+
+              use_this_block = true;
+
+              current_pts = (float)(kblock->GlobalTimecode() / 1000000.0 -
+                                    mkv_d->first_tc) / 1000.0;
+              if (current_pts < 0.0)
+                current_pts = 0.0;
+
+              if (ds == d->audio) {
+                if (mkv_d->a_skip_to_keyframe &&       
+                    (block_bref != 0))
+                  use_this_block = false;
+                
+                else if (mkv_d->v_skip_to_keyframe)
+                  use_this_block = false;
+
+                if (mkv_d->audio->fix_i_bps && use_this_block) {
+                  uint32_t i, sum;
+                  sh_audio_t *sh;
+
+                  for (i = 0, sum = 0; i < kblock->NumberFrames(); i++) {
+                    DataBuffer &data = kblock->GetBuffer(i);
+                    sum += data.Size();
+                  }
+                  sh = (sh_audio_t *)ds->sh;
+                  if (block_duration != -1) {
+                    sh->i_bps = sum * 1000 / block_duration;
+                    mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Changed i_bps to %d.\n",
+                           sh->i_bps);
+                    mkv_d->audio->fix_i_bps = false;
+                  } else if (mkv_d->audio->qt_last_a_pts == 0.0)
+                    mkv_d->audio->qt_last_a_pts = current_pts;
+                  else if (mkv_d->audio->qt_last_a_pts != current_pts) {
+                    sh->i_bps = (int)(sum / (current_pts -
+                                             mkv_d->audio->qt_last_a_pts));
+                    mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Changed i_bps to %d.\n",
+                           sh->i_bps);
+                    mkv_d->audio->fix_i_bps = false;
+                  }
+                }
+
+              } else if ((current_pts * 1000) < mkv_d->skip_to_timecode)
+                use_this_block = false;
+
+              else if (ds == d->video) {
+                if (mkv_d->v_skip_to_keyframe &&
+                    (block_bref != 0))
+                  use_this_block = false;
+                
+              } else if ((mkv_d->subs_track != NULL) &&
+                         (mkv_d->subs_track->tnum == kblock->TrackNum())) {
+                if (mkv_d->subtitle_type != MKV_SUBTYPE_VOBSUB) {
+                  if (!mkv_d->v_skip_to_keyframe)
+                    handle_subtitles(d, kblock, block_duration);
+                  use_this_block = false;
+                }
+
+              } else
+                use_this_block = false;
+
+              if (use_this_block) {
+                mkv_d->last_pts = current_pts;
+                ds->pts = current_pts;
+                d->filepos = mkv_d->in->getFilePointer();
+                mkv_d->last_filepos = d->filepos;
+
+                for (i = 0; i < (int)kblock->NumberFrames(); i++) {
+                  unsigned char *re_buffer;
+                  uint32_t re_size;
+                  bool re_modified;
+                  DataBuffer &data = kblock->GetBuffer(i);
+
+                  re_buffer = data.Buffer();
+                  re_size = data.Size();
+                  re_modified = reverse_encodings(t, re_buffer, re_size, 1);
+
+                  if ((ds == d->video) && mkv_d->video->realmedia)
+                    handle_realvideo(d, re_buffer, re_size, block_bref == 0,
+                                     found_data);
+
+                  else if ((ds == d->audio) && mkv_d->audio->realmedia)
+                    handle_realaudio(d, re_buffer, re_size, block_bref == 0,
+                                     found_data);
+
+                  else {
+                    dp = new_demux_packet(re_size);
+                    memcpy(dp->buffer, re_buffer, re_size);
+                    dp->flags = block_bref == 0 ? 1 : 0;
+                    dp->pts = mkv_d->last_pts + i * t->default_duration;
+                    ds_add_packet(ds, dp);
+                    found_data++;
+                  }
+                  if (re_modified)
+                    safefree(re_buffer);
+                }
+                if (ds == d->video) {
+                  mkv_d->v_skip_to_keyframe = false;
+                  mkv_d->skip_to_timecode = 0;
+                } else if (ds == d->audio)
+                  mkv_d->a_skip_to_keyframe = false;
+              }
+
+              delete block;
+            } // kblock != NULL
+
+          } else
+            l2->SkipData(*es, l2->Generic().Context);
+
+          if (!in_parent(l1)) {
+            delete l2;
+            break;
+          }
+
+          if (upper_lvl_el > 0) {
+            upper_lvl_el--;
+            if (upper_lvl_el > 0)
+              break;
+            delete l2;
+            l2 = l3;
+            continue;
+
+          } else if (upper_lvl_el < 0) {
+            upper_lvl_el++;
+            if (upper_lvl_el < 0)
+              break;
+
+          }
+
+          l2->SkipData(*es, l2->Generic().Context);
+          delete l2;
+          l2 = es->FindNextElement(l1->Generic().Context, upper_lvl_el,
+                                   0xFFFFFFFFL, true);
+
+        } // while (l2 != NULL)
+
+      } else if (EbmlId(*l1) == KaxCues::ClassInfos.GlobalId)
+        return 0;
+      else
+        l1->SkipData(*es, l1->Generic().Context);
+
+      if (!in_parent(l0)) {
+        delete l1;
+        break;
+      }
+
+      if (upper_lvl_el > 0) {
+        upper_lvl_el--;
+        if (upper_lvl_el > 0)
+          break;
+        delete l1;
+        l1 = l2;
+        continue;
+
+      } else if (upper_lvl_el < 0) {
+        upper_lvl_el++;
+        if (upper_lvl_el < 0)
+          break;
+
+      }
+
+      if (exit_loop)
+        break;
+
+      l1->SkipData(*es, l1->Generic().Context);
+      delete l1;
+      l1 = es->FindNextElement(l0->Generic().Context, upper_lvl_el,
+                               0xFFFFFFFFL, true);
+
+    } // while (l1 != NULL)
+  } catch (exception ex) {
+    mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] exception caught\n");
+    return 0;
+  }
+
+  if (found_data)
+    return 1;
+
+  return 0;
+}
+
+extern "C" void resync_audio_stream(sh_audio_t *sh_audio);
+
+extern "C" void demux_mkv_seek(demuxer_t *demuxer, float rel_seek_secs,
+                               int flags) {
+  int i, k, upper_lvl_el;
+  mkv_demuxer_t *mkv_d = (mkv_demuxer_t *)demuxer->priv;
+  int64_t target_timecode, target_filepos = 0, min_diff, diff, current_pos;
+  int64_t cluster_pos;
+  mkv_track_index_t *index;
+  mkv_index_entry_t *entry;
+  EbmlElement *l1;
+
+  mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] SEEK, relss: %.3f, flags: %d\n",
+         rel_seek_secs, flags);
+
+  if (!mkv_d->cues_found && !mkv_d->cues_searched) {
+    // We've not found an index so far. So let's skip over all level 1
+    // elements until we either hit another segment, the end of the file
+    // or - suprise - some cues.
+    current_pos = mkv_d->in->getFilePointer();
+
+    // Skip the data but do not delete the element! This is our current
+    // cluster, and we need it later on in demux_mkv_fill_buffer.
+    l1 = mkv_d->saved_l1;
+    l1->SkipData(static_cast<EbmlStream &>(*mkv_d->es), l1->Generic().Context);
+    l1 = mkv_d->es->FindNextElement(mkv_d->segment->Generic().Context,
+                                    upper_lvl_el, 0xFFFFFFFFL, true, 1);
+    while (l1 != NULL) {
+      if (upper_lvl_el)
+        break;
+
+      if (EbmlId(*l1) == KaxCues::ClassInfos.GlobalId) {
+        parse_cues(mkv_d, l1->GetElementPosition());
+        delete l1;
+        break;
+      } else {
+        if (EbmlId(*l1) == KaxCluster::ClassInfos.GlobalId)
+          add_cluster_position(mkv_d, l1->GetElementPosition());
+        l1->SkipData(static_cast<EbmlStream &>(*mkv_d->es),
+                     l1->Generic().Context);
+        delete l1;
+        l1 = mkv_d->es->FindNextElement(mkv_d->segment->Generic().Context,
+                                        upper_lvl_el, 0xFFFFFFFFL, true, 1);
+      }
+    }
+
+    if (demuxer->stream->eof)
+      stream_reset(demuxer->stream);
+    mkv_d->in->setFilePointer(current_pos);
+
+    mkv_d->cues_searched = 1;
+  }
+
+  if (!(flags & 2)) {           // Time in secs
+    if (flags & 1)              // Absolute seek
+      target_timecode = 0;
+    else                        // Relative seek
+      target_timecode = (int64_t)(mkv_d->last_pts * 1000.0);
+    target_timecode += (int64_t)(rel_seek_secs * 1000.0);
+    if (target_timecode < 0)
+      target_timecode = 0;
+
+    min_diff = 0xFFFFFFFL;
+
+    // Let's find the entry in the index with the smallest difference
+    // to the wanted timecode.
+    entry = NULL;
+    for (i = 0; i < mkv_d->num_indexes; i++)
+      if (mkv_d->index[i].tnum == mkv_d->video->tnum) {
+        index = &mkv_d->index[i];
+        for (k = 0; k < index->num_entries; k++) {
+          if (!index->entries[k].is_key)
+            continue;
+          diff = target_timecode - (int64_t)index->entries[k].timecode;
+          if (((flags & 1) || (target_timecode <= (mkv_d->last_pts * 1000))) &&
+              (diff >= 0) && (diff < min_diff)) {
+            min_diff = diff;
+            entry = &index->entries[k];
+            mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] seek BACK, solution: last_pts: "
+                   "%d, target: %d, diff: %d, entry->timecode: %d, PREV diff: "
+                   "%d, k: %d\n", (int)(mkv_d->last_pts * 1000),
+                   (int)target_timecode, (int)diff, (int)entry->timecode,
+                   k > 0 ? (int)(index->entries[k - 1].timecode -
+                                 target_timecode) : 0, k);
+                   
+          } else if ((target_timecode > (mkv_d->last_pts * 1000)) &&
+                     (diff < 0) && (-diff < min_diff)) {
+            min_diff = -diff;
+            entry = &index->entries[k];
+            mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] seek FORW, solution: last_pts: "
+                   "%d, target: %d, diff: %d, entry->timecode: %d, NEXT diff: "
+                   "%d, k: %d\n", (int)(mkv_d->last_pts * 1000),
+                   (int)target_timecode, (int)diff, (int)entry->timecode,
+                   k < index->num_entries ?
+                   (int)(index->entries[k + 1].timecode - target_timecode) :
+                   0, k);
+          }
+        }
+        break;
+      }
+
+    if (mkv_d->saved_l1 != NULL)
+      delete mkv_d->saved_l1;
+
+    if (mkv_d->saved_l2 != NULL) {
+      delete mkv_d->saved_l2;
+      mkv_d->saved_l2 = NULL;
+    }
+
+    if (entry != NULL) {        // We've found an entry.
+      mkv_d->in->setFilePointer(entry->filepos);
+      upper_lvl_el = 0;
+      mkv_d->saved_l1 =
+        mkv_d->es->FindNextElement(mkv_d->segment->Generic().Context,
+                                   upper_lvl_el, 0xFFFFFFFFL, true, 1);
+    } else {                    // We've not found an entry --> no index?
+      target_filepos = (int64_t)(target_timecode * mkv_d->last_filepos /
+        (mkv_d->last_pts * 1000.0));
+      mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] No index entry found. Calculated "
+             "filepos %lld. Old timecode %lld.\n", target_filepos,
+             (int64_t)(mkv_d->last_pts * 1000.0));
+      // Let's find the nearest cluster so that libebml does not have to
+      // do so much work.
+      cluster_pos = 0;
+      min_diff = 0x0FFFFFFFL;
+      for (i = 0; i < mkv_d->num_cluster_pos; i++) {
+        diff = mkv_d->cluster_positions[i] - target_filepos;
+        if (rel_seek_secs < 0) {
+          if ((diff > 0) && (diff < min_diff)) {
+            cluster_pos = mkv_d->cluster_positions[i];
+            min_diff = diff;
+          }
+        } else if ((diff < 0 ? -1 * diff : diff) < min_diff) {
+          cluster_pos = mkv_d->cluster_positions[i];
+          min_diff = diff < 0 ? -1 * diff : diff;
+        }
+      }
+      if (min_diff != 0x0FFFFFFFL) {
+        target_filepos = cluster_pos;
+        mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] New target_filepos because of "
+               "cluster: %lld.\n", target_filepos);
+      }
+      if (target_filepos >= demuxer->movi_end)
+        return;
+      mkv_d->in->setFilePointer(target_filepos);
+      upper_lvl_el = 0;
+      mkv_d->saved_l1 =
+        mkv_d->es->FindNextElement(mkv_d->segment->Generic().Context,
+                                   upper_lvl_el, 0xFFFFFFFFL, true, 1);
+      mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] seek result: target_timecode %lld, "
+             "did not find an entry. Calculated target_filspos: %lld\n",
+             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" :
+             mkv_d->saved_l1->Generic().DebugName);
+    }
+
+    if (mkv_d->video != NULL)
+      mkv_d->v_skip_to_keyframe = true;
+    if (rel_seek_secs > 0.0)
+      mkv_d->skip_to_timecode = target_timecode;
+
+    mkv_d->a_skip_to_keyframe = true;
+
+    demux_mkv_fill_buffer(demuxer);
+    mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] New timecode: %lld\n",
+           (int64_t)(mkv_d->last_pts * 1000.0));
+
+    mkv_d->subs.lines = 0;
+    vo_sub = &mkv_d->subs;
+    vo_osd_changed(OSDTYPE_SUBTITLE);
+
+    if(demuxer->audio->sh != NULL)
+      resync_audio_stream((sh_audio_t *)demuxer->audio->sh); 
+
+  } else
+    mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] seek unsupported flags\n");
+
+}
+
+extern "C" void demux_close_mkv(demuxer_t *demuxer) {
+  mkv_demuxer_t *mkv_d = (mkv_demuxer_t *)demuxer->priv;
+
+  free_mkv_demuxer(mkv_d);
+
+#ifdef USE_ICONV
+  subcp_close();
+#endif
+}
+
+extern "C" int demux_mkv_control(demuxer_t *demuxer, int cmd, void *arg) {
+  mkv_demuxer_t *mkv_d = (mkv_demuxer_t *)demuxer->priv;
+  
+  switch (cmd) {
+    case DEMUXER_CTRL_GET_TIME_LENGTH:
+      if (mkv_d->duration == -1.0)
+        return DEMUXER_CTRL_DONTKNOW;
+
+      *((unsigned long *)arg) = (unsigned long)mkv_d->duration;
+      return DEMUXER_CTRL_OK;
+
+    case DEMUXER_CTRL_GET_PERCENT_POS:
+      if (mkv_d->duration == -1.0) {
+        if (demuxer->movi_start == demuxer->movi_end)
+          return DEMUXER_CTRL_DONTKNOW;
+
+        *((int *)arg) =
+          (int)((demuxer->filepos - demuxer->movi_start) /
+                ((demuxer->movi_end - demuxer->movi_start) / 100));
+        return DEMUXER_CTRL_OK;
+      }
+
+      *((int *)arg) = (int)(100 * mkv_d->last_pts / mkv_d->duration);
+      return DEMUXER_CTRL_OK; 
+
+    default:
+      return DEMUXER_CTRL_NOTIMPL;
+  }
+}
+
+#endif /* HAVE_MATROSKA */