changeset 11229:b4040706e1d3

Added support for additional content encoding (compression, encryption) in general and zlib compression in particular (to be used with VobSubs).
author mosu
date Wed, 22 Oct 2003 17:59:28 +0000
parents f25d54466044
children 8eb5c1a0d21c
files libmpdemux/demux_mkv.cpp
diffstat 1 files changed, 361 insertions(+), 81 deletions(-) [+]
line wrap: on
line diff
--- a/libmpdemux/demux_mkv.cpp	Wed Oct 22 17:54:32 2003 +0000
+++ b/libmpdemux/demux_mkv.cpp	Wed Oct 22 17:59:28 2003 +0000
@@ -19,12 +19,17 @@
 #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>
@@ -44,6 +49,10 @@
 #include <stdio.h>
 #include <string.h>
 
+#ifdef HAVE_ZLIB
+#include <zlib.h>
+#endif
+
 #include "../mp_msg.h"
 #include "../help_mp.h"
 #include "stream.h"
@@ -61,10 +70,6 @@
 using namespace libmatroska;
 using namespace std;
 
-#ifndef LIBEBML_VERSION
-#define LIBEBML_VERSION 000000
-#endif // LIBEBML_VERSION
-
 #if LIBEBML_VERSION < 000500
 #error libebml version too old - need at least 0.5.0
 #endif
@@ -83,6 +88,29 @@
 #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;
@@ -149,6 +177,16 @@
   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 mkv_track {
   uint32_t tnum, xid;
   
@@ -190,7 +228,13 @@
 
   // Stuff for VobSubs
   mkv_sh_sub_t sh_sub;
-  int vobsub_compression;
+
+  // Generic content encoding support.
+  vector<mkv_content_encoding_t> *c_encodings;
+#ifdef HAVE_ZLIB
+  z_stream zstream;
+  bool zstream_initiated;
+#endif
 } mkv_track_t;
 
 typedef struct mkv_demuxer {
@@ -531,22 +575,22 @@
 static mkv_track_t *new_mkv_track(mkv_demuxer_t *d) {
   mkv_track_t *t;
   
-  t = (mkv_track_t *)malloc(sizeof(mkv_track_t));
-  if (t != NULL) {
-    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 = (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;
 }
@@ -657,17 +701,132 @@
   return (things_found == 3);
 }
 
+static bool reverse_encodings(mkv_track_t *track, unsigned char *&data,
+                              uint32_t &size, uint32_t type) {
+  int new_size;
+  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;
+
+      old_data = new_data;
+      new_data = (unsigned char *)safemalloc(new_size * 20);
+
+      track->zstream.next_in = (Bytef *)old_data;
+      track->zstream.next_out = (Bytef *)new_data;
+      track->zstream.avail_in = new_size;
+      track->zstream.avail_out = 20 * new_size;
+      result = inflate(&track->zstream, Z_FULL_FLUSH);
+      if (result != Z_OK) {
+        mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Zlib decompression failed. "
+              "Result: %d\n", result);
+        safefree(new_data);
+        data = old_data;
+        size = new_size;
+        return modified;
+      }
+
+      mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv] zlib decompression: from %d to "
+            "%d\n", new_size, 20 * new_size - track->zstream.avail_out);
+      new_size = 20 * new_size - track->zstream.avail_out;
+
+      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 = 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;
+#else
+        if (!t->zstream_initiated) {
+          t->zstream.zalloc = (alloc_func)0;
+          t->zstream.zfree = (free_func)0;
+          t->zstream.opaque = (voidpf)0;
+          inflateInit(&t->zstream);
+          t->zstream_initiated = true;
+        }
+#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)
@@ -888,7 +1047,7 @@
         break;
 
       case 's':
-        if (!strncmp(t->codec_id, MKV_S_VOBSUB, strlen(MKV_S_VOBSUB))) {
+        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), "
@@ -920,7 +1079,7 @@
 }
 
 static void free_mkv_demuxer(mkv_demuxer_t *d) {
-  int i;
+  int i, k;
   
   if (d == NULL)
     return;
@@ -931,6 +1090,17 @@
         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;
+#ifdef HAVE_ZLIB
+      if (d->tracks[i]->zstream_initiated)
+        inflateEnd(&d->tracks[i]->zstream);
+#endif
       free(d->tracks[i]);
     }
 
@@ -1244,9 +1414,7 @@
   
   try {
     // structure for storing the demuxer's private data
-    mkv_d = (mkv_demuxer_t *)malloc(sizeof(mkv_demuxer_t));
-    if (mkv_d == NULL)
-      return 0;
+    mkv_d = (mkv_demuxer_t *)safemalloc(sizeof(mkv_demuxer_t));
     memset(mkv_d, 0, sizeof(mkv_demuxer_t));
     mkv_d->duration = -1.0;
     
@@ -1356,6 +1524,11 @@
           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");
             
@@ -1507,13 +1680,9 @@
             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 = malloc(track->private_size);
-              if (track->private_data == NULL)
-                return 0;
-              memcpy(track->private_data, kcodecpriv->GetBuffer(),
-                     track->private_size);
-            }
+            if (track->private_size > 0)
+              track->private_data = safememdup(kcodecpriv->GetBuffer(),
+                                               track->private_size);
           }
 
           ktfdefault = FINDFIRST(ktentry, KaxTrackFlagDefault);
@@ -1532,6 +1701,115 @@
             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)
 
@@ -1650,11 +1928,8 @@
     BITMAPINFOHEADER *bih;
 
     idesc = NULL;
-    bih = (BITMAPINFOHEADER *)calloc(1, track->private_size);
-    if (bih == NULL) {
-      free_mkv_demuxer(mkv_d);
-      return 0;
-    }
+    bih = (BITMAPINFOHEADER *)safemalloc(track->private_size);
+    memset(bih, 0, sizeof(BITMAPINFOHEADER));
 
     if (track->ms_compat) {         // MS compatibility mode
       BITMAPINFOHEADER *src;
@@ -1816,19 +2091,12 @@
 
     mkv_d->audio = track;
 
-    if (track->ms_compat) {
-      sh_a->wf = (WAVEFORMATEX *)calloc(1, track->private_size);
-      if (sh_a->wf == NULL) {
-        free_mkv_demuxer(mkv_d);
-        return 0;
-      }
-      memcpy(sh_a->wf, track->private_data, track->private_size);
-    } else {
-      sh_a->wf = (WAVEFORMATEX *)calloc(1, sizeof(WAVEFORMATEX));
-      if (sh_a->wf == NULL) {
-        free_mkv_demuxer(mkv_d);
-        return 0;
-      }
+    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;
@@ -1866,8 +2134,8 @@
       track->fix_i_bps = true;
       track->qt_last_a_pts = 0.0;
       if (track->private_data != NULL) {
-        sh_a->codecdata = (unsigned char *)calloc(track->private_size, 1);
-        memcpy(sh_a->codecdata, track->private_data, track->private_size);
+        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))
@@ -1919,7 +2187,7 @@
       else
         srate_idx = 11;
 
-      sh_a->codecdata = (unsigned char *)calloc(1, 2);
+      sh_a->codecdata = (unsigned char *)safemalloc(2);
       sh_a->codecdata_len = 2;
       sh_a->codecdata[0] = ((profile + 1) << 3) | ((srate_idx & 0xe) >> 1);
       sh_a->codecdata[1] = ((srate_idx & 0x1) << 7) | (track->a_channels << 3);
@@ -1988,14 +2256,14 @@
   else if (dvdsub_lang != NULL)
     track = find_track_by_language(mkv_d, dvdsub_lang, NULL);
   if (track) {
-    if (!strncmp(track->codec_id, MKV_S_VOBSUB, strlen(MKV_S_VOBSUB))) {
+    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 *)malloc(sizeof(mkv_sh_sub_t));
+      demuxer->sub->sh = (mkv_sh_sub_t *)safememdup(&track->sh_sub,
+                                                    sizeof(mkv_sh_sub_t));
       demuxer->sub->id = track->xid;
-      memcpy(demuxer->sub->sh, &track->sh_sub, sizeof(mkv_sh_sub_t));
 
     } else if (strcmp(track->codec_id, MKV_S_TEXTASCII) &&
                strcmp(track->codec_id, MKV_S_TEXTUTF8) && 
@@ -2009,7 +2277,7 @@
       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 *)malloc(256);
+          mkv_d->subs.text[i] = (char *)safemalloc(256);
 
         if (!strcmp(track->codec_id, MKV_S_TEXTUTF8))
           sub_utf8 = 1;       // Force UTF-8 conversion.
@@ -2095,9 +2363,8 @@
   return v_pts;
 }
 
-static void handle_realvideo(demuxer_t *demuxer, DataBuffer &data,
-                             bool keyframe, int &found_data) {
-  unsigned char *p;
+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;
@@ -2106,12 +2373,11 @@
 
   mkv_d = (mkv_demuxer_t *)demuxer->priv;
   ds = demuxer->video;
-  p = (unsigned char *)data.Buffer();
-  chunks = p[0];
-  isize = data.Size() - 1 - (chunks + 1) * 8;
+  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)], &p[1 + (chunks + 1) * 8], isize);
-  memcpy(&dp->buffer[sizeof(dp_hdr_t) + isize], &p[1], (chunks + 1) * 8);
+  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;
@@ -2134,15 +2400,15 @@
   found_data++;
 }
 
-static void handle_realaudio(demuxer_t *demuxer, DataBuffer &data,
-                             bool keyframe, int &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(data.Size());
-  memcpy(dp->buffer, data.Buffer(), data.Size());
+  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;
@@ -2370,6 +2636,7 @@
   demux_packet_t *dp;
   demux_stream_t *ds;
   mkv_demuxer_t *mkv_d;
+  mkv_track_t *t;
   int upper_lvl_el, exit_loop, found_data, i, linei, sl;
   char *texttmp;
   // Elements for different levels
@@ -2490,14 +2757,18 @@
 
               ds = NULL;
               if ((mkv_d->video != NULL) &&
-                  (mkv_d->video->tnum == kblock->TrackNum()))
+                  (mkv_d->video->tnum == kblock->TrackNum())) {
                 ds = d->video;
-              else if ((mkv_d->audio != NULL) && 
-                         (mkv_d->audio->tnum == kblock->TrackNum()))
+                t = mkv_d->video;
+              } else if ((mkv_d->audio != NULL) && 
+                         (mkv_d->audio->tnum == kblock->TrackNum())) {
                 ds = d->audio;
-              else if ((mkv_d->subs_track != NULL) && 
-                       (mkv_d->subs_track->tnum == kblock->TrackNum()))
+                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;
 
@@ -2564,28 +2835,37 @@
                 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, data, block_bref == 0,
+                    handle_realvideo(d, re_buffer, re_size, block_bref == 0,
                                      found_data);
 
                   else if ((ds == d->audio) && mkv_d->audio->realmedia)
-                    handle_realaudio(d, data, block_bref == 0,
+                    handle_realaudio(d, re_buffer, re_size, block_bref == 0,
                                      found_data);
 
                   else if ((ds == d->sub) &&
                            (mkv_d->subtitle_type == MKV_SUBTYPE_VOBSUB))
-                    mpeg_run(d, (unsigned char *)data.Buffer(), data.Size());
+                    mpeg_run(d, re_buffer, re_size);
 
                   else {
-                    dp = new_demux_packet(data.Size());
-                    memcpy(dp->buffer, data.Buffer(), data.Size());
+                    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;
                     ds_add_packet(ds, dp);
                     found_data++;
                   }
+                  if (re_modified)
+                    safefree(re_buffer);
                 }
                 if (ds == d->video) {
                   mkv_d->v_skip_to_keyframe = false;