summaryrefslogtreecommitdiffstats
path: root/libmpdemux/demux_mkv.c
diff options
context:
space:
mode:
authormosu <mosu@b3059339-0415-0410-9bf9-f77b7e298cf2>2004-01-19 19:16:10 +0000
committermosu <mosu@b3059339-0415-0410-9bf9-f77b7e298cf2>2004-01-19 19:16:10 +0000
commitd6fad182c2f6aba9eb07c750052ab0b20d9dbf24 (patch)
tree3fcaf3e320ea69dcf19b874d7b2a3fc6eff803fe /libmpdemux/demux_mkv.c
parente482826611feee90cea2d85004cf3ee4210a8ddf (diff)
downloadmpv-d6fad182c2f6aba9eb07c750052ab0b20d9dbf24.tar.bz2
mpv-d6fad182c2f6aba9eb07c750052ab0b20d9dbf24.tar.xz
Added the new C based Matroska demuxer by Aurelien Jacobs.
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@11808 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'libmpdemux/demux_mkv.c')
-rw-r--r--libmpdemux/demux_mkv.c2850
1 files changed, 2850 insertions, 0 deletions
diff --git a/libmpdemux/demux_mkv.c b/libmpdemux/demux_mkv.c
new file mode 100644
index 0000000000..b38e23f90b
--- /dev/null
+++ b/libmpdemux/demux_mkv.c
@@ -0,0 +1,2850 @@
+/*
+ * native Matroska demuxer
+ * Written by Aurelien Jacobs <aurel@gnuage.org>
+ * Based on the one written by Ronald Bultje for gstreamer
+ * and on demux_mkv.cpp from Moritz Bunkus.
+ * Licence: GPL
+ */
+
+#include "config.h"
+#ifdef HAVE_MATROSKA
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "stream.h"
+#include "demuxer.h"
+#include "stheader.h"
+#include "ebml.h"
+#include "matroska.h"
+#include "bswap.h"
+
+#include "../subreader.h"
+#include "../libvo/sub.h"
+
+#ifdef USE_QTX_CODECS
+#include "qtx/qtxsdk/components.h"
+#endif
+
+#ifdef HAVE_ZLIB
+#include <zlib.h>
+#endif
+
+#ifdef USE_LIBLZO
+#include <lzo1x.h>
+#else
+#include "../libmpcodecs/native/minilzo.h"
+#endif
+
+
+typedef struct
+{
+ uint32_t order, type, scope;
+ uint32_t comp_algo;
+ uint8_t *comp_settings;
+ int comp_settings_len;
+} mkv_content_encoding_t;
+
+typedef struct mkv_track
+{
+ int tnum;
+
+ char *codec_id;
+ int ms_compat;
+ char *language;
+
+ int type;
+
+ 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];
+
+ /* stuff for realmedia */
+ int realmedia;
+ int rv_kf_base, rv_kf_pts;
+ float rv_pts; /* previous video timestamp */
+ float ra_pts; /* previous audio timestamp */
+
+ /* stuff for quicktime */
+ int fix_i_bps;
+ float qt_last_a_pts;
+
+ int subtitle_type;
+
+ /* generic content encoding support */
+ mkv_content_encoding_t *encodings;
+ int num_encodings;
+} mkv_track_t;
+
+typedef struct mkv_index
+{
+ int tnum;
+ uint64_t timecode, filepos;
+} mkv_index_t;
+
+typedef struct mkv_chapter
+{
+ uint64_t start, end;
+} mkv_chapter_t;
+
+typedef struct mkv_demuxer
+{
+ off_t segment_start;
+
+ float duration, last_pts;
+ uint64_t last_filepos;
+
+ mkv_track_t **tracks;
+ int num_tracks;
+
+ uint64_t tc_scale, cluster_tc, first_tc;
+ int has_first_tc;
+
+ uint64_t clear_subs_at[SUB_MAX_TEXT];
+ subtitle subs;
+
+ uint64_t cluster_size;
+ uint64_t blockgroup_size;
+
+ mkv_index_t *indexes;
+ int num_indexes;
+
+ off_t *parsed_cues;
+ int parsed_cues_num;
+ off_t *parsed_seekhead;
+ int parsed_seekhead_num;
+
+ uint64_t *cluster_positions;
+ int num_cluster_pos;
+
+ int64_t skip_to_timecode;
+ int v_skip_to_keyframe, a_skip_to_keyframe;
+
+ mkv_chapter_t *chapters;
+ int num_chapters;
+ int64_t stop_timecode;
+} mkv_demuxer_t;
+
+
+#if __GNUC__ == 2
+#pragma pack(2)
+#else
+#pragma pack(push,2)
+#endif
+
+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;
+
+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;
+
+
+/* for e.g. "-slang ger" */
+extern char *dvdsub_lang;
+extern char *audio_lang;
+
+
+static mkv_track_t *
+demux_mkv_find_track_by_num (mkv_demuxer_t *d, int n, int type)
+{
+ int i, id;
+
+ for (i=0, id=0; i < d->num_tracks; i++)
+ if (d->tracks[i] != NULL && d->tracks[i]->type == type)
+ if (id++ == n)
+ return d->tracks[i];
+
+ return NULL;
+}
+
+static mkv_track_t *
+demux_mkv_find_track_by_language (mkv_demuxer_t *d, char *language, int type)
+{
+ int i;
+
+ for (i=0; i < d->num_tracks; i++)
+ if (d->tracks[i] != NULL && d->tracks[i]->language != NULL &&
+ d->tracks[i]->type == type && !strcmp(d->tracks[i]->language,language))
+ return d->tracks[i];
+
+ return NULL;
+}
+
+static void
+add_cluster_position (mkv_demuxer_t *mkv_d, uint64_t position)
+{
+ int i = mkv_d->num_cluster_pos;
+
+ while (i--)
+ if (mkv_d->cluster_positions[i] == position)
+ return;
+
+ if (!mkv_d->cluster_positions)
+ mkv_d->cluster_positions = (uint64_t *) malloc (32 * sizeof (uint64_t));
+ else if (!(mkv_d->num_cluster_pos % 32))
+ mkv_d->cluster_positions = (uint64_t *) realloc(mkv_d->cluster_positions,
+ (mkv_d->num_cluster_pos+32)
+ * sizeof (uint64_t));
+ mkv_d->cluster_positions[mkv_d->num_cluster_pos++] = position;
+}
+
+
+#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;
+}
+
+
+static int
+demux_mkv_decode (mkv_track_t *track, uint8_t *src, uint8_t **dest,
+ uint32_t *size, uint32_t type)
+{
+ int i, result;
+ int modified = 0;
+
+ *dest = src;
+ if (track->num_encodings <= 0)
+ return 0;
+
+ for (i=0; i<track->num_encodings; i++)
+ {
+ if (!(track->encodings[i].scope & type))
+ continue;
+
+#ifdef HAVE_ZLIB
+ if (track->encodings[i].comp_algo == 0)
+ {
+ /* zlib encoded track */
+ z_stream zstream;
+
+ zstream.zalloc = (alloc_func) 0;
+ zstream.zfree = (free_func) 0;
+ zstream.opaque = (voidpf) 0;
+ if (inflateInit (&zstream) != Z_OK)
+ {
+ mp_msg (MSGT_DEMUX, MSGL_WARN,
+ "[mkv] zlib initialization failed.\n");
+ return modified;
+ }
+ zstream.next_in = (Bytef *) src;
+ zstream.avail_in = *size;
+
+ modified = 1;
+ *dest = (uint8_t *) malloc (*size);
+ zstream.avail_out = *size;
+ do {
+ *size += 4000;
+ *dest = (uint8_t *) realloc (*dest, *size);
+ zstream.next_out = (Bytef *) (*dest + zstream.total_out);
+ result = inflate (&zstream, Z_NO_FLUSH);
+ if (result != Z_OK && result != Z_STREAM_END)
+ {
+ mp_msg (MSGT_DEMUX, MSGL_WARN,
+ "[mkv] zlib decompression failed.\n");
+ free(*dest);
+ *dest = NULL;
+ inflateEnd (&zstream);
+ return modified;
+ }
+ zstream.avail_out += 4000;
+ } while (zstream.avail_out == 4000 &&
+ zstream.avail_in != 0 && result != Z_STREAM_END);
+
+ *size = zstream.total_out;
+ inflateEnd (&zstream);
+ }
+#endif
+ if (track->encodings[i].comp_algo == 2)
+ {
+ /* lzo encoded track */
+ int dstlen = *size * 3;
+
+ if (lzo_init () != LZO_E_OK)
+ {
+ mp_msg (MSGT_DEMUX, MSGL_WARN,
+ "[mkv] lzo initialization failed.\n");
+ return modified;
+ }
+
+ *dest = (uint8_t *) malloc (dstlen);
+ while (1)
+ {
+ result = lzo1x_decompress_safe (src, *size, *dest, &dstlen,
+ NULL);
+ if (result == LZO_E_OK)
+ break;
+ if (result != LZO_E_OUTPUT_OVERRUN)
+ {
+ mp_msg (MSGT_DEMUX, MSGL_WARN,
+ "[mkv] lzo decompression failed.\n");
+ return modified;
+ }
+ mp_msg (MSGT_DEMUX, MSGL_DBG2,
+ "[mkv] lzo decompression buffer too small.\n");
+ dstlen *= 2;
+ *dest = (uint8_t *) realloc (*dest, dstlen);
+ }
+ *size = dstlen;
+ }
+ }
+
+ return modified;
+}
+
+
+static int
+demux_mkv_read_info (demuxer_t *demuxer)
+{
+ mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
+ stream_t *s = demuxer->stream;
+ uint64_t length, l;
+ int il;
+
+ length = ebml_read_length (s, NULL);
+ while (length > 0)
+ {
+ switch (ebml_read_id (s, &il))
+ {
+ case MATROSKA_ID_TIMECODESCALE:
+ {
+ uint64_t num = ebml_read_uint (s, &l);
+ if (num == EBML_UINT_INVALID)
+ return 1;
+ mkv_d->tc_scale = num;
+ mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] | + timecode scale: %llu\n",
+ mkv_d->tc_scale);
+ break;
+ }
+
+ case MATROSKA_ID_DURATION:
+ {
+ long double num = ebml_read_float (s, &l);
+ if (num == EBML_FLOAT_INVALID)
+ return 1;
+ mkv_d->duration = num * mkv_d->tc_scale / 1000000000.0;
+ mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] | + duration: %.3fs\n",
+ mkv_d->duration);
+ break;
+ }
+
+ default:
+ ebml_read_skip (s, &l);
+ break;
+ }
+ length -= l + il;
+ }
+ return 0;
+}
+
+static int
+demux_mkv_read_trackencodings (demuxer_t *demuxer, mkv_track_t *track)
+{
+ stream_t *s = demuxer->stream;
+ mkv_content_encoding_t *ce, e;
+ uint64_t len, length, l;
+ int il, n;
+
+ ce = (mkv_content_encoding_t *) malloc (sizeof (*ce));
+ n = 0;
+
+ len = length = ebml_read_length (s, &il);
+ len += il;
+ while (length > 0)
+ {
+ switch (ebml_read_id (s, &il))
+ {
+ case MATROSKA_ID_CONTENTENCODING:
+ {
+ uint64_t len;
+ int i;
+
+ memset (&e, 0, sizeof (e));
+ e.scope = 1;
+
+ len = ebml_read_length (s, &i);
+ l = len + i;
+
+ while (len > 0)
+ {
+ uint64_t num, l;
+ int il;
+
+ switch (ebml_read_id (s, &il))
+ {
+ case MATROSKA_ID_CONTENTENCODINGORDER:
+ num = ebml_read_uint (s, &l);
+ if (num == EBML_UINT_INVALID)
+ return 0;
+ e.order = num;
+ break;
+
+ case MATROSKA_ID_CONTENTENCODINGSCOPE:
+ num = ebml_read_uint (s, &l);
+ if (num == EBML_UINT_INVALID)
+ return 0;
+ e.scope = num;
+ break;
+
+ case MATROSKA_ID_CONTENTENCODINGTYPE:
+ num = ebml_read_uint (s, &l);
+ if (num == EBML_UINT_INVALID)
+ return 0;
+ e.type = num;
+ break;
+
+ case MATROSKA_ID_CONTENTCOMPRESSION:
+ {
+ uint64_t le;
+
+ le = ebml_read_length (s, &i);
+ l = le + i;
+
+ while (le > 0)
+ {
+ uint64_t l;
+ int il;
+
+ switch (ebml_read_id (s, &il))
+ {
+ case MATROSKA_ID_CONTENTCOMPALGO:
+ num = ebml_read_uint (s, &l);
+ if (num == EBML_UINT_INVALID)
+ return 0;
+ e.comp_algo = num;
+ break;
+
+ case MATROSKA_ID_CONTENTCOMPSETTINGS:
+ l = ebml_read_length (s, &i);
+ e.comp_settings = (uint8_t *) malloc (l);
+ stream_read (s, e.comp_settings, l);
+ e.comp_settings_len = l;
+ l += i;
+ break;
+
+ default:
+ ebml_read_skip (s, &l);
+ break;
+ }
+ le -= l + il;
+ }
+
+ if (e.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", track->tnum);
+ }
+ else if (e.type != 0)
+ {
+ mp_msg(MSGT_DEMUX, MSGL_WARN,
+ "[mkv] Unknown content encoding type for "
+ "track %u. Skipping track.\n", track->tnum);
+ }
+
+ if (e.comp_algo != 0 && e.comp_algo != 2)
+ {
+ mp_msg (MSGT_DEMUX, MSGL_WARN,
+ "[mkv] Track %u has been compressed with an "
+ "unknown/unsupported compression algorithm "
+ "(%u). Skipping track.\n",
+ track->tnum, e.comp_algo);
+ }
+#ifndef HAVE_ZLIB
+ else if (e.comp_algo == 0)
+ {
+ 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",
+ track->tnum);
+ }
+#endif
+
+ break;
+ }
+
+ default:
+ ebml_read_skip (s, &l);
+ break;
+ }
+ len -= l + il;
+ }
+ for (i=0; i<n; i++)
+ if (e.order <= ce[i].order)
+ break;
+ ce = (mkv_content_encoding_t *) realloc (ce, (n+1) *sizeof (*ce));
+ memmove (ce+i+1, ce+i, (n-i) * sizeof (*ce));
+ memcpy (ce+i, &e, sizeof (e));
+ n++;
+ break;
+ }
+
+ default:
+ ebml_read_skip (s, &l);
+ break;
+ }
+
+ length -= l + il;
+ }
+
+ track->encodings = ce;
+ track->num_encodings = n;
+ return len;
+}
+
+static int
+demux_mkv_read_trackaudio (demuxer_t *demuxer, mkv_track_t *track)
+{
+ stream_t *s = demuxer->stream;
+ uint64_t len, length, l;
+ int il;
+
+ track->a_sfreq = 8000.0;
+ track->a_channels = 1;
+
+ len = length = ebml_read_length (s, &il);
+ len += il;
+ while (length > 0)
+ {
+ switch (ebml_read_id (s, &il))
+ {
+ case MATROSKA_ID_AUDIOSAMPLINGFREQ:
+ {
+ long double num = ebml_read_float (s, &l);
+ if (num == EBML_FLOAT_INVALID)
+ return 0;
+ track->a_sfreq = num;
+ mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] | + Sampling frequency: %f\n",
+ track->a_sfreq);
+ break;
+ }
+
+ case MATROSKA_ID_AUDIOBITDEPTH:
+ {
+ uint64_t num = ebml_read_uint (s, &l);
+ if (num == EBML_UINT_INVALID)
+ return 0;
+ track->a_bps = num;
+ mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] | + Bit depth: %u\n",
+ track->a_bps);
+ break;
+ }
+
+ case MATROSKA_ID_AUDIOCHANNELS:
+ {
+ uint64_t num = ebml_read_uint (s, &l);
+ if (num == EBML_UINT_INVALID)
+ return 0;
+ track->a_channels = num;
+ mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] | + Channels: %u\n",
+ track->a_channels);
+ break;
+ }
+
+ default:
+ ebml_read_skip (s, &l);
+ break;
+ }
+ length -= l + il;
+ }
+ return len;
+}
+
+static int
+demux_mkv_read_trackvideo (demuxer_t *demuxer, mkv_track_t *track)
+{
+ stream_t *s = demuxer->stream;
+ uint64_t len, length, l;
+ int il;
+
+ len = length = ebml_read_length (s, &il);
+ len += il;
+ while (length > 0)
+ {
+ switch (ebml_read_id (s, &il))
+ {
+ case MATROSKA_ID_VIDEOFRAMERATE:
+ {
+ long double num = ebml_read_float (s, &l);
+ if (num == EBML_FLOAT_INVALID)
+ return 0;
+ track->v_frate = num;
+ mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] | + Frame rate: %f\n",
+ track->v_frate);
+ break;
+ }
+
+ case MATROSKA_ID_VIDEODISPLAYWIDTH:
+ {
+ uint64_t num = ebml_read_uint (s, &l);
+ if (num == EBML_UINT_INVALID)
+ return 0;
+ track->v_dwidth = num;
+ mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] | + Display width: %u\n",
+ track->v_dwidth);
+ break;
+ }
+
+ case MATROSKA_ID_VIDEODISPLAYHEIGHT:
+ {
+ uint64_t num = ebml_read_uint (s, &l);
+ if (num == EBML_UINT_INVALID)
+ return 0;
+ track->v_dheight = num;
+ mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] | + Display height: %u\n",
+ track->v_dheight);
+ break;
+ }
+
+ case MATROSKA_ID_VIDEOPIXELWIDTH:
+ {
+ uint64_t num = ebml_read_uint (s, &l);
+ if (num == EBML_UINT_INVALID)
+ return 0;
+ track->v_width = num;
+ mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] | + Pixel width: %u\n",
+ track->v_width);
+ break;
+ }
+
+ case MATROSKA_ID_VIDEOPIXELHEIGHT:
+ {
+ uint64_t num = ebml_read_uint (s, &l);
+ if (num == EBML_UINT_INVALID)
+ return 0;
+ track->v_height = num;
+ mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] | + Pixel height: %u\n",
+ track->v_height);
+ break;
+ }
+
+ default:
+ ebml_read_skip (s, &l);
+ break;
+ }
+ length -= l + il;
+ }
+ return len;
+}
+
+static int
+demux_mkv_read_trackentry (demuxer_t *demuxer)
+{
+ mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
+ stream_t *s = demuxer->stream;
+ mkv_track_t *track;
+ uint64_t len, length, l;
+ int il;
+
+ track = (mkv_track_t *) malloc (sizeof (*track));
+ memset(track, 0, sizeof(*track));
+ /* set default values */
+ track->default_track = 1;
+ track->language = strdup("eng");
+
+ len = length = ebml_read_length (s, &il);
+ len += il;
+ while (length > 0)
+ {
+ switch (ebml_read_id (s, &il))
+ {
+ case MATROSKA_ID_TRACKNUMBER:
+ {
+ uint64_t num = ebml_read_uint (s, &l);
+ if (num == EBML_UINT_INVALID)
+ return 0;
+ track->tnum = num;
+ mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] | + Track number: %u\n",
+ track->tnum);
+ break;
+ }
+
+ case MATROSKA_ID_TRACKTYPE:
+ {
+ uint64_t num = ebml_read_uint (s, &l);
+ if (num == EBML_UINT_INVALID)
+ return 0;
+ track->type = num;
+ mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] | + Track type: ");
+ switch (track->type)
+ {
+ case MATROSKA_TRACK_AUDIO:
+ mp_msg (MSGT_DEMUX, MSGL_V, "Audio\n");
+ break;
+ case MATROSKA_TRACK_VIDEO:
+ mp_msg (MSGT_DEMUX, MSGL_V, "Video\n");
+ break;
+ case MATROSKA_TRACK_SUBTITLE:
+ mp_msg (MSGT_DEMUX, MSGL_V, "Subtitle\n");
+ break;
+ default:
+ mp_msg (MSGT_DEMUX, MSGL_V, "unknown\n");
+ break;
+ }
+ break;
+ }
+
+ case MATROSKA_ID_TRACKAUDIO:
+ mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] | + Audio track\n");
+ l = demux_mkv_read_trackaudio (demuxer, track);
+ if (l == 0)
+ return 0;
+ break;
+
+ case MATROSKA_ID_TRACKVIDEO:
+ mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] | + Video track\n");
+ l = demux_mkv_read_trackvideo (demuxer, track);
+ if (l == 0)
+ return 0;
+ break;
+
+ case MATROSKA_ID_CODECID:
+ track->codec_id = ebml_read_ascii (s, &l);
+ if (track->codec_id == NULL)
+ return 0;
+ if (!strcmp (track->codec_id, MKV_V_MSCOMP))
+ track->ms_compat = 1;
+ else if (!strcmp (track->codec_id, MKV_S_VOBSUB))
+ track->subtitle_type = MATROSKA_SUBTYPE_VOBSUB;
+ else if (!strcmp (track->codec_id, MKV_S_TEXTSSA)
+ || !strcmp (track->codec_id, MKV_S_TEXTASS)
+ || !strcmp (track->codec_id, MKV_S_SSA)
+ || !strcmp (track->codec_id, MKV_S_ASS))
+ {
+ track->subtitle_type = MATROSKA_SUBTYPE_SSA;
+ sub_utf8 = 1;
+ }
+ else if (!strcmp (track->codec_id, MKV_S_TEXTASCII))
+ track->subtitle_type = MATROSKA_SUBTYPE_TEXT;
+ if (!strcmp (track->codec_id, MKV_S_TEXTUTF8))
+ {
+ track->subtitle_type = MATROSKA_SUBTYPE_TEXT;
+ sub_utf8 = 1;
+ }
+ mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] | + Codec ID: %s\n",
+ track->codec_id);
+ break;
+
+ case MATROSKA_ID_CODECPRIVATE:
+ {
+ int x;
+ uint64_t num = ebml_read_length (s, &x);
+ l = x + num;
+ track->private_data = malloc (num);
+ if (stream_read(s, track->private_data, num) != (int) num)
+ return 0;
+ track->private_size = num;
+ mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] | + CodecPrivate, length "
+ "%u\n", track->private_size);
+ break;
+ }
+
+ case MATROSKA_ID_TRACKLANGUAGE:
+ track->language = ebml_read_utf8 (s, &l);
+ if (track->language == NULL)
+ return 0;
+ mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] | + Language: %s\n",
+ track->language);
+ break;
+
+ case MATROSKA_ID_TRACKFLAGDEFAULT:
+ {
+ uint64_t num = ebml_read_uint (s, &l);
+ if (num == EBML_UINT_INVALID)
+ return 0;
+ track->default_track = num;
+ mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] | + Default flag: %u\n",
+ track->default_track);
+ break;
+ }
+
+ case MATROSKA_ID_TRACKDEFAULTDURATION:
+ {
+ uint64_t num = ebml_read_uint (s, &l);
+ if (num == EBML_UINT_INVALID)
+ return 0;
+ if (num == 0)
+ mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] | + Default duration: 0");
+ else
+ {
+ track->v_frate = 1000000000.0 / num;
+ mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] | + Default duration: "
+ "%.3fms ( = %.3f fps)\n",num/1000000.0,track->v_frate);
+ }
+ break;
+ }
+
+ case MATROSKA_ID_TRACKENCODINGS:
+ l = demux_mkv_read_trackencodings (demuxer, track);
+ if (l == 0)
+ return 0;
+ break;
+
+ default:
+ ebml_read_skip (s, &l);
+ break;
+ }
+ length -= l + il;
+ }
+
+ mkv_d->tracks[mkv_d->num_tracks++] = track;
+ return len;
+}
+
+static int
+demux_mkv_read_tracks (demuxer_t *demuxer)
+{
+ mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
+ stream_t *s = demuxer->stream;
+ uint64_t length, l;
+ int il;
+
+ mkv_d->tracks = (mkv_track_t **) malloc (sizeof (*mkv_d->tracks));
+ mkv_d->num_tracks = 0;
+
+ length = ebml_read_length (s, NULL);
+ while (length > 0)
+ {
+ switch (ebml_read_id (s, &il))
+ {
+ case MATROSKA_ID_TRACKENTRY:
+ mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] | + a track...\n");
+ mkv_d->tracks = (mkv_track_t **) realloc (mkv_d->tracks,
+ (mkv_d->num_tracks+1)
+ *sizeof (*mkv_d->tracks));
+ l = demux_mkv_read_trackentry (demuxer);
+ if (l == 0)
+ return 1;
+ break;
+
+ default:
+ ebml_read_skip (s, &l);
+ break;
+ }
+ length -= l + il;
+ }
+ return 0;
+}
+
+static int
+demux_mkv_read_cues (demuxer_t *demuxer)
+{
+ mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
+ stream_t *s = demuxer->stream;
+ uint64_t length, l, time, track, pos;
+ off_t off;
+ int i, il;
+
+ off = stream_tell (s);
+ for (i=0; i<mkv_d->parsed_cues_num; i++)
+ if (mkv_d->parsed_cues[i] == off)
+ {
+ ebml_read_skip (s, NULL);
+ return 0;
+ }
+ mkv_d->parsed_cues = (off_t *) realloc (mkv_d->parsed_cues,
+ (mkv_d->parsed_cues_num+1)
+ * sizeof (off_t));
+ mkv_d->parsed_cues[mkv_d->parsed_cues_num++] = off;
+
+ mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] /---- [ parsing cues ] -----------\n");
+ length = ebml_read_length (s, NULL);
+
+ while (length > 0)
+ {
+ time = track = pos = EBML_UINT_INVALID;
+
+ switch (ebml_read_id (s, &il))
+ {
+ case MATROSKA_ID_POINTENTRY:
+ {
+ uint64_t len;
+
+ len = ebml_read_length (s, &i);
+ l = len + i;
+
+ while (len > 0)
+ {
+ uint64_t l;
+ int il;
+
+ switch (ebml_read_id (s, &il))
+ {
+ case MATROSKA_ID_CUETIME:
+ time = ebml_read_uint (s, &l);
+ break;
+
+ case MATROSKA_ID_CUETRACKPOSITION:
+ {
+ uint64_t le;
+
+ le = ebml_read_length (s, &i);
+ l = le + i;
+
+ while (le > 0)
+ {
+ uint64_t l;
+ int il;
+
+ switch (ebml_read_id (s, &il))
+ {
+ case MATROSKA_ID_CUETRACK:
+ track = ebml_read_uint (s, &l);
+ break;
+
+ case MATROSKA_ID_CUECLUSTERPOSITION:
+ pos = ebml_read_uint (s, &l);
+ break;
+
+ default:
+ ebml_read_skip (s, &l);
+ break;
+ }
+ le -= l + il;
+ }
+ break;
+ }
+
+ default:
+ ebml_read_skip (s, &l);
+ break;
+ }
+ len -= l + il;
+ }
+ break;
+ }
+
+ default:
+ ebml_read_skip (s, &l);
+ break;
+ }
+
+ length -= l + il;
+
+ if (time != EBML_UINT_INVALID && track != EBML_UINT_INVALID
+ && pos != EBML_UINT_INVALID)
+ {
+ if (mkv_d->indexes == NULL)
+ mkv_d->indexes = (mkv_index_t *) malloc (32*sizeof (mkv_index_t));
+ else if (mkv_d->num_indexes % 32 == 0)
+ mkv_d->indexes = (mkv_index_t *) realloc (mkv_d->indexes,
+ (mkv_d->num_indexes+32)
+ *sizeof (mkv_index_t));
+ mkv_d->indexes[mkv_d->num_indexes].tnum = track;
+ mkv_d->indexes[mkv_d->num_indexes].timecode = time;
+ mkv_d->indexes[mkv_d->num_indexes].filepos =mkv_d->segment_start+pos;
+ mp_msg (MSGT_DEMUX, MSGL_DBG2, "[mkv] |+ found cue point "
+ "for track %llu: timecode %llu, filepos: %llu\n",
+ track, time, mkv_d->segment_start + pos);
+ mkv_d->num_indexes++;
+ }
+ }
+
+ mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] \\---- [ parsing cues ] -----------\n");
+ return 0;
+}
+
+static int
+demux_mkv_read_chapters (demuxer_t *demuxer)
+{
+ mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
+ stream_t *s = demuxer->stream;
+ uint64_t length, l;
+ int il;
+
+ if (mkv_d->chapters)
+ {
+ ebml_read_skip (s, NULL);
+ return 0;
+ }
+
+ mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] /---- [ parsing chapters ] ---------\n");
+ length = ebml_read_length (s, NULL);
+
+ while (length > 0)
+ {
+ switch (ebml_read_id (s, &il))
+ {
+ case MATROSKA_ID_EDITIONENTRY:
+ {
+ uint64_t len;
+ int i;
+
+ len = ebml_read_length (s, &i);
+ l = len + i;
+
+ while (len > 0)
+ {
+ uint64_t l;
+ int il;
+
+ switch (ebml_read_id (s, &il))
+ {