diff options
-rwxr-xr-x | configure | 46 | ||||
-rw-r--r-- | libmpdemux/Makefile | 5 | ||||
-rw-r--r-- | libmpdemux/demux_mkv.c | 2850 | ||||
-rw-r--r-- | libmpdemux/ebml.c | 386 | ||||
-rw-r--r-- | libmpdemux/ebml.h | 175 | ||||
-rw-r--r-- | libmpdemux/matroska.h | 3 | ||||
-rw-r--r-- | libmpdemux/stream.h | 13 |
7 files changed, 3461 insertions, 17 deletions
@@ -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->pa |