diff options
author | arpi <arpi@b3059339-0415-0410-9bf9-f77b7e298cf2> | 2004-01-23 21:34:28 +0000 |
---|---|---|
committer | arpi <arpi@b3059339-0415-0410-9bf9-f77b7e298cf2> | 2004-01-23 21:34:28 +0000 |
commit | 0bd9ce052f695be12d5f329dacdde57c2b59d9ce (patch) | |
tree | 9852ce9ccbc9890d7409a061f8ed625a3fedd09e /libmpdemux/demux_mkv_old.cpp | |
parent | ac311f16f598ba608038cdc7ac59ddf8e31f4ae6 (diff) | |
download | mpv-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.cpp | 3182 |
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 |