summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xconfigure46
-rw-r--r--libmpdemux/Makefile5
-rw-r--r--libmpdemux/demux_mkv.c2850
-rw-r--r--libmpdemux/ebml.c386
-rw-r--r--libmpdemux/ebml.h175
-rw-r--r--libmpdemux/matroska.h3
-rw-r--r--libmpdemux/stream.h13
7 files changed, 3461 insertions, 17 deletions
diff --git a/configure b/configure
index a88ad192bf..9ed72f2691 100755
--- a/configure
+++ b/configure
@@ -203,7 +203,8 @@ Codecs:
--enable-vorbis build with OggVorbis support [autodetect]
--enable-tremor build with integer-only OggVorbis support [disabled]
--enable-theora build with OggTheora support [autodetect]
- --enable-matroska build with Matroska support [autodetect]
+ --enable-external-matroska build with external Matroska support [autodetect]
+ --disable-internal-matroska disable internal Matroska support [enabled]
--enable-external-faad build with external FAAD2 (AAC) support [autodetect]
--disable-internal-faad disable internal FAAD2 (AAC) support [autodetect]
--disable-libdv disable libdv 0.9.5 en/decoding support [autodetect]
@@ -1144,7 +1145,8 @@ _liblzo=auto
_mad=auto
_vorbis=auto
_theora=auto
-_matroska=auto
+_matroska_internal=yes
+_matroska_external=auto
_tremor=no
_faad_internal=auto
_faad_external=auto
@@ -1310,8 +1312,10 @@ for ac_option do
--disable-tremor) _tremor=no ;;
--enable-theora) _theora=yes ;;
--disable-theora) _theora=no ;;
- --enable-matroska) _matroska=yes ;;
- --disable-matroska) _matroska=no ;;
+ --enable-internal-matroska) _matroska_internal=yes _matroska_external=no ;;
+ --disable-internal-matroska) _matroska_internal=no ;;
+ --enable-external-matroska) _matroska_internal=no _matroska_external=yes ;;
+ --disable-external-matroska) _matroska_external=no ;;
--enable-internal-faad) _faad_internal=yes _faad_external=no ;;
--disable-internal-faad) _faad_internal=no ;;
--enable-external-faad) _faad_external=yes _faad_internal=no ;;
@@ -4494,9 +4498,15 @@ fi
echores "$_theora"
-echocheck "Matroska support (0.6.0 or later)"
-if test "$_matroska" != no ; then
- _matroska=no
+echocheck "Matroska support (external 0.6.0 or later OR internal)"
+_matroska_result="no"
+if test "$_matroska_internal" = yes ; then
+ _matroska_external=no
+ _inputmodules="matroska(internal) $_inputmodules"
+ _matroska_result="yes, internal"
+fi
+if test "$_matroska_external" != no ; then
+ _matroska_external=no
_TMPC=$TMPC
TMPC=${TMPC}pp
cat > $TMPC << EOF
@@ -4513,27 +4523,30 @@ if test "$_matroska" != no ; then
int main(void) { return 0; }
EOF
- cc_check -lmatroska -lebml -lstdc++ && _matroska=yes
- if test "$_matroska" = no ; then
+ cc_check -lmatroska -lebml -lstdc++ && _matroska_external=yes
+ if test "$_matroska_external" = no ; then
_saved_inc_extra=$_inc_extra
_inc_extra="$_inc_extra -I/usr/local/include"
- cc_check -lmatroska -lebml -lstdc++ && _matroska=yes
- if test "$_matroska" = no ; then
+ cc_check -lmatroska -lebml -lstdc++ && _matroska_external=yes
+ if test "$_matroska_external" = no ; then
_inc_extra=$_saved_inc_extra
fi
fi
rm ${TMPC} > /dev/null 2> /dev/null
TMPC=$_TMPC
+ if test "$_matroska_external" = yes ; then
+ _ld_matroska="-lmatroska -lebml -lstdc++"
+ _inputmodules="matroska(external) $_inputmodules"
+ _matroska_result="yes, external"
+ fi
fi
-if test "$_matroska" = yes ; then
+echores "$_matroska_result"
+if test "$_matroska_internal" != no -o "$_matroska_external" != no ; then
_def_matroska='#define HAVE_MATROSKA 1'
- _inputmodules="matroska $_inputmodules"
- _ld_matroska="-lmatroska -lebml -lstdc++"
else
_def_matroska='#undef HAVE_MATROSKA'
_noinputmodules="matroska $_noinputmodules"
fi
-echores "$_matroska"
@@ -5831,7 +5844,8 @@ CONFIG_RISKY = yes
CONFIG_MP3LAME = $_mp3lame
LIBMENU = $_menu
I18NLIBS = $_i18n_libs
-MATROSKA = $_matroska
+MATROSKA_INTERNAL = $_matroska_internal
+MATROSKA_EXTERNAL = $_matroska_external
MATROSKA_LIB = $_ld_matroska
OPENDIVX = $_opendivx
diff --git a/libmpdemux/Makefile b/libmpdemux/Makefile
index e3945ac9d5..ff6b288380 100644
--- a/libmpdemux/Makefile
+++ b/libmpdemux/Makefile
@@ -26,7 +26,10 @@ SRCS += dvbin.c
SRCS += dvb_tune.c
endif
-ifeq ($(MATROSKA),yes)
+ifeq ($(MATROSKA_INTERNAL),yes)
+SRCS += demux_mkv.c ebml.c
+endif
+ifeq ($(MATROSKA_EXTERNAL),yes)
CPLUSPLUSSRCS += demux_mkv.cpp
endif
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));
+ mk