diff options
Diffstat (limited to 'src/demuxers/demux_matroska.c')
-rw-r--r-- | src/demuxers/demux_matroska.c | 283 |
1 files changed, 232 insertions, 51 deletions
diff --git a/src/demuxers/demux_matroska.c b/src/demuxers/demux_matroska.c index bcc5f52ea..2bd8f3540 100644 --- a/src/demuxers/demux_matroska.c +++ b/src/demuxers/demux_matroska.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000-2005 the xine project + * Copyright (C) 2000-2007 the xine project * * This file is part of xine, a free video player. * @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: demux_matroska.c,v 1.49 2006/11/14 14:17:31 dgp85 Exp $ + * $Id: demux_matroska.c,v 1.53 2007/03/12 16:27:21 dgp85 Exp $ * * demultiplexer for matroska streams * @@ -362,6 +362,140 @@ static int parse_audio_track (demux_matroska_t *this, matroska_audio_track_t *at } +static int parse_content_compression (demux_matroska_t *this, matroska_track_t *track) { + ebml_parser_t *ebml = this->ebml; + int next_level = 6; + + while (next_level == 6) { + ebml_elem_t elem; + uint64_t val; + + if (!ebml_read_elem_head(ebml, &elem)) + return 0; + + switch (elem.id) { + case MATROSKA_ID_CE_COMPALGO: + lprintf("ContentCompAlgo\n"); + if (!ebml_read_uint(ebml, &elem, &val)) + return 0; + switch (val) + { + case MATROSKA_COMPRESS_ZLIB: + case MATROSKA_COMPRESS_BZLIB: + case MATROSKA_COMPRESS_LZO1X: + case MATROSKA_COMPRESS_HEADER_STRIP: + track->compress_algo = val; + break; + default: + track->compress_algo = MATROSKA_COMPRESS_UNKNOWN; + break; + } + break; + case MATROSKA_ID_CE_COMPSETTINGS: + lprintf("ContentCompSettings (UNSUPPORTED)\n"); + if (!ebml_skip(ebml, &elem)) + return 0; + break; + default: + lprintf("Unhandled ID: 0x%x\n", elem.id); + if (!ebml_skip(ebml, &elem)) + return 0; + } + next_level = ebml_get_next_level(ebml, &elem); + } + return 1; +} + + +static int parse_content_encoding (demux_matroska_t *this, matroska_track_t *track) { + ebml_parser_t *ebml = this->ebml; + int next_level = 5; + + while (next_level == 5) { + ebml_elem_t elem; + uint64_t val; + + if (!ebml_read_elem_head(ebml, &elem)) + return 0; + + switch (elem.id) { + case MATROSKA_ID_CE_ORDER: + lprintf("ContentEncodingOrder\n"); + if (!ebml_read_uint(ebml, &elem, &val)) + return 0; + if (val != 0) { // multiple content encoding isn't supported + lprintf(" warning: a non-zero encoding order is UNSUPPORTED\n"); + return 0; + } + break; + case MATROSKA_ID_CE_SCOPE: + lprintf("ContentEncodingScope\n"); + if (!ebml_read_uint(ebml, &elem, &val)) + return 0; + if (val != 1) { // 1 (all frame contents) is the only supported option + lprintf(" warning: UNSUPPORTED encoding scope (%" PRId64 ")\n", val); + return 0; + } + break; + case MATROSKA_ID_CE_TYPE: + lprintf("ContentEncodingType\n"); + if (!ebml_read_uint(ebml, &elem, &val)) + return 0; + if (val != 0) // only compression (0) is supported + return 0; + break; + case MATROSKA_ID_CE_COMPRESSION: + lprintf("ContentCompression\n"); + if (!ebml_read_master (ebml, &elem)) + return 0; + if ((elem.len > 0) && !parse_content_compression(this, track)) + return 0; + break; + case MATROSKA_ID_CE_ENCRYPTION: + lprintf("ContentEncryption (UNSUPPORTED)\n"); + if (!ebml_skip(ebml, &elem)) + return 0; + break; + default: + lprintf("Unhandled ID: 0x%x\n", elem.id); + if (!ebml_skip(ebml, &elem)) + return 0; + } + next_level = ebml_get_next_level(ebml, &elem); + } + return 1; +} + + +static int parse_content_encodings (demux_matroska_t *this, matroska_track_t *track) { + ebml_parser_t *ebml = this->ebml; + int next_level = 4; + + while (next_level == 4) { + ebml_elem_t elem; + + if (!ebml_read_elem_head(ebml, &elem)) + return 0; + + switch (elem.id) { + case MATROSKA_ID_CONTENTENCODING: + lprintf("ContentEncoding\n"); + if (!ebml_read_master (ebml, &elem)) + return 0; + if ((elem.len > 0) && !parse_content_encoding(this, track)) + return 0; + break; + default: + lprintf("Unhandled ID: 0x%x\n", elem.id); + if (!ebml_skip(ebml, &elem)) + return 0; + } + next_level = ebml_get_next_level(ebml, &elem); + } + return 1; +} + + static void init_codec_video(demux_matroska_t *this, matroska_track_t *track) { buf_element_t *buf; @@ -937,45 +1071,67 @@ static void handle_vobsub (demux_plugin_t *this_gen, matroska_track_t *track, int input_normpos, int input_time) { demux_matroska_t *this = (demux_matroska_t *) this_gen; buf_element_t *buf; - z_stream zstream; - uint8_t *dest; - int old_data_len, result; - - old_data_len = data_len; - zstream.zalloc = (alloc_func) 0; - zstream.zfree = (free_func) 0; - zstream.opaque = (voidpf) 0; - if (inflateInit (&zstream) != Z_OK) { - xprintf(this->stream->xine, XINE_VERBOSITY_LOG, - "demux_matroska: VobSub: zlib inflateInit failed.\n"); - return; - } - zstream.next_in = (Bytef *)data; - zstream.avail_in = data_len; - dest = (uint8_t *)malloc(data_len); - zstream.avail_out = data_len; - do { - data_len += 4000; - dest = (uint8_t *)realloc(dest, data_len); - zstream.next_out = (Bytef *)(dest + zstream.total_out); - result = inflate (&zstream, Z_NO_FLUSH); - if ((result != Z_OK) && (result != Z_STREAM_END)) { + if (track->compress_algo == MATROSKA_COMPRESS_ZLIB || + track->compress_algo == MATROSKA_COMPRESS_UNKNOWN) { + z_stream zstream; + uint8_t *dest; + int old_data_len, result; + + old_data_len = data_len; + zstream.zalloc = (alloc_func) 0; + zstream.zfree = (free_func) 0; + zstream.opaque = (voidpf) 0; + if (inflateInit (&zstream) != Z_OK) { xprintf(this->stream->xine, XINE_VERBOSITY_LOG, - "demux_matroska: VobSub: zlib decompression failed.\n"); - free(dest); - inflateEnd(&zstream); + "demux_matroska: VobSub: zlib inflateInit failed.\n"); return; } - zstream.avail_out += 4000; - } while ((zstream.avail_out == 4000) && - (zstream.avail_in != 0) && (result != Z_STREAM_END)); - - data_len = zstream.total_out; - inflateEnd(&zstream); - - lprintf("VobSub: decompression for track %d from %d to %d\n", - (int)track->track_num, old_data_len, data_len); + zstream.next_in = (Bytef *)data; + zstream.avail_in = data_len; + + dest = (uint8_t *)malloc(data_len); + zstream.avail_out = data_len; + do { + data_len += 4000; + dest = (uint8_t *)realloc(dest, data_len); + zstream.next_out = (Bytef *)(dest + zstream.total_out); + result = inflate (&zstream, Z_NO_FLUSH); + if ((result != Z_OK) && (result != Z_STREAM_END)) { + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + "demux_matroska: VobSub: zlib decompression failed for track %d (result = %d).\n", + (int)track->track_num, result); + free(dest); + inflateEnd(&zstream); + + if (result == Z_DATA_ERROR && track->compress_algo == MATROSKA_COMPRESS_UNKNOWN) { + track->compress_algo = MATROSKA_COMPRESS_NONE; + data_len = old_data_len; + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + "demux_matroska: VobSub: falling back to uncompressed mode.\n"); + break; + } + return; + } + zstream.avail_out += 4000; + } while ((zstream.avail_out == 4000) && + (zstream.avail_in != 0) && (result != Z_STREAM_END)); + + if (track->compress_algo != MATROSKA_COMPRESS_NONE) { + data_len = zstream.total_out; + inflateEnd(&zstream); + + data = dest; + track->compress_algo = MATROSKA_COMPRESS_ZLIB; + lprintf("VobSub: decompression for track %d from %d to %d\n", + (int)track->track_num, old_data_len, data_len); + } + } + else + { + lprintf("VobSub: track %d isn't compressed (%d bytes)\n", + (int)track->track_num, data_len); + } buf = track->fifo->buffer_pool_alloc(track->fifo); @@ -986,8 +1142,8 @@ static void handle_vobsub (demux_plugin_t *this_gen, matroska_track_t *track, buf->decoder_info[2] = SPU_DVD_SUBTYPE_VOBSUB_PACKAGE; buf->type = track->buf_type; - xine_fast_memcpy(buf->content, dest, data_len); - + xine_fast_memcpy(buf->content, data, data_len); + buf->extra_info->input_normpos = input_normpos; buf->extra_info->input_time = input_time; @@ -1000,7 +1156,8 @@ static void handle_vobsub (demux_plugin_t *this_gen, matroska_track_t *track, buf->free_buffer(buf); } - free(dest); + if (track->compress_algo == MATROSKA_COMPRESS_ZLIB) + free(data); } static int parse_track_entry(demux_matroska_t *this, matroska_track_t *track) { @@ -1100,7 +1257,16 @@ static int parse_track_entry(demux_matroska_t *this, matroska_track_t *track) { if (!ebml_read_uint(ebml, &elem, &val)) return 0; track->default_duration = val; - lprintf("Default Duration: %lld\n", track->default_duration); + lprintf("Default Duration: %"PRIu64"\n", track->default_duration); + } + break; + + case MATROSKA_ID_CONTENTENCODINGS: { + lprintf("ContentEncodings\n"); + if (!ebml_read_master (ebml, &elem)) + return 0; + if ((elem.len > 0) && !parse_content_encodings(this, track)) + return 0; } break; @@ -1230,6 +1396,10 @@ static int parse_track_entry(demux_matroska_t *this, matroska_track_t *track) { init_codec = init_codec_audio; } else if (!strcmp(track->codec_id, MATROSKA_CODEC_ID_A_DTS)) { + lprintf("MATROSKA_CODEC_ID_A_DTS\n"); + track->buf_type = BUF_AUDIO_DTS; + init_codec = init_codec_audio; + } else if (!strcmp(track->codec_id, MATROSKA_CODEC_ID_A_VORBIS)) { lprintf("MATROSKA_CODEC_ID_A_VORBIS\n"); @@ -1289,6 +1459,14 @@ static int parse_track_entry(demux_matroska_t *this, matroska_track_t *track) { track->buf_type = BUF_SPU_DVD; track->handle_content = handle_vobsub; init_codec = init_codec_vobsub; + + /* Enable autodetection of the zlib compression, unless it was + * explicitely set. Most vobsubs are compressed with zlib but + * are not declared as such. + */ + if (track->compress_algo == MATROSKA_COMPRESS_NONE) { + track->compress_algo = MATROSKA_COMPRESS_UNKNOWN; + } } else { lprintf("unknown codec\n"); } @@ -1339,12 +1517,17 @@ static int parse_tracks(demux_matroska_t *this) { switch (elem.id) { case MATROSKA_ID_TR_ENTRY: { + matroska_track_t *track; + /* alloc and initialize a track with 0 */ - this->tracks[this->num_tracks] = xine_xmalloc(sizeof(matroska_track_t)); + track = xine_xmalloc(sizeof(matroska_track_t)); + track->compress_algo = MATROSKA_COMPRESS_NONE; + this->tracks[this->num_tracks] = track; + lprintf("TrackEntry\n"); if (!ebml_read_master (ebml, &elem)) return 0; - if ((elem.len > 0) && !parse_track_entry(this, this->tracks[this->num_tracks])) + if ((elem.len > 0) && !parse_track_entry(this, track)) return 0; this->num_tracks++; } @@ -2623,13 +2806,11 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str break; case METHOD_BY_EXTENSION: { - char *mrl = input->get_mrl(input); - char *extensions; + const char *const mrl = input->get_mrl(input); + const char *const extensions = class_gen->get_extensions (class_gen);; lprintf ("stage by extension %s\n", mrl); - extensions = class_gen->get_extensions (class_gen); - if (!_x_demux_check_extension (mrl, extensions)) return NULL; @@ -2687,22 +2868,22 @@ error: * demux matroska class */ -static char *get_description (demux_class_t *this_gen) { +static const char *get_description (demux_class_t *this_gen) { return "matroska demux plugin"; } -static char *get_identifier (demux_class_t *this_gen) { +static const char *get_identifier (demux_class_t *this_gen) { return "matroska"; } -static char *get_extensions (demux_class_t *this_gen) { +static const char *get_extensions (demux_class_t *this_gen) { return "mkv"; } -static char *get_mimetypes (demux_class_t *this_gen) { +static const char *get_mimetypes (demux_class_t *this_gen) { return "video/mkv: mkv: matroska;"; } |