diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/demuxers/demux_matroska.c | 263 | ||||
-rw-r--r-- | src/demuxers/matroska.h | 13 |
2 files changed, 232 insertions, 44 deletions
diff --git a/src/demuxers/demux_matroska.c b/src/demuxers/demux_matroska.c index bcc5f52ea..98d2136a0 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.50 2007/01/07 12:33:50 molivier 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) { @@ -1104,6 +1261,15 @@ static int parse_track_entry(demux_matroska_t *this, matroska_track_t *track) { } 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; + case MATROSKA_ID_TR_UID: case MATROSKA_ID_TR_FLAGENABLED: case MATROSKA_ID_TR_FLAGLACING: @@ -1289,6 +1455,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 +1513,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++; } diff --git a/src/demuxers/matroska.h b/src/demuxers/matroska.h index 926d6d0a6..3bfdbdc0c 100644 --- a/src/demuxers/matroska.h +++ b/src/demuxers/matroska.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000-2003 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: matroska.h,v 1.10 2006/11/14 07:09:46 molivier Exp $ + * $Id: matroska.h,v 1.11 2007/01/07 12:33:50 molivier Exp $ * */ #ifndef MATROSKA_H @@ -224,6 +224,7 @@ struct matroska_track_s { uint8_t *codec_private; uint32_t codec_private_len; int default_flag; + uint32_t compress_algo; uint32_t buf_type; fifo_buffer_t *fifo; @@ -305,4 +306,12 @@ struct matroska_track_s { #define MATROSKA_TRACK_SUBTITLE 0x11 #define MATROSKA_TRACK_CONTROL 0x20 +/* compression algorithms */ +#define MATROSKA_COMPRESS_ZLIB 0x00 +#define MATROSKA_COMPRESS_BZLIB 0x01 +#define MATROSKA_COMPRESS_LZO1X 0x02 +#define MATROSKA_COMPRESS_HEADER_STRIP 0x03 +#define MATROSKA_COMPRESS_UNKNOWN 0xFFFFFFFE /* Xine internal type */ +#define MATROSKA_COMPRESS_NONE 0xFFFFFFFF /* Xine internal type */ + #endif /* MATROSKA_H */ |