summaryrefslogtreecommitdiffstats
path: root/libmpdemux/demux_mkv_old.cpp
diff options
context:
space:
mode:
authorarpi <arpi@b3059339-0415-0410-9bf9-f77b7e298cf2>2004-01-23 21:34:28 +0000
committerarpi <arpi@b3059339-0415-0410-9bf9-f77b7e298cf2>2004-01-23 21:34:28 +0000
commit0bd9ce052f695be12d5f329dacdde57c2b59d9ce (patch)
tree9852ce9ccbc9890d7409a061f8ed625a3fedd09e /libmpdemux/demux_mkv_old.cpp
parentac311f16f598ba608038cdc7ac59ddf8e31f4ae6 (diff)
downloadmpv-0bd9ce052f695be12d5f329dacdde57c2b59d9ce.tar.bz2
mpv-0bd9ce052f695be12d5f329dacdde57c2b59d9ce.tar.xz
mkv.cpp -> mkv_old.cpp, to avoid dependency name collision with mkv.c
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@11837 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'libmpdemux/demux_mkv_old.cpp')
-rw-r--r--libmpdemux/demux_mkv_old.cpp3182
1 files changed, 3182 insertions, 0 deletions
diff --git a/libmpdemux/demux_mkv_old.cpp b/libmpdemux/demux_mkv_old.cpp
new file mode 100644
index 0000000000..47f3b4cbfc
--- /dev/null
+++ b/libmpdemux/demux_mkv_old.cpp
@@ -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 = mmioFOU