diff options
Diffstat (limited to 'src/demuxers')
69 files changed, 4860 insertions, 2967 deletions
diff --git a/src/demuxers/Makefile.am b/src/demuxers/Makefile.am index ffbfa0a8d..027f6750f 100644 --- a/src/demuxers/Makefile.am +++ b/src/demuxers/Makefile.am @@ -1,3 +1,4 @@ +include $(top_builddir)/misc/Makefile.plugins include $(top_srcdir)/misc/Makefile.common AM_CFLAGS = $(VISIBILITY_FLAG) @@ -8,7 +9,7 @@ ogg_module = xineplug_dmx_ogg.la endif if BUILD_ASF -asf_module = xineplug_dmx_asf.la +asf_module = xineplug_dmx_asf.la endif if BUILD_NOSEFART @@ -48,7 +49,7 @@ xineplug_LTLIBRARIES = $(ogg_module) $(asf_module) $(mng_module) $(image_module) xineplug_dmx_nsv.la \ xineplug_dmx_matroska.la \ xineplug_dmx_iff.la \ - xineplug_dmx_flv.la + xineplug_dmx_flv.la xineplug_dmx_ogg_la_SOURCES = demux_ogg.c xineplug_dmx_ogg_la_LIBADD = $(XINE_LIB) $(VORBIS_LIBS) $(SPEEX_LIBS) $(THEORA_LIBS) $(OGG_LIBS) $(LTLIBINTL) @@ -61,7 +62,7 @@ xineplug_dmx_mpeg_block_la_SOURCES = demux_mpeg_block.c xineplug_dmx_mpeg_block_la_LIBADD = $(XINE_LIB) $(LTLIBINTL) xineplug_dmx_mpeg_la_SOURCES = demux_mpeg.c -xineplug_dmx_mpeg_la_LIBADD = $(XINE_LIB) +xineplug_dmx_mpeg_la_LIBADD = $(XINE_LIB) $(LTLIBINTL) xineplug_dmx_mpeg_elem_la_SOURCES = demux_elem.c xineplug_dmx_mpeg_elem_la_LIBADD = $(XINE_LIB) @@ -70,10 +71,10 @@ xineplug_dmx_mpeg_pes_la_SOURCES = demux_mpeg_pes.c xineplug_dmx_mpeg_pes_la_LIBADD = $(XINE_LIB) $(LTLIBINTL) xineplug_dmx_mpeg_ts_la_SOURCES = demux_ts.c -xineplug_dmx_mpeg_ts_la_LIBADD = $(XINE_LIB) +xineplug_dmx_mpeg_ts_la_LIBADD = $(XINE_LIB) $(LTLIBINTL) xineplug_dmx_qt_la_SOURCES = demux_qt.c -xineplug_dmx_qt_la_LIBADD = $(XINE_LIB) $(ZLIB_LIBS) +xineplug_dmx_qt_la_LIBADD = $(XINE_LIB) $(ZLIB_LIBS) $(LTLIBINTL) xineplug_dmx_qt_la_CPPFLAGS = $(ZLIB_CPPFLAGS) xineplug_dmx_asf_la_SOURCES = demux_asf.c asfheader.c @@ -129,8 +130,8 @@ xineplug_dmx_image_la_LIBADD = $(XINE_LIB) xineplug_dmx_nsv_la_SOURCES = demux_nsv.c xineplug_dmx_nsv_la_LIBADD = $(XINE_LIB) -xineplug_dmx_matroska_la_SOURCES = demux_matroska.c ebml.c -xineplug_dmx_matroska_la_LIBADD = $(XINE_LIB) $(ZLIB_LIBS) +xineplug_dmx_matroska_la_SOURCES = demux_matroska.c demux_matroska-chapters.c ebml.c +xineplug_dmx_matroska_la_LIBADD = $(XINE_LIB) $(ZLIB_LIBS) $(LTLIBINTL) xineplug_dmx_matroska_la_CPPFLAGS = $(ZLIB_CPPFLAGS) xineplug_dmx_matroska_la_CFLAGS = $(AM_CFLAGS) -fno-strict-aliasing @@ -141,4 +142,4 @@ xineplug_dmx_flv_la_SOURCES = demux_flv.c xineplug_dmx_flv_la_LIBADD = $(XINE_LIB) $(LTLIBINTL) xineinclude_HEADERS = demux.h -noinst_HEADERS = asfheader.h qtpalette.h group_games.h group_audio.h id3.h ebml.h matroska.h iff.h flacutils.h +noinst_HEADERS = asfheader.h qtpalette.h group_games.h group_audio.h id3.h ebml.h matroska.h demux_matroska.h iff.h flacutils.h real_common.h diff --git a/src/demuxers/asfheader.c b/src/demuxers/asfheader.c index ea92f878b..e9a36fc29 100644 --- a/src/demuxers/asfheader.c +++ b/src/demuxers/asfheader.c @@ -142,9 +142,9 @@ static uint8_t *asf_reader_get_bytes(asf_reader_t *reader, size_t size) { static char *asf_reader_get_string(asf_reader_t *reader, size_t size, iconv_t cd) {
char *inbuf, *outbuf;
size_t inbytesleft, outbytesleft;
- char scratch[2048];
+ char scratch[2048];
- if ((reader->size - reader->pos) < size)
+ if ((size == 0) ||((reader->size - reader->pos) < size))
return NULL;
inbuf = (char *)reader->buffer + reader->pos;
@@ -399,7 +399,7 @@ static int asf_header_parse_stream_extended_properties(asf_header_t *header, uin if (asf_stream_extension->stream_name_count) {
asf_stream_extension->stream_names = malloc (asf_stream_extension->stream_name_count * sizeof(void*));
for (i = 0; i < asf_stream_extension->stream_name_count; i++) {
- uint16_t lang_index, length;
+ uint16_t lang_index, length = 0;
asf_reader_get_16(&reader, &lang_index);
asf_reader_get_16(&reader, &length);
asf_stream_extension->stream_names[i] = (char*)asf_reader_get_bytes(&reader, length); /* store them */
@@ -411,7 +411,7 @@ static int asf_header_parse_stream_extended_properties(asf_header_t *header, uin for (i = 0; i < asf_stream_extension->payload_extension_system_count; i++) {
GUID guid;
uint16_t data_size;
- uint32_t length;
+ uint32_t length = 0;
asf_reader_get_guid(&reader, &guid);
asf_reader_get_16(&reader, &data_size);
asf_reader_get_32(&reader, &length);
@@ -427,7 +427,7 @@ static int asf_header_parse_stream_extended_properties(asf_header_t *header, uin /* embeded stream properties */
if (asf_reader_get_size(&reader) >= 24) {
GUID guid;
- uint64_t object_length;
+ uint64_t object_length = 0;
asf_reader_get_guid(&reader, &guid);
asf_reader_get_64(&reader, &object_length);
@@ -490,8 +490,8 @@ static int asf_header_parse_stream_bitrate_properties(asf_header_t *header_pub, lprintf (" bitrate count: %d\n", bitrate_count);
for(i = 0; i < bitrate_count; i++) {
- uint16_t flags;
- uint32_t bitrate;
+ uint16_t flags = 0;
+ uint32_t bitrate = 0;
int stream_number;
uint8_t *bitrate_pointer;
@@ -511,6 +511,61 @@ static int asf_header_parse_stream_bitrate_properties(asf_header_t *header_pub, return 1;
}
+static int asf_header_parse_metadata(asf_header_t *header_pub, uint8_t *buffer, int buffer_len)
+{
+ asf_header_internal_t *header = (asf_header_internal_t *)header_pub;
+ asf_reader_t reader;
+ uint16_t i, records_count;
+ iconv_t iconv_cd;
+
+ if (buffer_len < 2)
+ return 0;
+
+ if ((iconv_cd = iconv_open ("UTF-8", "UCS-2LE")) == (iconv_t)-1)
+ return 0;
+
+ asf_reader_init(&reader, buffer, buffer_len);
+ asf_reader_get_16(&reader, &records_count);
+
+ for (i = 0; i < records_count; i++)
+ {
+ uint16_t index, stream, name_len = 0, data_type;
+ uint32_t data_len = 0;
+ int stream_id;
+
+ asf_reader_get_16 (&reader, &index);
+ asf_reader_get_16 (&reader, &stream);
+ stream &= 0x7f;
+ asf_reader_get_16 (&reader, &name_len);
+ asf_reader_get_16 (&reader, &data_type);
+ asf_reader_get_32 (&reader, &data_len);
+
+ stream_id = asf_header_get_stream_id (&header->pub, stream);
+
+ if (data_len >= 4)
+ {
+ char *name = asf_reader_get_string (&reader, name_len, iconv_cd);
+ if (name && !strcmp (name, "AspectRatioX"))
+ {
+ asf_reader_get_32 (&reader, &header->pub.aspect_ratios[stream_id].x);
+ data_len -= 4;
+ }
+ else if (name && !strcmp (name, "AspectRatioY"))
+ {
+ asf_reader_get_32 (&reader, &header->pub.aspect_ratios[stream_id].y);
+ data_len -= 4;
+ }
+ free (name);
+ asf_reader_skip (&reader, data_len);
+ }
+ else
+ asf_reader_skip (&reader, data_len + name_len);
+ }
+
+ iconv_close (iconv_cd);
+ return 1;
+}
+
static int asf_header_parse_header_extension(asf_header_t *header, uint8_t *buffer, int buffer_len) {
asf_reader_t reader;
@@ -533,7 +588,7 @@ static int asf_header_parse_header_extension(asf_header_t *header, uint8_t *buff GUID guid;
int object_id;
- uint64_t object_length, object_data_length;
+ uint64_t object_length = 0, object_data_length;
if (asf_reader_get_size(&reader) < 24) {
printf("invalid buffer size\n");
@@ -549,12 +604,14 @@ static int asf_header_parse_header_extension(asf_header_t *header, uint8_t *buff case GUID_EXTENDED_STREAM_PROPERTIES:
asf_header_parse_stream_extended_properties(header, asf_reader_get_buffer(&reader), object_data_length);
break;
+ case GUID_METADATA:
+ asf_header_parse_metadata(header, asf_reader_get_buffer(&reader), object_data_length);
+ break;
case GUID_ADVANCED_MUTUAL_EXCLUSION:
case GUID_GROUP_MUTUAL_EXCLUSION:
case GUID_STREAM_PRIORITIZATION:
case GUID_BANDWIDTH_SHARING:
case GUID_LANGUAGE_LIST:
- case GUID_METADATA:
case GUID_METADATA_LIBRARY:
case GUID_INDEX_PARAMETERS:
case GUID_MEDIA_OBJECT_INDEX_PARAMETERS:
@@ -581,10 +638,9 @@ static int asf_header_parse_content_description(asf_header_t *header_pub, uint8_ if (buffer_len < 10)
return 0;
- content = malloc(sizeof(asf_content_t));
+ content = calloc(1, sizeof(asf_content_t));
if (!content)
return 0;
- memset(content, 0, sizeof(asf_content_t));
asf_reader_init(&reader, buffer, buffer_len);
asf_reader_get_16(&reader, &title_length);
@@ -599,6 +655,12 @@ static int asf_header_parse_content_description(asf_header_t *header_pub, uint8_ content->description = asf_reader_get_string(&reader, description_length, header->iconv_cd);
content->rating = asf_reader_get_string(&reader, rating_length, header->iconv_cd);
+ lprintf("title: %d chars: \"%s\"\n", title_length, content->title);
+ lprintf("author: %d chars: \"%s\"\n", author_length, content->author);
+ lprintf("copyright: %d chars: \"%s\"\n", copyright_length, content->copyright);
+ lprintf("description: %d chars: \"%s\"\n", description_length, content->description);
+ lprintf("rating: %d chars: \"%s\"\n", rating_length, content->rating);
+
header->pub.content = content;
return 1;
}
@@ -611,10 +673,9 @@ asf_header_t *asf_header_new (uint8_t *buffer, int buffer_len) { uint32_t object_count;
uint16_t junk;
- asf_header = malloc(sizeof(asf_header_internal_t));
+ asf_header = calloc(1, sizeof(asf_header_internal_t));
if (!asf_header)
return NULL;
- memset(asf_header, 0, sizeof(asf_header_internal_t));
lprintf("parsing_asf_header\n");
if (buffer_len < 6) {
@@ -638,7 +699,7 @@ asf_header_t *asf_header_new (uint8_t *buffer, int buffer_len) { GUID guid;
int object_id;
- uint64_t object_length, object_data_length;
+ uint64_t object_length = 0, object_data_length;
if (asf_reader_get_size(&reader) < 24) {
printf("invalid buffer size\n");
@@ -697,10 +758,9 @@ asf_header_t *asf_header_new (uint8_t *buffer, int buffer_len) { }
if (!asf_header->pub.content) {
lprintf("no content object present\n");
- asf_header->pub.content = malloc(sizeof(asf_content_t));
+ asf_header->pub.content = calloc(1, sizeof(asf_content_t));
if (!asf_header->pub.content)
goto exit_error;
- memset(asf_header->pub.content, 0, sizeof(asf_content_t));
}
return &asf_header->pub;
diff --git a/src/demuxers/asfheader.h b/src/demuxers/asfheader.h index 4bd13ab3f..265f0e643 100644 --- a/src/demuxers/asfheader.h +++ b/src/demuxers/asfheader.h @@ -320,6 +320,7 @@ struct asf_header_s { asf_stream_t *streams[ASF_MAX_NUM_STREAMS];
asf_stream_extension_t *stream_extensions[ASF_MAX_NUM_STREAMS];
uint32_t bitrates[ASF_MAX_NUM_STREAMS];
+ struct { uint32_t x, y; } aspect_ratios[ASF_MAX_NUM_STREAMS];
};
struct asf_file_s {
@@ -389,7 +390,7 @@ struct asf_stream_extension_s { int asf_find_object_id (GUID *g);
void asf_get_guid (uint8_t *buffer, GUID *value);
-asf_header_t *asf_header_new (uint8_t *buffer, int buffer_len);
+asf_header_t *asf_header_new (uint8_t *buffer, int buffer_len) XINE_MALLOC;
void asf_header_choose_streams (asf_header_t *header, uint32_t bandwidth,
int *video_id, int *audio_id);
void asf_header_disable_streams (asf_header_t *header,
diff --git a/src/demuxers/demux.h b/src/demuxers/demux.h index 81907cfcf..a824730ea 100644 --- a/src/demuxers/demux.h +++ b/src/demuxers/demux.h @@ -1,18 +1,18 @@ -/* +/* * Copyright (C) 2000-2003 the xine project - * + * * This file is part of xine, a free video player. - * + * * xine is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * xine is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA @@ -63,7 +63,7 @@ struct demux_class_s { */ const char* (*get_identifier) (demux_class_t *this); - + /* * return MIME types supported for this plugin */ @@ -73,7 +73,7 @@ struct demux_class_s { /* * return ' ' seperated list of file extensions this * demuxer is likely to handle - * (will be used to filter media files in + * (will be used to filter media files in * file selection dialogs) */ @@ -100,7 +100,7 @@ struct demux_plugin_s { void (*send_headers) (demux_plugin_t *this); /* - * ask demux to seek + * ask demux to seek * * for seekable streams, a start position can be specified * @@ -118,11 +118,11 @@ struct demux_plugin_s { * starting the demuxer) */ - int (*seek) (demux_plugin_t *this, + int (*seek) (demux_plugin_t *this, off_t start_pos, int start_time, int playing ); /* - * send a chunk of data down to decoder fifos + * send a chunk of data down to decoder fifos * * the meaning of "chunk" is specific to every demux, usually * it involves parsing one unit of data from stream. @@ -132,15 +132,15 @@ struct demux_plugin_s { */ int (*send_chunk) (demux_plugin_t *this); - + /* - * free resources + * free resources */ void (*dispose) (demux_plugin_t *this) ; /* - * returns DEMUX_OK or DEMUX_FINISHED + * returns DEMUX_OK or DEMUX_FINISHED */ int (*get_status) (demux_plugin_t *this) ; @@ -157,12 +157,12 @@ struct demux_plugin_s { */ uint32_t (*get_capabilities) (demux_plugin_t *this); - + /* * request optional data from input plugin. */ int (*get_optional_data) (demux_plugin_t *this, void *data, int data_type); - + /* * "backwards" link to plugin class */ @@ -181,8 +181,8 @@ struct demux_plugin_s { /* * DEMUX_CAP_AUDIOLANG: * DEMUX_CAP_SPULANG: - * demux plugin knows something about audio/spu languages, - * e.g. knows that audio stream #0 is english, + * demux plugin knows something about audio/spu languages, + * e.g. knows that audio stream #0 is english, * audio stream #1 is german, ... Same bits as INPUT * capabilities . */ diff --git a/src/demuxers/demux_4xm.c b/src/demuxers/demux_4xm.c index 24aee1ac4..a58cf0f22 100644 --- a/src/demuxers/demux_4xm.c +++ b/src/demuxers/demux_4xm.c @@ -125,25 +125,15 @@ static float get_le_float(unsigned char *buffer) * This function is called from the _open() function of this demuxer. * It returns 1 if 4xm file was opened successfully. */ static int open_fourxm_file(demux_fourxm_t *fourxm) { - unsigned char preview[12]; - int header_size; - unsigned char *header; - int i; - unsigned int fourcc_tag; - unsigned int size; - unsigned int current_track; - unsigned int audio_type; - unsigned int total_frames; - float fps; /* the file signature will be in the first 12 bytes */ if (_x_demux_read_header(fourxm->input, preview, 12) != 12) return 0; /* check for the signature tags */ - if ((_X_LE_32(&preview[0]) != RIFF_TAG) || - (_X_LE_32(&preview[8]) != _4XMV_TAG)) + if (!_x_is_fourcc(&preview[0], "RIFF") || + !_x_is_fourcc(&preview[8], "4XMV")) return 0; /* file is qualified; skip over the header bytes in the stream */ @@ -152,14 +142,14 @@ static int open_fourxm_file(demux_fourxm_t *fourxm) { /* fetch the LIST-HEAD header */ if (fourxm->input->read(fourxm->input, preview, 12) != 12) return 0; - if ((_X_LE_32(&preview[0]) != LIST_TAG) || - (_X_LE_32(&preview[8]) != HEAD_TAG)) + if (!_x_is_fourcc(&preview[0], "LIST") || + !_x_is_fourcc(&preview[8], "HEAD") ) return 0; /* read the whole header */ - header_size = _X_LE_32(&preview[4]) - 4; - header = xine_xmalloc(header_size); - if (fourxm->input->read(fourxm->input, header, header_size) != header_size) { + const uint32_t header_size = _X_LE_32(&preview[4]) - 4; + uint8_t *const header = malloc(header_size); + if (!header || fourxm->input->read(fourxm->input, header, header_size) != header_size) { free(header); return 0; } @@ -171,12 +161,13 @@ static int open_fourxm_file(demux_fourxm_t *fourxm) { fourxm->video_pts_inc = 0; /* take the lazy approach and search for any and all vtrk and strk chunks */ + int i; for (i = 0; i < header_size - 8; i++) { - fourcc_tag = _X_LE_32(&header[i]); - size = _X_LE_32(&header[i + 4]); + const uint32_t fourcc_tag = _X_LE_32(&header[i]); + const uint32_t size = _X_LE_32(&header[i + 4]); if (fourcc_tag == std__TAG) { - fps = get_le_float(&header[i + 12]); + const float fps = get_le_float(&header[i + 12]); fourxm->video_pts_inc = (int64_t)(90000.0 / fps); } else if (fourcc_tag == vtrk_TAG) { /* check that there is enough data */ @@ -184,7 +175,7 @@ static int open_fourxm_file(demux_fourxm_t *fourxm) { free(header); return 0; } - total_frames = _X_LE_32(&header[i + 24]); + const uint32_t total_frames = _X_LE_32(&header[i + 24]); fourxm->duration_in_ms = total_frames; fourxm->duration_in_ms *= fourxm->video_pts_inc; fourxm->duration_in_ms /= 90000; @@ -198,9 +189,13 @@ static int open_fourxm_file(demux_fourxm_t *fourxm) { free(header); return 0; } - current_track = _X_LE_32(&header[i + 8]); - if (current_track + 1 > fourxm->track_count) { + const uint32_t current_track = _X_LE_32(&header[i + 8]); + if (current_track >= fourxm->track_count) { fourxm->track_count = current_track + 1; + if (!fourxm->track_count || fourxm->track_count >= UINT_MAX / sizeof(audio_track_t)) { + free(header); + return 0; + } fourxm->tracks = realloc(fourxm->tracks, fourxm->track_count * sizeof(audio_track_t)); if (!fourxm->tracks) { @@ -212,7 +207,7 @@ static int open_fourxm_file(demux_fourxm_t *fourxm) { fourxm->tracks[current_track].channels = _X_LE_32(&header[i + 36]); fourxm->tracks[current_track].sample_rate = _X_LE_32(&header[i + 40]); fourxm->tracks[current_track].bits = _X_LE_32(&header[i + 44]); - audio_type = _X_LE_32(&header[i + 12]); + const uint32_t audio_type = _X_LE_32(&header[i + 12]); if (audio_type == 0) fourxm->tracks[current_track].audio_type = BUF_AUDIO_LPCM_LE; else if (audio_type == 1) @@ -239,20 +234,18 @@ static int demux_fourxm_send_chunk(demux_plugin_t *this_gen) { demux_fourxm_t *this = (demux_fourxm_t *) this_gen; buf_element_t *buf = NULL; - unsigned int fourcc_tag; - unsigned int size; - unsigned char header[8]; unsigned int remaining_bytes; unsigned int current_track; /* read the next header */ + uint8_t header[8]; if (this->input->read(this->input, header, 8) != 8) { this->status = DEMUX_FINISHED; return this->status; } - fourcc_tag = _X_LE_32(&header[0]); - size = _X_LE_32(&header[4]); + const uint32_t fourcc_tag = _X_LE_32(&header[0]); + const uint32_t size = _X_LE_32(&header[4]); switch (fourcc_tag) { @@ -263,7 +256,7 @@ static int demux_fourxm_send_chunk(demux_plugin_t *this_gen) { buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); buf->type = BUF_VIDEO_4XM; if( this->filesize ) - buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * + buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * 65535 / this->filesize ); buf->extra_info->input_time = this->video_pts / 90; buf->pts = this->video_pts; @@ -278,7 +271,7 @@ static int demux_fourxm_send_chunk(demux_plugin_t *this_gen) { buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); buf->type = BUF_VIDEO_4XM; if( this->filesize ) - buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * + buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * 65535 / this->filesize ); buf->extra_info->input_time = this->video_pts / 90; buf->pts = this->video_pts; @@ -327,7 +320,7 @@ static int demux_fourxm_send_chunk(demux_plugin_t *this_gen) { buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); buf->type = this->tracks[current_track].audio_type; if( this->filesize ) - buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * + buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * 65535 / this->filesize ); /* let the engine sort it out */ buf->extra_info->input_time = 0; @@ -361,7 +354,7 @@ static int demux_fourxm_send_chunk(demux_plugin_t *this_gen) { break; default: - lprintf("bad chunk: %c%c%c%c (%02X%02X%02X%02X)\n", + lprintf("bad chunk: %c%c%c%c (%02X%02X%02X%02X)\n", header[0], header[1], header[2], header[3], header[0], header[1], header[2], header[3]); this->status = DEMUX_FINISHED; @@ -472,7 +465,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str demux_fourxm_t *this; - this = xine_xmalloc (sizeof (demux_fourxm_t)); + this = calloc(1, sizeof(demux_fourxm_t)); this->stream = stream; this->input = input; @@ -491,10 +484,8 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str switch (stream->content_detection_method) { case METHOD_BY_EXTENSION: { - const char *extensions, *mrl; - - mrl = input->get_mrl (input); - extensions = class_gen->get_extensions (class_gen); + const char *const mrl = input->get_mrl (input); + const char *const extensions = class_gen->get_extensions (class_gen); if (!_x_demux_check_extension (mrl, extensions)) { free (this); @@ -546,7 +537,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_fourxm_init_plugin (xine_t *xine, void *data) { demux_fourxm_class_t *this; - this = xine_xmalloc (sizeof (demux_fourxm_class_t)); + this = calloc(1, sizeof(demux_fourxm_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_aac.c b/src/demuxers/demux_aac.c index d80413f83..6615f4f61 100644 --- a/src/demuxers/demux_aac.c +++ b/src/demuxers/demux_aac.c @@ -95,8 +95,7 @@ static int open_aac_file(demux_aac_t *this) { return 0; /* Check for an ADIF header - should be at the start of the file */ - if ((peak[0] == 'A') && (peak[1] == 'D') && - (peak[2] == 'I') && (peak[3] == 'F')) { + if (_x_is_fourcc(peak, "AIDF")) { lprintf("found ADIF header\n"); return 1; } @@ -109,7 +108,7 @@ static int open_aac_file(demux_aac_t *this) { if ( this->input->read(this->input, peak, MAX_PREVIEW_SIZE) != MAX_PREVIEW_SIZE ) return 0; this->input->seek(this->input, 0, SEEK_SET); - } else if (_x_demux_read_header(this->input, peak, MAX_PREVIEW_SIZE) != + } else if (_x_demux_read_header(this->input, peak, MAX_PREVIEW_SIZE) != MAX_PREVIEW_SIZE) return 0; @@ -134,9 +133,7 @@ static int open_aac_file(demux_aac_t *this) { if ((frame_size > 0) && (data_start+frame_size < MAX_PREVIEW_SIZE-1) && /* first 28 bits must be identical */ - (peak[data_start ] ==peak[data_start+frame_size ]) && - (peak[data_start+1] ==peak[data_start+frame_size+1]) && - (peak[data_start+2] ==peak[data_start+frame_size+2]) && + memcmp(&peak[data_start], &peak[data_start+frame_size], 4) == 0 && (peak[data_start+3]>>4==peak[data_start+frame_size+3]>>4)) { lprintf("found second ADTS header\n"); @@ -176,11 +173,11 @@ static int demux_aac_send_chunk(demux_plugin_t *this_gen) { buf->extra_info->input_time = (8*current_pos) / (bitrate/1000); bytes_read = this->input->read(this->input, buf->content, buf->max_size); - if (bytes_read == 0) { + if (bytes_read <= 0) { buf->free_buffer(buf); this->status = DEMUX_FINISHED; return this->status; - } else + } else buf->size = bytes_read; /* each buffer stands on its own */ @@ -262,7 +259,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str demux_aac_t *this; - this = xine_xmalloc (sizeof (demux_aac_t)); + this = calloc(1, sizeof(demux_aac_t)); this->stream = stream; this->input = input; @@ -333,7 +330,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_aac_init_plugin (xine_t *xine, void *data) { demux_aac_class_t *this; - this = xine_xmalloc (sizeof (demux_aac_class_t)); + this = calloc(1, sizeof(demux_aac_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_ac3.c b/src/demuxers/demux_ac3.c index c0fae275b..f13144254 100644 --- a/src/demuxers/demux_ac3.c +++ b/src/demuxers/demux_ac3.c @@ -37,6 +37,9 @@ #ifdef HAVE_ALLOCA_H #include <alloca.h> #endif +#ifdef HAVE_MALLOC_H +#include <malloc.h> +#endif #define LOG_MODULE "demux_ac3" #define LOG_VERBOSE @@ -304,17 +307,11 @@ static int demux_ac3_send_chunk (demux_plugin_t *this_gen) { } } else { buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); - buf->size = this->input->read(this->input, buf->content, + buf->size = this->input->read(this->input, buf->content, this->frame_size); } - if (buf->size == 0) { - buf->free_buffer(buf); - this->status = DEMUX_FINISHED; - return this->status; - } - - if (buf->size == 0) { + if (buf->size <= 0) { buf->free_buffer(buf); this->status = DEMUX_FINISHED; return this->status; @@ -322,7 +319,7 @@ static int demux_ac3_send_chunk (demux_plugin_t *this_gen) { buf->type = this->buf_type; if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = (int)( (double) current_stream_pos * + buf->extra_info->input_normpos = (int)( (double) current_stream_pos * 65535 / this->input->get_length (this->input) ); buf->extra_info->input_time = audio_pts / 90; buf->pts = audio_pts; @@ -417,7 +414,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str demux_ac3_t *this; - this = xine_xmalloc (sizeof (demux_ac3_t)); + this = calloc(1, sizeof(demux_ac3_t)); this->stream = stream; this->input = input; @@ -491,7 +488,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_ac3_init_plugin (xine_t *xine, void *data) { demux_ac3_class_t *this; - this = xine_xmalloc (sizeof (demux_ac3_class_t)); + this = calloc(1, sizeof(demux_ac3_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_aiff.c b/src/demuxers/demux_aiff.c index 3f2d0df11..ee45963a5 100644 --- a/src/demuxers/demux_aiff.c +++ b/src/demuxers/demux_aiff.c @@ -46,6 +46,10 @@ #define COMM_TAG FOURCC_TAG('C', 'O', 'M', 'M') #define SSND_TAG FOURCC_TAG('S', 'S', 'N', 'D') #define APCM_TAG FOURCC_TAG('A', 'P', 'C', 'M') +#define NAME_TAG FOURCC_TAG('N', 'A', 'M', 'E') +#define AUTH_TAG FOURCC_TAG('A', 'U', 'T', 'H') +#define COPY_TAG FOURCC_TAG('(', 'c', ')', ' ') +#define ANNO_TAG FOURCC_TAG('A', 'N', 'N', 'O') #define PREAMBLE_SIZE 8 #define AIFF_SIGNATURE_SIZE 12 @@ -80,6 +84,24 @@ typedef struct { demux_class_t demux_class; } demux_aiff_class_t; +/* converts IEEE 80bit extended into int, based on FFMPEG code */ +static int extended_to_int(const unsigned char p[10]) +{ + uint64_t m = 0; + int e, i; + + for (i = 0; i < 8; i++) + m = (m<<8) + p[2+i];; + e = (((int)p[0]&0x7f)<<8) | p[1]; + if (e == 0x7fff && m) + return 0.0/0.0; + e -= 16383 + 63; + + if (p[0]&0x80) + m= -m; + return (int) ldexp(m, e); +} + /* returns 1 if the AIFF file was opened successfully, 0 otherwise */ static int open_aiff_file(demux_aiff_t *this) { @@ -87,13 +109,14 @@ static int open_aiff_file(demux_aiff_t *this) { unsigned char preamble[PREAMBLE_SIZE]; unsigned int chunk_type; unsigned int chunk_size; + unsigned char extended_sample_rate[10]; if (_x_demux_read_header(this->input, signature, AIFF_SIGNATURE_SIZE) != AIFF_SIGNATURE_SIZE) return 0; /* check the signature */ - if ((_X_BE_32(&signature[0]) != FORM_TAG) || - (_X_BE_32(&signature[8]) != AIFF_TAG)) + if( !_x_is_fourcc(&signature[0], "FORM") || + !_x_is_fourcc(&signature[8], "AIFF") ) return 0; /* file is qualified; skip over the header bytes in the stream */ @@ -116,7 +139,7 @@ static int open_aiff_file(demux_aiff_t *this) { } chunk_type = _X_BE_32(&preamble[0]); chunk_size = _X_BE_32(&preamble[4]); - + if (chunk_type == COMM_TAG) { unsigned char buffer[100]; @@ -135,7 +158,8 @@ static int open_aiff_file(demux_aiff_t *this) { this->audio_channels = _X_BE_16(&buffer[0]); this->audio_frames = _X_BE_32(&buffer[2]); this->audio_bits = _X_BE_16(&buffer[6]); - this->audio_sample_rate = _X_BE_16(&buffer[0x0A]); + memcpy(&extended_sample_rate, &buffer[8], sizeof(extended_sample_rate)); + this->audio_sample_rate = extended_to_int(extended_sample_rate); this->audio_bytes_per_second = this->audio_channels * (this->audio_bits / 8) * this->audio_sample_rate; @@ -150,11 +174,18 @@ static int open_aiff_file(demux_aiff_t *this) { (this->audio_bits / 8); this->running_time = (this->audio_frames / this->audio_sample_rate) * 1000; - this->audio_block_align = PCM_BLOCK_ALIGN; + /* we should send only complete frames to decoder, as it + * doesn't handle underconsumption yet */ + this->audio_block_align = PCM_BLOCK_ALIGN - PCM_BLOCK_ALIGN % (this->audio_bits / 8 * this->audio_channels); break; } else { + /* if chunk contains metadata, it will be word-aligned (as seen at sox and ffmpeg) */ + if ( ((chunk_type == NAME_TAG) || (chunk_type==AUTH_TAG) || + (chunk_type == COPY_TAG) || (chunk_type==ANNO_TAG)) && (chunk_size&1)) + chunk_size++; + /* unrecognized; skip it */ this->input->seek(this->input, chunk_size, SEEK_CUR); } @@ -179,7 +210,7 @@ static int demux_aiff_send_chunk (demux_plugin_t *this_gen) { /* just load data chunks from wherever the stream happens to be * pointing; issue a DEMUX_FINISHED status if EOF is reached */ remaining_sample_bytes = this->audio_block_align; - current_file_pos = + current_file_pos = this->input->get_current_pos(this->input) - this->data_start; current_pts = current_file_pos; @@ -227,7 +258,7 @@ static int demux_aiff_send_chunk (demux_plugin_t *this_gen) { this->audio_fifo->put (this->audio_fifo, buf); } - + return this->status; } @@ -338,7 +369,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str demux_aiff_t *this; - this = xine_xmalloc (sizeof (demux_aiff_t)); + this = calloc(1, sizeof(demux_aiff_t)); this->stream = stream; this->input = input; @@ -414,7 +445,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_aiff_init_plugin (xine_t *xine, void *data) { demux_aiff_class_t *this; - this = xine_xmalloc (sizeof (demux_aiff_class_t)); + this = calloc(1, sizeof(demux_aiff_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_asf.c b/src/demuxers/demux_asf.c index 9aab59977..e2da05c75 100644 --- a/src/demuxers/demux_asf.c +++ b/src/demuxers/demux_asf.c @@ -70,6 +70,7 @@ #define ASF_MODE_HTTP_REF 2 #define ASF_MODE_ASF_REF 3 #define ASF_MODE_ENCRYPTED_CONTENT 4 +#define ASF_MODE_NO_CONTENT 5 typedef struct { int seq; @@ -87,13 +88,13 @@ typedef struct { int skip; int resync; int first_seq; - + int payload_size; /* palette handling */ int palette_count; palette_entry_t palette[256]; - + } asf_demux_stream_t; typedef struct demux_asf_s { @@ -108,13 +109,13 @@ typedef struct demux_asf_s { int64_t keyframe_ts; int keyframe_found; - + int seqno; uint32_t packet_size; uint8_t packet_len_flags; uint32_t data_size; uint64_t packet_count; - + asf_demux_stream_t streams[MAX_NUM_STREAMS]; int video_stream; int audio_stream; @@ -144,7 +145,7 @@ typedef struct demux_asf_s { int reorder_b; int buf_flag_seek; - + /* first packet position */ int64_t first_packet_pos; @@ -266,7 +267,7 @@ static int get_guid (demux_asf_t *this) { for(i = 0; i < 8; i++) { g.Data4[i] = get_byte(this); } - + return get_guid_id(this, &g); } @@ -305,7 +306,7 @@ static void asf_send_audio_header (demux_asf_t *this, int stream) { this->status = DEMUX_FINISHED; return; } - + memcpy (buf->content, wavex, asf_stream->private_data_length); _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_FOURCC, wavex->wFormatTag); @@ -346,11 +347,19 @@ static void asf_send_video_header (demux_asf_t *this, int stream) { this->status = DEMUX_FINISHED; return; } - + buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAMERATE| BUF_FLAG_FRAME_END; - + buf->decoder_info[0] = 0; + + if (this->asf_header->aspect_ratios[stream].x && this->asf_header->aspect_ratios[stream].y) + { + buf->decoder_flags |= BUF_FLAG_ASPECT; + buf->decoder_info[1] = bih->biWidth * this->asf_header->aspect_ratios[stream].x; + buf->decoder_info[2] = bih->biHeight * this->asf_header->aspect_ratios[stream].y; + } + buf->size = asf_stream->private_data_length - 11; memcpy (buf->content, bih, buf->size); buf->type = this->streams[stream].buf_type; @@ -360,7 +369,7 @@ static void asf_send_video_header (demux_asf_t *this, int stream) { /* send off the palette, if there is one */ if (demux_stream->palette_count) { - xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, "demux_asf: stream %d, palette : %d entries\n", stream, demux_stream->palette_count); buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); buf->decoder_flags = BUF_FLAG_SPECIAL|BUF_FLAG_HEADER; @@ -379,10 +388,21 @@ static int asf_read_header (demux_asf_t *this) { char *asf_header_buffer = NULL; asf_header_len = get_le64(this); - asf_header_buffer = alloca(asf_header_len); + if (asf_header_len > 4 * 1024 * 1024) + { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_asf: asf_read_header: overly-large header? (%"PRIu64" bytes)\n", + asf_header_len); + return 0; + } + + asf_header_buffer = malloc (asf_header_len); if (this->input->read (this->input, asf_header_buffer, asf_header_len) != asf_header_len) + { + free (asf_header_buffer); return 0; + } /* delete previous header */ if (this->asf_header) { @@ -395,19 +415,23 @@ static int asf_read_header (demux_asf_t *this) { */ this->asf_header = asf_header_new(asf_header_buffer, asf_header_len); if (!this->asf_header) + { + free (asf_header_buffer); return 0; + } + free (asf_header_buffer); lprintf("asf header parsing ok\n"); this->packet_size = this->asf_header->file->packet_size; this->packet_count = this->asf_header->file->data_packet_count; - + /* compute stream duration */ - this->length = (this->asf_header->file->send_duration - + this->length = (this->asf_header->file->send_duration - this->asf_header->file->preroll) / 10000; if (this->length < 0) this->length = 0; - + /* compute average byterate (needed for seeking) */ if (this->asf_header->file->max_bitrate) this->rate = this->asf_header->file->max_bitrate >> 3; @@ -420,6 +444,17 @@ static int asf_read_header (demux_asf_t *this) { asf_stream_t *asf_stream = this->asf_header->streams[i]; asf_demux_stream_t *demux_stream = &this->streams[i]; + if (!asf_stream) { + if (this->mode != ASF_MODE_NO_CONTENT) { + xine_log(this->stream->xine, XINE_LOG_MSG, + _("demux_asf: warning: A stream appears to be missing.\n")); + _x_message(this->stream, XINE_MSG_READ_ERROR, + _("Media stream missing?"), NULL); + this->mode = ASF_MODE_NO_CONTENT; + } + return 0; + } + if (asf_stream->encrypted_flag) { if (this->mode != ASF_MODE_ENCRYPTED_CONTENT) { xine_log(this->stream->xine, XINE_LOG_MSG, @@ -438,14 +473,14 @@ static int asf_read_header (demux_asf_t *this) { this->reorder_w = (asf_stream->error_correction_data[2]<<8)|asf_stream->error_correction_data[1]; this->reorder_b = (asf_stream->error_correction_data[4]<<8)|asf_stream->error_correction_data[3]; this->reorder_w /= this->reorder_b; - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_asf: audio conceal interleave detected (%d x %d x %d)\n", this->reorder_w, this->reorder_h, this->reorder_b ); } else { this->reorder_b = this->reorder_h = this->reorder_w = 1; } - - + + demux_stream->buf_type = _x_formattag_to_buf_audio ( ((xine_waveformatex *)asf_stream->private_data)->wFormatTag ); if ( !demux_stream->buf_type ) { @@ -454,9 +489,9 @@ static int asf_read_header (demux_asf_t *this) { ((xine_waveformatex *)asf_stream->private_data)->wFormatTag); demux_stream->buf_type = BUF_AUDIO_UNKNOWN; } - + _x_meta_info_set(this->stream, XINE_META_INFO_AUDIOCODEC, _x_buf_audio_name(demux_stream->buf_type)); - + this->streams[i].fifo = this->audio_fifo; this->streams[i].frag_offset = 0; this->streams[i].seq = 0; @@ -466,12 +501,12 @@ static int asf_read_header (demux_asf_t *this) { this->streams[i].defrag = 1; } else this->streams[i].defrag = 0; - + lprintf ("found an audio stream id=%d \n", asf_stream->stream_number); break; - + case GUID_ASF_VIDEO_MEDIA: - { + { /* video private data * 11 bytes : header * 40 bytes : bmiheader @@ -480,38 +515,38 @@ static int asf_read_header (demux_asf_t *this) { uint32_t width, height; uint16_t bmiheader_size; xine_bmiheader *bmiheader; - + width = _X_LE_32(asf_stream->private_data); height = _X_LE_32(asf_stream->private_data + 4); /* there is one unknown byte between height and the bmiheader size */ bmiheader_size = _X_LE_16(asf_stream->private_data + 9); - + /* FIXME: bmiheader_size must be >= sizeof(xine_bmiheader) */ - + bmiheader = (xine_bmiheader *) (asf_stream->private_data + 11); _x_bmiheader_le2me(bmiheader); - + /* FIXME: check if (bmi_header_size == bmiheader->biSize) ? */ demux_stream->buf_type = _x_fourcc_to_buf_video(bmiheader->biCompression); if( !demux_stream->buf_type ) { xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_asf: unknown video format %.4s\n", (char*)&(bmiheader->biCompression)); - + demux_stream->buf_type = BUF_VIDEO_UNKNOWN; } - + _x_meta_info_set(this->stream, XINE_META_INFO_VIDEOCODEC, _x_buf_video_name(demux_stream->buf_type)); _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, width); _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, height); - + this->streams[i].fifo = this->video_fifo; this->streams[i].frag_offset = 0; this->streams[i].defrag = 0; - + /* load the palette, if there is one */ demux_stream->palette_count = bmiheader->biClrUsed; - + lprintf ("palette_count: %d\n", demux_stream->palette_count); if (demux_stream->palette_count > 256) { lprintf ("number of colours exceeded 256 (%d)", demux_stream->palette_count); @@ -520,10 +555,10 @@ static int asf_read_header (demux_asf_t *this) { if ((asf_stream->private_data_length - sizeof(xine_bmiheader) - 11) >= (demux_stream->palette_count * 4)) { int j; uint8_t *palette; - + /* according to msdn the palette is located here : */ palette = (uint8_t *)bmiheader + bmiheader->biSize; - + /* load the palette */ for (j = 0; j < demux_stream->palette_count; j++) { demux_stream->palette[j].b = *(palette + j * 4 + 0); @@ -532,7 +567,7 @@ static int asf_read_header (demux_asf_t *this) { } } else { int j; - + /* generate a greyscale palette */ demux_stream->palette_count = 256; for (j = 0; j < demux_stream->palette_count; j++) { @@ -541,7 +576,7 @@ static int asf_read_header (demux_asf_t *this) { demux_stream->palette[j].b = j; } } - + lprintf ("found a video stream id=%d, buf_type=%08x \n", this->asf_header->streams[i]->stream_number, this->streams[i].buf_type); } @@ -703,12 +738,15 @@ static void asf_send_buffer_nodefrag (demux_asf_t *this, asf_demux_stream_t *str bufsize = stream->fifo->buffer_pool_buf_size; buf = stream->fifo->buffer_pool_alloc (stream->fifo); - this->input->read (this->input, buf->content, bufsize); + if (this->input->read (this->input, buf->content, bufsize) != bufsize) { + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_asf: input buffer starved\n"); + return ; + } lprintf ("data: %d %d %d %d\n", buf->content[0], buf->content[1], buf->content[2], buf->content[3]); if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * + buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * 65535 / this->input->get_length (this->input) ); buf->extra_info->input_time = timestamp; @@ -723,6 +761,9 @@ static void asf_send_buffer_nodefrag (demux_asf_t *this, asf_demux_stream_t *str buf->size = bufsize; timestamp = 0; + if (stream->frag_offset == 0) + buf->decoder_flags |= BUF_FLAG_FRAME_START; + stream->frag_offset += bufsize; frag_len -= bufsize; @@ -733,10 +774,6 @@ static void asf_send_buffer_nodefrag (demux_asf_t *this, asf_demux_stream_t *str else check_newpts (this, buf->pts, PTS_AUDIO, package_done); - - if (frag_offset == 0) - buf->decoder_flags |= BUF_FLAG_FRAME_START; - /* test if whole packet read */ if (package_done) { buf->decoder_flags |= BUF_FLAG_FRAME_END; @@ -783,7 +820,10 @@ static void asf_send_buffer_defrag (demux_asf_t *this, asf_demux_stream_t *strea if( stream->frag_offset + frag_len > DEFRAG_BUFSIZE ) { xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_asf: buffer overflow on defrag!\n"); } else { - this->input->read (this->input, &stream->buffer[stream->frag_offset], frag_len); + if (this->input->read (this->input, &stream->buffer[stream->frag_offset], frag_len) != frag_len) { + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_asf: input buffer starved\n"); + return ; + } stream->frag_offset += frag_len; } @@ -792,46 +832,46 @@ static void asf_send_buffer_defrag (demux_asf_t *this, asf_demux_stream_t *strea if (package_done) { int bufsize; uint8_t *p; - + lprintf("packet done: offset=%d, payload=%d\n", stream->frag_offset, stream->payload_size); if (stream->fifo == this->audio_fifo && this->reorder_h > 1 && this->reorder_w > 1 ) { asf_reorder(this,stream->buffer,stream->frag_offset); } - + p = stream->buffer; while( stream->frag_offset ) { if ( stream->frag_offset < stream->fifo->buffer_pool_buf_size ) bufsize = stream->frag_offset; else bufsize = stream->fifo->buffer_pool_buf_size; - + buf = stream->fifo->buffer_pool_alloc (stream->fifo); xine_fast_memcpy (buf->content, p, bufsize); - + if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * + buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * 65535 / this->input->get_length (this->input) ); buf->extra_info->input_time = stream->timestamp; - + /* send the same pts for the entire frame */ buf->pts = stream->timestamp * 90; - + buf->type = stream->buf_type; buf->size = bufsize; - + lprintf ("buffer type %08x %8d bytes, %8lld pts\n", buf->type, buf->size, buf->pts); - + stream->frag_offset -= bufsize; p+=bufsize; - + if ((buf->type & BUF_MAJOR_MASK) == BUF_VIDEO_BASE) check_newpts (this, buf->pts, PTS_VIDEO, !stream->frag_offset); else check_newpts (this, buf->pts, PTS_AUDIO, !stream->frag_offset); - + /* test if whole packet read */ if ( !stream->frag_offset ) buf->decoder_flags |= BUF_FLAG_FRAME_END; @@ -848,9 +888,9 @@ static int asf_parse_packet_align(demux_asf_t *this) { uint32_t mod; uint64_t packet_num; - + current_pos = this->input->get_current_pos (this->input); - + /* seek to the beginning of the next packet */ mod = (current_pos - this->first_packet_pos) % this->packet_size; this->packet_size_left = mod ? this->packet_size - mod : 0; @@ -864,7 +904,7 @@ static int asf_parse_packet_align(demux_asf_t *this) { } } this->packet_size_left = 0; - + /* check packet_count */ packet_num = (packet_pos - this->first_packet_pos) / this->packet_size; lprintf("packet_num=%"PRId64", packet_count=%"PRId64"\n", packet_num, this->packet_count); @@ -885,7 +925,7 @@ static int asf_parse_packet_align(demux_asf_t *this) { } } } - + return 0; } @@ -911,7 +951,7 @@ static int asf_parse_packet_ecd(demux_asf_t *this, uint32_t *p_hdr_size) { ecd_opaque = (ecd_flags >> 4) & 0x1; ecd_len_type = (ecd_flags >> 5) & 0x3; ecd_present = (ecd_flags >> 7) & 0x1; - + /* skip ecd */ if (ecd_present && !ecd_opaque && !ecd_len_type) { int read_size; @@ -925,7 +965,7 @@ static int asf_parse_packet_ecd(demux_asf_t *this, uint32_t *p_hdr_size) { } else { GUID *guid = (GUID *)buf; - + /* check if it's a new stream */ buf[0] = ecd_flags; if (this->input->read (this->input, buf + 1, 15) != 15) { @@ -942,7 +982,7 @@ static int asf_parse_packet_ecd(demux_asf_t *this, uint32_t *p_hdr_size) { if (demux_asf_send_headers_common(this)) return 1; } else { - + /* skip invalid packet */ xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_asf: skip invalid packet: %2X\n", ecd_flags); this->input->seek (this->input, this->packet_size - *p_hdr_size, SEEK_CUR); @@ -951,7 +991,7 @@ static int asf_parse_packet_ecd(demux_asf_t *this, uint32_t *p_hdr_size) { } } } while (invalid_packet); - + return 0; } @@ -1020,7 +1060,7 @@ static int asf_parse_packet_payload_header(demux_asf_t *this, uint32_t p_hdr_siz xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_asf: invalid padsize: %d\n", this->packet_padsize); return 1; } - + /* Multiple frames */ if (this->packet_len_flags & 0x01) { this->frame_flag = get_byte(this); p_hdr_size += 1; @@ -1057,7 +1097,7 @@ static int asf_parse_packet_payload_common(demux_asf_t *this, *stream = NULL; lprintf ("got raw_id=%d, stream_id=%d\n", raw_id, stream_id); - + for (i = 0; i < this->asf_header->stream_count; i++) { lprintf ("stream_number = %d\n", this->asf_header->streams[i]->stream_number); if ((this->asf_header->streams[i]->stream_number == stream_id) && @@ -1067,7 +1107,7 @@ static int asf_parse_packet_payload_common(demux_asf_t *this, break; } } - + switch ((this->packet_prop_flags >> 4) & 3){ case 1: seq = get_byte(this); s_hdr_size += 1; @@ -1224,10 +1264,10 @@ static int asf_parse_packet_compressed_payload(demux_asf_t *this, stream->resync = 0; stream->skip = 0; } - + if (!stream->skip) { lprintf ("sending buffer of type %08x\n", stream->buf_type); - + if (stream->defrag) asf_send_buffer_defrag (this, stream, 0, *timestamp, object_length); else @@ -1399,15 +1439,15 @@ static int demux_asf_parse_http_references( demux_asf_t *this) { if (!end) goto failure; *end = '\0'; } - + /* replace http by mmsh */ if (!strncmp(href, "http", 4)) { memcpy(href, "mmsh", 4); } - + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_asf: http ref: %s\n", href); _x_demux_send_mrl_reference (this->stream, 0, href, NULL, 0, 0); - + if (free_href) free(href); } @@ -1504,6 +1544,7 @@ static int demux_asf_parse_asx_references( demux_asf_t *this) { int buf_used = 0; int len; xml_node_t *xml_tree, *asx_entry, *asx_ref; + xml_parser_t *xml_parser; int result; @@ -1526,9 +1567,13 @@ static int demux_asf_parse_asx_references( demux_asf_t *this) { if(buf_used) buf[buf_used] = '\0'; - xml_parser_init(buf, buf_used, XML_PARSER_CASE_INSENSITIVE); - if((result = xml_parser_build_tree(&xml_tree)) != XML_PARSER_OK) + xml_parser = xml_parser_init_r(buf, buf_used, XML_PARSER_CASE_INSENSITIVE); + if((result = xml_parser_build_tree_r(xml_parser, &xml_tree)) != XML_PARSER_OK) { + xml_parser_finalize_r(xml_parser); goto failure; + } + + xml_parser_finalize_r(xml_parser); if(!strcasecmp(xml_tree->name, "ASX")) { /* Attributes: VERSION, PREVIEWMODE, BANNERBAR @@ -1586,13 +1631,13 @@ static int demux_asf_parse_asx_references( demux_asf_t *this) { else if (!strcasecmp (asx_ref->name, "STARTTIME")) { - if (start_time == (uint32_t)-1) + if (start_time == (uint32_t)-1) start_time = asx_get_time_value (asx_ref); } else if (!strcasecmp (asx_ref->name, "DURATION")) { - if (duration == (uint32_t)-1) + if (duration == (uint32_t)-1) duration = asx_get_time_value (asx_ref); } @@ -1645,7 +1690,7 @@ static int demux_asf_send_chunk (demux_plugin_t *this_gen) { uint32_t rlen = 0; uint8_t raw_id = 0; int64_t ts = 0; - + switch (this->mode) { case ASF_MODE_ASX_REF: return demux_asf_parse_asx_references(this); @@ -1657,13 +1702,14 @@ static int demux_asf_send_chunk (demux_plugin_t *this_gen) { return demux_asf_parse_asf_references(this); case ASF_MODE_ENCRYPTED_CONTENT: + case ASF_MODE_NO_CONTENT: this->status = DEMUX_FINISHED; return this->status; default: - { + { int header_size = 0; - + if (asf_parse_packet_align(this)) { xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_asf: asf_parse_packet_align failed\n"); this->status = DEMUX_FINISHED; @@ -1679,7 +1725,7 @@ static int demux_asf_send_chunk (demux_plugin_t *this_gen) { this->status = DEMUX_FINISHED; return this->status; } - + for (this->frame = 0; this->frame < (this->nb_frames & 0x3f); this->frame++) { raw_id = get_byte(this); this->packet_size_left -= 1; @@ -1704,7 +1750,7 @@ static void demux_asf_dispose (demux_plugin_t *this_gen) { if (this->asf_header) { int i; - + for (i=0; i<this->asf_header->stream_count; i++) { asf_demux_stream_t *asf_stream; @@ -1717,7 +1763,7 @@ static void demux_asf_dispose (demux_plugin_t *this_gen) { asf_header_delete (this->asf_header); } - + free (this); } @@ -1777,11 +1823,11 @@ static int demux_asf_seek (demux_plugin_t *this_gen, start_pos, start_time); this->status = DEMUX_OK; - + if (this->mode != ASF_MODE_NORMAL) { return this->status; } - + /* * seek to start position */ @@ -1795,7 +1841,7 @@ static int demux_asf_seek (demux_plugin_t *this_gen, this->last_pts[PTS_AUDIO] = 0; this->keyframe_ts = 0; this->keyframe_found = 0; - + /* engine sync stuff */ this->send_newpts = 1; this->buf_flag_seek = 1; @@ -1803,11 +1849,11 @@ static int demux_asf_seek (demux_plugin_t *this_gen, if (this->input->get_capabilities(this->input) & INPUT_CAP_SEEKABLE) { _x_demux_flush_engine(this->stream); - + start_time /= 1000; start_pos = (off_t) ( (double) start_pos / 65535 * this->input->get_length (this->input) ); - + if ( (!start_pos) && (start_time)) start_pos = start_time * this->rate; @@ -1868,7 +1914,7 @@ static int demux_asf_seek (demux_plugin_t *this_gen, this->status = DEMUX_FINISHED; return this->status; } - + for (this->frame = 0; this->frame < (this->nb_frames & 0x3f); this->frame++) { raw_id = get_byte(this); this->packet_size_left -= 1; @@ -1877,7 +1923,7 @@ static int demux_asf_seek (demux_plugin_t *this_gen, stream_id = raw_id & 0x7f; if (asf_parse_packet_payload_common(this, raw_id, &stream, &frag_offset, &rlen)) break; - + if (rlen == 1) { if (asf_parse_packet_compressed_payload(this, stream, raw_id, frag_offset, &ts)) break; @@ -1885,7 +1931,7 @@ static int demux_asf_seek (demux_plugin_t *this_gen, if (asf_parse_packet_payload(this, stream, raw_id, frag_offset, rlen, &ts)) break; } - + if (state == 0) { if (this->keyframe_found) { if (this->audio_stream == -1) { @@ -1935,12 +1981,12 @@ static int demux_asf_seek (demux_plugin_t *this_gen, this->streams[this->audio_stream].resync = 1; this->streams[this->audio_stream].skip = 1; } - } else if (!playing && this->input->seek_time != NULL) { + } else if (!playing && this->input->seek_time != NULL) { if (start_pos && !start_time) start_time = this->length * start_pos / 65535; - + this->input->seek_time (this->input, start_time, SEEK_SET); - + this->keyframe_ts = 0; this->keyframe_found = 0; /* means next keyframe */ if (this->video_stream >= 0) { @@ -1965,7 +2011,7 @@ static int demux_asf_seek (demux_plugin_t *this_gen, } } return this->status; - + error: this->status = DEMUX_FINISHED; return this->status; @@ -2059,7 +2105,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, return NULL; } - this = xine_xmalloc (sizeof (demux_asf_t)); + this = calloc(1, sizeof(demux_asf_t)); this->stream = stream; this->input = input; @@ -2094,7 +2140,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, this->demux_plugin.demux_class = class_gen; this->status = DEMUX_FINISHED; - + return &this->demux_plugin; } @@ -2134,7 +2180,7 @@ static void *init_class (xine_t *xine, void *data) { demux_asf_class_t *this; - this = xine_xmalloc (sizeof (demux_asf_class_t)); + this = calloc(1, sizeof(demux_asf_class_t)); this->config = xine->config; this->xine = xine; @@ -2155,7 +2201,7 @@ static void *init_class (xine_t *xine, void *data) { static const demuxer_info_t demux_info_asf = { 10 /* priority */ }; - + const plugin_info_t xine_plugin_info[] EXPORTED = { /* type, API, "name", version, special_info, init_function */ { PLUGIN_DEMUX, 26, "asf", XINE_VERSION_CODE, &demux_info_asf, init_class }, diff --git a/src/demuxers/demux_aud.c b/src/demuxers/demux_aud.c index a6f88ff48..caaa4e91a 100644 --- a/src/demuxers/demux_aud.c +++ b/src/demuxers/demux_aud.c @@ -105,7 +105,7 @@ remove this case for the time being since this audio type is not supported anyway. if (header[11] == 1) this->audio_type = BUF_AUDIO_WESTWOOD; - else + else #endif if (header[11] == 99) this->audio_type = BUF_AUDIO_VQA_IMA; @@ -143,7 +143,7 @@ static int demux_aud_send_chunk(demux_plugin_t *this_gen) { } /* validate the chunk */ - if (_X_LE_32(&chunk_preamble[4]) != 0x0000DEAF) { + if (!_x_is_fourcc(&chunk_preamble[4], "\xAF\xDE\x00\x00")) { this->status = DEMUX_FINISHED; return this->status; } @@ -270,7 +270,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str demux_aud_t *this; - this = xine_xmalloc (sizeof (demux_aud_t)); + this = calloc(1, sizeof(demux_aud_t)); this->stream = stream; this->input = input; @@ -343,7 +343,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_aud_init_plugin (xine_t *xine, void *data) { demux_aud_class_t *this; - this = xine_xmalloc (sizeof (demux_aud_class_t)); + this = calloc(1, sizeof(demux_aud_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_avi.c b/src/demuxers/demux_avi.c index 6bb0b289c..100828bd2 100644 --- a/src/demuxers/demux_avi.c +++ b/src/demuxers/demux_avi.c @@ -7,12 +7,12 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * xine is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA @@ -134,7 +134,7 @@ typedef struct _avistdindex_chunk { uint32_t dwReserved3; /* must be 0 */ avistdindex_entry *aIndex; } avistdindex_chunk; - + /* Base Index Form 'indx' */ typedef struct _avisuperindex_chunk { @@ -150,7 +150,7 @@ typedef struct _avisuperindex_chunk { avisuperindex_entry *aIndex; /* where are the ix## chunks */ avistdindex_chunk **stdindex; /* the ix## chunks itself (array) */ } avisuperindex_chunk; - + /* These next three are the video and audio structures that can grow * during the playback of a streaming file. */ @@ -317,6 +317,8 @@ typedef struct { getIndex==0, but an operation has been performed that needs an index */ +#define AVI_ERR_BAD_SIZE 14 /* A chunk has an invalid size */ + #define AVI_HEADER_UNKNOWN -1 #define AVI_HEADER_AUDIO 0 #define AVI_HEADER_VIDEO 1 @@ -471,7 +473,7 @@ static int start_pos_stopper(demux_avi_t *this, void *data) { maxframe--; } return -1; -} +} /* Use this one to ensure that a video frame with the given timestamp * is in the index. */ @@ -598,11 +600,11 @@ static int idx_grow(demux_avi_t *this, int (*stopper)(demux_avi_t *, void *), } } else { int i; - + /* Audio chunk */ for(i = 0; i < this->avi->n_audio; ++i) { avi_audio_t *audio = this->avi->audio[i]; - + if ((data[0] == audio->audio_tag[0]) && (data[1] == audio->audio_tag[1])) { off_t pos = chunk_pos + AVI_HEADER_SIZE; @@ -615,7 +617,7 @@ static int idx_grow(demux_avi_t *this, int (*stopper)(demux_avi_t *, void *), } else { audio->block_no += 1; } - + if (audio_index_append(this->avi, i, pos, chunk_len, audio->audio_tot, audio->block_no) == -1) { /* As above. */ @@ -709,17 +711,17 @@ do { \ static void reset_idx(demux_avi_t *this, avi_t *AVI) { int n; - + this->idx_grow.nexttagoffset = AVI->movi_start; this->has_index = 0; - + AVI->video_idx.video_frames = 0; for(n = 0; n < AVI->n_audio; n++) { AVI->audio[n]->audio_idx.audio_chunks = 0; } } -static avi_t *AVI_init(demux_avi_t *this) { +static avi_t *XINE_MALLOC AVI_init(demux_avi_t *this) { avi_t *AVI; int i, j, idx_type; @@ -739,7 +741,7 @@ static avi_t *AVI_init(demux_avi_t *this) { /* Create avi_t structure */ lprintf("start\n"); - AVI = (avi_t *) xine_xmalloc(sizeof(avi_t)); + AVI = (avi_t *) calloc(1, sizeof(avi_t)); if(AVI==NULL) { this->AVI_errno = AVI_ERR_NO_MEM; return 0; @@ -776,28 +778,28 @@ static avi_t *AVI_init(demux_avi_t *this) { n = _X_LE_32(data + 4); n = PAD_EVEN(n); next_chunk = this->idx_grow.nexttagoffset + 8 + n; - + lprintf("chunk: %c%c%c%c, size: %" PRId64 "\n", data[0], data[1], data[2], data[3], (int64_t)n); - - if((strncasecmp(data,"LIST",4) == 0) && (n >= 4)) { + + if (n >= 4 && strncasecmp(data,"LIST",4) == 0) { if( this->input->read(this->input, data,4) != 4 ) ERR_EXIT(AVI_ERR_READ); n -= 4; - + lprintf(" chunk: %c%c%c%c\n", data[0], data[1], data[2], data[3]); if(strncasecmp(data,"hdrl",4) == 0) { hdrl_len = n; - hdrl_data = (unsigned char *) xine_xmalloc(n); + hdrl_data = (unsigned char *) malloc(n); if(hdrl_data==0) ERR_EXIT(AVI_ERR_NO_MEM); if (this->input->read(this->input, hdrl_data,n) != n ) ERR_EXIT(AVI_ERR_READ); } else if(strncasecmp(data,"movi",4) == 0) { - + AVI->movi_start = this->input->get_current_pos(this->input); AVI->movi_end = AVI->movi_start + n - 1; @@ -812,9 +814,8 @@ static avi_t *AVI_init(demux_avi_t *this) { break if this is not the case */ AVI->n_idx = AVI->max_idx = n / 16; - if (AVI->idx) - free(AVI->idx); /* On the off chance there are multiple index chunks */ - AVI->idx = (unsigned char((*)[16])) xine_xmalloc(n); + free(AVI->idx); /* On the off chance there are multiple index chunks */ + AVI->idx = (unsigned char((*)[16])) malloc(n); if (AVI->idx == 0) ERR_EXIT(AVI_ERR_NO_MEM); @@ -836,6 +837,8 @@ static avi_t *AVI_init(demux_avi_t *this) { /* Interpret the header list */ for (i = 0; i < hdrl_len;) { + const int old_i = i; + /* List tags are completly ignored */ lprintf("tag: %c%c%c%c\n", hdrl_data[i], hdrl_data[i+1], hdrl_data[i+2], hdrl_data[i+3]); @@ -874,15 +877,14 @@ static avi_t *AVI_init(demux_avi_t *this) { lasttag = 1; /* vids */ lprintf("dwScale=%d, dwRate=%d, dwInitialFrames=%d, dwStart=%d, num_stream=%d\n", AVI->dwScale, AVI->dwRate, AVI->dwInitialFrames, AVI->dwStart, num_stream); - + } else if (strncasecmp (hdrl_data+i,"auds",4) ==0 /* && ! auds_strh_seen*/) { if(AVI->n_audio < MAX_AUDIO_STREAMS) { - avi_audio_t *a = (avi_audio_t *) xine_xmalloc(sizeof(avi_audio_t)); + avi_audio_t *a = (avi_audio_t *) calloc(1, sizeof(avi_audio_t)); if(a==NULL) { this->AVI_errno = AVI_ERR_NO_MEM; return 0; } - memset((void *)a,0,sizeof(avi_audio_t)); AVI->audio[AVI->n_audio] = a; a->audio_strn = num_stream; @@ -890,10 +892,10 @@ static avi_t *AVI_init(demux_avi_t *this) { a->dwScale = _X_LE_32(hdrl_data + i + 20); a->dwRate = _X_LE_32(hdrl_data + i + 24); a->dwStart = _X_LE_32(hdrl_data + i + 28); - + lprintf("dwScale=%d, dwRate=%d, dwInitialFrames=%d, dwStart=%d, num_stream=%d\n", a->dwScale, a->dwRate, a->dwInitialFrames, a->dwStart, num_stream); - + a->dwSampleSize = _X_LE_32(hdrl_data + i + 44); a->audio_tot = 0; auds_strh_seen = 1; @@ -907,14 +909,14 @@ static avi_t *AVI_init(demux_avi_t *this) { lasttag = 0; } num_stream++; - + } else if(strncasecmp(hdrl_data+i,"dmlh",4) == 0) { AVI->total_frames = _X_LE_32(hdrl_data+i+8); #ifdef DEBUG_ODML lprintf( "AVI: real number of frames %d\n", AVI->total_frames); #endif i += 8; - + } else if(strncasecmp(hdrl_data + i, "strf", 4) == 0) { i += 4; strf_size = _X_LE_32(hdrl_data + i); @@ -922,7 +924,7 @@ static avi_t *AVI_init(demux_avi_t *this) { if(lasttag == 1) { /* lprintf ("size : %d\n",sizeof(AVI->bih)); */ AVI->bih = (xine_bmiheader *) - xine_xmalloc((n < sizeof(xine_bmiheader)) ? sizeof(xine_bmiheader) : n); + malloc((n < sizeof(xine_bmiheader)) ? sizeof(xine_bmiheader) : n); if(AVI->bih == NULL) { this->AVI_errno = AVI_ERR_NO_MEM; return 0; @@ -971,8 +973,12 @@ static avi_t *AVI_init(demux_avi_t *this) { } else if(lasttag == 2) { xine_waveformatex *wavex; - + wavex = (xine_waveformatex *)malloc(n); + if (!wavex) { + this->AVI_errno = AVI_ERR_NO_MEM; + return 0; + } memcpy((void *)wavex, hdrl_data+i, n); _x_waveformatex_le2me( wavex ); @@ -1079,6 +1085,8 @@ static avi_t *AVI_init(demux_avi_t *this) { lasttag = 0; } i += n; + if (i <= old_i) + ERR_EXIT(AVI_ERR_BAD_SIZE); } if( hdrl_data ) @@ -1167,7 +1175,7 @@ static avi_t *AVI_init(demux_avi_t *this) { } lprintf("idx_type=%d, AVI->n_idx=%d\n", idx_type, AVI->n_idx); - + if (idx_type != 0 && !AVI->is_opendml) { /* Now generate the video index and audio index arrays from the * idx1 record. */ @@ -1224,7 +1232,7 @@ static avi_t *AVI_init(demux_avi_t *this) { xprintf (this->stream->xine, XINE_VERBOSITY_LOG, "demux_avi: This is an OpenDML stream\n"); nvi = 0; - for(audtr=0; audtr<AVI->n_audio; ++audtr) nai[audtr] = 0; + for(audtr=0; audtr<AVI->n_audio; ++audtr) nai[audtr] = 0; /* ************************ */ /* VIDEO */ @@ -1237,6 +1245,9 @@ static avi_t *AVI_init(demux_avi_t *this) { /* read from file */ chunk_start = en = malloc (AVI->video_superindex->aIndex[j].dwSize+hdrl_len); + if (!chunk_start) + ERR_EXIT(AVI_ERR_NO_MEM); + if (this->input->seek(this->input, AVI->video_superindex->aIndex[j].qwOffset, SEEK_SET) == (off_t)-1) { lprintf("cannot seek to 0x%" PRIx64 "\n", AVI->video_superindex->aIndex[j].qwOffset); free(chunk_start); @@ -1289,7 +1300,7 @@ static avi_t *AVI_init(demux_avi_t *this) { "demux_avi: Warning: the video super index is NULL\n"); } - + /* ************************ */ /* AUDIO */ /* ************************ */ @@ -1308,6 +1319,9 @@ static avi_t *AVI_init(demux_avi_t *this) { /* read from file */ chunk_start = en = malloc (audio->audio_superindex->aIndex[j].dwSize+hdrl_len); + if (!chunk_start) + ERR_EXIT(AVI_ERR_NO_MEM); + if (this->input->seek(this->input, audio->audio_superindex->aIndex[j].qwOffset, SEEK_SET) == (off_t)-1) { lprintf("cannot seek to 0x%" PRIx64 "\n", audio->audio_superindex->aIndex[j].qwOffset); free(chunk_start); @@ -1330,7 +1344,7 @@ static avi_t *AVI_init(demux_avi_t *this) { /* skip header */ en += hdrl_len; nai[audtr] += nrEntries; - + while (k < nai[audtr]) { off_t pos; @@ -1338,7 +1352,7 @@ static avi_t *AVI_init(demux_avi_t *this) { pos = offset + _X_LE_32(en); en += 4; len = odml_len(en); en += 4; - + /* VBR streams (hack from mplayer) */ if (audio->wavex && audio->wavex->nBlockAlign) { audio->block_no += (len + audio->wavex->nBlockAlign - 1) / @@ -1380,7 +1394,7 @@ static avi_t *AVI_init(demux_avi_t *this) { this->idx_grow.nexttagoffset = AVI->movi_start; this->has_index = 0; } - + /* Reposition the file */ if (!this->streaming) this->input->seek(this->input, AVI->movi_start, SEEK_SET); @@ -1466,7 +1480,7 @@ static int AVI_read_video(demux_avi_t *this, avi_t *AVI, char *vidbuf, nr = 0; /* total number of bytes read */ left = vie->len - AVI->video_posb; - + while ((bytes > 0) && (left > 0)) { if (bytes < left) todo = bytes; @@ -1508,7 +1522,7 @@ static int demux_avi_next (demux_avi_t *this, int decoder_flags) { int audio_sent = 0; lprintf("begin\n"); - + /* Try to grow the index, in case more of the avi file has shown up * since we last checked. If it's still too small, well then we're at * the end of the stream. */ @@ -1517,7 +1531,7 @@ static int demux_avi_next (demux_avi_t *this, int decoder_flags) { lprintf("end of stream\n"); } } - + for (i = 0; i < this->avi->n_audio; i++) { avi_audio_t *audio = this->avi->audio[i]; @@ -1528,7 +1542,7 @@ static int demux_avi_next (demux_avi_t *this, int decoder_flags) { } } } - + video_pts = get_video_pts (this, this->avi->video_posf); for (i=0; i < this->avi->n_audio; i++) { @@ -1554,7 +1568,7 @@ static int demux_avi_next (demux_avi_t *this, int decoder_flags) { /* read audio */ buf->pts = audio_pts; - + buf->size = AVI_read_audio (this, audio, buf->mem, buf->max_size, &buf->decoder_flags); buf->decoder_flags |= decoder_flags; @@ -1566,12 +1580,12 @@ static int demux_avi_next (demux_avi_t *this, int decoder_flags) { buf->type = audio->audio_type | i; buf->extra_info->input_time = audio_pts / 90; if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * + buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * 65535 / this->input->get_length (this->input) ); - + check_newpts (this, buf->pts, PTS_AUDIO); this->audio_fifo->put (this->audio_fifo, buf); - + audio_sent++; } } else @@ -1581,7 +1595,7 @@ static int demux_avi_next (demux_avi_t *this, int decoder_flags) { if (audio_sent == 0) { do_read_video = 1; } - + if (do_read_video) { buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); @@ -1597,12 +1611,12 @@ static int demux_avi_next (demux_avi_t *this, int decoder_flags) { if (this->has_index && this->avi->video_idx.video_frames > 2) { /* use video_frames-2 instead of video_frames-1 to fix problems with weird non-interleaved streams */ - buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * + buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * 65535 / this->avi->video_idx.vindex[this->avi->video_idx.video_frames - 2].pos); } else { if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * + buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * 65535 / this->input->get_length (this->input) ); } buf->extra_info->frame_number = this->avi->video_posf; @@ -1617,7 +1631,7 @@ static int demux_avi_next (demux_avi_t *this, int decoder_flags) { lprintf ("adding buf %d to video fifo, decoder_info[0]: %d\n", buf, buf->decoder_info[0]); */ - + check_newpts (this, buf->pts, PTS_VIDEO); this->video_fifo->put (this->video_fifo, buf); video_sent++; @@ -1738,7 +1752,7 @@ static int demux_avi_next_streaming (demux_avi_t *this, int decoder_flags) { } buf->extra_info->input_time = audio_pts / 90; if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * + buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * 65535 / this->input->get_length (this->input) ); buf->type = audio->audio_type | audio_stream; @@ -1769,7 +1783,7 @@ static int demux_avi_next_streaming (demux_avi_t *this, int decoder_flags) { /* read video */ buf->pts = video_pts; lprintf("video pts: %" PRId64 "\n", video_pts); - + if (left > this->video_fifo->buffer_pool_buf_size) { buf->size = this->video_fifo->buffer_pool_buf_size; buf->decoder_flags = 0; @@ -1824,7 +1838,7 @@ static int demux_avi_send_chunk (demux_plugin_t *this_gen) { this->seek_request = 0; demux_avi_seek_internal(this); } - + if (!demux_avi_next (this, 0)) { this->status = DEMUX_FINISHED; } @@ -1904,7 +1918,7 @@ static void demux_avi_send_headers (demux_plugin_t *this_gen) { this->avi->bih->biCompression = this->avi->compressor; this->avi->video_type = BUF_VIDEO_XVID; } - + _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, 1); _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, !this->no_audio); _x_meta_info_set(this->stream, XINE_META_INFO_VIDEOCODEC, _x_buf_video_name(this->avi->video_type)); @@ -1922,7 +1936,7 @@ static void demux_avi_send_headers (demux_plugin_t *this_gen) { _x_demux_control_start (this->stream); buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); - + if (this->avi->bih->biSize > buf->max_size) { xprintf(this->stream->xine, XINE_VERBOSITY_LOG, "demux_avi: private video decoder data length (%d) is greater than fifo buffer length (%d)\n", @@ -1931,9 +1945,9 @@ static void demux_avi_send_headers (demux_plugin_t *this_gen) { this->status = DEMUX_FINISHED; return; } - + /* wait, before sending out the video header, one more special case hack: - * if the video type is RGB, indicate that it is upside down with a + * if the video type is RGB, indicate that it is upside down with a * negative height */ if (this->avi->video_type == BUF_VIDEO_RGB) { this->avi->bih->biHeight = -this->avi->bih->biHeight; @@ -1944,7 +1958,7 @@ static void demux_avi_send_headers (demux_plugin_t *this_gen) { buf->decoder_info[0] = this->video_step; memcpy (buf->content, this->avi->bih, this->avi->bih->biSize); buf->size = this->avi->bih->biSize; - + if (this->avi->video_type) { this->avi->compressor = this->avi->bih->biCompression; } else { @@ -1992,7 +2006,7 @@ static void demux_avi_send_headers (demux_plugin_t *this_gen) { buf->size = todo; } todo -= buf->size; - + buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER; if (todo == 0) buf->decoder_flags |= BUF_FLAG_FRAME_END; @@ -2009,7 +2023,7 @@ static void demux_avi_send_headers (demux_plugin_t *this_gen) { } if(this->avi->n_audio == 1) - _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_FOURCC, + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_FOURCC, this->avi->audio[0]->wavex->wFormatTag); } @@ -2059,7 +2073,7 @@ static int demux_avi_seek_internal (demux_avi_t *this) { int64_t audio_pts; off_t start_pos = this->seek_start_pos; int start_time = this->seek_start_time; - + start_pos = (off_t) ( (double) start_pos / 65535 * this->input->get_length (this->input) ); @@ -2094,12 +2108,12 @@ static int demux_avi_seek_internal (demux_avi_t *this) { video_pts = start_time * 90; idx_grow(this, start_time_stopper, &video_pts); } - + if (start_pos || start_time) max_pos = this->avi->video_idx.video_frames - 1; else max_pos=0; - + cur_pos = this->avi->video_posf; if (max_pos < 0) { this->status = DEMUX_FINISHED; @@ -2127,7 +2141,7 @@ static int demux_avi_seek_internal (demux_avi_t *this) { } } } - + while (vie && !(vie->flags & AVIIF_KEYFRAME) && cur_pos) { this->avi->video_posf = --cur_pos; vie = video_cur_index_entry(this); @@ -2150,7 +2164,7 @@ static int demux_avi_seek_internal (demux_avi_t *this) { if (!this->no_audio && this->status == DEMUX_OK) { audio_index_entry_t *aie; int i; - + for(i = 0; i < this->avi->n_audio; i++) { max_pos = this->avi->audio[i]->audio_idx.audio_chunks - 1; min_pos = 0; @@ -2271,7 +2285,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str return NULL; } - this = xine_xmalloc (sizeof (demux_avi_t)); + this = calloc(1, sizeof(demux_avi_t)); this->stream = stream; this->input = input; @@ -2337,7 +2351,7 @@ static void class_dispose (demux_class_t *this_gen) { static void *init_class (xine_t *xine, void *data) { demux_avi_class_t *this; - this = xine_xmalloc (sizeof (demux_avi_class_t)); + this = calloc(1, sizeof(demux_avi_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_cdda.c b/src/demuxers/demux_cdda.c index 0f34a7cec..6aee5042e 100644 --- a/src/demuxers/demux_cdda.c +++ b/src/demuxers/demux_cdda.c @@ -60,6 +60,7 @@ typedef struct { input_plugin_t *input; int status; + int send_newpts; int seek_flag; /* this is set when a seek just occurred */ } demux_cdda_t; @@ -83,7 +84,7 @@ static int demux_cdda_send_chunk (demux_plugin_t *this_gen) { buf->type = BUF_AUDIO_LPCM_LE; if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * + buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * 65535 / this->input->get_length (this->input) ); buf->pts = this->input->get_current_pos(this->input); buf->pts *= 90000; @@ -91,9 +92,9 @@ static int demux_cdda_send_chunk (demux_plugin_t *this_gen) { buf->extra_info->input_time = buf->pts / 90; buf->decoder_flags |= BUF_FLAG_FRAME_END; - if (this->seek_flag) { - _x_demux_control_newpts(this->stream, buf->pts, BUF_FLAG_SEEK); - this->seek_flag = 0; + if (this->send_newpts) { + _x_demux_control_newpts(this->stream, buf->pts, this->seek_flag); + this->send_newpts = this->seek_flag = 0; } this->audio_fifo->put (this->audio_fifo, buf); @@ -146,9 +147,14 @@ static int demux_cdda_seek (demux_plugin_t *this_gen, off_t start_pos, int start this->input->seek(this->input, start_pos & ~3, SEEK_SET); else this->input->seek(this->input, start_time * CD_BYTES_PER_SECOND, SEEK_SET); - this->seek_flag = 1; + this->status = DEMUX_OK; - _x_demux_flush_engine (this->stream); + + this->send_newpts = 1; + if (playing) { + this->seek_flag = BUF_FLAG_SEEK; + _x_demux_flush_engine (this->stream); + } return this->status; } @@ -187,7 +193,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str demux_cdda_t *this; - this = xine_xmalloc (sizeof (demux_cdda_t)); + this = calloc(1, sizeof(demux_cdda_t)); this->stream = stream; this->input = input; @@ -250,7 +256,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_cdda_init_plugin (xine_t *xine, void *data) { demux_cdda_class_t *this; - this = xine_xmalloc (sizeof (demux_cdda_class_t)); + this = calloc(1, sizeof(demux_cdda_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_dts.c b/src/demuxers/demux_dts.c index 7c9b47fcd..0c73877e9 100644 --- a/src/demuxers/demux_dts.c +++ b/src/demuxers/demux_dts.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 the xine project + * Copyright (C) 2005-2008 the xine project * * This file is part of xine, a free video player. * @@ -33,6 +33,9 @@ #ifdef HAVE_ALLOCA_H #include <alloca.h> #endif +#ifdef HAVE_MALLOC_H +#include <malloc.h> +#endif #define LOG_MODULE "demux_dts" #define LOG_VERBOSE @@ -140,29 +143,69 @@ static int open_dts_file(demux_dts_t *this) { } } + /* DTS bitstream encoding version + * -1 - not detected + * 0 - 16 bits and big endian + * 1 - 16 bits and low endian (detection not implemented) + * 2 - 14 bits and big endian (detection not implemented) + * 3 - 14 bits and low endian + */ + int dts_version = -1; + /* Look for a valid DTS syncword */ for (i=offset; i<peak_size-1; i++) { + /* 16 bits and big endian bitstream */ + if (syncword == 0x7ffe8001) { + dts_version = 0; + break; + } /* 14 bits and little endian bitstream */ - if ((syncword == 0xff1f00e8) && - ((peak[i] & 0xf0) == 0xf0) && (peak[i+1] == 0x07)) { - this->data_start = i-4; - lprintf("found DTS syncword at offset %d\n", i-4); - break; + else if ((syncword == 0xff1f00e8) && + ((peak[i] & 0xf0) == 0xf0) && (peak[i+1] == 0x07)) { + dts_version = 3; + break; } syncword = (syncword << 8) | peak[i]; } + if (dts_version == -1) { + xprintf (this->stream->xine, XINE_VERBOSITY_LOG, + LOG_MODULE ": unsupported DTS stream type, or not a DTS stream\n"); + return 0; + } + + this->data_start = i-4; + lprintf("found DTS syncword at offset %d\n", i-4); + if (i < peak_size-9) { unsigned int nblks, fsize, sfreq; + switch (dts_version) + { + case 0: /* BE16 */ + nblks = ((peak[this->data_start+4] & 0x01) << 6) | + ((peak[this->data_start+5] & 0xfc) >> 2); + fsize = (((peak[this->data_start+5] & 0x03) << 12) |(peak[this->data_start+6] << 4) | + ((peak[this->data_start+7] & 0xf0) >> 4)) + 1; + sfreq = (peak[this->data_start+8] & 0x3c) >> 2; + break; - /* 14 bits and little endian bitstream */ - nblks = ((peak[this->data_start+4] & 0x07) << 4) | - ((peak[this->data_start+7] & 0x3c) >> 2); - fsize = (((peak[this->data_start+7] & 0x03) << 12) | - (peak[this->data_start+6] << 4) | - ((peak[this->data_start+9] & 0x3c) >> 2)) + 1; - sfreq = peak[this->data_start+8] & 0x0f; + case 3: /* LE14 */ + nblks = ((peak[this->data_start+4] & 0x07) << 4) | + ((peak[this->data_start+7] & 0x3c) >> 2); + fsize = (((peak[this->data_start+7] & 0x03) << 12) | + (peak[this->data_start+6] << 4) | + ((peak[this->data_start+9] & 0x3c) >> 2)) + 1; + sfreq = peak[this->data_start+8] & 0x0f; + break; + + default: + xprintf (this->stream->xine, XINE_VERBOSITY_LOG, + LOG_MODULE ": unsupported DTS bitstream encoding %d\n", + dts_version); + return 0; + + } if ((sfreq > sizeof(dts_sample_rates)/sizeof(int)) || (dts_sample_rates[sfreq] == 0)) @@ -170,7 +213,19 @@ static int open_dts_file(demux_dts_t *this) { /* Big assumption - this is CBR data */ this->samples_per_frame = (nblks + 1) * 32; - this->frame_size = fsize * 8 / 14 * 2; + + switch (dts_version) + { + case 0: /* BE16 */ + case 1: /* LE16 */ + this->frame_size = fsize * 8 / 16 * 2; + break; + case 2: /* BE14 */ + case 3: /* LE14 */ + this->frame_size = fsize * 8 / 14 * 2; + break; + } + this->sample_rate = dts_sample_rates[sfreq]; lprintf("samples per frame: %d\n", this->samples_per_frame); @@ -195,7 +250,7 @@ static int demux_dts_send_chunk (demux_plugin_t *this_gen) { int frame_number; uint32_t blocksize; - current_stream_pos = this->input->get_current_pos(this->input) - + current_stream_pos = this->input->get_current_pos(this->input) - this->data_start; frame_number = current_stream_pos / this->frame_size; @@ -219,11 +274,11 @@ static int demux_dts_send_chunk (demux_plugin_t *this_gen) { } } else { buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); - buf->size = this->input->read(this->input, buf->content, + buf->size = this->input->read(this->input, buf->content, this->frame_size); } - if (buf->size == 0) { + if (buf->size <= 0) { buf->free_buffer(buf); this->status = DEMUX_FINISHED; return this->status; @@ -231,7 +286,7 @@ static int demux_dts_send_chunk (demux_plugin_t *this_gen) { buf->type = BUF_AUDIO_DTS; if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = (int)( (double) current_stream_pos * + buf->extra_info->input_normpos = (int)( (double) current_stream_pos * 65535 / (this->input->get_length(this->input) - this->data_start) ); buf->extra_info->input_time = audio_pts / 90; buf->pts = audio_pts; @@ -305,7 +360,7 @@ static int demux_dts_seek (demux_plugin_t *this_gen, if (start_time) { int length = demux_dts_get_stream_length (this_gen); if (length != 0) { - start_pos = start_time * + start_pos = start_time * (this->input->get_length(this->input) - this->data_start) / length; } } @@ -346,7 +401,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str demux_dts_t *this; - this = xine_xmalloc (sizeof (demux_dts_t)); + this = calloc(1, sizeof(demux_dts_t)); this->stream = stream; this->input = input; @@ -418,7 +473,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_dts_init_plugin (xine_t *xine, void *data) { demux_dts_class_t *this; - this = xine_xmalloc (sizeof (demux_dts_class_t)); + this = calloc(1, sizeof(demux_dts_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_eawve.c b/src/demuxers/demux_eawve.c index 2359d3baf..2e393847c 100644 --- a/src/demuxers/demux_eawve.c +++ b/src/demuxers/demux_eawve.c @@ -78,16 +78,16 @@ typedef struct { */ static uint32_t read_arbitary(input_plugin_t *input){ - uint8_t size, byte; - int i; - uint32_t word; + uint8_t size; if (input->read(input, (void*)&size, 1) != 1) { return 0; } - word = 0; + uint32_t word = 0; + int i; for (i=0;i<size;i++) { + uint8_t byte; if (input->read(input, (void*)&byte, 1) != 1) { return 0; } @@ -104,33 +104,25 @@ static uint32_t read_arbitary(input_plugin_t *input){ */ static int process_header(demux_eawve_t *this){ - int inHeader; - uint32_t blockid, size; + uint8_t header[12]; if (this->input->get_current_pos(this->input) != 0) this->input->seek(this->input, 0, SEEK_SET); - if (this->input->read(this->input, (void*)&blockid, 4) != 4) { - return 0; - } - if (be2me_32(blockid) != FOURCC_TAG('S', 'C', 'H', 'l')) { + if (this->input->read(this->input, header, sizeof(header)) != sizeof(header)) return 0; - } - if (this->input->read(this->input, (void*)&size, 4) != 4) { + if (!_x_is_fourcc(&header[0], "SCHl")) return 0; - } - size = le2me_32(size); - if (this->input->read(this->input, (void*)&blockid, 4) != 4) { - return 0; - } - if (be2me_32(blockid) != FOURCC_TAG('P', 'T', '\0', '\0')) { + if (!_x_is_fourcc(&header[8], "PT\0\0")) { lprintf("PT header missing\n"); return 0; } - inHeader = 1; + const uint32_t size = _X_LE_32(&header[4]); + + int inHeader = 1; while (inHeader) { int inSubheader; uint8_t byte; @@ -221,7 +213,7 @@ static int demux_eawve_send_chunk(demux_eawve_t *this){ buf = this->audio_fifo->buffer_pool_alloc(this->audio_fifo); buf->type = BUF_AUDIO_EA_ADPCM; if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * + buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * 65535 / this->input->get_length (this->input) ); buf->extra_info->input_time = (int)((int64_t)this->sample_counter * 1000 / 22050); buf->pts = this->sample_counter; @@ -349,7 +341,7 @@ static demux_plugin_t* open_plugin(demux_class_t *class_gen, xine_stream_t *stre if (!INPUT_IS_SEEKABLE(input)) return NULL; - this = xine_xmalloc(sizeof(demux_eawve_t)); + this = calloc(1, sizeof(demux_eawve_t)); this->stream = stream; this->input = input; @@ -421,7 +413,7 @@ static void class_dispose(demux_class_t *this){ void *demux_eawve_init_plugin(xine_t *xine, void *data) { demux_eawve_class_t *this; - this = xine_xmalloc(sizeof(demux_eawve_class_t)); + this = calloc(1, sizeof(demux_eawve_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_elem.c b/src/demuxers/demux_elem.c index d0a821504..d38fe3c62 100644 --- a/src/demuxers/demux_elem.c +++ b/src/demuxers/demux_elem.c @@ -1,18 +1,18 @@ /* * Copyright (C) 2000-2003 the xine project - * + * * This file is part of xine, a free video player. - * + * * xine is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * xine is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA @@ -46,7 +46,7 @@ #define NUM_PREVIEW_BUFFERS 50 #define SCRATCH_SIZE 256 -typedef struct { +typedef struct { demux_plugin_t demux_plugin; xine_stream_t *stream; @@ -83,7 +83,7 @@ static int demux_mpeg_elem_next (demux_mpeg_elem_t *this, int preview_mode) { buf->content = buf->mem; buf->pts = 0; if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * + buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * 65535 / this->input->get_length (this->input) ); buf->type = BUF_VIDEO_MPEG; @@ -91,7 +91,7 @@ static int demux_mpeg_elem_next (demux_mpeg_elem_t *this, int preview_mode) { buf->decoder_flags = BUF_FLAG_PREVIEW; this->video_fifo->put(this->video_fifo, buf); - + return 1; } @@ -240,7 +240,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str return NULL; } - this = xine_xmalloc (sizeof (demux_mpeg_elem_t)); + this = calloc(1, sizeof(demux_mpeg_elem_t)); this->stream = stream; this->input = input; @@ -284,7 +284,7 @@ static void class_dispose (demux_class_t *this_gen) { static void *init_plugin (xine_t *xine, void *data) { demux_mpeg_elem_class_t *this; - this = xine_xmalloc (sizeof (demux_mpeg_elem_class_t)); + this = calloc(1, sizeof(demux_mpeg_elem_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; @@ -304,7 +304,7 @@ static const demuxer_info_t demux_info_elem = { }; const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ + /* type, API, "name", version, special_info, init_function */ { PLUGIN_DEMUX, 26, "elem", XINE_VERSION_CODE, &demux_info_elem, init_plugin }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; diff --git a/src/demuxers/demux_film.c b/src/demuxers/demux_film.c index 13036afc1..a8bd0b288 100644 --- a/src/demuxers/demux_film.c +++ b/src/demuxers/demux_film.c @@ -141,9 +141,9 @@ static int open_film_file(demux_film_t *film) { return 0; /* FILM signature correct? */ - if (strncmp(scratch, "FILM", 4)) { + if (!_x_is_fourcc(scratch, "FILM")) return 0; - } + llprintf(DEBUG_FILM_LOAD, "found 'FILM' signature\n"); /* file is qualified; skip over the header bytes in the stream */ @@ -151,7 +151,7 @@ static int open_film_file(demux_film_t *film) { /* header size = header size - 16-byte FILM signature */ film_header_size = _X_BE_32(&scratch[4]) - 16; - film_header = xine_xmalloc(film_header_size); + film_header = malloc(film_header_size); if (!film_header) return 0; strncpy(film->version, &scratch[8], 4); @@ -163,7 +163,7 @@ static int open_film_file(demux_film_t *film) { film->version[3]); /* load the rest of the FILM header */ - if (film->input->read(film->input, film_header, film_header_size) != + if (film->input->read(film->input, film_header, film_header_size) != film_header_size) { free (film->interleave_buffer); free (film->sample_table); @@ -202,7 +202,7 @@ static int open_film_file(demux_film_t *film) { if( !film->video_type ) film->video_type = BUF_VIDEO_UNKNOWN; - + /* fetch the audio information if the chunk size checks out */ if (chunk_size == 32) { film->audio_channels = film_header[21]; @@ -256,7 +256,9 @@ static int open_film_file(demux_film_t *film) { film->frequency = _X_BE_32(&film_header[i + 8]); film->sample_count = _X_BE_32(&film_header[i + 12]); film->sample_table = - xine_xmalloc(film->sample_count * sizeof(film_sample_t)); + calloc(film->sample_count, sizeof(film_sample_t)); + if (!film->sample_table) + goto film_abort; for (j = 0; j < film->sample_count; j++) { film->sample_table[j].sample_offset = @@ -329,15 +331,16 @@ static int open_film_file(demux_film_t *film) { /* allocate enough space in the interleave preload buffer for the * first chunk (which will be more than enough for successive chunks) */ if (film->audio_type) { - if (film->interleave_buffer) - free(film->interleave_buffer); - film->interleave_buffer = - xine_xmalloc(film->sample_table[0].sample_size); + free(film->interleave_buffer); + film->interleave_buffer = calloc(1, film->sample_table[0].sample_size); + if (!film->interleave_buffer) + goto film_abort; } break; default: xine_log(film->stream->xine, XINE_LOG_MSG, _("unrecognized FILM chunk\n")); + film_abort: free (film->interleave_buffer); free (film->sample_table); free (film_header); @@ -385,7 +388,7 @@ static int demux_film_send_chunk(demux_plugin_t *this_gen) { } /* check if we're only sending audio samples until the next keyframe */ - if ((this->waiting_for_keyframe) && + if ((this->waiting_for_keyframe) && (!this->sample_table[i].audio)) { if (this->sample_table[i].keyframe) { this->waiting_for_keyframe = 0; @@ -425,7 +428,7 @@ static int demux_film_send_chunk(demux_plugin_t *this_gen) { /* set the frame duration */ buf->decoder_flags |= BUF_FLAG_FRAMERATE; buf->decoder_info[0] = this->sample_table[i].duration; - + if (remaining_sample_bytes > buf->max_size) buf->size = buf->max_size; else @@ -440,11 +443,11 @@ static int demux_film_send_chunk(demux_plugin_t *this_gen) { } /* skip over the extra non-spec CVID bytes */ - this->input->seek(this->input, + this->input->seek(this->input, this->sample_table[i].sample_size - cvid_chunk_size, SEEK_CUR); /* load the rest of the chunk */ - if (this->input->read(this->input, buf->content + 10, + if (this->input->read(this->input, buf->content + 10, buf->size - 10) != buf->size - 10) { buf->free_buffer(buf); this->status = DEMUX_FINISHED; @@ -496,7 +499,7 @@ static int demux_film_send_chunk(demux_plugin_t *this_gen) { /* set the frame duration */ buf->decoder_flags |= BUF_FLAG_FRAMERATE; buf->decoder_info[0] = this->sample_table[i].duration; - + if (remaining_sample_bytes > buf->max_size) buf->size = buf->max_size; else @@ -624,8 +627,8 @@ static int demux_film_send_chunk(demux_plugin_t *this_gen) { buf->content[j] = this->interleave_buffer[k]; buf->content[j + 1] = this->interleave_buffer[k + 1]; } - for (j = 2, - k = interleave_index + this->sample_table[i].sample_size / 2; + for (j = 2, + k = interleave_index + this->sample_table[i].sample_size / 2; j < buf->size; j += 4, k += 2) { buf->content[j] = this->interleave_buffer[k]; buf->content[j + 1] = this->interleave_buffer[k + 1]; @@ -635,8 +638,8 @@ static int demux_film_send_chunk(demux_plugin_t *this_gen) { for (j = 0, k = interleave_index; j < buf->size; j += 2, k += 1) { buf->content[j] = this->interleave_buffer[k] += 0x80; } - for (j = 1, - k = interleave_index + this->sample_table[i].sample_size / 2; + for (j = 1, + k = interleave_index + this->sample_table[i].sample_size / 2; j < buf->size; j += 2, k += 1) { buf->content[j] = this->interleave_buffer[k] += 0x80; } @@ -651,7 +654,7 @@ static int demux_film_send_chunk(demux_plugin_t *this_gen) { this->audio_fifo->put(this->audio_fifo, buf); } } - + return this->status; } @@ -734,13 +737,13 @@ static int demux_film_seek (demux_plugin_t *this_gen, off_t start_pos, int start this->waiting_for_keyframe = 0; this->last_sample = 0; } - + /* if input is non-seekable, do not proceed with the rest of this * seek function */ if (!INPUT_IS_SEEKABLE(this->input)) return this->status; - /* perform a binary search on the sample table, testing the offset + /* perform a binary search on the sample table, testing the offset * boundaries first */ if (start_pos) { if (start_pos <= 0) @@ -757,7 +760,7 @@ static int demux_film_seek (demux_plugin_t *this_gen, off_t start_pos, int start while (!found) { middle = (left + right) / 2; if ((start_pos >= this->sample_table[middle].sample_offset) && - (start_pos <= this->sample_table[middle].sample_offset + + (start_pos <= this->sample_table[middle].sample_offset + this->sample_table[middle].sample_size)) { found = 1; } else if (start_pos < this->sample_table[middle].sample_offset) { @@ -814,7 +817,7 @@ static int demux_film_seek (demux_plugin_t *this_gen, off_t start_pos, int start } this->current_sample = best_index; - + return this->status; } @@ -853,7 +856,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str demux_film_t *this; - this = xine_xmalloc (sizeof (demux_film_t)); + this = calloc(1, sizeof(demux_film_t)); this->stream = stream; this->input = input; @@ -927,7 +930,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_film_init_plugin (xine_t *xine, void *data) { demux_film_class_t *this; - this = xine_xmalloc (sizeof (demux_film_class_t)); + this = calloc(1, sizeof(demux_film_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_flac.c b/src/demuxers/demux_flac.c index 3afb5b031..976656016 100644 --- a/src/demuxers/demux_flac.c +++ b/src/demuxers/demux_flac.c @@ -33,6 +33,9 @@ #include <unistd.h> #include <string.h> #include <stdlib.h> +#ifdef HAVE_MALLOC_H +#include <malloc.h> +#endif #define LOG_MODULE "demux_flac" #define LOG_VERBOSE @@ -116,7 +119,7 @@ static int open_flac_file(demux_flac_t *flac) { * will always be 1 metadata block */ do { - if (flac->input->read(flac->input, preamble, FLAC_SIGNATURE_SIZE) != + if (flac->input->read(flac->input, preamble, FLAC_SIGNATURE_SIZE) != FLAC_SIGNATURE_SIZE) return 0; @@ -130,11 +133,11 @@ static int open_flac_file(demux_flac_t *flac) { case 0: lprintf ("STREAMINFO metadata\n"); if (block_length != FLAC_STREAMINFO_SIZE) { - lprintf ("expected STREAMINFO chunk of %d bytes\n", + lprintf ("expected STREAMINFO chunk of %d bytes\n", FLAC_STREAMINFO_SIZE); return 0; } - if (flac->input->read(flac->input, + if (flac->input->read(flac->input, flac->streaminfo + sizeof(xine_waveformatex), FLAC_STREAMINFO_SIZE) != FLAC_STREAMINFO_SIZE) return 0; @@ -143,8 +146,8 @@ static int open_flac_file(demux_flac_t *flac) { flac->bits_per_sample = ((flac->sample_rate >> 4) & 0x1F) + 1; flac->sample_rate >>= 12; flac->total_samples = _X_BE_64(&streaminfo[10]) & UINT64_C(0x0FFFFFFFFF); /* 36 bits */ - lprintf ("%d Hz, %d bits, %d channels, %"PRId64" total samples\n", - flac->sample_rate, flac->bits_per_sample, + lprintf ("%d Hz, %d bits, %d channels, %"PRId64" total samples\n", + flac->sample_rate, flac->bits_per_sample, flac->channels, flac->total_samples); break; @@ -164,8 +167,10 @@ static int open_flac_file(demux_flac_t *flac) { case 3: lprintf ("SEEKTABLE metadata, %d bytes\n", block_length); flac->seekpoint_count = block_length / FLAC_SEEKPOINT_SIZE; - flac->seekpoints = xine_xmalloc(flac->seekpoint_count * + flac->seekpoints = calloc(flac->seekpoint_count, sizeof(flac_seekpoint_t)); + if (flac->seekpoint_count && !flac->seekpoints) + return 0; for (i = 0; i < flac->seekpoint_count; i++) { if (flac->input->read(flac->input, buffer, FLAC_SEEKPOINT_SIZE) != FLAC_SEEKPOINT_SIZE) return 0; @@ -173,7 +178,7 @@ static int open_flac_file(demux_flac_t *flac) { lprintf (" %d: sample %"PRId64", ", i, flac->seekpoints[i].sample_number); flac->seekpoints[i].offset = _X_BE_64(&buffer[8]); flac->seekpoints[i].size = _X_BE_16(&buffer[16]); - lprintf ("@ 0x%"PRIX64", size = %d bytes, ", + lprintf ("@ 0x%"PRIX64", size = %d bytes, ", flac->seekpoints[i].offset, flac->seekpoints[i].size); flac->seekpoints[i].pts = flac->seekpoints[i].sample_number; flac->seekpoints[i].pts *= 90000; @@ -182,14 +187,14 @@ static int open_flac_file(demux_flac_t *flac) { } break; - /* VORBIS_COMMENT + /* VORBIS_COMMENT * * For a description of the format please have a look at * http://www.xiph.org/vorbis/doc/v-comment.html */ case 4: lprintf ("VORBIS_COMMENT metadata\n"); { - char comments[block_length]; + char comments[block_length + 1]; /* last byte for NUL termination */ char *ptr = comments; uint32_t length, user_comment_list_length; int cn; @@ -202,27 +207,37 @@ static int open_flac_file(demux_flac_t *flac) { length = _X_LE_32(ptr); ptr += 4 + length; + if (length > block_length - 8) + return 0; /* bad length or too little left in the buffer */ user_comment_list_length = _X_LE_32(ptr); ptr += 4; cn = 0; for (; cn < user_comment_list_length; cn++) { + if (ptr > comments + block_length - 4) + return 0; /* too little left in the buffer */ + length = _X_LE_32(ptr); ptr += 4; + if (length >= block_length || ptr + length > comments + block_length) + return 0; /* bad length */ comment = (char*) ptr; c = comment[length]; - comment[length] = 0; + comment[length] = 0; /* NUL termination */ lprintf ("comment[%02d] = %s\n", cn, comment); - if ((strncasecmp ("TITLE=", comment, 6) == 0) + if ((strncasecmp ("TITLE=", comment, 6) == 0) && (length - 6 > 0)) { _x_meta_info_set_utf8 (flac->stream, XINE_META_INFO_TITLE, comment + 6); } else if ((strncasecmp ("ARTIST=", comment, 7) == 0) && (length - 7 > 0)) { _x_meta_info_set_utf8 (flac->stream, XINE_META_INFO_ARTIST, comment + 7); + } else if ((strncasecmp ("COMPOSER=", comment, 9) == 0) + && (length - 9 > 0)) { + _x_meta_info_set_utf8 (flac->stream, XINE_META_INFO_COMPOSER, comment + 9); } else if ((strncasecmp ("ALBUM=", comment, 6) == 0) && (length - 6 > 0)) { _x_meta_info_set_utf8 (flac->stream, XINE_META_INFO_ALBUM, comment + 6); @@ -248,8 +263,8 @@ static int open_flac_file(demux_flac_t *flac) { } if ((tracknumber > 0) && (tracktotal > 0)) { - char tn[16]; - snprintf (tn, 16, "%02d/%02d", tracknumber, tracktotal); + char tn[24]; + snprintf (tn, 24, "%02d/%02d", tracknumber, tracktotal); _x_meta_info_set(flac->stream, XINE_META_INFO_TRACK_NUMBER, tn); } else if (tracknumber > 0) { @@ -381,12 +396,13 @@ static int demux_flac_seek (demux_plugin_t *this_gen, demux_flac_t *this = (demux_flac_t *) this_gen; int seekpoint_index = 0; int64_t start_pts; - + unsigned char buf[4]; + start_pos = (off_t) ( (double) start_pos / 65535 * this->data_size ); /* if thread is not running, initialize demuxer */ - if( !playing ) { + if( !playing && !start_pos) { /* send new pts */ _x_demux_control_newpts(this->stream, 0, 0); @@ -394,28 +410,39 @@ static int demux_flac_seek (demux_plugin_t *this_gen, this->status = DEMUX_OK; } else { - if (this->seekpoints == NULL) { + if (this->seekpoints == NULL && !start_pos) { /* cannot seek if there is no seekpoints */ this->status = DEMUX_OK; return this->status; } - /* do a lazy, linear seek based on the assumption that there are not - * that many seek points */ + /* Don't use seekpoints if start_pos != 0. This allows smooth seeking */ if (start_pos) { /* offset-based seek */ - if (start_pos < this->seekpoints[0].offset) - seekpoint_index = 0; - else { - for (seekpoint_index = 0; seekpoint_index < this->seekpoint_count - 1; - seekpoint_index++) { - if (start_pos < this->seekpoints[seekpoint_index + 1].offset) { - break; - } - } + this->status = DEMUX_OK; + start_pos += this->data_start; + this->input->seek(this->input, start_pos, SEEK_SET); + while(1){ /* here we try to find something that resembles a frame header */ + + if (this->input->read(this->input, buf, 2) != 2){ + this->status = DEMUX_FINISHED; /* we sought past the end of stream ? */ + break; + } + + if (buf[0] == 0xff && buf[1] == 0xf8) + break; /* this might be the frame header... or it may be not. We pass it to the decoder + * to decide, but this way we reduce the number of warnings */ + start_pos +=2; } + + _x_demux_flush_engine(this->stream); + this->input->seek(this->input, start_pos, SEEK_SET); + _x_demux_control_newpts(this->stream, 0, BUF_FLAG_SEEK); + return this->status; + } else { - /* time-based seek */ + /* do a lazy, linear seek based on the assumption that there are not + * that many seek points; time-based seek */ start_pts = start_time; start_pts *= 90; if (start_pts < this->seekpoints[0].pts) @@ -431,9 +458,9 @@ static int demux_flac_seek (demux_plugin_t *this_gen, } _x_demux_flush_engine(this->stream); - this->input->seek(this->input, this->seekpoints[seekpoint_index].offset, + this->input->seek(this->input, this->seekpoints[seekpoint_index].offset, SEEK_SET); - _x_demux_control_newpts(this->stream, + _x_demux_control_newpts(this->stream, this->seekpoints[seekpoint_index].pts, BUF_FLAG_SEEK); } @@ -444,6 +471,7 @@ static void demux_flac_dispose (demux_plugin_t *this_gen) { demux_flac_t *this = (demux_flac_t *) this_gen; free(this->seekpoints); + free(this); } static int demux_flac_get_status (demux_plugin_t *this_gen) { @@ -482,7 +510,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str return NULL; } - this = xine_xmalloc (sizeof (demux_flac_t)); + this = calloc(1, sizeof(demux_flac_t)); this->stream = stream; this->input = input; @@ -544,7 +572,8 @@ static const char *get_extensions (demux_class_t *this_gen) { } static const char *get_mimetypes (demux_class_t *this_gen) { - return NULL; + return "audio/x-flac: flac: FLAC Audio;" + "audio/flac: flac: FLAC Audio;"; } static void class_dispose (demux_class_t *this_gen) { @@ -556,7 +585,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_flac_init_plugin (xine_t *xine, void *data) { demux_flac_class_t *this; - this = xine_xmalloc (sizeof (demux_flac_class_t)); + this = calloc(1, sizeof(demux_flac_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_fli.c b/src/demuxers/demux_fli.c index 99843a68c..7735671b9 100644 --- a/src/demuxers/demux_fli.c +++ b/src/demuxers/demux_fli.c @@ -112,7 +112,7 @@ static int open_fli_file(demux_fli_t *this) { this->speed = _X_LE_32(&this->fli_header[16]); if (this->magic_number == FLI_FILE_MAGIC_1) { - /* + /* * in this case, the speed (n) is number of 1/70s ticks between frames: * * xine pts n * frame # @@ -123,7 +123,7 @@ static int open_fli_file(demux_fli_t *this) { */ this->frame_pts_inc = this->speed * 1285.7; } else if (this->magic_number == FLI_FILE_MAGIC_2) { - /* + /* * in this case, the speed (n) is number of milliseconds between frames: * * xine pts n * frame # @@ -244,7 +244,7 @@ static void demux_fli_send_headers(demux_plugin_t *this_gen) { BUF_FLAG_FRAME_END; buf->decoder_info[0] = this->frame_pts_inc; /* initial video_step */ buf->size = this->bih.biSize; - memcpy(buf->content, &this->bih, sizeof(xine_bmiheader) + this->bih.biSize); + memcpy(buf->content, &this->bih, this->bih.biSize); buf->type = BUF_VIDEO_FLI; this->video_fifo->put (this->video_fifo, buf); } @@ -303,7 +303,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str demux_fli_t *this; - this = xine_xmalloc (sizeof (demux_fli_t)); + this = calloc(1, sizeof(demux_fli_t)); this->stream = stream; this->input = input; @@ -377,7 +377,7 @@ static void class_dispose (demux_class_t *this_gen) { static void *init_plugin (xine_t *xine, void *data) { demux_fli_class_t *this; - this = xine_xmalloc (sizeof (demux_fli_class_t)); + this = calloc(1, sizeof(demux_fli_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_flv.c b/src/demuxers/demux_flv.c index bdb33d21d..813f33086 100644 --- a/src/demuxers/demux_flv.c +++ b/src/demuxers/demux_flv.c @@ -20,11 +20,11 @@ /* * Flash Video (.flv) File Demuxer - * by Mike Melanson (melanson@pcisys.net) and - * Claudio Ciccani (klan@directfb.org) + * by Mike Melanson (melanson@pcisys.net) and + * Claudio Ciccani (klan@users.sf.net) * * For more information on the FLV file format, visit: - * http://download.macromedia.com/pub/flash/flash_file_format_specification.pdf + * http://www.adobe.com/devnet/flv/pdf/video_file_format_spec_v9.pdf */ #ifdef HAVE_CONFIG_H @@ -67,28 +67,28 @@ typedef struct { unsigned char flags; off_t start; /* in bytes */ off_t size; /* in bytes */ - + unsigned char got_video_header; unsigned char got_audio_header; - + unsigned int length; /* in ms */ int width; int height; int duration; int videocodec; - + int samplerate; int samplesize; int stereo; int audiocodec; - + off_t filesize; - + flv_index_entry_t *index; - int num_indices; - + unsigned int num_indices; + unsigned int cur_pts; - + int64_t last_pts[2]; int send_newpts; int buf_flag_seek; @@ -110,14 +110,20 @@ typedef struct { #define FLV_SOUND_FORMAT_ADPCM 0x01 #define FLV_SOUND_FORMAT_MP3 0x02 #define FLV_SOUND_FORMAT_PCM_LE 0x03 +#define FLV_SOUND_FORMAT_NELLY16 0x04 /* Nellymoser 16KHz */ #define FLV_SOUND_FORMAT_NELLY8 0x05 /* Nellymoser 8KHz */ #define FLV_SOUND_FORMAT_NELLY 0x06 /* Nellymoser */ +#define FLV_SOUND_FORMAT_ALAW 0x07 /* G.711 A-LAW */ +#define FLV_SOUND_FORMAT_MULAW 0x08 /* G.711 MU-LAW */ +#define FLV_SOUND_FORMAT_AAC 0x0a +#define FLV_SOUND_FORMAT_MP38 0x0e /* MP3 8KHz */ #define FLV_VIDEO_FORMAT_FLV1 0x02 /* Sorenson H.263 */ #define FLV_VIDEO_FORMAT_SCREEN 0x03 #define FLV_VIDEO_FORMAT_VP6 0x04 /* On2 VP6 */ #define FLV_VIDEO_FORMAT_VP6A 0x05 /* On2 VP6 with alphachannel */ #define FLV_VIDEO_FORMAT_SCREEN2 0x06 +#define FLV_VIDEO_FORMAT_H264 0x07 #define FLV_DATA_TYPE_NUMBER 0x00 #define FLV_DATA_TYPE_BOOL 0x01 @@ -172,7 +178,7 @@ static int open_flv_file(demux_flv_t *this) { if ((buffer[0] != 'F') || (buffer[1] != 'L') || (buffer[2] != 'V')) return 0; - + if (buffer[3] != 0x01) { xprintf(this->xine, XINE_VERBOSITY_LOG, _("unsupported FLV version (%d).\n"), buffer[3]); @@ -188,10 +194,10 @@ static int open_flv_file(demux_flv_t *this) { this->start = _X_BE_32(&buffer[5]); this->size = this->input->get_length(this->input); - + this->input->seek(this->input, this->start, SEEK_SET); - - lprintf(" qualified FLV file, repositioned @ offset 0x%" PRIxMAX "\n", + + lprintf(" qualified FLV file, repositioned @ offset 0x%" PRIxMAX "\n", (intmax_t)this->start); return 1; @@ -203,19 +209,19 @@ static int open_flv_file(demux_flv_t *this) { _tmp.d;\ })\ -static int parse_flv_var(demux_flv_t *this, +static int parse_flv_var(demux_flv_t *this, unsigned char *buf, int size, char *key, int keylen) { unsigned char *tmp = buf; unsigned char *end = buf + size; char *str; unsigned char type; - int len, num; - + unsigned int len, num; + if (size < 1) return 0; - + type = *tmp++; - + switch (type) { case FLV_DATA_TYPE_NUMBER: lprintf(" got number (%f)\n", BE_F64(tmp)); @@ -283,6 +289,8 @@ static int parse_flv_var(demux_flv_t *this, str = tmp + 2; tmp += len + 2; len = parse_flv_var(this, tmp, end-tmp, str, len); + if (!len) + return 0; tmp += len; } if (*tmp++ != FLV_DATA_TYPE_ENDOBJECT) @@ -298,6 +306,8 @@ static int parse_flv_var(demux_flv_t *this, str = tmp + 2; tmp += len + 2; len = parse_flv_var(this, tmp, end-tmp, str, len); + if (!len) + return 0; tmp += len; } break; @@ -306,10 +316,14 @@ static int parse_flv_var(demux_flv_t *this, num = _X_BE_32(tmp); tmp += 4; if (key && keylen == 5 && !strncmp(key, "times", 5)) { - if (this->index) - free (this->index); - this->index = xine_xmalloc(num*sizeof(flv_index_entry_t)); - this->num_indices = num; + if (!this->index || this->num_indices != num) { + if (this->index) + free(this->index); + this->index = calloc(num, sizeof(flv_index_entry_t)); + if (!this->index) + return 0; + this->num_indices = num; + } for (num = 0; num < this->num_indices && tmp < end; num++) { if (*tmp++ == FLV_DATA_TYPE_NUMBER) { lprintf(" got number (%f)\n", BE_F64(tmp)); @@ -320,19 +334,27 @@ static int parse_flv_var(demux_flv_t *this, break; } if (key && keylen == 13 && !strncmp(key, "filepositions", 13)) { - if (this->index && this->num_indices == num) { - for (num = 0; num < this->num_indices && tmp < end; num++) { - if (*tmp++ == FLV_DATA_TYPE_NUMBER) { - lprintf(" got number (%f)\n", BE_F64(tmp)); - this->index[num].offset = BE_F64(tmp); - tmp += 8; - } + if (!this->index || this->num_indices != num) { + if (this->index) + free(this->index); + this->index = calloc(num, sizeof(flv_index_entry_t)); + if (!this->index) + return 0; + this->num_indices = num; + } + for (num = 0; num < this->num_indices && tmp < end; num++) { + if (*tmp++ == FLV_DATA_TYPE_NUMBER) { + lprintf(" got number (%f)\n", BE_F64(tmp)); + this->index[num].offset = BE_F64(tmp); + tmp += 8; } - break; } + break; } while (num-- && tmp < end) { len = parse_flv_var(this, tmp, end-tmp, NULL, 0); + if (!len) + return 0; tmp += len; } break; @@ -344,17 +366,17 @@ static int parse_flv_var(demux_flv_t *this, lprintf(" got type %d\n", type); break; } - + return (tmp - buf); } static void parse_flv_script(demux_flv_t *this, int size) { - unsigned char *buf = xine_xmalloc(size); + unsigned char *buf = malloc(size); unsigned char *tmp = buf; unsigned char *end = buf + size; int len; - - if (this->input->read(this->input, buf, size ) != size) { + + if (!buf || this->input->read(this->input, buf, size ) != size) { this->status = DEMUX_FINISHED; free(buf); return; @@ -366,7 +388,7 @@ static void parse_flv_script(demux_flv_t *this, int size) { break; tmp += len; } - + free(buf); } @@ -379,7 +401,7 @@ static int read_flv_packet(demux_flv_t *this, int preview) { unsigned int buf_type = 0; unsigned int buf_flags = 0; unsigned int pts; - + while (1) { lprintf (" reading FLV tag...\n"); this->input->seek(this->input, 4, SEEK_CUR); @@ -391,7 +413,7 @@ static int read_flv_packet(demux_flv_t *this, int preview) { tag_type = buffer[0]; remaining_bytes = _X_BE_24(&buffer[1]); pts = _X_BE_24(&buffer[4]) | (buffer[7] << 24); - + lprintf(" tag_type = 0x%02X, 0x%X bytes, pts %u\n", tag_type, remaining_bytes, pts/90); @@ -400,10 +422,10 @@ static int read_flv_packet(demux_flv_t *this, int preview) { lprintf(" got audio tag..\n"); if (this->input->read(this->input, buffer, 1) != 1) { this->status = DEMUX_FINISHED; - return this->status; + return this->status; } remaining_bytes--; - + this->audiocodec = buffer[0] >> 4; /* override */ switch (this->audiocodec) { case FLV_SOUND_FORMAT_PCM_BE: @@ -413,17 +435,30 @@ static int read_flv_packet(demux_flv_t *this, int preview) { buf_type = BUF_AUDIO_FLVADPCM; break; case FLV_SOUND_FORMAT_MP3: + case FLV_SOUND_FORMAT_MP38: buf_type = BUF_AUDIO_MPEG; break; case FLV_SOUND_FORMAT_PCM_LE: buf_type = BUF_AUDIO_LPCM_LE; break; + case FLV_SOUND_FORMAT_ALAW: + buf_type = BUF_AUDIO_ALAW; + break; + case FLV_SOUND_FORMAT_MULAW: + buf_type = BUF_AUDIO_MULAW; + break; + case FLV_SOUND_FORMAT_AAC: + buf_type = BUF_AUDIO_AAC; + /* AAC extra header */ + this->input->read(this->input, buffer, 1 ); + remaining_bytes--; + break; default: lprintf(" unsupported audio format (%d)...\n", buffer[0] >> 4); buf_type = BUF_AUDIO_UNKNOWN; break; } - + fifo = this->audio_fifo; if (preview && !this->got_audio_header) { /* send init info to audio decoder */ @@ -439,7 +474,7 @@ static int read_flv_packet(demux_flv_t *this, int preview) { this->got_audio_header = 1; } break; - + case FLV_TAG_TYPE_VIDEO: lprintf(" got video tag..\n"); if (this->input->read(this->input, buffer, 1) != 1) { @@ -447,10 +482,19 @@ static int read_flv_packet(demux_flv_t *this, int preview) { return this->status; } remaining_bytes--; - - if ((buffer[0] >> 4) == 0x01) - buf_flags = BUF_FLAG_KEYFRAME; - + + switch ((buffer[0] >> 4)) { + case 0x01: + buf_flags = BUF_FLAG_KEYFRAME; + break; + case 0x05: + /* skip server command */ + this->input->seek(this->input, remaining_bytes, SEEK_CUR); + continue; + default: + break; + } + this->videocodec = buffer[0] & 0x0F; /* override */ switch (this->videocodec) { case FLV_VIDEO_FORMAT_FLV1: @@ -468,17 +512,23 @@ static int read_flv_packet(demux_flv_t *this, int preview) { this->input->read(this->input, buffer, 4); remaining_bytes -= 4; break; + case FLV_VIDEO_FORMAT_H264: + buf_type = BUF_VIDEO_H264; + /* AVC extra header */ + this->input->read(this->input, buffer, 4); + remaining_bytes -= 4; + break; default: lprintf(" unsupported video format (%d)...\n", buffer[0] & 0x0F); buf_type = BUF_VIDEO_UNKNOWN; break; } - + fifo = this->video_fifo; if (preview && !this->got_video_header) { xine_bmiheader *bih; /* send init info to video decoder; send the bitmapinfo header to the decoder - * primarily as a formality since there is no real data inside */ + * primarily as a formality since there is no real data inside */ buf = fifo->buffer_pool_alloc(fifo); buf->decoder_flags = BUF_FLAG_HEADER | BUF_FLAG_STDHEADER | BUF_FLAG_FRAMERATE | BUF_FLAG_FRAME_END; @@ -495,16 +545,33 @@ static int read_flv_packet(demux_flv_t *this, int preview) { bih->biSize++; buf->size++; } + else if (buf_type == BUF_VIDEO_H264 && buffer[0] == 0) { + /* AVC sequence header */ + if (remaining_bytes > buf->max_size-buf->size) { + xprintf(this->xine, XINE_VERBOSITY_LOG, + _("sequence header too big (%u bytes)!\n"), remaining_bytes); + this->input->read(this->input, buf->content+buf->size, buf->max_size-buf->size); + this->input->seek(this->input, remaining_bytes-buf->max_size-buf->size, SEEK_CUR); + bih->biSize = buf->max_size; + buf->size = buf->max_size; + } + else { + this->input->read(this->input, buf->content+buf->size, remaining_bytes); + bih->biSize += remaining_bytes; + buf->size += remaining_bytes; + } + remaining_bytes = 0; + } fifo->put(fifo, buf); this->got_video_header = 1; } break; - + case FLV_TAG_TYPE_SCRIPT: lprintf(" got script tag...\n"); - parse_flv_script(this, remaining_bytes); - if (preview) { + parse_flv_script(this, remaining_bytes); + /* send init info to decoders using script information as reference */ if (!this->got_audio_header && this->audiocodec) { buf = this->audio_fifo->buffer_pool_alloc(this->audio_fifo); @@ -521,11 +588,21 @@ static int read_flv_packet(demux_flv_t *this, int preview) { buf->type = BUF_AUDIO_FLVADPCM; break; case FLV_SOUND_FORMAT_MP3: + case FLV_SOUND_FORMAT_MP38: buf->type = BUF_AUDIO_MPEG; break; case FLV_SOUND_FORMAT_PCM_LE: buf->type = BUF_AUDIO_LPCM_LE; break; + case FLV_SOUND_FORMAT_ALAW: + buf->type = BUF_AUDIO_ALAW; + break; + case FLV_SOUND_FORMAT_MULAW: + buf->type = BUF_AUDIO_MULAW; + break; + case FLV_SOUND_FORMAT_AAC: + buf->type = BUF_AUDIO_AAC; + break; default: buf->type = BUF_AUDIO_UNKNOWN; break; @@ -533,9 +610,10 @@ static int read_flv_packet(demux_flv_t *this, int preview) { buf->size = 0; this->audio_fifo->put(this->audio_fifo, buf); this->got_audio_header = 1; + lprintf(" got audio header from metadata...\n"); } - - if (!this->got_video_header && this->videocodec) { + + if (!this->got_video_header && this->videocodec && this->videocodec != FLV_VIDEO_FORMAT_H264) { xine_bmiheader *bih; buf = this->video_fifo->buffer_pool_alloc(this->video_fifo); buf->decoder_flags = BUF_FLAG_HEADER | BUF_FLAG_STDHEADER | @@ -567,57 +645,88 @@ static int read_flv_packet(demux_flv_t *this, int preview) { } this->video_fifo->put(this->video_fifo, buf); this->got_video_header = 1; + lprintf(" got video header from metadata...\n"); } - + return this->status; - } + } + /* no preview */ + this->input->seek(this->input, remaining_bytes, SEEK_CUR); continue; - + default: lprintf(" skipping packet...\n"); this->input->seek(this->input, remaining_bytes, SEEK_CUR); continue; } - + while (remaining_bytes) { buf = fifo->buffer_pool_alloc(fifo); buf->type = buf_type; - buf->pts = (int64_t) pts * 90; - - if (!preview) - check_newpts(this, buf->pts, (tag_type == FLV_TAG_TYPE_VIDEO)); - + buf->extra_info->input_time = pts; if (this->input->get_length(this->input)) { - buf->extra_info->input_normpos = + buf->extra_info->input_normpos = (int)((double)this->input->get_current_pos(this->input) * 65535.0 / this->size); } - if (remaining_bytes > buf->max_size) - buf->size = buf->max_size; - else - buf->size = remaining_bytes; - remaining_bytes -= buf->size; + if ((buf_type == BUF_VIDEO_H264 || buf_type == BUF_AUDIO_AAC) && buffer[0] == 0) { + /* AVC/AAC sequence header */ + buf->pts = 0; + buf->size = 0; - buf->decoder_flags = buf_flags; - if (preview) - buf->decoder_flags |= BUF_FLAG_PREVIEW; - if (!remaining_bytes) - buf->decoder_flags |= BUF_FLAG_FRAME_END; + buf->decoder_flags = BUF_FLAG_SPECIAL | BUF_FLAG_HEADER; + if (preview) + buf->decoder_flags |= BUF_FLAG_PREVIEW; - if (this->input->read(this->input, buf->content, buf->size) != buf->size) { - buf->free_buffer(buf); - this->status = DEMUX_FINISHED; - break; + buf->decoder_info[1] = BUF_SPECIAL_DECODER_CONFIG; + buf->decoder_info[2] = MIN(remaining_bytes, buf->max_size); + buf->decoder_info_ptr[2] = buf->mem; + + if (this->input->read(this->input, buf->mem, buf->decoder_info[2]) != buf->decoder_info[2]) { + buf->free_buffer(buf); + this->status = DEMUX_FINISHED; + break; + } + + if (remaining_bytes > buf->max_size) { + xprintf(this->xine, XINE_VERBOSITY_LOG, + _("sequence header too big (%u bytes)!\n"), remaining_bytes); + this->input->seek(this->input, remaining_bytes-buf->max_size, SEEK_CUR); + } + remaining_bytes = 0; + } + else { + buf->pts = (int64_t) pts * 90; + if (!preview) + check_newpts(this, buf->pts, (tag_type == FLV_TAG_TYPE_VIDEO)); + + if (remaining_bytes > buf->max_size) + buf->size = buf->max_size; + else + buf->size = remaining_bytes; + remaining_bytes -= buf->size; + + buf->decoder_flags = buf_flags; + if (preview) + buf->decoder_flags |= BUF_FLAG_PREVIEW; + if (!remaining_bytes) + buf->decoder_flags |= BUF_FLAG_FRAME_END; + + if (this->input->read(this->input, buf->content, buf->size) != buf->size) { + buf->free_buffer(buf); + this->status = DEMUX_FINISHED; + break; + } } fifo->put(fifo, buf); } - + this->cur_pts = pts; break; } - + return this->status; } @@ -628,52 +737,50 @@ static void seek_flv_file(demux_flv_t *this, off_t seek_pos, int seek_pts) { int next_tag = 0; int do_rewind = (seek_pts < this->cur_pts); int i; - - lprintf(" seeking %s to %d...\n", + + lprintf(" seeking %s to %d...\n", do_rewind ? "backward" : "forward", seek_pts); - - if (seek_pts == 0) { + + if (seek_pos == 0 && seek_pts == 0) { this->input->seek(this->input, this->start, SEEK_SET); this->cur_pts = 0; return; } - + if (this->index) { if (do_rewind) { for (i = this->num_indices-1; i > 0; i--) { if (this->index[i-1].pts < seek_pts) break; } - } + } else { for (i = 0; i < (this->num_indices-1); i++) { if (this->index[i+1].pts > seek_pts) break; } } - + if (this->index[i].offset >= this->start+4) { - lprintf(" seeking to index entry %d (pts:%u, offset:%u).\n", + lprintf(" seeking to index entry %d (pts:%u, offset:%u).\n", i, this->index[i].pts, this->index[i].offset); this->input->seek(this->input, this->index[i].offset-4, SEEK_SET); this->cur_pts = this->index[i].pts; - return; } } - - if (seek_pos && this->videocodec) { + else if (seek_pos && this->videocodec && abs(seek_pts-this->cur_pts) > 300000) { off_t pos, size; - + pos = this->input->get_current_pos(this->input); size = this->filesize ? : this->input->get_length(this->input); this->input->seek(this->input, (uint64_t)size * seek_pos / 65535, SEEK_SET); lprintf(" resyncing...\n"); - + /* resync */ for (i = 0; i < 200000; i++) { uint8_t buf[4]; - + if (this->input->read(this->input, buf, 1) < 1) { this->status = DEMUX_FINISHED; return; @@ -694,58 +801,59 @@ static void seek_flv_file(demux_flv_t *this, off_t seek_pos, int seek_pts) { this->input->seek(this->input, -11, SEEK_CUR); } } - + lprintf(" ...resync failed!\n"); this->input->seek(this->input, pos, SEEK_SET); - return; - } - - while (do_rewind ? (seek_pts < this->cur_pts) : (seek_pts > this->cur_pts)) { - unsigned char tag_type; - int data_size; - int ptag_size; - - if (next_tag) - this->input->seek(this->input, next_tag, SEEK_CUR); - - len = this->input->read(this->input, buffer, 16); - if (len != 16) { - len = (len < 0) ? 0 : len; - break; - } - - ptag_size = _X_BE_32(&buffer[0]); - tag_type = buffer[4]; - data_size = _X_BE_24(&buffer[5]); - pts = _X_BE_24(&buffer[8]) | (buffer[11] << 24); - - if (do_rewind) { - if (!ptag_size) break; /* beginning of movie */ - next_tag = -(ptag_size + 16 + 4); - } - else { - next_tag = data_size - 1; - } - - if (this->flags & FLV_FLAG_HAS_VIDEO) { - /* sync to video key frame */ - if (tag_type != FLV_TAG_TYPE_VIDEO || (buffer[15] >> 4) != 0x01) - continue; - lprintf(" video keyframe found at %d...\n", pts); + } + else if (seek_pts) { + while (do_rewind ? (seek_pts < this->cur_pts) : (seek_pts > this->cur_pts)) { + unsigned char tag_type; + int data_size; + int ptag_size; + + if (next_tag) + this->input->seek(this->input, next_tag, SEEK_CUR); + + len = this->input->read(this->input, buffer, 16); + if (len != 16) { + len = (len < 0) ? 0 : len; + break; + } + + ptag_size = _X_BE_32(&buffer[0]); + tag_type = buffer[4]; + data_size = _X_BE_24(&buffer[5]); + pts = _X_BE_24(&buffer[8]) | (buffer[11] << 24); + + if (do_rewind) { + if (!ptag_size) + break; /* beginning of movie */ + next_tag = -(ptag_size + 16 + 4); + } + else { + next_tag = data_size - 1; + } + + if (this->flags & FLV_FLAG_HAS_VIDEO) { + /* sync to video key frame */ + if (tag_type != FLV_TAG_TYPE_VIDEO || (buffer[15] >> 4) != 0x01) + continue; + lprintf(" video keyframe found at %d...\n", pts); + } + this->cur_pts = pts; } - this->cur_pts = pts; + + /* seek back to the beginning of the tag */ + this->input->seek(this->input, -len, SEEK_CUR); + + lprintf( " seeked to %d.\n", pts); } - - /* seek back to the beginning of the tag */ - this->input->seek(this->input, -len, SEEK_CUR); - - lprintf( " seeked to %d.\n", pts); } static int demux_flv_send_chunk(demux_plugin_t *this_gen) { demux_flv_t *this = (demux_flv_t *) this_gen; - + return read_flv_packet(this, 0); } @@ -757,11 +865,11 @@ static void demux_flv_send_headers(demux_plugin_t *this_gen) { this->audio_fifo = this->stream->audio_fifo; this->status = DEMUX_OK; - + this->buf_flag_seek = 1; /* load stream information */ - _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, + _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, (this->flags & FLV_FLAG_HAS_VIDEO) ? 1 : 0); _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, (this->flags & FLV_FLAG_HAS_AUDIO) ? 1 : 0); @@ -789,18 +897,22 @@ static int demux_flv_seek (demux_plugin_t *this_gen, this->status = DEMUX_OK; if (INPUT_IS_SEEKABLE(this->input)) { - if (start_pos && !start_time) - start_time = (int64_t) this->length * start_pos / 65535; + if (start_pos && !start_time) { + if (this->length) + start_time = (int64_t) this->length * start_pos / 65535; + else if (this->index) + start_time = this->index[(int)(start_pos * (this->num_indices-1) / 65535)].pts; + } if (!this->length || start_time < this->length) { seek_flv_file(this, start_pos, start_time); - + if (playing) { this->buf_flag_seek = 1; _x_demux_flush_engine(this->stream); } } - } + } return this->status; } @@ -838,7 +950,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str input_plugin_t *input) { demux_flv_t *this; - this = xine_xmalloc(sizeof (demux_flv_t)); + this = calloc(1, sizeof(demux_flv_t)); this->xine = stream->xine; this->stream = stream; this->input = input; @@ -857,12 +969,6 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str switch (stream->content_detection_method) { case METHOD_BY_EXTENSION: - if (!_x_demux_check_extension(input->get_mrl(input), "flv")) { - free (this); - return NULL; - } - - /* falling through is intended */ case METHOD_BY_CONTENT: case METHOD_EXPLICIT: if (!open_flv_file(this)) { @@ -906,7 +1012,7 @@ static void class_dispose (demux_class_t *this_gen) { static void *init_plugin (xine_t *xine, void *data) { demux_flv_class_t *this; - this = xine_xmalloc (sizeof (demux_flv_class_t)); + this = calloc(1, sizeof(demux_flv_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_idcin.c b/src/demuxers/demux_idcin.c index 99754c797..46d4c284b 100644 --- a/src/demuxers/demux_idcin.c +++ b/src/demuxers/demux_idcin.c @@ -328,7 +328,7 @@ static int open_idcin_file(demux_idcin_t *this) { this->input->seek(this->input, IDCIN_HEADER_SIZE, SEEK_SET); /* read the Huffman table */ - if (this->input->read(this->input, huffman_table, HUFFMAN_TABLE_SIZE) != + if (this->input->read(this->input, huffman_table, HUFFMAN_TABLE_SIZE) != HUFFMAN_TABLE_SIZE) return 0; @@ -347,7 +347,7 @@ static int open_idcin_file(demux_idcin_t *this) { _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITS, this->wave.wBitsPerSample); - this->filesize = this->input->get_length(this->input) - + this->filesize = this->input->get_length(this->input) - IDCIN_HEADER_SIZE - HUFFMAN_TABLE_SIZE; return 1; @@ -433,7 +433,7 @@ static int demux_idcin_seek (demux_plugin_t *this_gen, off_t start_pos, int star this->status = DEMUX_OK; /* reposition stream past the Huffman tables */ - this->input->seek(this->input, IDCIN_HEADER_SIZE + HUFFMAN_TABLE_SIZE, + this->input->seek(this->input, IDCIN_HEADER_SIZE + HUFFMAN_TABLE_SIZE, SEEK_SET); this->pts_counter = 0; @@ -472,7 +472,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str demux_idcin_t *this; - this = xine_xmalloc (sizeof (demux_idcin_t)); + this = calloc(1, sizeof(demux_idcin_t)); this->stream = stream; this->input = input; @@ -547,7 +547,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_idcin_init_plugin (xine_t *xine, void *data) { demux_idcin_class_t *this; - this = xine_xmalloc (sizeof (demux_idcin_class_t)); + this = calloc(1, sizeof(demux_idcin_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_iff.c b/src/demuxers/demux_iff.c index d914405db..1785e86d7 100644 --- a/src/demuxers/demux_iff.c +++ b/src/demuxers/demux_iff.c @@ -212,7 +212,7 @@ static int read_iff_chunk(demux_iff_t *this) { break; case IFF_VHDR_CHUNK: if( this->vhdr == NULL ) - this->vhdr = (Voice8Header *)xine_xmalloc(sizeof(Voice8Header)); + this->vhdr = (Voice8Header *)calloc(1, sizeof(Voice8Header)); this->vhdr->oneShotHiSamples = _X_BE_32(&buffer[0]); this->vhdr->repeatHiSamples = _X_BE_32(&buffer[4]); this->vhdr->samplesPerHiCycle = _X_BE_32(&buffer[8]); @@ -330,7 +330,7 @@ static int read_iff_chunk(demux_iff_t *this) { break; case IFF_BMHD_CHUNK: if( this->bmhd == NULL ) - this->bmhd = (BitMapHeader *)xine_xmalloc(sizeof(BitMapHeader)); + this->bmhd = (BitMapHeader *)calloc(1, sizeof(BitMapHeader)); this->bmhd->w = _X_BE_16(&buffer[0]); this->bmhd->h = _X_BE_16(&buffer[2]); this->bmhd->x = _X_BE_16(&buffer[4]); @@ -399,20 +399,20 @@ static int read_iff_chunk(demux_iff_t *this) { case IFF_CMAP_CHUNK: /* every color contains red, green and blue componente using 8Bit */ this->cmap_num = junk_size / PIC_SIZE_OF_COLOR_REGISTER; - this->cmap = (ColorRegister *)xine_xmalloc(junk_size); + this->cmap = (ColorRegister *)malloc(junk_size); this->video_send_palette = 1; - if (this->input->read(this->input, (char *)this->cmap, junk_size) != junk_size) + if (!this->cmap || this->input->read(this->input, (char *)this->cmap, junk_size) != junk_size) return 0; break; case IFF_GRAB_CHUNK: if( this->grab == NULL ) - this->grab = (Point2D *)xine_xmalloc(sizeof(Point2D)); + this->grab = (Point2D *)calloc(1, sizeof(Point2D)); this->grab->x = _X_BE_16(&buffer[0]); this->grab->y = _X_BE_16(&buffer[2]); break; case IFF_DEST_CHUNK: if( this->dest == NULL ) - this->dest = (DestMerge *)xine_xmalloc(sizeof(DestMerge)); + this->dest = (DestMerge *)calloc(1, sizeof(DestMerge)); this->dest->depth = buffer[0]; this->dest->pad1 = buffer[1]; this->dest->plane_pick = _X_BE_16(&buffer[2]); @@ -424,7 +424,7 @@ static int read_iff_chunk(demux_iff_t *this) { break; case IFF_CAMG_CHUNK: if( this->camg == NULL ) - this->camg = (CamgChunk *)xine_xmalloc(sizeof(CamgChunk)); + this->camg = (CamgChunk *)calloc(1, sizeof(CamgChunk)); this->camg->view_modes = _X_BE_32(&buffer[0]); this->bih.biCompression = this->camg->view_modes; if( this->camg->view_modes & CAMG_PAL && @@ -443,7 +443,7 @@ static int read_iff_chunk(demux_iff_t *this) { break; case IFF_CCRT_CHUNK: if( this->ccrt == NULL ) - this->ccrt = (CcrtChunk *)xine_xmalloc(sizeof(CcrtChunk)); + this->ccrt = (CcrtChunk *)calloc(1, sizeof(CcrtChunk)); this->ccrt->direction = _X_BE_16(&buffer[0]); this->ccrt->start = buffer[2]; this->ccrt->end = buffer[3]; @@ -453,13 +453,13 @@ static int read_iff_chunk(demux_iff_t *this) { break; case IFF_DPI_CHUNK: if( this->dpi == NULL ) - this->dpi = (DPIHeader *)xine_xmalloc(sizeof(DPIHeader)); + this->dpi = (DPIHeader *)calloc(1, sizeof(DPIHeader)); this->dpi->x = _X_BE_16(&buffer[0]); this->dpi->y = _X_BE_16(&buffer[0]); break; case IFF_ANHD_CHUNK: if( this->anhd == NULL ) - this->anhd = (AnimHeader *)xine_xmalloc(sizeof(AnimHeader)); + this->anhd = (AnimHeader *)calloc(1, sizeof(AnimHeader)); this->anhd->operation = buffer[0]; this->anhd->mask = buffer[1]; this->anhd->w = _X_BE_16(&buffer[2]); @@ -500,7 +500,7 @@ static int read_iff_chunk(demux_iff_t *this) { break; case IFF_DPAN_CHUNK: if( this->dpan == NULL ) - this->dpan = (DPAnimChunk *)xine_xmalloc(sizeof(DPAnimChunk)); + this->dpan = (DPAnimChunk *)calloc(1, sizeof(DPAnimChunk)); this->dpan->version = _X_BE_16(&buffer[0]); this->dpan->nframes = _X_BE_16(&buffer[2]); this->dpan->fps = buffer[4]; @@ -709,11 +709,19 @@ static int demux_iff_send_chunk(demux_plugin_t *this_gen) { /* load the whole chunk into the buffer */ if (this->audio_buffer_filled == 0) { if (this->audio_interleave_buffer_size > 0) + { this->audio_interleave_buffer = - xine_xmalloc(this->audio_interleave_buffer_size); + calloc(1, this->audio_interleave_buffer_size); + if (!this->audio_interleave_buffer) + return this->status = DEMUX_FINISHED; + } if (this->audio_read_buffer_size > 0) + { this->audio_read_buffer = - xine_xmalloc(this->audio_read_buffer_size); + calloc(1, this->audio_read_buffer_size); + if (!this->audio_read_buffer) + return this->status = DEMUX_FINISHED; + } if (this->audio_read_buffer) { if (this->input->read(this->input, this->audio_read_buffer, this->data_size) != this->data_size) { @@ -1234,7 +1242,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str demux_iff_t *this; - this = xine_xmalloc (sizeof (demux_iff_t)); + this = calloc(1, sizeof(demux_iff_t)); this->stream = stream; this->input = input; @@ -1315,7 +1323,7 @@ static void class_dispose (demux_class_t *this_gen) { static void *init_plugin (xine_t *xine, void *data) { demux_iff_class_t *this; - this = xine_xmalloc (sizeof (demux_iff_class_t)); + this = calloc(1, sizeof(demux_iff_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_image.c b/src/demuxers/demux_image.c index 9f53e4173..08136edba 100644 --- a/src/demuxers/demux_image.c +++ b/src/demuxers/demux_image.c @@ -1,18 +1,18 @@ /* * Copyright (C) 2003-2005 the xine project - * + * * This file is part of xine, a free video player. - * + * * xine is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * xine is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA @@ -82,7 +82,7 @@ static int demux_image_next (demux_plugin_t *this_gen, int preview) { } else { this->status = DEMUX_OK; } - + if (preview) buf->decoder_flags = BUF_FLAG_PREVIEW; @@ -198,7 +198,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, * if we reach this point, the input has been accepted. */ - this = xine_xmalloc (sizeof (demux_image_t)); + this = calloc(1, sizeof(demux_image_t)); this->stream = stream; this->input = input; @@ -211,7 +211,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, this->demux_plugin.get_capabilities = demux_image_get_capabilities; this->demux_plugin.get_optional_data = demux_image_get_optional_data; this->demux_plugin.demux_class = class_gen; - + this->status = DEMUX_FINISHED; this->buf_type = buf_type; @@ -226,7 +226,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, static const char *get_description (demux_class_t *this_gen) { return "image demux plugin"; } - + static const char *get_identifier (demux_class_t *this_gen) { return "imagedmx"; } @@ -249,7 +249,7 @@ static void class_dispose (demux_class_t *this_gen) { static void *init_class (xine_t *xine, void *data) { demux_image_class_t *this; - this = xine_xmalloc (sizeof (demux_image_class_t)); + this = calloc(1, sizeof(demux_image_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_ipmovie.c b/src/demuxers/demux_ipmovie.c index cd21896c0..5b4e12ef8 100644 --- a/src/demuxers/demux_ipmovie.c +++ b/src/demuxers/demux_ipmovie.c @@ -183,7 +183,7 @@ static int process_ipmovie_chunk(demux_ipmovie_t *this) { while ((chunk_size > 0) && (chunk_type != CHUNK_BAD)) { /* read the next chunk, wherever the file happens to be pointing */ - if (this->input->read(this->input, opcode_preamble, + if (this->input->read(this->input, opcode_preamble, OPCODE_PREAMBLE_SIZE) != OPCODE_PREAMBLE_SIZE) { chunk_type = CHUNK_BAD; break; @@ -221,7 +221,7 @@ static int process_ipmovie_chunk(demux_ipmovie_t *this) { chunk_type = CHUNK_BAD; break; } - if (this->input->read(this->input, scratch, opcode_size) != + if (this->input->read(this->input, scratch, opcode_size) != opcode_size) { chunk_type = CHUNK_BAD; break; @@ -239,7 +239,7 @@ static int process_ipmovie_chunk(demux_ipmovie_t *this) { chunk_type = CHUNK_BAD; break; } - if (this->input->read(this->input, scratch, opcode_size) != + if (this->input->read(this->input, scratch, opcode_size) != opcode_size) { chunk_type = CHUNK_BAD; break; @@ -275,7 +275,7 @@ static int process_ipmovie_chunk(demux_ipmovie_t *this) { chunk_type = CHUNK_BAD; break; } - if (this->input->read(this->input, scratch, opcode_size) != + if (this->input->read(this->input, scratch, opcode_size) != opcode_size) { chunk_type = CHUNK_BAD; break; @@ -283,9 +283,10 @@ static int process_ipmovie_chunk(demux_ipmovie_t *this) { this->bih.biWidth = _X_LE_16(&scratch[0]) * 8; this->bih.biHeight = _X_LE_16(&scratch[2]) * 8; /* set up staging area for decode map */ - this->decode_map_size = (this->bih.biWidth * this->bih.biHeight) / - (8 * 8) / 2; + this->decode_map_size = (this->bih.biWidth / 8) * (this->bih.biHeight / 8) / 2; this->decode_map = xine_xmalloc(this->decode_map_size); + if (!this->decode_map) + this->status = DEMUX_FINISHED; lprintf("video resolution: %d x %d\n", this->bih.biWidth, this->bih.biHeight); break; @@ -335,23 +336,23 @@ static int process_ipmovie_chunk(demux_ipmovie_t *this) { buf->extra_info->input_normpos = (int)( (double) current_file_pos * 65535 / this->data_size); buf->extra_info->input_time = audio_pts / 90; buf->pts = audio_pts; - + if (opcode_size > buf->max_size) buf->size = buf->max_size; else buf->size = opcode_size; opcode_size -= buf->size; - + if (this->input->read(this->input, buf->content, buf->size) != buf->size) { buf->free_buffer(buf); chunk_type = CHUNK_BAD; break; } - + if (!opcode_size) buf->decoder_flags |= BUF_FLAG_FRAME_END; - + this->audio_fifo->put (this->audio_fifo, buf); } }else{ @@ -376,7 +377,7 @@ static int process_ipmovie_chunk(demux_ipmovie_t *this) { case OPCODE_SET_PALETTE: lprintf("set palette\n"); - /* check for the logical maximum palette size + /* check for the logical maximum palette size * (3 * 256 + 4 bytes) */ if (opcode_size > 0x304) { lprintf("set_palette opcode too large\n"); @@ -671,7 +672,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str demux_ipmovie_t *this; - this = xine_xmalloc (sizeof (demux_ipmovie_t)); + this = calloc(1, sizeof(demux_ipmovie_t)); this->stream = stream; this->input = input; @@ -746,7 +747,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_ipmovie_init_plugin (xine_t *xine, void *data) { demux_ipmovie_class_t *this; - this = xine_xmalloc (sizeof (demux_ipmovie_class_t)); + this = calloc(1, sizeof(demux_ipmovie_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_matroska-chapters.c b/src/demuxers/demux_matroska-chapters.c new file mode 100644 index 000000000..4bfafe0da --- /dev/null +++ b/src/demuxers/demux_matroska-chapters.c @@ -0,0 +1,433 @@ +/* + * Copyright (C) 2009 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * demultiplexer for matroska streams: chapter handling + * + * TODO: + * - nested chapters + * + * Authors: + * Nicos Gollan <gtdev@spearhead.de> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define LOG_MODULE "demux_matroska_chapters" +#define LOG_VERBOSE +/* +#define LOG +*/ + +#include "xine_internal.h" +#include "xineutils.h" +#include "demux.h" + +#include "ebml.h" +#include "matroska.h" +#include "demux_matroska.h" + +/* TODO: this only handles one single (title, language, country) tuple. + * See the header for information. */ +static int parse_chapter_display(demux_matroska_t *this, matroska_chapter_t *chap, int level) { + ebml_parser_t *ebml = this->ebml; + int next_level = level+1; + char* tmp_name = NULL; + char* tmp_lang = NULL; + char* tmp_country = NULL; + + while (next_level == level+1) { + ebml_elem_t elem; + + if (!ebml_read_elem_head(ebml, &elem)) + return 0; + + switch (elem.id) { + + case MATROSKA_ID_CH_STRING: + tmp_name = ebml_alloc_read_ascii(ebml, &elem); + break; + + case MATROSKA_ID_CH_LANGUAGE: + tmp_lang = ebml_alloc_read_ascii(ebml, &elem); + break; + + case MATROSKA_ID_CH_COUNTRY: + tmp_country = ebml_alloc_read_ascii(ebml, &elem); + break; + + default: + lprintf("Unhandled ID (inside ChapterDisplay): 0x%x\n", elem.id); + if (!ebml_skip(ebml, &elem)) + return 0; + } + + next_level = ebml_get_next_level(ebml, &elem); + } + + if (NULL != chap->title) { + chap->title = tmp_name; + + free(chap->language); + chap->language = tmp_lang; + + free(chap->country); + chap->country = tmp_country; + } else if (tmp_lang != NULL && !strcmp("eng", tmp_lang) && (chap->language == NULL || strcmp("eng", chap->language))) { + free(chap->title); + chap->title = tmp_name; + + free(chap->language); + chap->language = tmp_lang; + + free(chap->country); + chap->country = tmp_country; + } else { + free(tmp_name); + free(tmp_lang); + free(tmp_country); + } + + return 1; +} + +static int parse_chapter_atom(demux_matroska_t *this, matroska_chapter_t *chap, int level) { + ebml_parser_t *ebml = this->ebml; + int next_level = level+1; + uint64_t num; + + chap->time_start = 0; + chap->time_end = 0; + chap->hidden = 0; + chap->enabled = 1; + + while (next_level == level+1) { + ebml_elem_t elem; + + if (!ebml_read_elem_head(ebml, &elem)) { + lprintf("invalid head\n"); + return 0; + } + + switch (elem.id) { + case MATROSKA_ID_CH_UID: + if (!ebml_read_uint(ebml, &elem, &chap->uid)) { + lprintf("invalid UID\n"); + return 0; + } + break; + + case MATROSKA_ID_CH_TIMESTART: + if (!ebml_read_uint(ebml, &elem, &chap->time_start)) { + lprintf("invalid start time\n"); + return 0; + } + /* convert to xine timing: Matroska timestamps are in nanoseconds, + * xine's PTS are in 1/90,000s */ + chap->time_start /= 100000; + chap->time_start *= 9; + break; + + case MATROSKA_ID_CH_TIMEEND: + if (!ebml_read_uint(ebml, &elem, &chap->time_end)) { + lprintf("invalid end time\n"); + return 0; + } + /* convert to xine timing */ + chap->time_end /= 100000; + chap->time_end *= 9; + break; + + case MATROSKA_ID_CH_DISPLAY: + if (!ebml_read_master(ebml, &elem)) + return 0; + + lprintf("ChapterDisplay\n"); + if(!parse_chapter_display(this, chap, level+1)) { + lprintf("invalid display information\n"); + return 0; + } + break; + + case MATROSKA_ID_CH_HIDDEN: + if (!ebml_read_uint(ebml, &elem, &num)) + return 0; + chap->hidden = (int)num; + break; + + case MATROSKA_ID_CH_ENABLED: + if (!ebml_read_uint(ebml, &elem, &num)) + return 0; + chap->enabled = (int)num; + break; + + case MATROSKA_ID_CH_ATOM: /* TODO */ + xprintf(this->stream->xine, XINE_VERBOSITY_NONE, + LOG_MODULE ": Warning: Nested chapters are not supported, playback may suffer!\n"); + if (!ebml_skip(ebml, &elem)) + return 0; + break; + + case MATROSKA_ID_CH_TRACK: /* TODO */ + xprintf(this->stream->xine, XINE_VERBOSITY_NONE, + LOG_MODULE ": Warning: Specific track information in chapters is not supported, playback may suffer!\n"); + if (!ebml_skip(ebml, &elem)) + return 0; + break; + + default: + lprintf("Unhandled ID (inside ChapterAtom): 0x%x\n", elem.id); + if (!ebml_skip(ebml, &elem)) + return 0; + } + + next_level = ebml_get_next_level(ebml, &elem); + } + + /* fallback information */ + /* FIXME: check allocations! */ + if (NULL == chap->title) { + chap->title = malloc(9); + if (chap->title != NULL) + strncpy(chap->title, "No title", 9); + } + + if (NULL == chap->language) { + chap->language = malloc(4); + if (chap->language != NULL) + strncpy(chap->language, "unk", 4); + } + + if (NULL == chap->country) { + chap->country = malloc(3); + if (chap->country != NULL) + strncpy(chap->country, "XX", 3); + } + + lprintf( "Chapter 0x%" PRIx64 ": %" PRIu64 "-%" PRIu64 "(pts), %s (%s). %shidden, %senabled.\n", + chap->uid, chap->time_start, chap->time_end, + chap->title, chap->language, + (chap->hidden ? "" : "not "), + (chap->enabled ? "" : "not ")); + + return 1; +} + +static void free_chapter(demux_matroska_t *this, matroska_chapter_t *chap) { + free(chap->title); + free(chap->language); + free(chap->country); + + free(chap); +} + +static int parse_edition_entry(demux_matroska_t *this, matroska_edition_t *ed) { + ebml_parser_t *ebml = this->ebml; + int next_level = 3; + uint64_t num; + int i; + + ed->hidden = 0; + ed->is_default = 0; + ed->ordered = 0; + + while (next_level == 3) { + ebml_elem_t elem; + + if (!ebml_read_elem_head(ebml, &elem)) + return 0; + + switch (elem.id) { + case MATROSKA_ID_CH_ED_UID: + if (!ebml_read_uint(ebml, &elem, &ed->uid)) + return 0; + break; + + case MATROSKA_ID_CH_ED_HIDDEN: + if (!ebml_read_uint(ebml, &elem, &num)) + return 0; + ed->hidden = (int)num; + break; + + case MATROSKA_ID_CH_ED_DEFAULT: + if (!ebml_read_uint(ebml, &elem, &num)) + return 0; + ed->is_default = (int)num; + break; + + case MATROSKA_ID_CH_ED_ORDERED: + if (!ebml_read_uint(ebml, &elem, &num)) + return 0; + ed->ordered = (int)num; + break; + + case MATROSKA_ID_CH_ATOM: + { + matroska_chapter_t *chapter = calloc(1, sizeof(matroska_chapter_t)); + if (NULL == chapter) + return 0; + + lprintf("ChapterAtom\n"); + if (!ebml_read_master(ebml, &elem)) + return 0; + + if (!parse_chapter_atom(this, chapter, next_level)) + return 0; + + /* resize chapters array if necessary */ + if (ed->num_chapters >= ed->cap_chapters) { + matroska_chapter_t** old_chapters = ed->chapters; + ed->cap_chapters += 10; + ed->chapters = realloc(ed->chapters, ed->cap_chapters * sizeof(matroska_chapter_t*)); + + if (NULL == ed->chapters) { + ed->chapters = old_chapters; + ed->cap_chapters -= 10; + return 0; + } + } + + ed->chapters[ed->num_chapters] = chapter; + ++ed->num_chapters; + + break; + } + + default: + lprintf("Unhandled ID (inside EditionEntry): 0x%x\n", elem.id); + if (!ebml_skip(ebml, &elem)) + return 0; + } + + next_level = ebml_get_next_level(ebml, &elem); + } + + xprintf( this->stream->xine, XINE_VERBOSITY_LOG, + LOG_MODULE ": Edition 0x%" PRIx64 ": %shidden, %sdefault, %sordered. %d chapters:\n", + ed->uid, + (ed->hidden ? "" : "not "), + (ed->is_default ? "" : "not "), + (ed->ordered ? "" : "not "), + ed->num_chapters ); + + for (i=0; i<ed->num_chapters; ++i) { + matroska_chapter_t* chap = ed->chapters[i]; + xprintf( this->stream->xine, XINE_VERBOSITY_LOG, + LOG_MODULE ": Chapter %d: %" PRIu64 "-%" PRIu64 "(pts), %s (%s). %shidden, %senabled.\n", + i+1, chap->time_start, chap->time_end, + chap->title, chap->language, + (chap->hidden ? "" : "not "), + (chap->enabled ? "" : "not ")); + } + + return 1; +} + +static void free_edition(demux_matroska_t *this, matroska_edition_t *ed) { + int i; + + for(i=0; i<ed->num_chapters; ++i) { + free_chapter(this, ed->chapters[i]); + } + free(ed->chapters); + free(ed); +} + +int matroska_parse_chapters(demux_matroska_t *this) { + ebml_parser_t *ebml = this->ebml; + int next_level = 2; + + while (next_level == 2) { + ebml_elem_t elem; + + if (!ebml_read_elem_head(ebml, &elem)) + return 0; + + switch (elem.id) { + case MATROSKA_ID_CH_EDITIONENTRY: + { + matroska_edition_t *edition = calloc(1, sizeof(matroska_edition_t)); + if (NULL == edition) + return 0; + + lprintf("EditionEntry\n"); + if (!ebml_read_master(ebml, &elem)) + return 0; + + if (!parse_edition_entry(this, edition)) + return 0; + + /* resize editions array if necessary */ + if (this->num_editions >= this->cap_editions) { + matroska_edition_t** old_editions = this->editions; + this->cap_editions += 10; + this->editions = realloc(this->editions, this->cap_editions * sizeof(matroska_edition_t*)); + + if (NULL == this->editions) { + this->editions = old_editions; + this->cap_editions -= 10; + return 0; + } + } + + this->editions[this->num_editions] = edition; + ++this->num_editions; + + 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; +} + +void matroska_free_editions(demux_matroska_t *this) { + int i; + + for(i=0; i<this->num_editions; ++i) { + free_edition(this, this->editions[i]); + } + free(this->editions); + this->num_editions = 0; + this->cap_editions = 0; +} + +int matroska_get_chapter(demux_matroska_t *this, uint64_t tc, matroska_edition_t** ed) { + uint64_t block_pts = (tc * this->timecode_scale) / 100000 * 9; + int chapter_idx = 0; + + if (this->num_editions < 1) + return -1; + + while (chapter_idx < (*ed)->num_chapters && block_pts > (*ed)->chapters[chapter_idx]->time_start) + ++chapter_idx; + + if (chapter_idx > 0) + --chapter_idx; + + return chapter_idx; +} diff --git a/src/demuxers/demux_matroska.c b/src/demuxers/demux_matroska.c index b973c1caf..94f47db44 100644 --- a/src/demuxers/demux_matroska.c +++ b/src/demuxers/demux_matroska.c @@ -1,18 +1,18 @@ /* - * Copyright (C) 2000-2007 the xine project - * + * Copyright (C) 2000-2008 the xine project + * * This file is part of xine, a free video player. - * + * * xine is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * xine is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA @@ -42,6 +42,7 @@ /* #define LOG */ + #include "xine_internal.h" #include "xineutils.h" #include "demux.h" @@ -50,96 +51,7 @@ #include "ebml.h" #include "matroska.h" - -#define NUM_PREVIEW_BUFFERS 10 - -#define MAX_STREAMS 128 -#define MAX_FRAMES 32 - -#define WRAP_THRESHOLD 90000 - -#if !defined(MIN) -#define MIN(a, b) ((a)<(b)?(a):(b)) -#endif -#if !defined(MAX) -#define MAX(a, b) ((a)>(b)?(a):(b)) -#endif - -typedef struct { - int track_num; - off_t *pos; - uint64_t *timecode; - int num_entries; - -} matroska_index_t; - -typedef struct { - - demux_plugin_t demux_plugin; - - xine_stream_t *stream; - - input_plugin_t *input; - - int status; - - ebml_parser_t *ebml; - - /* segment element */ - ebml_elem_t segment; - uint64_t timecode_scale; - int duration; /* in millis */ - int preview_sent; - int preview_mode; - - /* meta seek info */ - int has_seekhead; - int seekhead_handled; - - /* seek info */ - matroska_index_t *indexes; - int num_indexes; - int first_cluster_found; - int skip_to_timecode; - int skip_for_track; - - /* tracks */ - int num_tracks; - int num_video_tracks; - int num_audio_tracks; - int num_sub_tracks; - - matroska_track_t *tracks[MAX_STREAMS]; - - /* block */ - uint8_t *block_data; - int block_data_size; - - /* current tracks */ - matroska_track_t *video_track; /* to remove */ - matroska_track_t *audio_track; /* to remove */ - matroska_track_t *sub_track; /* to remove */ - - int send_newpts; - int buf_flag_seek; - - /* seekhead parsing */ - int top_level_list_size; - int top_level_list_max_size; - off_t *top_level_list; - -} demux_matroska_t ; - -typedef struct { - - demux_class_t demux_class; - - /* class-wide, global variables here */ - - xine_t *xine; - -} demux_matroska_class_t; - +#include "demux_matroska.h" static void check_newpts (demux_matroska_t *this, int64_t pts, matroska_track_t *track) { @@ -147,7 +59,7 @@ static void check_newpts (demux_matroska_t *this, int64_t pts, if ((track->track_type == MATROSKA_TRACK_VIDEO) || (track->track_type == MATROSKA_TRACK_AUDIO)) { - + diff = pts - track->last_pts; if (pts && (this->send_newpts || (track->last_pts && abs(diff)>WRAP_THRESHOLD)) ) { @@ -213,10 +125,10 @@ static int parse_info(demux_matroska_t *this) { ebml_parser_t *ebml = this->ebml; int next_level = 2; double duration = 0.0; /* in matroska unit */ - + while (next_level == 2) { ebml_elem_t elem; - + if (!ebml_read_elem_head(ebml, &elem)) return 0; @@ -226,14 +138,22 @@ static int parse_info(demux_matroska_t *this) { if (!ebml_read_uint(ebml, &elem, &this->timecode_scale)) return 0; break; - case MATROSKA_ID_I_DURATION: { - + + case MATROSKA_ID_I_DURATION: lprintf("duration\n"); if (!ebml_read_float(ebml, &elem, &duration)) return 0; - } - break; - + break; + + case MATROSKA_ID_I_TITLE: + lprintf("title\n"); + if (NULL != this->title) + free(this->title); + + this->title = ebml_alloc_read_ascii(ebml, &elem); + _x_meta_info_set_utf8(this->stream, XINE_META_INFO_TITLE, this->title); + break; + default: lprintf("Unhandled ID: 0x%x\n", elem.id); if (!ebml_skip(ebml, &elem)) @@ -247,6 +167,8 @@ static int parse_info(demux_matroska_t *this) { this->duration = (int)(duration * (double)this->timecode_scale / 1000000.0); lprintf("timecode_scale: %" PRId64 "\n", this->timecode_scale); lprintf("duration: %d\n", this->duration); + lprintf("title: %s\n", (NULL != this->title ? this->title : "(none)")); + return 1; } @@ -488,9 +410,9 @@ static int parse_content_encodings (demux_matroska_t *this, matroska_track_t *tr static void init_codec_video(demux_matroska_t *this, matroska_track_t *track) { buf_element_t *buf; - + buf = track->fifo->buffer_pool_alloc (track->fifo); - + if (track->codec_private_len > buf->max_size) { xprintf(this->stream->xine, XINE_VERBOSITY_LOG, "demux_matroska: private decoder data length (%d) is greater than fifo buffer length (%" PRId32 ")\n", @@ -507,20 +429,20 @@ static void init_codec_video(demux_matroska_t *this, matroska_track_t *track) { xine_fast_memcpy (buf->content, track->codec_private, buf->size); else buf->content = NULL; - + if(track->default_duration) { buf->decoder_flags |= BUF_FLAG_FRAMERATE; - buf->decoder_info[0] = (int64_t)track->default_duration * + buf->decoder_info[0] = (int64_t)track->default_duration * (int64_t)90 / (int64_t)1000000; } - - if(track->video_track && track->video_track->display_width && + + if(track->video_track && track->video_track->display_width && track->video_track->display_height) { buf->decoder_flags |= BUF_FLAG_ASPECT; buf->decoder_info[1] = track->video_track->display_width; buf->decoder_info[2] = track->video_track->display_height; } - + track->fifo->put (track->fifo, buf); } @@ -538,7 +460,7 @@ static void init_codec_audio(demux_matroska_t *this, matroska_track_t *track) { return; } buf->size = track->codec_private_len; - + /* default param */ buf->decoder_info[0] = 0; buf->decoder_info[1] = 44100; @@ -570,9 +492,9 @@ static void init_codec_audio(demux_matroska_t *this, matroska_track_t *track) { static void init_codec_real(demux_matroska_t *this, matroska_track_t * track) { buf_element_t *buf; - + buf = track->fifo->buffer_pool_alloc (track->fifo); - + if (track->codec_private_len > buf->max_size) { xprintf(this->stream->xine, XINE_VERBOSITY_LOG, "demux_matroska: private decoder data length (%d) is greater than fifo buffer length (%" PRId32 ")\n", @@ -580,30 +502,30 @@ static void init_codec_real(demux_matroska_t *this, matroska_track_t * track) { buf->free_buffer(buf); return; } - + buf->size = track->codec_private_len; buf->decoder_flags = BUF_FLAG_HEADER | BUF_FLAG_FRAME_END; buf->type = track->buf_type; buf->pts = 0; - + if (buf->size) xine_fast_memcpy (buf->content, track->codec_private, buf->size); else buf->content = NULL; - + if(track->default_duration) { buf->decoder_flags |= BUF_FLAG_FRAMERATE; - buf->decoder_info[0] = (int64_t)track->default_duration * + buf->decoder_info[0] = (int64_t)track->default_duration * (int64_t)90 / (int64_t)1000000; } - - if(track->video_track && track->video_track->display_width && + + if(track->video_track && track->video_track->display_width && track->video_track->display_height) { buf->decoder_flags |= BUF_FLAG_ASPECT; buf->decoder_info[1] = track->video_track->display_width; buf->decoder_info[2] = track->video_track->display_height; } - + track->fifo->put (track->fifo, buf); } @@ -614,6 +536,8 @@ static void init_codec_xiph(demux_matroska_t *this, matroska_track_t *track) { int i; uint8_t *data; + if (track->codec_private_len < 3) + return; nb_lace = track->codec_private[0]; if (nb_lace != 2) return; @@ -621,11 +545,13 @@ static void init_codec_xiph(demux_matroska_t *this, matroska_track_t *track) { frame[0] = track->codec_private[1]; frame[1] = track->codec_private[2]; frame[2] = track->codec_private_len - frame[0] - frame[1] - 3; + if (frame[2] < 0) + return; data = track->codec_private + 3; for (i = 0; i < 3; i++) { buf = track->fifo->buffer_pool_alloc (track->fifo); - + if (frame[i] > buf->max_size) { xprintf(this->stream->xine, XINE_VERBOSITY_LOG, "demux_matroska: private decoder data length (%d) is greater than fifo buffer length (%" PRId32 ")\n", @@ -634,10 +560,8 @@ static void init_codec_xiph(demux_matroska_t *this, matroska_track_t *track) { return; } buf->size = frame[i]; - - buf->decoder_flags = BUF_FLAG_HEADER; - if (i == 2) - buf->decoder_flags |= BUF_FLAG_FRAME_END; + + buf->decoder_flags = BUF_FLAG_HEADER | BUF_FLAG_FRAME_START | BUF_FLAG_FRAME_END; buf->type = track->buf_type; buf->pts = 0; @@ -685,7 +609,11 @@ static void init_codec_aac(demux_matroska_t *this, matroska_track_t *track) { /* Create a DecoderSpecificInfo for initialising libfaad */ sr_index = aac_get_sr_index(atrack->sampling_freq); - if (!strncmp (&track->codec_id[12], "MAIN", 4)) + /* newer specification with appended CodecPrivate */ + if (strlen(track->codec_id) <= 12) + profile = 3; + /* older specification */ + else if (!strncmp (&track->codec_id[12], "MAIN", 4)) profile = 0; else if (!strncmp (&track->codec_id[12], "LC", 2)) profile = 1; @@ -884,7 +812,7 @@ static void init_codec_vobsub(demux_matroska_t *this, static void handle_realvideo (demux_plugin_t *this_gen, matroska_track_t *track, int decoder_flags, - uint8_t *data, int data_len, + uint8_t *data, size_t data_len, int64_t data_pts, int data_duration, int input_normpos, int input_time) { demux_matroska_t *this = (demux_matroska_t *) this_gen; @@ -921,7 +849,7 @@ static void handle_realvideo (demux_plugin_t *this_gen, matroska_track_t *track, buf->decoder_info[1] = BUF_SPECIAL_RV_CHUNK_TABLE; buf->decoder_info[2] = chunks; buf->decoder_info_ptr[2] = buf->content; - + buf->size = 0; buf->type = track->buf_type; @@ -933,7 +861,7 @@ static void handle_realvideo (demux_plugin_t *this_gen, matroska_track_t *track, static void handle_sub_ssa (demux_plugin_t *this_gen, matroska_track_t *track, int decoder_flags, - uint8_t *data, int data_len, + uint8_t *data, size_t data_len, int64_t data_pts, int data_duration, int input_normpos, int input_time) { buf_element_t *buf; @@ -988,7 +916,7 @@ static void handle_sub_ssa (demux_plugin_t *this_gen, matroska_track_t *track, } } } - + last_char = *data; data++; data_len--; } @@ -999,16 +927,16 @@ static void handle_sub_ssa (demux_plugin_t *this_gen, matroska_track_t *track, buf->size = dest - (char *)buf->content; buf->extra_info->input_normpos = input_normpos; buf->extra_info->input_time = input_time; - + track->fifo->put(track->fifo, buf); } else { buf->free_buffer(buf); - } + } } static void handle_sub_utf8 (demux_plugin_t *this_gen, matroska_track_t *track, int decoder_flags, - uint8_t *data, int data_len, + uint8_t *data, size_t data_len, int64_t data_pts, int data_duration, int input_normpos, int input_time) { demux_matroska_t *this = (demux_matroska_t *) this_gen; @@ -1018,7 +946,7 @@ static void handle_sub_utf8 (demux_plugin_t *this_gen, matroska_track_t *track, buf = track->fifo->buffer_pool_alloc(track->fifo); buf->size = data_len + 9; /* 2 uint32_t + '\0' */ - + if (buf->max_size >= buf->size) { buf->decoder_flags = decoder_flags; @@ -1027,7 +955,7 @@ static void handle_sub_utf8 (demux_plugin_t *this_gen, matroska_track_t *track, buf->decoder_info[1] = BUF_SPECIAL_CHARSET_ENCODING; buf->decoder_info_ptr[2] = "utf-8"; buf->decoder_info[2] = strlen(buf->decoder_info_ptr[2]); - + val = (uint32_t *)buf->content; *val++ = data_pts / 90; /* start time */ *val++ = (data_pts + data_duration) / 90; /* end time */ @@ -1055,7 +983,7 @@ static void handle_sub_utf8 (demux_plugin_t *this_gen, matroska_track_t *track, */ static void handle_vobsub (demux_plugin_t *this_gen, matroska_track_t *track, int decoder_flags, - uint8_t *data, int data_len, + uint8_t *data, size_t data_len, int64_t data_pts, int data_duration, int input_normpos, int input_time) { demux_matroska_t *this = (demux_matroska_t *) this_gen; @@ -1092,7 +1020,7 @@ static void handle_vobsub (demux_plugin_t *this_gen, matroska_track_t *track, (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; @@ -1105,11 +1033,11 @@ static void handle_vobsub (demux_plugin_t *this_gen, matroska_track_t *track, 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", @@ -1152,120 +1080,140 @@ static void handle_vobsub (demux_plugin_t *this_gen, matroska_track_t *track, static int parse_track_entry(demux_matroska_t *this, matroska_track_t *track) { ebml_parser_t *ebml = this->ebml; int next_level = 3; - + while (next_level == 3) { ebml_elem_t elem; - + if (!ebml_read_elem_head(ebml, &elem)) return 0; switch (elem.id) { - case MATROSKA_ID_TR_NUMBER: { - uint64_t num; - lprintf("TrackNumber\n"); - if (!ebml_read_uint(ebml, &elem, &num)) - return 0; - track->track_num = num; - } - break; - - case MATROSKA_ID_TR_TYPE: { - uint64_t num; - lprintf("TrackType\n"); - if (!ebml_read_uint(ebml, &elem, &num)) - return 0; - track->track_type = num; - } - break; - - case MATROSKA_ID_TR_CODECID: { - char *codec_id = malloc (elem.len + 1); - lprintf("CodecID\n"); - if (!ebml_read_ascii(ebml, &elem, codec_id)) { - free(codec_id); - return 0; - } - codec_id[elem.len] = '\0'; - track->codec_id = codec_id; - } - break; - - case MATROSKA_ID_TR_CODECPRIVATE: { - char *codec_private = malloc (elem.len); - lprintf("CodecPrivate\n"); - if (!ebml_read_binary(ebml, &elem, codec_private)) { - free(codec_private); - return 0; - } - track->codec_private = codec_private; - track->codec_private_len = elem.len; - } - break; - - case MATROSKA_ID_TR_LANGUAGE: { - char *language = malloc (elem.len + 1); - lprintf("Language\n"); - if (!ebml_read_ascii(ebml, &elem, language)) { - free(language); - return 0; - } - language[elem.len] = '\0'; - track->language = language; - } - break; - + case MATROSKA_ID_TR_NUMBER: + { + uint64_t num; + lprintf("TrackNumber\n"); + if (!ebml_read_uint(ebml, &elem, &num)) + return 0; + track->track_num = num; + } + break; + + case MATROSKA_ID_TR_TYPE: + { + uint64_t num; + lprintf("TrackType\n"); + if (!ebml_read_uint(ebml, &elem, &num)) + return 0; + track->track_type = num; + } + break; + + case MATROSKA_ID_TR_CODECID: + { + char *codec_id = ebml_alloc_read_ascii (ebml, &elem); + lprintf("CodecID\n"); + if (!codec_id) + return 0; + track->codec_id = codec_id; + } + break; + + case MATROSKA_ID_TR_CODECPRIVATE: + { + char *codec_private; + if (elem.len >= 0x80000000) + return 0; + codec_private = malloc (elem.len); + if (! codec_private) + return 0; + lprintf("CodecPrivate\n"); + if (!ebml_read_binary(ebml, &elem, codec_private)) { + free(codec_private); + return 0; + } + track->codec_private = codec_private; + track->codec_private_len = elem.len; + } + break; + + case MATROSKA_ID_TR_LANGUAGE: + { + char *language = ebml_alloc_read_ascii (ebml, &elem); + lprintf("Language\n"); + if (!language) + return 0; + track->language = language; + } + break; + case MATROSKA_ID_TV: lprintf("Video\n"); if (track->video_track) return 1; - track->video_track = (matroska_video_track_t *)xine_xmalloc(sizeof(matroska_video_track_t)); + track->video_track = (matroska_video_track_t *)calloc(1, sizeof(matroska_video_track_t)); if (!ebml_read_master (ebml, &elem)) return 0; if ((elem.len > 0) && !parse_video_track(this, track->video_track)) return 0; - break; - + break; + case MATROSKA_ID_TA: lprintf("Audio\n"); if (track->audio_track) return 1; - track->audio_track = (matroska_audio_track_t *)xine_xmalloc(sizeof(matroska_audio_track_t)); + track->audio_track = (matroska_audio_track_t *)calloc(1, sizeof(matroska_audio_track_t)); if (!ebml_read_master (ebml, &elem)) return 0; if ((elem.len > 0) && !parse_audio_track(this, track->audio_track)) return 0; - break; - - case MATROSKA_ID_TR_FLAGDEFAULT: { - uint64_t val; - - lprintf("Default\n"); - if (!ebml_read_uint(ebml, &elem, &val)) - return 0; - track->default_flag = (int)val; - } - break; + break; - case MATROSKA_ID_TR_DEFAULTDURATION: { - uint64_t val; + case MATROSKA_ID_TR_FLAGDEFAULT: + { + uint64_t val; - if (!ebml_read_uint(ebml, &elem, &val)) - return 0; - track->default_duration = val; - lprintf("Default Duration: %"PRIu64"\n", track->default_duration); - } - break; + lprintf("Default\n"); + if (!ebml_read_uint(ebml, &elem, &val)) + return 0; + track->default_flag = (int)val; + } + 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_DEFAULTDURATION: + { + uint64_t val; + + if (!ebml_read_uint(ebml, &elem, &val)) + return 0; + track->default_duration = val; + 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; case MATROSKA_ID_TR_UID: + { + uint64_t val; + + if (!ebml_read_uint(ebml, &elem, &val)) { + lprintf("Track UID (invalid)\n"); + return 0; + } + + track->uid = val; + lprintf("Track UID: 0x%" PRIx64 "\n", track->uid); + } + break; + case MATROSKA_ID_TR_FLAGENABLED: case MATROSKA_ID_TR_FLAGLACING: case MATROSKA_ID_TR_MINCACHE: @@ -1286,68 +1234,76 @@ static int parse_track_entry(demux_matroska_t *this, matroska_track_t *track) { } next_level = ebml_get_next_level(ebml, &elem); } - + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, - "demux_matroska: Track %d, %s %s\n", - track->track_num, - (track->codec_id ? track->codec_id : ""), - (track->language ? track->language : "")); + "demux_matroska: Track %d, %s %s\n", + track->track_num, + (track->codec_id ? track->codec_id : ""), + (track->language ? track->language : "")); if (track->codec_id) { void (*init_codec)(demux_matroska_t *, matroska_track_t *) = NULL; if (!strcmp(track->codec_id, MATROSKA_CODEC_ID_V_VFW_FOURCC)) { xine_bmiheader *bih; - lprintf("MATROSKA_CODEC_ID_V_VFW_FOURCC\n"); - bih = (xine_bmiheader*)track->codec_private; - _x_bmiheader_le2me(bih); + if (track->codec_private_len >= sizeof(xine_bmiheader)) { + lprintf("MATROSKA_CODEC_ID_V_VFW_FOURCC\n"); + bih = (xine_bmiheader*)track->codec_private; + _x_bmiheader_le2me(bih); - track->buf_type = _x_fourcc_to_buf_video(bih->biCompression); - init_codec = init_codec_video; + track->buf_type = _x_fourcc_to_buf_video(bih->biCompression); + init_codec = init_codec_video; + } } else if (!strcmp(track->codec_id, MATROSKA_CODEC_ID_V_UNCOMPRESSED)) { } else if ((!strcmp(track->codec_id, MATROSKA_CODEC_ID_V_MPEG4_SP)) || - (!strcmp(track->codec_id, MATROSKA_CODEC_ID_V_MPEG4_ASP)) || - (!strcmp(track->codec_id, MATROSKA_CODEC_ID_V_MPEG4_AP))) { + (!strcmp(track->codec_id, MATROSKA_CODEC_ID_V_MPEG4_ASP)) || + (!strcmp(track->codec_id, MATROSKA_CODEC_ID_V_MPEG4_AP))) { xine_bmiheader *bih; - + lprintf("MATROSKA_CODEC_ID_V_MPEG4_*\n"); + if (track->codec_private_len > 0x7fffffff - sizeof(xine_bmiheader)) + track->codec_private_len = 0x7fffffff - sizeof(xine_bmiheader); + /* create a bitmap info header struct for MPEG 4 */ - bih = malloc(sizeof(xine_bmiheader) + track->codec_private_len); + bih = calloc(1, sizeof(xine_bmiheader) + track->codec_private_len); bih->biSize = sizeof(xine_bmiheader) + track->codec_private_len; bih->biCompression = ME_FOURCC('M', 'P', '4', 'S'); bih->biWidth = track->video_track->pixel_width; bih->biHeight = track->video_track->pixel_height; _x_bmiheader_le2me(bih); - + /* add bih extra data */ memcpy(bih + 1, track->codec_private, track->codec_private_len); free(track->codec_private); track->codec_private = (uint8_t *)bih; track->codec_private_len = bih->biSize; track->buf_type = BUF_VIDEO_MPEG4; - + /* init as a vfw decoder */ init_codec = init_codec_video; } else if (!strcmp(track->codec_id, MATROSKA_CODEC_ID_V_MPEG4_AVC)) { xine_bmiheader *bih; - + lprintf("MATROSKA_CODEC_ID_V_MPEG4_AVC\n"); + if (track->codec_private_len > 0x7fffffff - sizeof(xine_bmiheader)) + track->codec_private_len = 0x7fffffff - sizeof(xine_bmiheader); + /* create a bitmap info header struct for h264 */ - bih = malloc(sizeof(xine_bmiheader) + track->codec_private_len); + bih = calloc(1, sizeof(xine_bmiheader) + track->codec_private_len); bih->biSize = sizeof(xine_bmiheader) + track->codec_private_len; bih->biCompression = ME_FOURCC('a', 'v', 'c', '1'); bih->biWidth = track->video_track->pixel_width; bih->biHeight = track->video_track->pixel_height; _x_bmiheader_le2me(bih); - + /* add bih extra data */ memcpy(bih + 1, track->codec_private, track->codec_private_len); free(track->codec_private); track->codec_private = (uint8_t *)bih; track->codec_private_len = bih->biSize; track->buf_type = BUF_VIDEO_H264; - + /* init as a vfw decoder */ init_codec = init_codec_video; } else if (!strcmp(track->codec_id, MATROSKA_CODEC_ID_V_MSMPEG4V3)) { @@ -1368,7 +1324,7 @@ static int parse_track_entry(demux_matroska_t *this, matroska_track_t *track) { track->handle_content = handle_realvideo; init_codec = init_codec_real; } else if (!strcmp(track->codec_id, MATROSKA_CODEC_ID_V_REAL_RV40)) { - + lprintf("MATROSKA_CODEC_ID_V_REAL_RV40\n"); track->buf_type = BUF_VIDEO_RV40; track->handle_content = handle_realvideo; @@ -1380,8 +1336,8 @@ static int parse_track_entry(demux_matroska_t *this, matroska_track_t *track) { track->buf_type = BUF_VIDEO_THEORA_RAW; init_codec = init_codec_xiph; } else if ((!strcmp(track->codec_id, MATROSKA_CODEC_ID_A_MPEG1_L1)) || - (!strcmp(track->codec_id, MATROSKA_CODEC_ID_A_MPEG1_L2)) || - (!strcmp(track->codec_id, MATROSKA_CODEC_ID_A_MPEG1_L3))) { + (!strcmp(track->codec_id, MATROSKA_CODEC_ID_A_MPEG1_L2)) || + (!strcmp(track->codec_id, MATROSKA_CODEC_ID_A_MPEG1_L3))) { lprintf("MATROSKA_CODEC_ID_A_MPEG1\n"); track->buf_type = BUF_AUDIO_MPEG; init_codec = init_codec_audio; @@ -1393,7 +1349,7 @@ static int parse_track_entry(demux_matroska_t *this, matroska_track_t *track) { lprintf("MATROSKA_CODEC_ID_A_AC3\n"); track->buf_type = BUF_AUDIO_A52; 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; @@ -1409,13 +1365,15 @@ static int parse_track_entry(demux_matroska_t *this, matroska_track_t *track) { xine_waveformatex *wfh; lprintf("MATROSKA_CODEC_ID_A_ACM\n"); - wfh = (xine_waveformatex*)track->codec_private; - _x_waveformatex_le2me(wfh); + if (track->codec_private_len >= sizeof(xine_waveformatex)) { + wfh = (xine_waveformatex*)track->codec_private; + _x_waveformatex_le2me(wfh); - track->buf_type = _x_formattag_to_buf_audio(wfh->wFormatTag); - init_codec = init_codec_audio; + track->buf_type = _x_formattag_to_buf_audio(wfh->wFormatTag); + init_codec = init_codec_audio; + } } else if (!strncmp(track->codec_id, MATROSKA_CODEC_ID_A_AAC, - sizeof(MATROSKA_CODEC_ID_A_AAC) - 1)) { + sizeof(MATROSKA_CODEC_ID_A_AAC) - 1)) { lprintf("MATROSKA_CODEC_ID_A_AAC\n"); track->buf_type = BUF_AUDIO_AAC; init_codec = init_codec_aac; @@ -1435,17 +1393,17 @@ static int parse_track_entry(demux_matroska_t *this, matroska_track_t *track) { track->buf_type = BUF_AUDIO_ATRK; init_codec = init_codec_real; } else if (!strcmp(track->codec_id, MATROSKA_CODEC_ID_S_TEXT_UTF8) || - !strcmp(track->codec_id, MATROSKA_CODEC_ID_S_UTF8)) { + !strcmp(track->codec_id, MATROSKA_CODEC_ID_S_UTF8)) { lprintf("MATROSKA_CODEC_ID_S_TEXT_UTF8\n"); track->buf_type = BUF_SPU_OGM; track->handle_content = handle_sub_utf8; } else if (!strcmp(track->codec_id, MATROSKA_CODEC_ID_S_TEXT_SSA) || - !strcmp(track->codec_id, MATROSKA_CODEC_ID_S_SSA)) { + !strcmp(track->codec_id, MATROSKA_CODEC_ID_S_SSA)) { lprintf("MATROSKA_CODEC_ID_S_TEXT_SSA\n"); track->buf_type = BUF_SPU_OGM; track->handle_content = handle_sub_ssa; } else if (!strcmp(track->codec_id, MATROSKA_CODEC_ID_S_TEXT_ASS) || - !strcmp(track->codec_id, MATROSKA_CODEC_ID_S_ASS)) { + !strcmp(track->codec_id, MATROSKA_CODEC_ID_S_ASS)) { lprintf("MATROSKA_CODEC_ID_S_TEXT_ASS\n"); track->buf_type = BUF_SPU_OGM; track->handle_content = handle_sub_ssa; @@ -1458,7 +1416,7 @@ 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. @@ -1494,12 +1452,17 @@ static int parse_track_entry(demux_matroska_t *this, matroska_track_t *track) { break; } - if (init_codec) + if (init_codec) { + if (! track->fifo) { + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + "demux_matroska: Error: fifo not set up for track of type type %" PRIu32 "\n", track->track_type); + return 0; + } init_codec(this, track); - + } } } - + return 1; } @@ -1507,10 +1470,10 @@ static int parse_track_entry(demux_matroska_t *this, matroska_track_t *track) { static int parse_tracks(demux_matroska_t *this) { ebml_parser_t *ebml = this->ebml; int next_level = 2; - + while (next_level == 2) { ebml_elem_t elem; - + if (!ebml_read_elem_head(ebml, &elem)) return 0; @@ -1518,8 +1481,14 @@ static int parse_tracks(demux_matroska_t *this) { case MATROSKA_ID_TR_ENTRY: { matroska_track_t *track; + /* bail out early if no more tracks can be handled! */ + if (this->num_tracks >= MAX_STREAMS) { + lprintf("Too many tracks!\n"); + return 0; + } + /* alloc and initialize a track with 0 */ - track = xine_xmalloc(sizeof(matroska_track_t)); + track = calloc(1, sizeof(matroska_track_t)); track->compress_algo = MATROSKA_COMPRESS_NONE; this->tracks[this->num_tracks] = track; @@ -1531,29 +1500,7 @@ static int parse_tracks(demux_matroska_t *this) { this->num_tracks++; } 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_chapters(demux_matroska_t *this) { - ebml_parser_t *ebml = this->ebml; - int next_level = 2; - - while (next_level == 2) { - ebml_elem_t elem; - - if (!ebml_read_elem_head(ebml, &elem)) - return 0; - - switch (elem.id) { default: lprintf("Unhandled ID: 0x%x\n", elem.id); if (!ebml_skip(ebml, &elem)) @@ -1564,15 +1511,14 @@ static int parse_chapters(demux_matroska_t *this) { return 1; } - static int parse_cue_trackposition(demux_matroska_t *this, int *track_num, int64_t *pos) { 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; @@ -1609,10 +1555,10 @@ static int parse_cue_point(demux_matroska_t *this) { int next_level = 3; int64_t timecode = -1, pos = -1; int track_num = -1; - + while (next_level == 3) { ebml_elem_t elem; - + if (!ebml_read_elem_head(ebml, &elem)) return 0; @@ -1677,10 +1623,10 @@ static int parse_cue_point(demux_matroska_t *this) { static int parse_cues(demux_matroska_t *this) { ebml_parser_t *ebml = this->ebml; int next_level = 2; - + while (next_level == 2) { ebml_elem_t elem; - + if (!ebml_read_elem_head(ebml, &elem)) return 0; @@ -1706,10 +1652,10 @@ static int parse_cues(demux_matroska_t *this) { static int parse_attachments(demux_matroska_t *this) { ebml_parser_t *ebml = this->ebml; int next_level = 2; - + while (next_level == 2) { ebml_elem_t elem; - + if (!ebml_read_elem_head(ebml, &elem)) return 0; @@ -1728,10 +1674,10 @@ static int parse_attachments(demux_matroska_t *this) { static int parse_tags(demux_matroska_t *this) { ebml_parser_t *ebml = this->ebml; int next_level = 2; - + while (next_level == 2) { ebml_elem_t elem; - + if (!ebml_read_elem_head(ebml, &elem)) return 0; @@ -1746,7 +1692,7 @@ static int parse_tags(demux_matroska_t *this) { return 1; } -static void alloc_block_data (demux_matroska_t *this, int len) { +static void alloc_block_data (demux_matroska_t *this, size_t len) { /* memory management */ if (this->block_data_size < len) { if (this->block_data) @@ -1770,7 +1716,7 @@ static int parse_ebml_uint(demux_matroska_t *this, uint8_t *data, uint64_t *num) } if (size > 8) { off_t pos = this->input->get_current_pos(this->input); - xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, "demux_matroska: Invalid Track Number at position %" PRIdMAX "\n", (intmax_t)pos); return 0; @@ -1799,7 +1745,7 @@ static int parse_ebml_sint(demux_matroska_t *this, uint8_t *data, int64_t *num) *num = -1; else *num = unum - ((1 << ((7 * size) - 1)) - 1); - + return size; } @@ -1818,10 +1764,15 @@ static int find_track_by_id(demux_matroska_t *this, int track_num, } -static int read_block_data (demux_matroska_t *this, int len) { +static int read_block_data (demux_matroska_t *this, size_t len) { alloc_block_data(this, len); /* block datas */ + if (! this->block_data) { + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + "demux_matroska: memory allocation error\n"); + return 0; + } if (this->input->read(this->input, this->block_data, len) != len) { off_t pos = this->input->get_current_pos(this->input); xprintf(this->stream->xine, XINE_VERBOSITY_LOG, @@ -1832,15 +1783,24 @@ static int read_block_data (demux_matroska_t *this, int len) { return 1; } -static int parse_block (demux_matroska_t *this, uint64_t block_size, +static int parse_int16(uint8_t *data) { + int value = (int)_X_BE_16(data); + if (value & 1<<15) + { + value -= 1<<16; + } + return value; +} + +static int parse_block (demux_matroska_t *this, size_t block_size, uint64_t cluster_timecode, uint64_t block_duration, int normpos, int is_key) { matroska_track_t *track; - int64_t track_num; + uint64_t track_num; uint8_t *data; uint8_t flags; int gap, lacing, num_len; - int timecode_diff; + int16_t timecode_diff; int64_t pts, xduration; int decoder_flags = 0; @@ -1848,14 +1808,15 @@ static int parse_block (demux_matroska_t *this, uint64_t block_size, if (!(num_len = parse_ebml_uint(this, data, &track_num))) return 0; data += num_len; - - timecode_diff = (int)_X_BE_16(data); + + /* timecode_diff is signed */ + timecode_diff = (int16_t)parse_int16(data); data += 2; flags = *data; data += 1; - - lprintf("track_num: %" PRId64 ", timecode_diff: %d, flags: 0x%x\n", track_num, timecode_diff, flags); + + lprintf("track_num: %" PRIu64 ", timecode_diff: %d, flags: 0x%x\n", track_num, timecode_diff, flags); gap = flags & 1; lacing = (flags >> 1) & 0x3; @@ -1863,7 +1824,7 @@ static int parse_block (demux_matroska_t *this, uint64_t block_size, if (!find_track_by_id(this, (int)track_num, &track)) { xprintf(this->stream->xine, XINE_VERBOSITY_LOG, - "demux_matroska: invalid track id: %" PRId64 "\n", track_num); + "demux_matroska: invalid track id: %" PRIu64 "\n", track_num); return 0; } @@ -1897,11 +1858,11 @@ static int parse_block (demux_matroska_t *this, uint64_t block_size, } if (lacing == MATROSKA_NO_LACING) { - int block_size_left; + size_t block_size_left; lprintf("no lacing\n"); block_size_left = (this->block_data + block_size) - data; - lprintf("size: %d, block_size: %" PRIu64 "\n", block_size_left, block_size); + lprintf("size: %d, block_size: %u\n", block_size_left, block_size); if (track->handle_content != NULL) { track->handle_content((demux_plugin_t *)this, track, @@ -1917,9 +1878,9 @@ static int parse_block (demux_matroska_t *this, uint64_t block_size, } } else { - int block_size_left; + size_t block_size_left; uint8_t lace_num; - int frame[MAX_FRAMES]; + size_t frame[MAX_FRAMES]; int i; /* number of laced frames */ @@ -1961,7 +1922,7 @@ static int parse_block (demux_matroska_t *this, uint64_t block_size, int frame_size; lprintf("fixed size lacing\n"); - + frame_size = block_size_left / (lace_num + 1); for (i = 0; i < lace_num; i++) { frame[i] = frame_size; @@ -1972,24 +1933,51 @@ static int parse_block (demux_matroska_t *this, uint64_t block_size, break; case MATROSKA_EBML_LACING: { - int64_t tmp; + uint64_t first_frame_size; lprintf("ebml lacing\n"); /* size of each frame */ - if (!(num_len = parse_ebml_uint(this, data, &tmp))) + if (!(num_len = parse_ebml_uint(this, data, &first_frame_size))) + return 0; + if (num_len > block_size_left) { + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + "demux_matroska: block too small\n"); return 0; + } + if (first_frame_size > INT_MAX) { + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + "demux_matroska: invalid first frame size (%" PRId64 ")\n", + first_frame_size); + return 0; + } data += num_len; block_size_left -= num_len; - frame[0] = (int) tmp; + frame[0] = (int) first_frame_size; lprintf("first frame len: %d\n", frame[0]); block_size_left -= frame[0]; for (i = 1; i < lace_num; i++) { - if (!(num_len = parse_ebml_sint(this, data, &tmp))) + int64_t frame_size_diff; + int64_t frame_size; + + if (!(num_len = parse_ebml_sint(this, data, &frame_size_diff))) return 0; + if (num_len > block_size_left) { + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + "demux_matroska: block too small\n"); + return 0; + } data += num_len; block_size_left -= num_len; - frame[i] = frame[i-1] + tmp; + + frame_size = frame[i-1] + frame_size_diff; + if (frame_size > INT_MAX || frame_size < 0) { + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + "demux_matroska: invalid frame size (%" PRId64 ")\n", + frame_size); + return 0; + } + frame[i] = frame_size; block_size_left -= frame[i]; } @@ -2023,6 +2011,31 @@ static int parse_block (demux_matroska_t *this, uint64_t block_size, return 1; } +static int parse_simpleblock(demux_matroska_t *this, size_t block_len, uint64_t cluster_timecode, uint64_t block_duration) +{ + int has_block = 0; + off_t block_pos = 0; + off_t file_len = 0; + int normpos = 0; + int is_key = 1; + + lprintf("simpleblock\n"); + block_pos = this->input->get_current_pos(this->input); + file_len = this->input->get_length(this->input); + if( file_len ) + normpos = (int) ( (double) block_pos * 65535 / file_len ); + + if (!read_block_data(this, block_len)) + return 0; + + has_block = 1; + /* we have the duration, we can parse the block now */ + if (!parse_block(this, block_len, cluster_timecode, block_duration, + normpos, is_key)) + return 0; + return 1; +} + static int parse_block_group(demux_matroska_t *this, uint64_t cluster_timecode, uint64_t cluster_duration) { @@ -2033,7 +2046,7 @@ static int parse_block_group(demux_matroska_t *this, off_t block_pos = 0; off_t file_len = 0; int normpos = 0; - int block_len = 0; + size_t block_len = 0; int is_key = 1; while (next_level == 3) { @@ -2085,9 +2098,52 @@ static int parse_block_group(demux_matroska_t *this, return 1; } +static int demux_matroska_seek (demux_plugin_t*, off_t, int, int); + +static void handle_events(demux_matroska_t *this) { + xine_event_t* event; + + while ((event = xine_event_get(this->event_queue))) { + if (this->num_editions > 0) { + matroska_edition_t* ed = this->editions[0]; + int chapter_idx = matroska_get_chapter(this, this->last_timecode, &ed); + uint64_t next_time; + + if (chapter_idx < 0) { + xine_event_free(event); + continue; + } + + switch(event->type) { + case XINE_EVENT_INPUT_NEXT: + if (chapter_idx < ed->num_chapters-1) { + next_time = ed->chapters[chapter_idx+1]->time_start / 90; + demux_matroska_seek((demux_plugin_t*)this, 0, next_time, 1); + } + break; + + /* TODO: should this try to implement common "start of chapter" + * functionality? */ + case XINE_EVENT_INPUT_PREVIOUS: + if (chapter_idx > 0) { + next_time = ed->chapters[chapter_idx-1]->time_start / 90; + demux_matroska_seek((demux_plugin_t*)this, 0, next_time, 1); + } + break; + + default: + break; + } + } + + xine_event_free(event); + } +} + static int parse_cluster(demux_matroska_t *this) { ebml_parser_t *ebml = this->ebml; - int next_level = 2; + int this_level = ebml->level; + int next_level = this_level; uint64_t timecode = 0; uint64_t duration = 0; @@ -2104,7 +2160,9 @@ static int parse_cluster(demux_matroska_t *this) { this->first_cluster_found = 1; } - while (next_level == 2) { + handle_events(this); + + while (next_level == this_level) { ebml_elem_t elem; if (!ebml_read_elem_head(ebml, &elem)) @@ -2128,6 +2186,11 @@ static int parse_cluster(demux_matroska_t *this) { if ((elem.len > 0) && !parse_block_group(this, timecode, duration)) return 0; break; + case MATROSKA_ID_CL_SIMPLEBLOCK: + lprintf("simpleblock\n"); + if (!parse_simpleblock(this, elem.len, timecode, duration)) + return 0; + break; case MATROSKA_ID_CL_BLOCK: lprintf("block\n"); if (!ebml_skip(ebml, &elem)) @@ -2140,6 +2203,49 @@ static int parse_cluster(demux_matroska_t *this) { } next_level = ebml_get_next_level(ebml, &elem); } + + /* at this point, we MUST have a timecode (according to format spec). + * Use that to find the chapter we are in, and adjust the title. + * + * TODO: this only looks at the chapters in the first edition. + */ + + this->last_timecode = timecode; + + if (this->num_editions <= 0) + return 1; + matroska_edition_t *ed = this->editions[0]; + + if (ed->num_chapters <= 0) + return 1; + + /* fix up a makeshift title if none has been set yet (e.g. filename) */ + if (NULL == this->title && NULL != _x_meta_info_get(this->stream, XINE_META_INFO_TITLE)) + this->title = strdup(_x_meta_info_get(this->stream, XINE_META_INFO_TITLE)); + + if (NULL == this->title) + this->title = strdup("(No title)"); + + if (NULL == this->title) { + lprintf("Failed to determine a valid stream title!\n"); + return 1; + } + + int chapter_idx = matroska_get_chapter(this, timecode, &ed); + if (chapter_idx < 0) { + _x_meta_info_set_utf8(this->stream, XINE_META_INFO_TITLE, this->title); + return 1; + } + + xine_ui_data_t uidata = { + .str = {0, }, + .str_len = 0, + }; + + uidata.str_len = snprintf(uidata.str, sizeof(uidata.str), "%s / (%d) %s", + this->title, chapter_idx+1, ed->chapters[chapter_idx]->title); + _x_meta_info_set_utf8(this->stream, XINE_META_INFO_TITLE, uidata.str); + return 1; } @@ -2152,10 +2258,10 @@ static int parse_seek_entry(demux_matroska_t *this) { int has_position = 0; uint64_t id = 0; uint64_t pos; - + while (next_level == 3) { ebml_elem_t elem; - + if (!ebml_read_elem_head(ebml, &elem)) return 0; @@ -2179,26 +2285,26 @@ static int parse_seek_entry(demux_matroska_t *this) { } next_level = ebml_get_next_level(ebml, &elem); } - + /* do not parse clusters */ if (id == MATROSKA_ID_CLUSTER) { lprintf("skip cluster\n"); return 1; } - - /* parse the referenced element */ + + /* parse the referenced element */ if (has_id && has_position) { off_t current_pos, seek_pos; - + seek_pos = this->segment.start + pos; - + if ((seek_pos > 0) && (seek_pos < this->input->get_length(this->input))) { ebml_parser_t ebml_bak; /* backup current state */ current_pos = this->input->get_current_pos(this->input); memcpy(&ebml_bak, this->ebml, sizeof(ebml_parser_t)); /* FIXME */ - + /* seek and parse the top_level element */ this->ebml->level = 1; if (this->input->seek(this->input, seek_pos, SEEK_SET) < 0) { @@ -2237,7 +2343,7 @@ static int parse_seekhead(demux_matroska_t *this) { while (next_level == 2) { ebml_elem_t elem; - + if (!ebml_read_elem_head(ebml, &elem)) return 0; @@ -2274,18 +2380,19 @@ static int parse_top_level_head(demux_matroska_t *this, int *next_level) { ebml_elem_t elem; int ret_value = 1; off_t current_pos; - + + current_pos = this->input->get_current_pos(this->input); lprintf("current_pos: %" PRIdMAX "\n", (intmax_t)current_pos); - + if (!ebml_read_elem_head(ebml, &elem)) return 0; - + if (!find_top_level_entry(this, current_pos)) { if (!add_top_level_entry(this, current_pos)) return 0; - + switch (elem.id) { case MATROSKA_ID_SEEKHEAD: lprintf("SeekHead\n"); @@ -2312,7 +2419,7 @@ static int parse_top_level_head(demux_matroska_t *this, int *next_level) { lprintf("Chapters\n"); if (!ebml_read_master (ebml, &elem)) return 0; - if ((elem.len > 0) && !parse_chapters(this)) + if ((elem.len > 0) && !matroska_parse_chapters(this)) return 0; break; case MATROSKA_ID_CLUSTER: @@ -2352,7 +2459,7 @@ static int parse_top_level_head(demux_matroska_t *this, int *next_level) { if (!ebml_skip(ebml, &elem)) return 0; } - + if (next_level) *next_level = ebml_get_next_level(ebml, &elem); @@ -2439,12 +2546,12 @@ static int parse_segment(demux_matroska_t *this) { if (this->segment.id == MATROSKA_ID_SEGMENT) { int res; int next_level; - + lprintf("Segment detected\n"); if (!ebml_read_master (ebml, &this->segment)) return 0; - + res = 1; next_level = 1; /* stop the loop on the first cluster */ @@ -2496,14 +2603,14 @@ static void demux_matroska_send_headers (demux_plugin_t *this_gen) { _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, (this->num_video_tracks != 0)); _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, (this->num_audio_tracks != 0)); - + /* * send preview buffers */ /* enter in the segment */ ebml_read_master (this->ebml, &this->segment); - + /* seek back to the beginning of the segment */ next_level = 1; if (this->input->seek(this->input, this->segment.start, SEEK_SET) < 0) { @@ -2513,7 +2620,7 @@ static void demux_matroska_send_headers (demux_plugin_t *this_gen) { this->status = DEMUX_FINISHED; return; } - + this->preview_sent = 0; this->preview_mode = 1; @@ -2599,7 +2706,7 @@ static int demux_matroska_seek (demux_plugin_t *this_gen, matroska_index_t *index; matroska_track_t *track; int i, entry; - + start_pos = (off_t) ( (double) start_pos / 65535 * this->input->get_length (this->input) ); @@ -2655,10 +2762,10 @@ static int demux_matroska_seek (demux_plugin_t *this_gen, index->track_num, start_pos ? "pos" : "time", start_pos ? (intmax_t)start_pos : (intmax_t)start_time, index->track_num, index->timecode[entry], (intmax_t)index->pos[entry]); - + if (this->input->seek(this->input, index->pos[entry], SEEK_SET) < 0) this->status = DEMUX_FINISHED; - + /* we always seek to the ebml level 1 */ this->ebml->level = 1; @@ -2672,10 +2779,12 @@ static int demux_matroska_seek (demux_plugin_t *this_gen, static void demux_matroska_dispose (demux_plugin_t *this_gen) { - + demux_matroska_t *this = (demux_matroska_t *) this_gen; int i; + free(this->block_data); + /* free tracks */ for (i = 0; i < this->num_tracks; i++) { matroska_track_t *track; @@ -2693,7 +2802,7 @@ static void demux_matroska_dispose (demux_plugin_t *this_gen) { free (track->audio_track); if (track->sub_track) free (track->sub_track); - + free (track); } /* Free the cues. */ @@ -2705,12 +2814,17 @@ static void demux_matroska_dispose (demux_plugin_t *this_gen) { } if (this->indexes) free(this->indexes); - - /* Free the top_level elem list */ + + /* Free the top_level elem list */ if (this->top_level_list) free(this->top_level_list); + free(this->title); + + matroska_free_editions(this); + dispose_ebml_parser(this->ebml); + xine_event_dispose_queue(this->event_queue); free (this); } @@ -2724,7 +2838,13 @@ static int demux_matroska_get_stream_length (demux_plugin_t *this_gen) { static uint32_t demux_matroska_get_capabilities (demux_plugin_t *this_gen) { - return DEMUX_CAP_SPULANG | DEMUX_CAP_AUDIOLANG; + demux_matroska_t* this = (demux_matroska_t*)this_gen; + uint32_t caps = DEMUX_CAP_SPULANG | DEMUX_CAP_AUDIOLANG; + + if(this->num_editions > 0 && this->editions[0]->num_chapters > 0) + caps |= DEMUX_CAP_CHAPTERS; + + return caps; } @@ -2741,7 +2861,7 @@ static int demux_matroska_get_optional_data (demux_plugin_t *this_gen, if ((channel >= 0) && (channel < this->num_sub_tracks)) { for (track_num = 0; track_num < this->num_tracks; track_num++) { matroska_track_t *track = this->tracks[track_num]; - + if ((track->buf_type & 0xFF00001F) == (BUF_SPU_BASE + channel)) { if (track->language) { strncpy (str, track->language, XINE_LANG_MAX); @@ -2757,13 +2877,13 @@ static int demux_matroska_get_optional_data (demux_plugin_t *this_gen, } } return DEMUX_OPTIONAL_UNSUPPORTED; - + case DEMUX_OPTIONAL_DATA_AUDIOLANG: lprintf ("DEMUX_OPTIONAL_DATA_AUDIOLANG channel = %d\n",channel); if ((channel >= 0) && (channel < this->num_audio_tracks)) { for (track_num = 0; track_num < this->num_tracks; track_num++) { matroska_track_t *track = this->tracks[track_num]; - + if ((track->buf_type & 0xFF00001F) == (BUF_AUDIO_BASE + channel)) { if (track->language) { strncpy (str, track->language, XINE_LANG_MAX); @@ -2824,7 +2944,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str return NULL; } - this = xine_xmalloc (sizeof (demux_matroska_t)); + this = calloc(1, sizeof(demux_matroska_t)); this->demux_plugin.send_headers = demux_matroska_send_headers; this->demux_plugin.send_chunk = demux_matroska_send_chunk; @@ -2855,11 +2975,18 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str if (strcmp(ebml->doctype, "matroska")) goto error; + this->event_queue = xine_event_new_queue(this->stream); + return &this->demux_plugin; error: dispose_ebml_parser(ebml); - free(this); + + if (NULL != this) { + xine_event_dispose_queue(this->event_queue); + free(this); + } + return NULL; } @@ -2884,7 +3011,8 @@ static const char *get_extensions (demux_class_t *this_gen) { static const char *get_mimetypes (demux_class_t *this_gen) { - return "video/mkv: mkv: matroska;"; + return "video/mkv: mkv: matroska;" + "video/x-matroska: mkv: matroska;"; } @@ -2899,7 +3027,7 @@ static void *init_class (xine_t *xine, void *data) { demux_matroska_class_t *this; - this = xine_xmalloc (sizeof (demux_matroska_class_t)); + this = calloc(1, sizeof(demux_matroska_class_t)); this->xine = xine; this->demux_class.open_plugin = open_plugin; diff --git a/src/demuxers/demux_matroska.h b/src/demuxers/demux_matroska.h new file mode 100644 index 000000000..e1611f397 --- /dev/null +++ b/src/demuxers/demux_matroska.h @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2000-2008 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * demultiplexer for matroska streams: shared header + */ + +#ifndef _DEMUX_MATROSKA_H_ +#define _DEMUX_MATROSKA_H_ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <ctype.h> +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <zlib.h> + +#include "xine_internal.h" +#include "demux.h" +#include "buffer.h" +#include "bswap.h" + +#include "ebml.h" +#include "matroska.h" + +#define NUM_PREVIEW_BUFFERS 10 + +#define MAX_STREAMS 128 +#define MAX_FRAMES 32 + +#define WRAP_THRESHOLD 90000 + +typedef struct { + int track_num; + off_t *pos; + uint64_t *timecode; + int num_entries; + +} matroska_index_t; + +typedef struct { + + demux_plugin_t demux_plugin; + + xine_stream_t *stream; + + input_plugin_t *input; + + int status; + + ebml_parser_t *ebml; + + /* segment element */ + ebml_elem_t segment; + uint64_t timecode_scale; + int duration; /* in millis */ + int preview_sent; + int preview_mode; + char *title; + + /* meta seek info */ + int has_seekhead; + int seekhead_handled; + + /* seek info */ + matroska_index_t *indexes; + int num_indexes; + int first_cluster_found; + int skip_to_timecode; + int skip_for_track; + + /* tracks */ + int num_tracks; + int num_video_tracks; + int num_audio_tracks; + int num_sub_tracks; + + matroska_track_t *tracks[MAX_STREAMS]; + + /* maintain editions, number and capacity */ + int num_editions, cap_editions; + matroska_edition_t **editions; + + /* block */ + uint8_t *block_data; + size_t block_data_size; + + /* current tracks */ + matroska_track_t *video_track; /* to remove */ + matroska_track_t *audio_track; /* to remove */ + matroska_track_t *sub_track; /* to remove */ + uint64_t last_timecode; + + int send_newpts; + int buf_flag_seek; + + /* seekhead parsing */ + int top_level_list_size; + int top_level_list_max_size; + off_t *top_level_list; + + /* event handling (chapter navigation) */ + xine_event_queue_t *event_queue; +} demux_matroska_t ; + +typedef struct { + + demux_class_t demux_class; + + /* class-wide, global variables here */ + + xine_t *xine; + +} demux_matroska_class_t; + +/* "entry points" for chapter handling. + * The parser descends into "Chapters" elements at the _parse_ function, + * and editions care about cleanup internally. */ +int matroska_parse_chapters(demux_matroska_t*); +void matroska_free_editions(demux_matroska_t*); + +/* Search an edition for the chapter matching a given timecode. + * + * Return: chapter index, or -1 if none is found. + * + * TODO: does not handle chapter end times yet. + */ +int matroska_get_chapter(demux_matroska_t*, uint64_t, matroska_edition_t**); + +#endif /* _DEMUX_MATROSKA_H_ */ diff --git a/src/demuxers/demux_mng.c b/src/demuxers/demux_mng.c index 12da8ca86..2fccd0b9e 100644 --- a/src/demuxers/demux_mng.c +++ b/src/demuxers/demux_mng.c @@ -104,7 +104,12 @@ static mng_bool mymng_close_stream(mng_handle mngh){ static mng_bool mymng_read_stream(mng_handle mngh, mng_ptr buffer, mng_uint32 size, mng_uint32 *bytesread){ demux_mng_t *this = (demux_mng_t*)mng_get_userdata(mngh); - *bytesread = this->input->read(this->input, buffer, size); + off_t n = this->input->read(this->input, buffer, size); + if (n < 0) { + *bytesread = 0; + return MNG_FALSE; + } + *bytesread = n; return MNG_TRUE; } @@ -112,11 +117,16 @@ static mng_bool mymng_read_stream(mng_handle mngh, mng_ptr buffer, mng_uint32 si static mng_bool mymng_process_header(mng_handle mngh, mng_uint32 width, mng_uint32 height){ demux_mng_t *this = (demux_mng_t*)mng_get_userdata(mngh); + if (width > 0x8000 || height > 0x8000) + return MNG_FALSE; + this->bih.biWidth = (width + 7) & ~7; this->bih.biHeight = height; this->left_edge = (this->bih.biWidth - width) / 2; - this->image = malloc(this->bih.biWidth * height * 3); + this->image = malloc((mng_size_t)this->bih.biWidth * (mng_size_t)height * 3); + if (!this->image) + return MNG_FALSE; mng_set_canvasstyle(mngh, MNG_CANVAS_RGB8); @@ -171,7 +181,7 @@ static int demux_mng_send_chunk(demux_mng_t *this){ buf->decoder_flags = BUF_FLAG_FRAMERATE; buf->decoder_info[0] = 90 * this->timer_count; if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * + buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * 65535 / this->input->get_length (this->input) ); buf->extra_info->input_time = this->tick_count; buf->pts = 90 * this->tick_count; @@ -260,7 +270,7 @@ static demux_plugin_t* open_plugin(demux_class_t *class_gen, xine_stream_t *stre demux_mng_t *this; - this = xine_xmalloc (sizeof (demux_mng_t)); + this = calloc(1, sizeof(demux_mng_t)); this->stream = stream; this->input = input; @@ -360,7 +370,7 @@ static void class_dispose(demux_class_t *this){ static void *init_plugin(xine_t *xine, void *data){ demux_mng_class_t *this; - this = xine_xmalloc (sizeof (demux_mng_class_t)); + this = calloc(1, sizeof(demux_mng_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_mod.c b/src/demuxers/demux_mod.c index e7c6f86b3..0439be7ee 100644 --- a/src/demuxers/demux_mod.c +++ b/src/demuxers/demux_mod.c @@ -73,17 +73,17 @@ typedef struct { char *title; char *artist; char *copyright; - off_t filesize; - + size_t filesize; + char *buffer; int64_t current_pts; - + ModPlug_Settings settings; ModPlugFile *mpfile; int mod_length; int seek_flag; /* this is set when a seek just occurred */ - + } demux_mod_t; typedef struct { @@ -130,30 +130,41 @@ static int probe_mod_file(demux_mod_t *this) { /* returns 1 if the MOD file was opened successfully, 0 otherwise */ static int open_mod_file(demux_mod_t *this) { int total_read; - + off_t input_length; + /* Get size and create buffer */ - this->filesize = this->input->get_length(this->input); + input_length = this->input->get_length(this->input); + /* Avoid potential issues with signed variables and e.g. read() returning -1 */ + if (input_length > 0x7FFFFFFF || input_length < 0) { + xine_log(this->stream->xine, XINE_LOG_PLUGIN, "modplug - size overflow\n"); + return 0; + } + this->filesize = input_length; this->buffer = (char *)malloc(this->filesize); - + if(!this->buffer) { + xine_log(this->stream->xine, XINE_LOG_PLUGIN, "modplug - allocation failure\n"); + return 0; + } + /* Seek to beginning */ this->input->seek(this->input, 0, SEEK_SET); - + /* Read data */ total_read = this->input->read(this->input, this->buffer, this->filesize); - + if(total_read != this->filesize) { xine_log(this->stream->xine, XINE_LOG_PLUGIN, "modplug - filesize error\n"); free(this->buffer); return 0; } - + this->mpfile = ModPlug_Load(this->buffer, this->filesize); if (this->mpfile==NULL) { xine_log(this->stream->xine, XINE_LOG_PLUGIN, "modplug - load error\n"); free(this->buffer); return 0; } - + /* Set up modplug engine */ ModPlug_GetSettings(&this->settings); this->settings.mResamplingMode = MODPLUG_RESAMPLE_FIR; /* RESAMP */ @@ -161,13 +172,15 @@ static int open_mod_file(demux_mod_t *this) { this->settings.mBits = MOD_BITS; this->settings.mFrequency = MOD_SAMPLERATE; ModPlug_SetSettings(&this->settings); - + this->title = strdup(ModPlug_GetName(this->mpfile)); this->artist = strdup(""); this->copyright = strdup(""); - + this->mod_length = ModPlug_GetLength(this->mpfile); - + if (this->mod_length < 1) + this->mod_length = 1; /* avoids -ve & div-by-0 */ + return 1; } @@ -188,20 +201,20 @@ static int demux_mod_send_chunk(demux_plugin_t *this_gen) { buf->size = mlen; buf->pts = this->current_pts; buf->extra_info->input_time = buf->pts / 90; - + buf->extra_info->input_normpos = buf->extra_info->input_time * 65535 / this->mod_length; buf->decoder_flags = BUF_FLAG_FRAME_END; - + if (this->seek_flag) { _x_demux_control_newpts(this->stream, buf->pts, BUF_FLAG_SEEK); this->seek_flag = 0; } this->audio_fifo->put (this->audio_fifo, buf); - + this->current_pts += 90000 * mlen / OUT_BYTES_PER_SECOND; } - + return this->status; } @@ -247,9 +260,9 @@ static int demux_mod_seek (demux_plugin_t *this_gen, demux_mod_t *this = (demux_mod_t *) this_gen; int64_t seek_millis; - + if (start_pos) { - seek_millis = this->mod_length; + seek_millis = this->mod_length; seek_millis *= start_pos; seek_millis /= 65535; } else { @@ -259,14 +272,14 @@ static int demux_mod_seek (demux_plugin_t *this_gen, _x_demux_flush_engine(this->stream); ModPlug_Seek(this->mpfile, seek_millis); this->current_pts = seek_millis * 90; - + this->seek_flag = 1; return this->status; } static void demux_mod_dispose (demux_plugin_t *this_gen) { demux_mod_t *this = (demux_mod_t *) this_gen; - + ModPlug_Unload(this->mpfile); free(this->buffer); free(this->title); @@ -305,7 +318,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str return NULL; } - this = xine_xmalloc (sizeof (demux_mod_t)); + this = calloc(1, sizeof(demux_mod_t)); this->stream = stream; this->input = input; @@ -322,7 +335,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str this->status = DEMUX_FINISHED; xprintf(stream->xine, XINE_VERBOSITY_DEBUG, "TEST mod decode\n"); - + switch (stream->content_detection_method) { case METHOD_EXPLICIT: @@ -368,7 +381,19 @@ static const char *get_extensions (demux_class_t *this_gen) { } static const char *get_mimetypes (demux_class_t *this_gen) { - return NULL; + return "audio/x-mod: mod: SoundTracker/NoiseTracker/ProTracker Module;" + "audio/mod: mod: SoundTracker/NoiseTracker/ProTracker Module;" + "audio/it: it: ImpulseTracker Module;" + "audio/x-it: it: ImpulseTracker Module;" + "audio/x-stm: stm: ScreamTracker 2 Module;" + "audio/x-s3m: s3m: ScreamTracker 3 Module;" + "audio/s3m: s3m: ScreamTracker 3 Module;" + "application/playerpro: 669: 669 Tracker Module;" + "application/adrift: amf: ADRIFT Module File;" + "audio/med: med: Amiga MED/OctaMED Tracker Module Sound File;" + "audio/x-amf: amf: ADRIFT Module File;" + "audio/x-xm: xm: FastTracker II Audio;" + "audio/xm: xm: FastTracker II Audio;"; } static void class_dispose (demux_class_t *this_gen) { @@ -380,7 +405,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_mod_init_plugin (xine_t *xine, void *data) { demux_mod_class_t *this; - this = xine_xmalloc (sizeof (demux_mod_class_t)); + this = calloc(1, sizeof(demux_mod_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_mpc.c b/src/demuxers/demux_mpc.c index 346f0c2e6..04b25eeb5 100644 --- a/src/demuxers/demux_mpc.c +++ b/src/demuxers/demux_mpc.c @@ -24,7 +24,7 @@ * APE tag reading * Seeking?? */ - + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -47,6 +47,7 @@ #include "buffer.h" #include "bswap.h" #include "group_audio.h" +#include "id3.h" /* Note that the header is actually 25 bytes long, so we'd only read 28 * (because of byte swapping we have to round up to nearest multiple of 4) @@ -65,7 +66,7 @@ typedef struct { unsigned int frames; double samplerate; unsigned int length; - + unsigned int current_frame; unsigned int next_frame_bits; } demux_mpc_t; @@ -81,7 +82,7 @@ typedef struct { static int open_mpc_file(demux_mpc_t *this) { unsigned int first_frame_size; unsigned int id3v2_size = 0; - + /* Read the file header */ if (_x_demux_read_header(this->input, this->header, HEADER_SIZE) != HEADER_SIZE) return 0; @@ -89,46 +90,40 @@ static int open_mpc_file(demux_mpc_t *this) { /* TODO: non-seeking version */ if (INPUT_IS_SEEKABLE(this->input)) { /* Check for id3v2 tag */ - if ((this->header[0] == 'I') || - (this->header[1] == 'D') || - (this->header[2] == '3')) { - + if (id3v2_istag(this->header)) { + lprintf("found id3v2 header\n"); - + /* Read tag size */ - id3v2_size = (this->header[6] << 21) + - (this->header[7] << 14) + - (this->header[8] << 7) + - this->header[9] + 10; - + + id3v2_size = _X_BE_32_synchsafe(&this->header[6]) + 10; + /* Add footer size if one is present */ if (this->header[5] & 0x10) id3v2_size += 10; - + lprintf("id3v2 size: %u\n", id3v2_size); - + /* Seek past tag */ if (this->input->seek(this->input, id3v2_size, SEEK_SET) < 0) return 0; - + /* Read musepack header */ if (this->input->read(this->input, this->header, HEADER_SIZE) != HEADER_SIZE) return 0; } } - + /* Validate signature - We only support SV 7.x at the moment */ - if ((this->header[0] != 'M') || - (this->header[1] != 'P') || - (this->header[2] != '+') || + if ( memcmp(this->header, "MP+", 3) != 0 || ((this->header[3]&0x0f) != 0x07)) return 0; - + /* Get frame count */ this->current_frame = 0; this->frames = _X_LE_32(&this->header[4]); lprintf("number of frames: %u\n", this->frames); - + /* Get sample rate */ switch ((_X_LE_32(&this->header[8]) >> 16) & 0x3) { case 0: @@ -147,7 +142,7 @@ static int open_mpc_file(demux_mpc_t *this) { break; } lprintf("samplerate: %f kHz\n", this->samplerate); - + /* Calculate stream length */ this->length = (int) ((double) this->frames * 1152 / this->samplerate); lprintf("stream length: %d ms\n", this->length); @@ -156,14 +151,14 @@ static int open_mpc_file(demux_mpc_t *this) { first_frame_size = (_X_LE_32(&this->header[24]) >> 4) & 0xFFFFF; this->next_frame_bits = first_frame_size - 4; lprintf("first frame size: %u\n", first_frame_size); - + /* Move input to start of data (to nearest multiple of 4) */ this->input->seek(this->input, 28+id3v2_size, SEEK_SET); - + /* Set stream info */ _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, 1); _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_FOURCC, _X_ME_32(this->header)); - + return 1; } @@ -173,30 +168,30 @@ static int demux_mpc_send_chunk(demux_plugin_t *this_gen) { off_t bytes_read; buf_element_t *buf = NULL; - + /* Check if we've finished */ if (this->current_frame++ == this->frames) { lprintf("all frames read\n"); this->status = DEMUX_FINISHED; - return this->status; + return this->status; } lprintf("current frame: %u\n", this->current_frame); - - /* Get a buffer */ + + /* Get a buffer */ buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); buf->type = BUF_AUDIO_MPC; buf->pts = 0; buf->extra_info->total_time = this->length; - + /* Set normalised position */ - buf->extra_info->input_normpos = - (int) ((double) this->input->get_current_pos(this->input) * 65535 / + buf->extra_info->input_normpos = + (int) ((double) this->input->get_current_pos(this->input) * 65535 / this->input->get_length(this->input)); - + /* Set time based on there being 1152 audio frames per frame */ - buf->extra_info->input_time = + buf->extra_info->input_time = (int) ((double) this->current_frame * 1152 / this->samplerate); - + /* Calculate the number of bits that need to be read to finish reading * the current frame and read the size of the next frame. This number * has to be rounded up to the nearest 4 bytes on account of the @@ -209,35 +204,35 @@ static int demux_mpc_send_chunk(demux_plugin_t *this_gen) { xprintf(this->stream->xine, XINE_VERBOSITY_LOG, _("demux_mpc: frame too big for buffer")); this->status = DEMUX_FINISHED; - return this->status; + return this->status; } - + /* Read data */ bytes_read = this->input->read(this->input, buf->content, bytes_to_read); - if(bytes_read == 0) { + if(bytes_read <= 0) { buf->free_buffer(buf); this->status = DEMUX_FINISHED; return this->status; - } else + } else buf->size = bytes_read; - + /* Read the size of the next frame */ if (this->current_frame < this->frames) { - /* The number of bits of the next frame we've read */ + /* The number of bits of the next frame we've read */ extra_bits_read = bits_to_read - (this->next_frame_bits+20); - + if(extra_bits_read <= 12) next_frame_size = (_X_LE_32(&buf->content[bytes_to_read-4]) >> extra_bits_read) & 0xFFFFF; else next_frame_size = ((_X_LE_32(&buf->content[bytes_to_read-8]) << (32-extra_bits_read)) | (_X_LE_32(&buf->content[bytes_to_read-4]) >> extra_bits_read)) & 0xFFFFF; - + lprintf("next frame size: %u\n", next_frame_size); - + /* The number of bits of the next frame still to read */ - this->next_frame_bits = next_frame_size - extra_bits_read; + this->next_frame_bits = next_frame_size - extra_bits_read; } - + /* Each buffer contains at least one frame */ buf->decoder_flags |= BUF_FLAG_FRAME_END; @@ -260,14 +255,14 @@ static void demux_mpc_send_headers(demux_plugin_t *this_gen) { /* Send header to decoder */ if (this->audio_fifo) { buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); - + buf->type = BUF_AUDIO_MPC; buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_FRAME_END; buf->decoder_info[0] = this->input->get_length(this->input); buf->decoder_info[1] = 0; buf->decoder_info[2] = 0; buf->decoder_info[3] = 0; - + /* Copy the header */ buf->size = HEADER_SIZE; memcpy(buf->content, this->header, buf->size); @@ -324,7 +319,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str demux_mpc_t *this; - this = xine_xmalloc (sizeof (demux_mpc_t)); + this = calloc(1, sizeof(demux_mpc_t)); this->stream = stream; this->input = input; @@ -356,12 +351,12 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str case METHOD_BY_CONTENT: case METHOD_EXPLICIT: - + if (!open_mpc_file(this)) { free (this); return NULL; } - + break; default: @@ -381,11 +376,12 @@ static const char *get_identifier (demux_class_t *this_gen) { } static const char *get_extensions (demux_class_t *this_gen) { - return "mpc mp+"; + return "mpc mp+ mpp"; } static const char *get_mimetypes (demux_class_t *this_gen) { - return NULL; + return "audio/musepack: mpc, mp+, mpp: Musepack audio;" + "audio/x-musepack: mpc, mp+, mpp: Musepack audio;"; } static void class_dispose (demux_class_t *this_gen) { @@ -397,7 +393,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_mpc_init_plugin (xine_t *xine, void *data) { demux_mpc_class_t *this; - this = xine_xmalloc (sizeof (demux_mpc_class_t)); + this = calloc(1, sizeof(demux_mpc_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_mpeg.c b/src/demuxers/demux_mpeg.c index 4419f8404..dbaae108d 100644 --- a/src/demuxers/demux_mpeg.c +++ b/src/demuxers/demux_mpeg.c @@ -170,7 +170,7 @@ static void find_mdat_atom(input_plugin_t *input, off_t *mdat_offset, } else atom_size -= ATOM_PREAMBLE_SIZE; - + input->seek(input, atom_size, SEEK_CUR); } } @@ -279,6 +279,10 @@ static void parse_mpeg2_packet (demux_mpeg_t *this, int stream_id, int64_t scr) if((this->dummy_space[0] & 0xE0) == 0x20) { buf = this->input->read_block (this->input, this->video_fifo, len-1); + if (! buf) { + this->status = DEMUX_FINISHED; + return; + } track = (this->dummy_space[0] & 0x1f); @@ -298,17 +302,21 @@ static void parse_mpeg2_packet (demux_mpeg_t *this, int stream_id, int64_t scr) int spu_id = this->dummy_space[1] & 0x03; buf = this->input->read_block (this->input, this->video_fifo, len-1); + if (! buf) { + this->status = DEMUX_FINISHED; + return; + } buf->type = BUF_SPU_SVCD + spu_id; buf->pts = pts; - /* There is a bug in WinSubMux doesn't redo PACK headers in + /* There is a bug in WinSubMux doesn't redo PACK headers in the private stream 1. This might cause the below to mess up. if( !preview_mode ) check_newpts( this, this->pts, PTS_VIDEO ); */ this->video_fifo->put (this->video_fifo, buf); - lprintf ("SPU SVCD PACK (pts: %"PRId64", spu id: %d) put on FIFO\n", + lprintf ("SPU SVCD PACK (pts: %"PRId64", spu id: %d) put on FIFO\n", buf->pts, spu_id); return; @@ -318,6 +326,10 @@ static void parse_mpeg2_packet (demux_mpeg_t *this, int stream_id, int64_t scr) if((this->dummy_space[0] & 0xfc) == 0x00) { buf = this->input->read_block (this->input, this->video_fifo, len-1); + if (! buf) { + this->status = DEMUX_FINISHED; + return; + } buf->type = BUF_SPU_CVD + (this->dummy_space[0] & 0x03); buf->pts = pts; @@ -330,7 +342,7 @@ static void parse_mpeg2_packet (demux_mpeg_t *this, int stream_id, int64_t scr) if((this->dummy_space[0] & 0xf0) == 0x80) { /* read rest of header - AC3 */ - i = this->input->read (this->input, this->dummy_space+1, 3); + this->input->read (this->input, this->dummy_space+1, 3); /* contents */ for (i = len - 4; i > 0; i -= (this->audio_fifo) @@ -356,10 +368,10 @@ static void parse_mpeg2_packet (demux_mpeg_t *this, int stream_id, int64_t scr) buf->decoder_flags = BUF_FLAG_PREVIEW; if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = - (int)( ((int64_t)this->input->get_current_pos (this->input) * + buf->extra_info->input_normpos = + (int)( ((int64_t)this->input->get_current_pos (this->input) * 65535) / this->input->get_length (this->input) ); - + if (this->rate) buf->extra_info->input_time = (int)((int64_t)this->input->get_current_pos (this->input) * 1000 / (this->rate * 50)); @@ -376,6 +388,10 @@ static void parse_mpeg2_packet (demux_mpeg_t *this, int stream_id, int64_t scr) i = this->input->read (this->input, this->dummy_space+1, 6); buf = this->input->read_block (this->input, this->video_fifo, len-7); + if (! buf) { + this->status = DEMUX_FINISHED; + return; + } buf->type = BUF_AUDIO_LPCM_BE + track; buf->decoder_flags |= BUF_FLAG_SPECIAL; @@ -389,8 +405,8 @@ static void parse_mpeg2_packet (demux_mpeg_t *this, int stream_id, int64_t scr) buf->decoder_flags |= BUF_FLAG_PREVIEW; if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = - (int)( ((int64_t)this->input->get_current_pos (this->input) * + buf->extra_info->input_normpos = + (int)( ((int64_t)this->input->get_current_pos (this->input) * 65535) / this->input->get_length (this->input) ); if (this->rate) buf->extra_info->input_time = (int)((int64_t)this->input->get_current_pos (this->input) @@ -431,9 +447,9 @@ static void parse_mpeg2_packet (demux_mpeg_t *this, int stream_id, int64_t scr) header_len -= 5 ; } - i = this->input->read (this->input, this->dummy_space, header_len); + this->input->read (this->input, this->dummy_space, header_len); - for (i = len; i > 0; i -= (this->audio_fifo) + for (i = len; i > 0; i -= (this->audio_fifo) ? this->audio_fifo->buffer_pool_buf_size : this->video_fifo->buffer_pool_buf_size) { if(this->audio_fifo) { buf = this->input->read_block (this->input, this->audio_fifo, @@ -453,8 +469,8 @@ static void parse_mpeg2_packet (demux_mpeg_t *this, int stream_id, int64_t scr) buf->decoder_flags = BUF_FLAG_PREVIEW; if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = - (int)( ((int64_t)this->input->get_current_pos (this->input) * + buf->extra_info->input_normpos = + (int)( ((int64_t)this->input->get_current_pos (this->input) * 65535) / this->input->get_length (this->input) ); if (this->rate) buf->extra_info->input_time = (int)((int64_t)this->input->get_current_pos (this->input) @@ -489,21 +505,21 @@ static void parse_mpeg2_packet (demux_mpeg_t *this, int stream_id, int64_t scr) header_len -= 5 ; } - + if ((flags & 0x40) == 0x40) { - + w = read_bytes(this, 1); dts = (int64_t)(w & 0x0e) << 29 ; w = read_bytes(this, 2); dts |= (w & 0xFFFE) << 14; w = read_bytes(this, 2); dts |= (w & 0xFFFE) >> 1; - + header_len -= 5 ; - } + } /* read rest of header */ - i = this->input->read (this->input, this->dummy_space, header_len); + this->input->read (this->input, this->dummy_space, header_len); /* contents */ @@ -526,8 +542,8 @@ static void parse_mpeg2_packet (demux_mpeg_t *this, int stream_id, int64_t scr) buf->decoder_flags = BUF_FLAG_PREVIEW; if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = - (int)( ((int64_t)this->input->get_current_pos (this->input) * + buf->extra_info->input_normpos = + (int)( ((int64_t)this->input->get_current_pos (this->input) * 65535) / this->input->get_length (this->input) ); if (this->rate) buf->extra_info->input_time = (int)((int64_t)this->input->get_current_pos (this->input) @@ -538,7 +554,7 @@ static void parse_mpeg2_packet (demux_mpeg_t *this, int stream_id, int64_t scr) } else { - for (i = len; i > 0; i -= 10000) + for (i = len; i > 0; i -= 10000) this->input->read (this->input, this->dummy_space, (i > 10000) ? 10000 : i); } @@ -606,7 +622,7 @@ static void parse_mpeg1_packet (demux_mpeg_t *this, int stream_id, int64_t scr) pts |= (w & 0xFFFE) << 14; w = read_bytes(this, 2); len -= 2; - + pts |= (w & 0xFFFE) >> 1; w = read_bytes(this, 1); len -= 1; @@ -633,11 +649,11 @@ static void parse_mpeg1_packet (demux_mpeg_t *this, int stream_id, int64_t scr) lprintf("use scr\n"); pts = scr; } - + if ((stream_id & 0xe0) == 0xc0) { int track = stream_id & 0x1f; - for (i = len; i > 0; i -= (this->audio_fifo) + for (i = len; i > 0; i -= (this->audio_fifo) ? this->audio_fifo->buffer_pool_buf_size : this->video_fifo->buffer_pool_buf_size) { if(this->audio_fifo) { buf = this->input->read_block (this->input, this->audio_fifo, @@ -657,8 +673,8 @@ static void parse_mpeg1_packet (demux_mpeg_t *this, int stream_id, int64_t scr) buf->decoder_flags = BUF_FLAG_PREVIEW; if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = - (int)( ((int64_t)this->input->get_current_pos (this->input) * + buf->extra_info->input_normpos = + (int)( ((int64_t)this->input->get_current_pos (this->input) * 65535) / this->input->get_length (this->input) ); if (this->rate) buf->extra_info->input_time = (int)((int64_t)this->input->get_current_pos (this->input) @@ -692,8 +708,8 @@ static void parse_mpeg1_packet (demux_mpeg_t *this, int stream_id, int64_t scr) buf->decoder_flags = BUF_FLAG_PREVIEW; if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = - (int)( ((int64_t)this->input->get_current_pos (this->input) * + buf->extra_info->input_normpos = + (int)( ((int64_t)this->input->get_current_pos (this->input) * 65535) / this->input->get_length (this->input) ); if (this->rate) buf->extra_info->input_time = (int)((int64_t)this->input->get_current_pos (this->input) @@ -704,12 +720,12 @@ static void parse_mpeg1_packet (demux_mpeg_t *this, int stream_id, int64_t scr) } else if (stream_id == 0xbd) { - for (i = len; i > 0; i -= 10000) + for (i = len; i > 0; i -= 10000) this->input->read (this->input, this->dummy_space, (i > 10000) ? 10000 : i); } else { - for (i = len; i > 0; i -= 10000) + for (i = len; i > 0; i -= 10000) this->input->read (this->input, this->dummy_space, (i > 10000) ? 10000 : i); } } @@ -920,7 +936,7 @@ static void demux_mpeg_resync (demux_mpeg_t *this, uint32_t buf) { if (pos == len) { len = this->input->read(this->input, dummy_buf, sizeof(dummy_buf)); pos = 0; - if (len == 0) { + if (len <= 0) { this->status = DEMUX_FINISHED; break; } @@ -962,40 +978,40 @@ static void demux_mpeg_send_headers (demux_plugin_t *this_gen) { demux_mpeg_t *this = (demux_mpeg_t *) this_gen; uint32_t w; int num_buffers = NUM_PREVIEW_BUFFERS; - + this->video_fifo = this->stream->video_fifo; this->audio_fifo = this->stream->audio_fifo; this->rate = 0; /* fixme */ this->last_pts[0] = 0; this->last_pts[1] = 0; - + _x_demux_control_start(this->stream); /* * send preview buffers for stream/meta_info */ - + _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, 1); _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, 1); this->preview_mode = 1; - + this->input->seek (this->input, 4, SEEK_SET); - + this->status = DEMUX_OK ; - + do { w = parse_pack_preview (this, &num_buffers); - + if (w != 0x000001ba) demux_mpeg_resync (this, w); - + num_buffers --; - + } while ( (this->status == DEMUX_OK) && (num_buffers > 0)); - + this->status = DEMUX_OK ; _x_stream_info_set(this->stream, XINE_STREAM_INFO_BITRATE, this->rate * 50 * 8); @@ -1067,7 +1083,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str input_plugin_t *input) { demux_mpeg_t *this; - this = xine_xmalloc (sizeof (demux_mpeg_t)); + this = calloc(1, sizeof(demux_mpeg_t)); this->stream = stream; this->input = input; @@ -1139,7 +1155,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str /* go through the same MPEG detection song and dance */ if (input->read(input, buf, 4) == 4) { - if (!buf[0] && !buf[1] && (buf[2] == 0x01) + if (!buf[0] && !buf[1] && (buf[2] == 0x01) && (buf[3] == 0xba)) /* if so, take it */ break; } @@ -1147,7 +1163,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str free (this); return NULL; } - + /* reset position for next check */ if (input->seek(input, 0, SEEK_SET) != 0) { free (this); @@ -1158,7 +1174,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str fourcc_tag = _X_BE_32(&buf[0]); if (fourcc_tag == RIFF_TAG) { uint8_t large_buf[1024]; - + if (input->read(input, large_buf, 12) != 12) { free(this); return NULL; @@ -1177,7 +1193,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str * MPEG video marker. No, it's not a very efficient approach, but * if execution has reached this special case, this is currently * the best chance for detecting the file automatically. Also, - * be extra lazy and do not bother skipping over the data + * be extra lazy and do not bother skipping over the data * header. */ for (i = 0; i < RIFF_CHECK_KILOBYTES && !ok; i++) { if (input->read(input, large_buf, 1024) != 1024) @@ -1246,7 +1262,7 @@ static void class_dispose (demux_class_t *this_gen) { static void *init_plugin (xine_t *xine, void *data) { demux_mpeg_class_t *this; - this = xine_xmalloc (sizeof (demux_mpeg_class_t)); + this = calloc(1, sizeof(demux_mpeg_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; @@ -1266,7 +1282,7 @@ static const demuxer_info_t demux_info_mpeg = { }; const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ + /* type, API, "name", version, special_info, init_function */ { PLUGIN_DEMUX, 26, "mpeg", XINE_VERSION_CODE, &demux_info_mpeg, init_plugin }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; diff --git a/src/demuxers/demux_mpeg_block.c b/src/demuxers/demux_mpeg_block.c index 32638129d..aa5294e8b 100644 --- a/src/demuxers/demux_mpeg_block.c +++ b/src/demuxers/demux_mpeg_block.c @@ -1,18 +1,18 @@ /* * Copyright (C) 2000-2006 the xine project - * + * * This file is part of xine, a free video player. - * + * * xine is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * xine is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA @@ -20,7 +20,7 @@ * demultiplexer for mpeg 1/2 program streams * used with fixed blocksize devices (like dvd/vcd) */ - + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -44,7 +44,7 @@ #define NUM_PREVIEW_BUFFERS 250 #define DISC_TRESHOLD 90000 -#define WRAP_THRESHOLD 120000 +#define WRAP_THRESHOLD 120000 #define PTS_AUDIO 0 #define PTS_VIDEO 1 @@ -56,22 +56,19 @@ typedef struct demux_mpeg_block_s { demux_plugin_t demux_plugin; - xine_stream_t *stream; + xine_stream_t *stream; fifo_buffer_t *audio_fifo; fifo_buffer_t *video_fifo; input_plugin_t *input; int status; - + int blocksize; int rate; char cur_mrl[256]; - uint8_t *scratch; - void *scratch_base; - int64_t nav_last_end_pts; int64_t nav_last_start_pts; int64_t last_pts[2]; @@ -126,30 +123,30 @@ static int32_t parse_program_stream_pack_header(demux_mpeg_block_t *this, uint8_ /* OK, i think demux_mpeg_block discontinuity handling demands some explanation: - + - The preferred discontinuity handling/detection for DVD is based on NAV packets information. Most of the time it will provide us very accurate and reliable information. - + - Has been shown that sometimes a DVD discontinuity may happen before a new NAV packet arrives (seeking?). To avoid sending wrong PTS to decoders we _used_ to check for SCR discontinuities. Unfortunately some VCDs have very broken SCR values causing false triggering. - + - To fix the above problem (also note that VCDs don't have NAV packets) we fallback to the same PTS-based wrap detection as used in demux_mpeg. The only trick is to not send discontinuity information if NAV packets have already done the job. - + [Miguel 02-05-2002] */ static void check_newpts( demux_mpeg_block_t *this, int64_t pts, int video ) { int64_t diff; - + diff = pts - this->last_pts[video]; - + if( pts && (this->send_newpts || (this->last_pts[video] && abs(diff)>WRAP_THRESHOLD) ) ) { /* check if pts is outside nav pts range. any stream without nav must enter here. */ @@ -167,10 +164,10 @@ static void check_newpts( demux_mpeg_block_t *this, int64_t pts, int video ) } else { lprintf("no wrap detected\n" ); } - + this->last_pts[1-video] = 0; } - + if( pts ) this->last_pts[video] = pts; } @@ -223,9 +220,9 @@ static void demux_mpeg_block_parse_pack (demux_mpeg_block_t *this, int preview_m buf->decoder_flags = BUF_FLAG_PREVIEW; else buf->decoder_flags = 0; - + if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * + buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * 65535 / this->input->get_length (this->input) ); while(p < (buf->content + this->blocksize)) { @@ -438,7 +435,7 @@ static int32_t parse_program_stream_pack_header(demux_mpeg_block_t *this, uint8_ return 12; } else { /* mpeg2 */ - + int num_stuffing_bytes; /* system_clock_reference */ @@ -502,7 +499,7 @@ static int32_t parse_private_stream_2(demux_mpeg_block_t *this, uint8_t *p, buf_ * the NAV packet for a much more accurate timing */ if (buf->extra_info->input_time) { int64_t cell_time, frames; - + cell_time = (p[7+0x18] >> 4 ) * 10 * 60 * 60 * 1000; cell_time += (p[7+0x18] & 0x0f) * 60 * 60 * 1000; cell_time += (p[7+0x19] >> 4 ) * 10 * 60 * 1000; @@ -511,7 +508,7 @@ static int32_t parse_private_stream_2(demux_mpeg_block_t *this, uint8_t *p, buf_ cell_time += (p[7+0x1a] & 0x0f) * 1000; frames = ((p[7+0x1b] & 0x30) >> 4) * 10; frames += ((p[7+0x1b] & 0x0f) ) ; - + if (p[7+0x1b] & 0x80) cell_time += (frames * 1000)/25; else @@ -521,7 +518,7 @@ static int32_t parse_private_stream_2(demux_mpeg_block_t *this, uint8_t *p, buf_ this->last_cell_pos = this->input->get_current_pos (this->input); this->last_begin_time = buf->extra_info->input_time; } - + lprintf ("NAV packet, start pts = %"PRId64", end_pts = %"PRId64"\n", start_pts, end_pts); @@ -572,14 +569,14 @@ static int32_t parse_pes_for_pts(demux_mpeg_block_t *this, uint8_t *p, buf_eleme } if (this->rate && !buf->extra_info->input_time) - buf->extra_info->input_time = (int)((int64_t)this->input->get_current_pos (this->input) + buf->extra_info->input_time = (int)((int64_t)this->input->get_current_pos (this->input) * 1000 / (this->rate * 50)); if (this->mpeg1) { header_len = 6; p += 6; /* packet_len -= 6; */ while ((p[0] & 0x80) == 0x80) { - p++; + p++; header_len++; this->packet_len--; /* printf ("stuffing\n");*/ @@ -592,9 +589,9 @@ static int32_t parse_pes_for_pts(demux_mpeg_block_t *this, uint8_t *p, buf_eleme this->packet_len -= 2; } - this->pts = 0; + this->pts = 0; this->dts = 0; - + if ((p[0] & 0xf0) == 0x20) { this->pts = (int64_t)(p[ 0] & 0x0E) << 29 ; this->pts |= p[ 1] << 22 ; @@ -611,19 +608,19 @@ static int32_t parse_pes_for_pts(demux_mpeg_block_t *this, uint8_t *p, buf_eleme this->pts |= (p[ 2] & 0xFE) << 14 ; this->pts |= p[ 3] << 7 ; this->pts |= (p[ 4] & 0xFE) >> 1 ; - + this->dts = (int64_t)(p[ 5] & 0x0E) << 29 ; this->dts |= p[ 6] << 22 ; this->dts |= (p[ 7] & 0xFE) << 14 ; this->dts |= p[ 8] << 7 ; this->dts |= (p[ 9] & 0xFE) >> 1 ; - + p += 10; header_len += 10; this->packet_len -= 10; return header_len; } else { - p++; + p++; header_len++; this->packet_len--; return header_len; @@ -667,13 +664,13 @@ static int32_t parse_pes_for_pts(demux_mpeg_block_t *this, uint8_t *p, buf_eleme this->pts = 0; if (p[7] & 0x40) { /* dts avail */ - + this->dts = (int64_t)(p[14] & 0x0E) << 29 ; this->dts |= p[15] << 22 ; this->dts |= (p[16] & 0xFE) << 14 ; this->dts |= p[17] << 7 ; this->dts |= (p[18] & 0xFE) >> 1 ; - + } else this->dts = 0; @@ -702,16 +699,16 @@ static int32_t parse_private_stream_1(demux_mpeg_block_t *this, uint8_t *p, buf_ buf->content = p+1; buf->size = this->packet_len-1; - + buf->type = BUF_SPU_DVD + spu_id; buf->decoder_flags |= BUF_FLAG_SPECIAL; buf->decoder_info[1] = BUF_SPECIAL_SPU_DVD_SUBTYPE; buf->decoder_info[2] = SPU_DVD_SUBTYPE_PACKAGE; buf->pts = this->pts; - - this->video_fifo->put (this->video_fifo, buf); + + this->video_fifo->put (this->video_fifo, buf); lprintf ("SPU PACK put on fifo\n"); - + return -1; } @@ -727,9 +724,9 @@ static int32_t parse_private_stream_1(demux_mpeg_block_t *this, uint8_t *p, buf_ if( !preview_mode ) check_newpts( this, this->pts, PTS_VIDEO ); */ - this->video_fifo->put (this->video_fifo, buf); + this->video_fifo->put (this->video_fifo, buf); lprintf ("SPU SVCD PACK (%"PRId64", %d) put on fifo\n", this->pts, spu_id); - + return -1; } @@ -744,29 +741,29 @@ static int32_t parse_private_stream_1(demux_mpeg_block_t *this, uint8_t *p, buf_ /* this is probably wrong: if( !preview_mode ) check_newpts( this, this->pts, PTS_VIDEO ); - */ - this->video_fifo->put (this->video_fifo, buf); + */ + this->video_fifo->put (this->video_fifo, buf); lprintf ("SPU CVD PACK (%"PRId64", %d) put on fifo\n", this->pts, spu_id); - + return -1; } if ((p[0]&0xF0) == 0x80) { - + track = p[0] & 0x0F; /* hack : ac3 track */ - /* Number of frame headers + /* Number of frame headers * * Describes the number of a52 frame headers that start in this pack (One pack per DVD sector). * * Likely values: 1 or 2. */ buf->decoder_info[1] = p[1]; - /* First access unit pointer. + /* First access unit pointer. * * Describes the byte offset within this pack to the beginning of the first A52 frame header. * The PTS from this pack applies to the beginning of the first A52 frame that starts in this pack. - * Any bytes before this offset should be considered to belong to the previous A52 frame. + * Any bytes before this offset should be considered to belong to the previous A52 frame. * and therefore be tagged with a PTS value derived from the previous pack. * * Likely values: Anything from 1 to the size of an A52 frame. @@ -867,7 +864,7 @@ static int32_t parse_private_stream_1(demux_mpeg_block_t *this, uint8_t *p, buf_ buf->free_buffer(buf); return -1; } - + } else if ((p[0]&0xf0) == 0xa0) { int pcm_offset; @@ -914,7 +911,7 @@ static int32_t parse_private_stream_1(demux_mpeg_block_t *this, uint8_t *p, buf_ buf->decoder_flags |= BUF_FLAG_SPECIAL; buf->decoder_info[1] = BUF_SPECIAL_LPCM_CONFIG; buf->decoder_info[2] = p[5]; - + pcm_offset = 7; buf->content = p+pcm_offset; @@ -933,7 +930,7 @@ static int32_t parse_private_stream_1(demux_mpeg_block_t *this, uint8_t *p, buf_ buf->free_buffer(buf); return -1; } - + } /* Some new streams have been encountered. 1) DVD+RW disc recorded with a Philips DVD recorder: - new unknown sub-stream id of 0xff @@ -1006,10 +1003,10 @@ static int demux_mpeg_block_send_chunk (demux_plugin_t *this_gen) { } #ifdef ESTIMATE_RATE_FIXED -/*! - Estimate bitrate by looking inside the MPEG file for presentation - time stamps (PTS) and computing how far apart these are - in bytes and in time. +/*! + Estimate bitrate by looking inside the MPEG file for presentation + time stamps (PTS) and computing how far apart these are + in bytes and in time. On failure return 0. @@ -1040,23 +1037,23 @@ static int demux_mpeg_block_estimate_rate (demux_mpeg_block_t *this) { int rate=0; /* The return rate value */ int stream_id; - /* We can't estimate by sampling if we don't thave the ability to + /* We can't estimate by sampling if we don't thave the ability to randomly access the and more importantly reset after accessessing. */ if (!(this->input->get_capabilities(this->input) & INPUT_CAP_SEEKABLE)) return 0; mpeg_length= this->input->get_length (this->input); - step = TRUNC((mpeg_length/MAX_SAMPLES), blocksize); + step = TRUNC((mpeg_length/MAX_SAMPLES), blocksize); if (step <= 0) step = blocksize; /* avoid endless loop for tiny files */ pos = step; /* At this point "pos", and "step" are a multiple of blocksize and they should continue to be so throughout. */ - + this->input->seek (this->input, pos, SEEK_SET); - while ( (buf = this->input->read_block (this->input, this->video_fifo, blocksize)) + while ( (buf = this->input->read_block (this->input, this->video_fifo, blocksize)) && count < MAX_SAMPLES && reads++ < MAX_READS ) { p = buf->content; /* len = this->mnBlocksize; */ @@ -1065,9 +1062,9 @@ static int demux_mpeg_block_estimate_rate (demux_mpeg_block_t *this) { is_mpeg1 = (p[4] & 0x40) == 0; - if (is_mpeg1) + if (is_mpeg1) p += 12; - else + else p += 14 + (p[0xD] & 0x07); } @@ -1084,7 +1081,7 @@ static int demux_mpeg_block_estimate_rate (demux_mpeg_block_t *this) { } stream_id = p[3]; - pts = 0; + pts = 0; if ((stream_id < 0xbc) || ((stream_id & 0xf0) != 0xe0)) { pos += (off_t) blocksize; @@ -1114,18 +1111,18 @@ static int demux_mpeg_block_estimate_rate (demux_mpeg_block_t *this) { pts |= (p[ 2] & 0xFE) << 14 ; pts |= p[ 3] << 7 ; pts |= (p[ 4] & 0xFE) >> 1 ; - } + } } } else { /* mpeg 2 */ - + if (p[7] & 0x80) { /* pts avail */ - + pts = (int64_t)(p[ 9] & 0x0E) << 29 ; pts |= p[10] << 22 ; pts |= (p[11] & 0xFE) << 14 ; pts |= p[12] << 7 ; pts |= (p[13] & 0xFE) >> 1 ; - + } else pts = 0; } @@ -1135,16 +1132,16 @@ static int demux_mpeg_block_estimate_rate (demux_mpeg_block_t *this) { if ( (pos>last_pos) && (pts>last_pts) ) { int cur_rate; - + cur_rate = ((pos - last_pos)*90000) / ((pts - last_pts) * 50); - + rate = (count * rate + cur_rate) / (count+1); count ++; - + /* - printf ("demux_mpeg_block: stream_id %02x, pos: %"PRId64", pts: %d, cur_rate = %d, overall rate : %d\n", - stream_id, pos, pts, cur_rate, rate); + printf ("demux_mpeg_block: stream_id %02x, pos: %"PRId64", pts: %d, cur_rate = %d, overall rate : %d\n", + stream_id, pos, pts, cur_rate, rate); */ } @@ -1168,15 +1165,14 @@ static int demux_mpeg_block_estimate_rate (demux_mpeg_block_t *this) { lprintf("est_rate=%d\n",rate); return rate; - + } #endif /*ESTIMATE_RATE_FIXED*/ static void demux_mpeg_block_dispose (demux_plugin_t *this_gen) { demux_mpeg_block_t *this = (demux_mpeg_block_t *) this_gen; - - free (this->scratch_base); + free (this); } @@ -1186,23 +1182,24 @@ static int demux_mpeg_block_get_status (demux_plugin_t *this_gen) { return this->status; } -static int demux_mpeg_detect_blocksize(demux_mpeg_block_t *this, +static int demux_mpeg_detect_blocksize(demux_mpeg_block_t *this, input_plugin_t *input) { + uint8_t scratch[4]; input->seek(input, 2048, SEEK_SET); - if (!input->read(input, this->scratch, 4)) + if (input->read(input, scratch, 4) != 4) return 0; - if (this->scratch[0] || this->scratch[1] - || (this->scratch[2] != 0x01) || (this->scratch[3] != 0xba)) { + if (scratch[0] || scratch[1] + || (scratch[2] != 0x01) || (scratch[3] != 0xba)) { input->seek(input, 2324, SEEK_SET); - if (!input->read(input, this->scratch, 4)) + if (input->read(input, scratch, 4) != 4) return 0; - if (this->scratch[0] || this->scratch[1] - || (this->scratch[2] != 0x01) || (this->scratch[3] != 0xba)) + if (scratch[0] || scratch[1] + || (scratch[2] != 0x01) || (scratch[3] != 0xba)) return 0; - + return 2324; } else return 2048; @@ -1222,34 +1219,34 @@ static void demux_mpeg_block_send_headers (demux_plugin_t *this_gen) { if (!this->blocksize) return; } - - /* + + /* * send start buffer */ - + _x_demux_control_start(this->stream); - + #ifdef USE_ILL_ADVISED_ESTIMATE_RATE_INITIALLY - if (!this->rate) + if (!this->rate) this->rate = demux_mpeg_block_estimate_rate (this); -#else +#else /* Set to Use rate given in by stream initially. */ - this->rate = 0; + this->rate = 0; #endif - + if((this->input->get_capabilities(this->input) & INPUT_CAP_SEEKABLE) != 0) { - + int num_buffers = NUM_PREVIEW_BUFFERS; - + this->input->seek (this->input, 0, SEEK_SET); - + this->status = DEMUX_OK ; while ( (num_buffers>0) && (this->status == DEMUX_OK) ) { - + demux_mpeg_block_parse_pack(this, 1); num_buffers --; } - } + } /* else FIXME: implement preview generation from PREVIEW data */ this->status = DEMUX_OK; @@ -1268,19 +1265,19 @@ static int demux_mpeg_block_seek (demux_plugin_t *this_gen, this->input->get_length (this->input) ); if((this->input->get_capabilities(this->input) & INPUT_CAP_SEEKABLE) != 0) { - + if (start_pos) { start_pos /= (off_t) this->blocksize; start_pos *= (off_t) this->blocksize; - + this->input->seek (this->input, start_pos, SEEK_SET); } else if (start_time) { - + if( this->input->seek_time ) { this->input->seek_time (this->input, start_time, SEEK_SET); } else { start_time /= 1000; - + if (this->last_cell_time) { start_pos = start_time - (this->last_cell_time + this->last_begin_time)/1000; start_pos *= this->rate; @@ -1293,20 +1290,20 @@ static int demux_mpeg_block_seek (demux_plugin_t *this_gen, } start_pos /= (off_t) this->blocksize; start_pos *= (off_t) this->blocksize; - + this->input->seek (this->input, start_pos, SEEK_SET); } } else this->input->seek (this->input, 0, SEEK_SET); } - + /* * now start demuxing */ this->last_cell_time = 0; this->send_newpts = 1; if( !playing ) { - + this->buf_flag_seek = 0; this->nav_last_end_pts = this->nav_last_start_pts = 0; this->status = DEMUX_OK ; @@ -1317,7 +1314,7 @@ static int demux_mpeg_block_seek (demux_plugin_t *this_gen, this->nav_last_end_pts = this->nav_last_start_pts = 0; _x_demux_flush_engine(this->stream); } - + return this->status; } @@ -1335,7 +1332,7 @@ static void demux_mpeg_block_accept_input (demux_mpeg_block_t *this, lprintf ("mrl %s is new\n", this->cur_mrl); - } + } else { lprintf ("mrl %s is known, bitrate: %d\n", this->cur_mrl, this->rate * 50 * 8); @@ -1349,7 +1346,7 @@ static int demux_mpeg_block_get_stream_length (demux_plugin_t *this_gen) { * find input plugin */ - if (this->rate) + if (this->rate) return (int)((int64_t) 1000 * this->input->get_length (this->input) / (this->rate * 50)); else @@ -1371,10 +1368,10 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str input_plugin_t *input = (input_plugin_t *) input_gen; demux_mpeg_block_t *this; - this = xine_xmalloc (sizeof (demux_mpeg_block_t)); + this = calloc(1, sizeof(demux_mpeg_block_t)); this->stream = stream; this->input = input; - + this->demux_plugin.send_headers = demux_mpeg_block_send_headers; this->demux_plugin.send_chunk = demux_mpeg_block_send_chunk; this->demux_plugin.seek = demux_mpeg_block_seek; @@ -1385,25 +1382,25 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str this->demux_plugin.get_optional_data = demux_mpeg_block_get_optional_data; this->demux_plugin.demux_class = class_gen; - this->scratch = xine_xmalloc_aligned (512, 4096, &this->scratch_base); this->status = DEMUX_FINISHED; lprintf ("open_plugin:detection_method=%d\n", stream->content_detection_method); - + switch (stream->content_detection_method) { - + case METHOD_BY_CONTENT: { /* use demux_mpeg for non-block devices */ if (!(input->get_capabilities(input) & INPUT_CAP_BLOCK)) { - free (this->scratch_base); free (this); return NULL; } if (((input->get_capabilities(input) & INPUT_CAP_SEEKABLE) != 0) ) { + uint8_t scratch[5] = {0xff, 0xff, 0xff, 0xff, 0xff}; /* result of input->read() won't matter */ + this->blocksize = input->get_blocksize(input); lprintf("open_plugin:blocksize=%d\n",this->blocksize); @@ -1411,28 +1408,25 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str this->blocksize = demux_mpeg_detect_blocksize( this, input ); if (!this->blocksize) { - free (this->scratch_base); free (this); return NULL; } input->seek(input, 0, SEEK_SET); - if (input->read(input, this->scratch, this->blocksize)) { + if (input->read(input, scratch, 5)) { lprintf("open_plugin:read worked\n"); - if (this->scratch[0] || this->scratch[1] - || (this->scratch[2] != 0x01) || (this->scratch[3] != 0xba)) { + if (scratch[0] || scratch[1] + || (scratch[2] != 0x01) || (scratch[3] != 0xba)) { lprintf("open_plugin:scratch failed\n"); - free (this->scratch_base); free (this); return NULL; } /* if it's a file then make sure it's mpeg-2 */ if ( !input->get_blocksize(input) - && ((this->scratch[4]>>4) != 4) ) { - free (this->scratch_base); + && ((scratch[4]>>4) != 4) ) { free (this); return NULL; } @@ -1446,7 +1440,6 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str break; } } - free (this->scratch_base); free (this); return NULL; } @@ -1467,7 +1460,6 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str ending = strrchr(mrl, '.'); if (!ending) { - free (this->scratch_base); free (this); return NULL; } @@ -1477,7 +1469,6 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str this->blocksize = 2048; demux_mpeg_block_accept_input(this, input); } else { - free (this->scratch_base); free (this); return NULL; } @@ -1495,7 +1486,6 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str this->blocksize = demux_mpeg_detect_blocksize( this, input ); if (!this->blocksize) { - free (this->scratch_base); free (this); return NULL; } @@ -1505,7 +1495,6 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str break; default: - free (this->scratch_base); free (this); return NULL; } @@ -1540,7 +1529,7 @@ static void *init_plugin (xine_t *xine, void *data) { demux_mpeg_block_class_t *this; - this = xine_xmalloc (sizeof (demux_mpeg_block_class_t)); + this = calloc(1, sizeof(demux_mpeg_block_class_t)); this->config = xine->config; this->xine = xine; @@ -1562,7 +1551,7 @@ static const demuxer_info_t demux_info_mpeg_block = { }; const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ + /* type, API, "name", version, special_info, init_function */ { PLUGIN_DEMUX, 26, "mpeg_block", XINE_VERSION_CODE, &demux_info_mpeg_block, init_plugin }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; diff --git a/src/demuxers/demux_mpeg_pes.c b/src/demuxers/demux_mpeg_pes.c index 423da5e24..0fe97fb93 100644 --- a/src/demuxers/demux_mpeg_pes.c +++ b/src/demuxers/demux_mpeg_pes.c @@ -1,18 +1,18 @@ /* - * Copyright (C) 2000-2006 the xine project - * + * Copyright (C) 2000-2008 the xine project + * * This file is part of xine, a free video player. - * + * * xine is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * xine is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA @@ -24,7 +24,7 @@ * (c) 2003 James Courtier-Dutton James@superbug.demon.co.uk * This code might also decode normal MPG files. */ - + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -48,7 +48,7 @@ #define NUM_PREVIEW_BUFFERS 250 #define DISC_TRESHOLD 90000 -#define WRAP_THRESHOLD 270000 +#define WRAP_THRESHOLD 270000 #define PTS_AUDIO 0 #define PTS_VIDEO 1 @@ -60,14 +60,14 @@ typedef struct demux_mpeg_pes_s { demux_plugin_t demux_plugin; - xine_stream_t *stream; + xine_stream_t *stream; fifo_buffer_t *audio_fifo; fifo_buffer_t *video_fifo; input_plugin_t *input; int status; - + int rate; char cur_mrl[256]; @@ -91,7 +91,7 @@ typedef struct demux_mpeg_pes_s { uint8_t mpeg1:1; uint8_t wait_for_program_stream_pack_header:1; uint8_t mpeg12_h264_detected:2; - + int last_begin_time; int64_t last_cell_time; off_t last_cell_pos; @@ -202,7 +202,7 @@ static int detect_pts_discontinuity( demux_mpeg_pes_t *this, int64_t pts, int vi /* no discontinuity detected */ return 0; } - + static void check_newpts( demux_mpeg_pes_t *this, int64_t pts, int video ) { if( pts && (this->send_newpts || detect_pts_discontinuity(this, pts, video) ) ) { @@ -226,7 +226,7 @@ static void check_newpts( demux_mpeg_pes_t *this, int64_t pts, int video ) /* clear pts on the other track to avoid detecting the same discontinuity again */ this->last_pts[1-video] = 0; } - + if( pts ) this->last_pts[video] = pts; } @@ -257,9 +257,8 @@ static void demux_mpeg_pes_parse_pack (demux_mpeg_pes_t *this, int preview_mode) uint8_t *p; int32_t result; off_t i; - int32_t n; uint8_t buf6[ 6 ]; - + this->scr = 0; this->preview_mode = preview_mode; @@ -274,16 +273,16 @@ static void demux_mpeg_pes_parse_pack (demux_mpeg_pes_t *this, int preview_mode) while ((p[2] != 1) || p[0] || p[1]) { /* resync code */ - for(n=0;n<5;n++) p[n]=p[n+1]; + memmove(p, p+1, 5); i = read_data(this, p+5, (off_t) 1); if (i != 1) { this->status = DEMUX_FINISHED; return; } } - + /* FIXME: buf must be allocated from somewhere before calling here. */ - + /* these streams should be allocated on the audio_fifo, if available. */ if ((0xC0 <= p[ 3 ] && p[ 3 ] <= 0xDF) /* audio_stream */ || 0xBD == p[ 3 ]) /* private_sream_1 */ @@ -302,20 +301,19 @@ static void demux_mpeg_pes_parse_pack (demux_mpeg_pes_t *this, int preview_mode) return; } } - + p = buf->mem; /* copy local buffer to fifo element. */ - for (n = 0; n < sizeof (buf6); n++) - p[ n ] = buf6[ n ]; - + memcpy(p, buf6, sizeof(buf6)); + if (preview_mode) buf->decoder_flags = BUF_FLAG_PREVIEW; else buf->decoder_flags = 0; - + if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * + buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * 65535 / this->input->get_length (this->input) ); this->stream_id = p[3]; @@ -414,7 +412,7 @@ static void demux_mpeg_pes_parse_pack (demux_mpeg_pes_t *this, int preview_mode) xprintf(this->stream->xine, XINE_VERBOSITY_LOG, _("xine-lib:demux_mpeg_pes: Unrecognised stream_id 0x%02x. " "Please report this to xine developers.\n"), this->stream_id); - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "xine-lib:demux_mpeg_pes: packet_len=%d\n", this->packet_len); buf->free_buffer (buf); return; @@ -437,11 +435,11 @@ static int32_t parse_padding_stream(demux_mpeg_pes_t *this, uint8_t *p, buf_elem { /* Handle Jumbo frames from VDR. */ int i; - + int size = buf->max_size; if ((todo - done) < size) size = todo - done; - + i = read_data(this, buf->mem, (off_t)size); if (i != size) break; @@ -458,98 +456,98 @@ static int32_t parse_padding_stream(demux_mpeg_pes_t *this, uint8_t *p, buf_elem static int32_t parse_program_stream_map(demux_mpeg_pes_t *this, uint8_t *p, buf_element_t *buf) { /* FIXME: Implement */ - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "xine-lib:demux_mpeg_pes: Unhandled stream_id 0x%02x.\n", this->stream_id); buf->free_buffer (buf); return -1; } static int32_t parse_ecm_stream(demux_mpeg_pes_t *this, uint8_t *p, buf_element_t *buf) { /* FIXME: Implement */ - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "xine-lib:demux_mpeg_pes: Unhandled stream_id 0x%02x\n", this->stream_id); buf->free_buffer (buf); return -1; } static int32_t parse_emm_stream(demux_mpeg_pes_t *this, uint8_t *p, buf_element_t *buf) { /* FIXME: Implement */ - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "xine-lib:demux_mpeg_pes: Unhandled stream_id 0x%02x\n", this->stream_id); buf->free_buffer (buf); return -1; } static int32_t parse_dsmcc_stream(demux_mpeg_pes_t *this, uint8_t *p, buf_element_t *buf) { /* FIXME: Implement */ - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "xine-lib:demux_mpeg_pes: Unhandled stream_id 0x%02x\n", this->stream_id); buf->free_buffer (buf); return -1; } static int32_t parse_iec_13522_stream(demux_mpeg_pes_t *this, uint8_t *p, buf_element_t *buf) { /* FIXME: Implement */ - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "xine-lib:demux_mpeg_pes: Unhandled stream_id 0x%02x\n", this->stream_id); buf->free_buffer (buf); return -1; } static int32_t parse_h222_typeA_stream(demux_mpeg_pes_t *this, uint8_t *p, buf_element_t *buf) { /* FIXME: Implement */ - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "xine-lib:demux_mpeg_pes: Unhandled stream_id 0x%02x\n", this->stream_id); buf->free_buffer (buf); return -1; } static int32_t parse_h222_typeB_stream(demux_mpeg_pes_t *this, uint8_t *p, buf_element_t *buf) { /* FIXME: Implement */ - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "xine-lib:demux_mpeg_pes: Unhandled stream_id 0x%02x\n", this->stream_id); buf->free_buffer (buf); return -1; } static int32_t parse_h222_typeC_stream(demux_mpeg_pes_t *this, uint8_t *p, buf_element_t *buf) { /* FIXME: Implement */ - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "xine-lib:demux_mpeg_pes: Unhandled stream_id 0x%02x\n", this->stream_id); buf->free_buffer (buf); return -1; } static int32_t parse_h222_typeD_stream(demux_mpeg_pes_t *this, uint8_t *p, buf_element_t *buf) { /* FIXME: Implement */ - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "xine-lib:demux_mpeg_pes: Unhandled stream_id 0x%02x\n", this->stream_id); buf->free_buffer (buf); return -1; } static int32_t parse_h222_typeE_stream(demux_mpeg_pes_t *this, uint8_t *p, buf_element_t *buf) { /* FIXME: Implement */ - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "xine-lib:demux_mpeg_pes: Unhandled stream_id 0x%02x\n", this->stream_id); buf->free_buffer (buf); return -1; } static int32_t parse_IEC14496_SL_packetized_stream(demux_mpeg_pes_t *this, uint8_t *p, buf_element_t *buf) { /* FIXME: Implement */ - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "xine-lib:demux_mpeg_pes: Unhandled stream_id 0x%02x\n", this->stream_id); buf->free_buffer (buf); return -1; } static int32_t parse_IEC14496_FlexMux_stream(demux_mpeg_pes_t *this, uint8_t *p, buf_element_t *buf) { /* FIXME: Implement */ - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "xine-lib:demux_mpeg_pes: Unhandled stream_id 0x%02x\n", this->stream_id); buf->free_buffer (buf); return -1; } static int32_t parse_program_stream_directory(demux_mpeg_pes_t *this, uint8_t *p, buf_element_t *buf) { /* FIXME: Implement */ - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "xine-lib:demux_mpeg_pes: Unhandled stream_id 0x%02x\n", this->stream_id); buf->free_buffer (buf); return -1; } static int32_t parse_ancillary_stream(demux_mpeg_pes_t *this, uint8_t *p, buf_element_t *buf) { /* FIXME: Implement */ - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "xine-lib:demux_mpeg_pes: Unhandled stream_id 0x%02x\n", this->stream_id); buf->free_buffer (buf); return -1; @@ -590,7 +588,7 @@ static int32_t parse_program_stream_pack_header(demux_mpeg_pes_t *this, uint8_t return 12; } else { /* mpeg2 */ - + int num_stuffing_bytes; /* system_clock_reference */ @@ -664,7 +662,7 @@ static int32_t parse_private_stream_2(demux_mpeg_pes_t *this, uint8_t *p, buf_el * the NAV packet for a much more accurate timing */ if (buf->extra_info->input_time) { int64_t cell_time, frames; - + cell_time = (p[7+0x18] >> 4 ) * 10 * 60 * 60 * 1000; cell_time += (p[7+0x18] & 0x0f) * 60 * 60 * 1000; cell_time += (p[7+0x19] >> 4 ) * 10 * 60 * 1000; @@ -673,7 +671,7 @@ static int32_t parse_private_stream_2(demux_mpeg_pes_t *this, uint8_t *p, buf_el cell_time += (p[7+0x1a] & 0x0f) * 1000; frames = ((p[7+0x1b] & 0x30) >> 4) * 10; frames += ((p[7+0x1b] & 0x0f) ) ; - + if (p[7+0x1b] & 0x80) cell_time += (frames * 1000)/25; else @@ -683,7 +681,7 @@ static int32_t parse_private_stream_2(demux_mpeg_pes_t *this, uint8_t *p, buf_el this->last_cell_pos = this->input->get_current_pos (this->input); this->last_begin_time = buf->extra_info->input_time; } - + lprintf ("NAV packet, start pts = %"PRId64", end_pts = %"PRId64"\n", start_pts, end_pts); @@ -733,7 +731,7 @@ static int32_t parse_pes_for_pts(demux_mpeg_pes_t *this, uint8_t *p, buf_element } if (this->rate && !buf->extra_info->input_time) - buf->extra_info->input_time = (int)((int64_t)this->input->get_current_pos (this->input) + buf->extra_info->input_time = (int)((int64_t)this->input->get_current_pos (this->input) * 1000 / (this->rate * 50)); /* FIXME: This was determined by comparing a single MPEG1 and a single MPEG2 stream */ @@ -748,7 +746,7 @@ static int32_t parse_pes_for_pts(demux_mpeg_pes_t *this, uint8_t *p, buf_element p += 6; /* packet_len -= 6; */ while ((p[0] & 0x80) == 0x80) { - p++; + p++; header_len++; this->packet_len--; /* printf ("stuffing\n");*/ @@ -761,9 +759,9 @@ static int32_t parse_pes_for_pts(demux_mpeg_pes_t *this, uint8_t *p, buf_element this->packet_len -= 2; } - this->pts = 0; + this->pts = 0; this->dts = 0; - + if ((p[0] & 0xf0) == 0x20) { this->pts = (int64_t) (p[ 0] & 0x0E) << 29 ; this->pts |= (int64_t) p[ 1] << 22 ; @@ -780,19 +778,19 @@ static int32_t parse_pes_for_pts(demux_mpeg_pes_t *this, uint8_t *p, buf_element this->pts |= (int64_t) (p[ 2] & 0xFE) << 14 ; this->pts |= (int64_t) p[ 3] << 7 ; this->pts |= (int64_t) (p[ 4] & 0xFE) >> 1 ; - + this->dts = (int64_t) (p[ 5] & 0x0E) << 29 ; this->dts |= (int64_t) p[ 6] << 22 ; this->dts |= (int64_t) (p[ 7] & 0xFE) << 14 ; this->dts |= (int64_t) p[ 8] << 7 ; this->dts |= (int64_t) (p[ 9] & 0xFE) >> 1 ; - + p += 10; header_len += 10; this->packet_len -= 10; return header_len; } else { - p++; + p++; header_len++; this->packet_len--; return header_len; @@ -836,13 +834,13 @@ static int32_t parse_pes_for_pts(demux_mpeg_pes_t *this, uint8_t *p, buf_element this->pts = 0; if (p[7] & 0x40) { /* dts avail */ - + this->dts = (int64_t) (p[14] & 0x0E) << 29 ; this->dts |= (int64_t) p[15] << 22 ; this->dts |= (int64_t) (p[16] & 0xFE) << 14 ; this->dts |= (int64_t) p[17] << 7 ; this->dts |= (int64_t) (p[18] & 0xFE) >> 1 ; - + } else this->dts = 0; @@ -871,16 +869,16 @@ static int32_t parse_private_stream_1(demux_mpeg_pes_t *this, uint8_t *p, buf_el buf->content = p+1; buf->size = this->packet_len-1; - + buf->type = BUF_SPU_DVD + spu_id; buf->decoder_flags |= BUF_FLAG_SPECIAL; buf->decoder_info[1] = BUF_SPECIAL_SPU_DVD_SUBTYPE; buf->decoder_info[2] = SPU_DVD_SUBTYPE_PACKAGE; buf->pts = this->pts; - - this->video_fifo->put (this->video_fifo, buf); + + this->video_fifo->put (this->video_fifo, buf); lprintf ("SPU PACK put on fifo\n"); - + return this->packet_len + result; } @@ -896,9 +894,9 @@ static int32_t parse_private_stream_1(demux_mpeg_pes_t *this, uint8_t *p, buf_el if( !preview_mode ) check_newpts( this, this->pts, PTS_VIDEO ); */ - this->video_fifo->put (this->video_fifo, buf); + this->video_fifo->put (this->video_fifo, buf); lprintf ("SPU SVCD PACK (%"PRId64", %d) put on fifo\n", this->pts, spu_id); - + return this->packet_len + result; } @@ -913,15 +911,15 @@ static int32_t parse_private_stream_1(demux_mpeg_pes_t *this, uint8_t *p, buf_el /* this is probably wrong: if( !preview_mode ) check_newpts( this, this->pts, PTS_VIDEO ); - */ - this->video_fifo->put (this->video_fifo, buf); + */ + this->video_fifo->put (this->video_fifo, buf); lprintf ("SPU CVD PACK (%"PRId64", %d) put on fifo\n", this->pts, spu_id); - + return this->packet_len + result; } if ((p[0]&0xF0) == 0x80) { - + track = p[0] & 0x0F; /* hack : ac3 track */ buf->decoder_info[1] = p[1]; /* Number of frame headers */ buf->decoder_info[2] = p[2] << 8 | p[3]; /* First access unit pointer */ @@ -945,7 +943,7 @@ static int32_t parse_private_stream_1(demux_mpeg_pes_t *this, uint8_t *p, buf_el buf->free_buffer(buf); } return this->packet_len + result; - + } else if ((p[0]&0xf0) == 0xa0) { int pcm_offset; @@ -985,7 +983,7 @@ static int32_t parse_private_stream_1(demux_mpeg_pes_t *this, uint8_t *p, buf_el switch ((p[5]>>6) & 3) { case 3: /* illegal, use 16-bits? */ default: - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "illegal lpcm sample format (%d), assume 16-bit samples\n", (p[5]>>6) & 3 ); case 0: bits_per_sample = 16; break; @@ -998,7 +996,7 @@ static int32_t parse_private_stream_1(demux_mpeg_pes_t *this, uint8_t *p, buf_el buf->decoder_flags |= BUF_FLAG_SPECIAL; buf->decoder_info[1] = BUF_SPECIAL_LPCM_CONFIG; buf->decoder_info[2] = p[5]; - + pcm_offset = 7; buf->content = p+pcm_offset; @@ -1022,7 +1020,7 @@ static int32_t parse_private_stream_1(demux_mpeg_pes_t *this, uint8_t *p, buf_el int size; /* - * A52/AC3 streams in some DVB-S recordings made with VDR. + * A52/AC3 streams in some DVB-S recordings made with VDR. * It is broadcast by a german tv-station called PRO7. * PRO7 uses dolby 5.1 (A52 5.1) in some of the movies they broadcast, * (and they would switch it to stereo-sound(A52 2.0) during commercials.) @@ -1075,18 +1073,18 @@ static int32_t parse_private_stream_1(demux_mpeg_pes_t *this, uint8_t *p, buf_el lprintf ("A52 PACK put on fifo\n"); } else { buf->free_buffer(buf); - } + } } return this->packet_len + result; } - + /* Some new streams have been encountered. 1) DVD+RW disc recorded with a Philips DVD recorder: - new unknown sub-stream id of 0xff */ - xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, _("demux_mpeg_pes:Unrecognised private stream 1 0x%02x. Please report this to xine developers.\n"), p[0]); buf->free_buffer(buf); return this->packet_len + result; @@ -1168,14 +1166,14 @@ static int32_t parse_video_stream(demux_mpeg_pes_t *this, uint8_t *p, buf_elemen if (this->mpeg12_h264_detected > 2) { int nal_type_code = -1; if (payload_size >= 4 && p[2] == 0x01 && p[1] == 0x00 && p[0] == 0x00) - nal_type_code = p[3] & 0x1f; + nal_type_code = p[3] & 0x1f; if (nal_type_code == 9) { /* access unit delimiter */ buf_element_t *b = this->video_fifo->buffer_pool_alloc (this->video_fifo); b->content = b->mem; b->size = 0; b->pts = 0; b->type = buf_type; - b->decoder_flags = BUF_FLAG_FRAME_END; + b->decoder_flags = BUF_FLAG_FRAME_END | (this->preview_mode ? BUF_FLAG_PREVIEW : 0); this->video_fifo->put (this->video_fifo, b); } } @@ -1189,7 +1187,7 @@ static int32_t parse_video_stream(demux_mpeg_pes_t *this, uint8_t *p, buf_elemen if (this->mpeg12_h264_detected & 1) { uint8_t *t = buf->content + buf->size; if (buf->size >=4 && t[-1] == 10 && t[-2] == 0x01 && t[-3] == 0x00 && t[-4] == 0x00) /* end of sequence */ - buf->decoder_flags = BUF_FLAG_FRAME_END; + buf->decoder_flags = BUF_FLAG_FRAME_END | (this->preview_mode ? BUF_FLAG_PREVIEW : 0); } } else { buf->size = buf->max_size - result; @@ -1227,7 +1225,7 @@ static int32_t parse_video_stream(demux_mpeg_pes_t *this, uint8_t *p, buf_elemen if ((this->mpeg12_h264_detected & 1) && todo_length <= 0) { uint8_t *t = buf->content + buf->size; if (buf->size >= 4 && t[-1] == 10 && t[-2] == 0x01 && t[-3] == 0x00 && t[-4] == 0x00) /* end of sequence */ - buf->decoder_flags = BUF_FLAG_FRAME_END; + buf->decoder_flags = BUF_FLAG_FRAME_END | (this->preview_mode ? BUF_FLAG_PREVIEW : 0); } this->video_fifo->put (this->video_fifo, buf); @@ -1277,10 +1275,10 @@ static int demux_mpeg_pes_send_chunk (demux_plugin_t *this_gen) { } #ifdef ESTIMATE_RATE_FIXED -/*! - Estimate bitrate by looking inside the MPEG file for presentation - time stamps (PTS) and computing how far apart these are - in bytes and in time. +/*! + Estimate bitrate by looking inside the MPEG file for presentation + time stamps (PTS) and computing how far apart these are + in bytes and in time. On failure return 0. @@ -1310,23 +1308,23 @@ static int demux_mpeg_pes_estimate_rate (demux_mpeg_pes_t *this) { int rate=0; /* The return rate value */ int stream_id; - /* We can't estimate by sampling if we don't thave the ability to + /* We can't estimate by sampling if we don't thave the ability to randomly access the and more importantly reset after accessessing. */ if (!(this->input->get_capabilities(this->input) & INPUT_CAP_SEEKABLE)) return 0; mpeg_length= this->input->get_length (this->input); - step = TRUNC((mpeg_length/MAX_SAMPLES), 2048); + step = TRUNC((mpeg_length/MAX_SAMPLES), 2048); if (step <= 0) step = 2048; /* avoid endless loop for tiny files */ pos = step; /* At this point "pos", and "step" are a multiple of blocksize and they should continue to be so throughout. */ - + this->input->seek (this->input, pos, SEEK_SET); - while ( (buf = this->input->read_block (this->input, this->video_fifo, 2048)) + while ( (buf = this->input->read_block (this->input, this->video_fifo, 2048)) && count < MAX_SAMPLES && reads++ < MAX_READS ) { p = buf->content; /* len = this->mnBlocksize; */ @@ -1335,9 +1333,9 @@ static int demux_mpeg_pes_estimate_rate (demux_mpeg_pes_t *this) { is_mpeg1 = (p[4] & 0x40) == 0; - if (is_mpeg1) + if (is_mpeg1) p += 12; - else + else p += 14 + (p[0xD] & 0x07); } @@ -1347,14 +1345,14 @@ static int demux_mpeg_pes_estimate_rate (demux_mpeg_pes_t *this) { /* we should now have a PES packet here */ if (p[0] || p[1] || (p[2] != 1)) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_mpeg_pes: error %02x %02x %02x (should be 0x000001) \n", p[0], p[1], p[2]); buf->free_buffer (buf); return rate; } stream_id = p[3]; - pts = 0; + pts = 0; if ((stream_id < 0xbc) || ((stream_id & 0xf0) != 0xe0)) { pos += (off_t) 2048; @@ -1383,18 +1381,18 @@ static int demux_mpeg_pes_estimate_rate (demux_mpeg_pes_t *this) { pts |= (p[ 2] & 0xFE) << 14 ; pts |= p[ 3] << 7 ; pts |= (p[ 4] & 0xFE) >> 1 ; - } + } } } else { /* mpeg 2 */ - + if (p[7] & 0x80) { /* pts avail */ - + pts = (int64_t)(p[ 9] & 0x0E) << 29 ; pts |= p[10] << 22 ; pts |= (p[11] & 0xFE) << 14 ; pts |= p[12] << 7 ; pts |= (p[13] & 0xFE) >> 1 ; - + } else pts = 0; } @@ -1404,16 +1402,16 @@ static int demux_mpeg_pes_estimate_rate (demux_mpeg_pes_t *this) { if ( (pos>last_pos) && (pts>last_pts) ) { int cur_rate; - + cur_rate = ((pos - last_pos)*90000) / ((pts - last_pts) * 50); - + rate = (count * rate + cur_rate) / (count+1); count ++; - + /* - printf ("demux_mpeg_pes: stream_id %02x, pos: %"PRId64", pts: %d, cur_rate = %d, overall rate : %d\n", - stream_id, pos, pts, cur_rate, rate); + printf ("demux_mpeg_pes: stream_id %02x, pos: %"PRId64", pts: %d, cur_rate = %d, overall rate : %d\n", + stream_id, pos, pts, cur_rate, rate); */ } @@ -1433,14 +1431,14 @@ static int demux_mpeg_pes_estimate_rate (demux_mpeg_pes_t *this) { lprintf("est_rate=%d\n",rate); return rate; - + } #endif /*ESTIMATE_RATE_FIXED*/ static void demux_mpeg_pes_dispose (demux_plugin_t *this_gen) { demux_mpeg_pes_t *this = (demux_mpeg_pes_t *) this_gen; - + free (this->scratch_base); free (this); } @@ -1458,35 +1456,35 @@ static void demux_mpeg_pes_send_headers (demux_plugin_t *this_gen) { this->video_fifo = this->stream->video_fifo; this->audio_fifo = this->stream->audio_fifo; - /* + /* * send start buffer */ - + _x_demux_control_start(this->stream); - + #ifdef USE_ILL_ADVISED_ESTIMATE_RATE_INITIALLY - if (!this->rate) + if (!this->rate) this->rate = demux_mpeg_pes_estimate_rate (this); -#else +#else /* Set to Use rate given in by stream initially. */ - this->rate = 0; + this->rate = 0; #endif - + if((this->input->get_capabilities(this->input) & INPUT_CAP_SEEKABLE) != 0) { - + int num_buffers = NUM_PREVIEW_BUFFERS; - + this->input->seek (this->input, 0, SEEK_SET); - + this->status = DEMUX_OK ; while ( (num_buffers>0) && (this->status == DEMUX_OK) ) { - + demux_mpeg_pes_parse_pack(this, 1); num_buffers --; } - } + } else if((this->input->get_capabilities(this->input) & INPUT_CAP_PREVIEW) != 0) { - + this->preview_size = this->input->get_optional_data(this->input, &this->preview_data, INPUT_OPTIONAL_DATA_PREVIEW); this->preview_done = 0; @@ -1514,14 +1512,14 @@ static int demux_mpeg_pes_seek (demux_plugin_t *this_gen, this->input->get_length (this->input) ); if((this->input->get_capabilities(this->input) & INPUT_CAP_SEEKABLE) != 0) { - + if (start_pos) { start_pos /= (off_t) 2048; start_pos *= (off_t) 2048; - + this->input->seek (this->input, start_pos, SEEK_SET); } else if (start_time) { - + if (this->last_cell_time) { start_pos = start_time - (this->last_cell_time + this->last_begin_time)/1000; start_pos *= this->rate; @@ -1534,19 +1532,19 @@ static int demux_mpeg_pes_seek (demux_plugin_t *this_gen, } start_pos /= (off_t) 2048; start_pos *= (off_t) 2048; - + this->input->seek (this->input, start_pos, SEEK_SET); } else this->input->seek (this->input, 0, SEEK_SET); } - + /* * now start demuxing */ this->last_cell_time = 0; this->send_newpts = 1; if( !playing ) { - + this->buf_flag_seek = 0; this->nav_last_end_pts = this->nav_last_start_pts = 0; this->status = DEMUX_OK ; @@ -1559,7 +1557,7 @@ static int demux_mpeg_pes_seek (demux_plugin_t *this_gen, this->mpeg12_h264_detected = 0; _x_demux_flush_engine(this->stream); } - + return this->status; } @@ -1577,7 +1575,7 @@ static void demux_mpeg_pes_accept_input (demux_mpeg_pes_t *this, lprintf ("mrl %s is new\n", this->cur_mrl); - } + } else { lprintf ("mrl %s is known, bitrate: %d\n", this->cur_mrl, this->rate * 50 * 8); @@ -1591,7 +1589,7 @@ static int demux_mpeg_pes_get_stream_length (demux_plugin_t *this_gen) { * find input plugin */ - if (this->rate) + if (this->rate) return (int)((int64_t) 1000 * this->input->get_length (this->input) / (this->rate * 50)); else @@ -1613,10 +1611,10 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str input_plugin_t *input = (input_plugin_t *) input_gen; demux_mpeg_pes_t *this; - this = xine_xmalloc (sizeof (demux_mpeg_pes_t)); + this = calloc(1, sizeof(demux_mpeg_pes_t)); this->stream = stream; this->input = input; - + this->demux_plugin.send_headers = demux_mpeg_pes_send_headers; this->demux_plugin.send_chunk = demux_mpeg_pes_send_chunk; this->demux_plugin.seek = demux_mpeg_pes_seek; @@ -1639,9 +1637,9 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str lprintf ("open_plugin:detection_method=%d\n", stream->content_detection_method); - + switch (stream->content_detection_method) { - + case METHOD_BY_CONTENT: { /* use demux_mpeg_block for block devices */ @@ -1688,7 +1686,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str if (((input->get_capabilities(input) & INPUT_CAP_SEEKABLE) != 0) ) { input->seek(input, 0, SEEK_SET); - if (input->read(input, (char *)this->scratch, 6)) { + if (input->read(input, (char *)this->scratch, 6) == 6) { lprintf("open_plugin:read worked\n"); if (this->scratch[0] || this->scratch[1] @@ -1786,7 +1784,7 @@ static void class_dispose (demux_class_t *this_gen) { static void *init_plugin (xine_t *xine, void *data) { demux_mpeg_pes_class_t *this; - this = xine_xmalloc (sizeof (demux_mpeg_pes_class_t)); + this = calloc(1, sizeof(demux_mpeg_pes_class_t)); this->config = xine->config; this->xine = xine; @@ -1808,7 +1806,7 @@ static const demuxer_info_t demux_info_mpeg_pes = { }; const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ + /* type, API, "name", version, special_info, init_function */ { PLUGIN_DEMUX, 26, "mpeg_pes", XINE_VERSION_CODE, &demux_info_mpeg_pes, init_plugin }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; diff --git a/src/demuxers/demux_mpgaudio.c b/src/demuxers/demux_mpgaudio.c index 17916f837..6205f9a08 100644 --- a/src/demuxers/demux_mpgaudio.c +++ b/src/demuxers/demux_mpgaudio.c @@ -1,18 +1,18 @@ /* * Copyright (C) 2000-2007 the xine project - * + * * This file is part of xine, a free video player. - * + * * xine is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * xine is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA @@ -33,7 +33,7 @@ #include <string.h> #include <stdlib.h> -#define LOG_MODULE "demux_mpeg_audio" +#define LOG_MODULE "demux_mpgaudio" #define LOG_VERBOSE /* #define LOG @@ -51,8 +51,8 @@ * the second mp3 frame is sent to the decoder */ #define NUM_PREVIEW_BUFFERS 2 +#define NUM_VALID_FRAMES 3 -#define WRAP_THRESHOLD 120000 #define FOURCC_TAG BE_FOURCC #define RIFF_CHECK_BYTES 1024 @@ -79,16 +79,16 @@ /* mp3 frame struct */ typedef struct { /* header */ - double duration; - uint32_t size; /* in bytes */ + double duration; /* in milliseconds */ + uint32_t size; /* in bytes; including padding */ uint32_t bitrate; /* in bit per second */ uint16_t freq; /* in Hz */ - uint8_t layer; - uint8_t version_idx:2; /* 0: mpeg1, 1: mpeg2, 2: mpeg2.5 */ uint8_t lsf_bit:1; uint8_t channel_mode:3; + uint8_t padding:3; /* in bytes */ + uint8_t is_free_bitrate:1; } mpg_audio_frame_t; /* Xing Vbr Header struct */ @@ -98,7 +98,7 @@ typedef struct { uint32_t stream_size; uint8_t toc[XING_TOC_LENGTH]; uint32_t vbr_scale; - + /* Lame extension */ uint16_t start_delay; uint16_t end_delay; @@ -131,7 +131,13 @@ typedef struct { int br; /* bitrate in bits/second */ uint32_t blocksize; + /* current mp3 frame */ mpg_audio_frame_t cur_frame; + + /* next mp3 frame, used when the frame size cannot be computed from the + * current frame header */ + mpg_audio_frame_t next_frame; + double cur_time; /* in milliseconds */ off_t mpg_frame_start; /* offset */ @@ -141,7 +147,15 @@ typedef struct { int check_vbr_header; xing_header_t *xing_header; vbri_header_t *vbri_header; - + + int found_next_frame:1; + int free_bitrate_count; + off_t free_bitrate_size; /* use this size if 3 free bitrate frames are encountered */ + uint8_t next_header[4]; + int mpg_version; + int mpg_layer; + int valid_frames; + } demux_mpgaudio_t ; /* demuxer class struct */ @@ -212,14 +226,14 @@ static int parse_frame_header(mpg_audio_frame_t *const frame, const uint8_t *con const uint32_t head = _X_BE_32(buf); const uint16_t frame_sync = head >> 21; - lprintf("header: %08X\n", head); if (frame_sync != 0x7ff) { - lprintf("invalid frame sync\n"); + lprintf("invalid frame sync %08X\n", head); return 0; } + lprintf("header: %08X\n", head); frame_header.mpeg25_bit = (head >> 20) & 0x1; - frame->lsf_bit = (head >> 19) & 0x1; + frame->lsf_bit = (head >> 19) & 0x1; if (!frame_header.mpeg25_bit) { if (frame->lsf_bit) { lprintf("reserved mpeg25 lsf combination\n"); @@ -240,14 +254,14 @@ static int parse_frame_header(mpg_audio_frame_t *const frame, const uint8_t *con } frame_header.bitrate_idx = (head >> 12) & 0xf; - if ((frame_header.bitrate_idx == 0) || (frame_header.bitrate_idx == 15)) { - lprintf("invalid bitrate index\n"); + if (frame_header.bitrate_idx == 15) { + lprintf("invalid bitrate index: %d\n", frame_header.bitrate_idx); return 0; } frame_header.freq_idx = (head >> 10) & 0x3; if (frame_header.freq_idx == 3) { - lprintf("invalid frequence index\n"); + lprintf("invalid frequence index: %d\n", frame_header.freq_idx); return 0; } @@ -275,24 +289,32 @@ static int parse_frame_header(mpg_audio_frame_t *const frame, const uint8_t *con return 0; } #endif - + { const uint16_t samples = mp3_samples[frame->version_idx][frame->layer - 1]; frame->bitrate = mp3_bitrates[frame->version_idx][frame->layer - 1][frame_header.bitrate_idx] * 1000; frame->freq = mp3_freqs[frame->version_idx][frame_header.freq_idx]; - - frame->size = samples * (frame->bitrate / 8); - frame->size /= frame->freq; - /* Padding: only if padding_bit is set; 4 bytes for Layer 1 and 1 byte for others */ - frame->size += ( frame_header.padding_bit ? ( frame->layer == 1 ? 4 : 1 ) : 0 ); - frame->duration = 1000.0f * (double)samples / (double)frame->freq; + frame->padding = ( frame_header.padding_bit ? ( frame->layer == 1 ? 4 : 1 ) : 0 ); + frame->channel_mode = frame_header.channel_mode; + + if (frame->bitrate > 0) { + frame->size = samples * (frame->bitrate / 8); + frame->size /= frame->freq; + /* Padding: only if padding_bit is set; 4 bytes for Layer 1 and 1 byte for others */ + frame->size += frame->padding; + } else { + /* Free bitrate frame, the size of the frame cannot be computed from the header. */ + frame->is_free_bitrate = 1; + frame->size = 0; + } } - lprintf("mpeg %d, layer %d\n", frame->version_idx + 1, frame->layer); - lprintf("bitrate: %d bps, samplerate: %d Hz\n", frame->bitrate, frame->freq); + lprintf("mpeg %d, layer %d, channel_mode: %d\n", frame->version_idx + 1, + frame->layer, frame->channel_mode); + lprintf("bitrate: %d bps, output freq: %d Hz\n", frame->bitrate, frame->freq); lprintf("length: %d bytes, %f ms\n", frame->size, frame->duration); - lprintf("padding: %d bytes\n", ( frame_header.padding_bit ? ( frame->layer == 1 ? 4 : 1 ) : 0 )); + lprintf("padding: %d bytes\n", frame->padding); return 1; } @@ -300,8 +322,8 @@ static int parse_frame_header(mpg_audio_frame_t *const frame, const uint8_t *con * Parse a Xing header * return the Xing header or NULL on error */ -static xing_header_t* parse_xing_header(mpg_audio_frame_t *frame, - uint8_t *buf, int bufsize) { +static xing_header_t *XINE_MALLOC parse_xing_header(mpg_audio_frame_t *frame, + uint8_t *buf, int bufsize) { uint8_t *ptr = buf; xing_header_t *xing = NULL; @@ -317,21 +339,21 @@ static xing_header_t* parse_xing_header(mpg_audio_frame_t *frame, else ptr += (9 + 4); } - + if (ptr >= (buf + bufsize - 4)) goto exit_error; lprintf("checking %08X\n", *ptr); - + if (_X_BE_32(ptr) == XING_TAG) { int has_frames_flag = 0; int has_bytes_flag = 0; - - xing = xine_xmalloc (sizeof (xing_header_t)); + + xing = calloc(1, sizeof(xing_header_t)); if (!xing) goto exit_error; - - lprintf("Xing header found\n"); + + lprintf("found Xing header\n"); ptr += 4; - + if (ptr >= (buf + bufsize - 4)) goto exit_error; xing->flags = _X_BE_32(ptr); ptr += 4; @@ -347,7 +369,7 @@ static xing_header_t* parse_xing_header(mpg_audio_frame_t *frame, lprintf("stream size: %d\n", xing->stream_size); has_bytes_flag = 1; } - + /* check if it's a useful Xing header */ if (!has_frames_flag || !has_bytes_flag) { lprintf("Stupid Xing tag, cannot do anything with it !\n"); @@ -405,7 +427,7 @@ static xing_header_t* parse_xing_header(mpg_audio_frame_t *frame, lprintf("Xing header not found\n"); } return xing; - + exit_error: lprintf("Xing header parse error\n"); free(xing); @@ -416,25 +438,25 @@ exit_error: * Parse a Vbri header * return the Vbri header or NULL on error */ -static vbri_header_t* parse_vbri_header(mpg_audio_frame_t *frame, - uint8_t *buf, int bufsize) { +static vbri_header_t *XINE_MALLOC parse_vbri_header(mpg_audio_frame_t *frame, + uint8_t *buf, int bufsize) { int i; uint8_t *ptr = buf; vbri_header_t *vbri; - vbri = xine_xmalloc (sizeof (vbri_header_t)); + vbri = calloc(1, sizeof(vbri_header_t)); if (!vbri) return NULL; ptr += (32 + 4); - + if ((ptr + 4) >= (buf + bufsize)) return 0; lprintf("Checking %08X\n", *ptr); if (_X_BE_32(ptr) == VBRI_TAG) { - lprintf("Vbri header found\n"); + lprintf("found Vbri header\n"); ptr += 4; - + if ((ptr + 22) >= (buf + bufsize)) return 0; vbri->version = _X_BE_16(ptr); ptr += 2; vbri->delai = _X_BE_16(ptr); ptr += 2; @@ -456,7 +478,7 @@ static vbri_header_t* parse_vbri_header(mpg_audio_frame_t *frame, lprintf("entry_frames: %d\n", vbri->entry_frames); if ((ptr + (vbri->toc_entries + 1) * vbri->entry_size) >= (buf + bufsize)) return 0; - vbri->toc = xine_xmalloc (sizeof(int) * (vbri->toc_entries + 1)); + vbri->toc = calloc (vbri->toc_entries + 1, sizeof (int)); if (!vbri->toc) { free (vbri); return NULL; @@ -496,6 +518,7 @@ static vbri_header_t* parse_vbri_header(mpg_audio_frame_t *frame, } } + /* * Parse a mp3 frame paylod * return 1 on success, 0 on error @@ -506,43 +529,97 @@ static int parse_frame_payload(demux_mpgaudio_t *this, buf_element_t *buf; off_t frame_pos, len; uint64_t pts = 0; + int payload_size = 0; frame_pos = this->input->get_current_pos(this->input) - 4; - lprintf("frame_pos = %"PRId64"\n", frame_pos); + lprintf("frame_pos = %"PRId64", header: %08X\n", frame_pos, _X_BE_32(frame_header)); buf = this->audio_fifo->buffer_pool_alloc(this->audio_fifo); if (this->cur_frame.size > buf->max_size) { xprintf(this->stream->xine, XINE_VERBOSITY_LOG, - "demux_mpgaudio: frame size is greater than fifo buffer size\n"); + LOG_MODULE ": frame size is greater than fifo buffer size\n"); buf->free_buffer(buf); return 0; } - - /* the decoder needs the frame header */ - memcpy(buf->mem, frame_header, 4); - len = this->input->read(this->input, buf->mem + 4, this->cur_frame.size - 4); - if (len != (this->cur_frame.size - 4)) { - buf->free_buffer(buf); - return 0; + memcpy(buf->content, frame_header, 4); + + /* compute the payload size */ + if (this->cur_frame.size > 0) { + payload_size = this->cur_frame.size - 4; + this->free_bitrate_count = 0; + } else if (this->free_bitrate_count >= NUM_VALID_FRAMES) { + payload_size = this->free_bitrate_size + this->cur_frame.padding - 4; + this->cur_frame.size = payload_size + 4; + } else { + this->free_bitrate_count++; + payload_size = 0; + } + + /* Read the payload data. */ + if (payload_size > 0) { + off_t len; + + /* If we know the payload size, it's easy */ + this->found_next_frame = 0; + len = this->input->read(this->input, buf->content + 4, payload_size); + if (len != payload_size) { + buf->free_buffer(buf); + return 0; + } + } else { + /* Search for the beginning of the next frame and deduce the size of the + * current frame from the position of the next one. */ + int payload_size = 0; + int max_size = buf->max_size - 4; + + while (payload_size < max_size) { + len = this->input->read(this->input, &buf->content[4 + payload_size], 1); + if (len != 1) { + lprintf("EOF\n"); + buf->free_buffer(buf); + return 0; + } + payload_size += len; + + if (parse_frame_header(&this->next_frame, &buf->content[payload_size])) { + lprintf("found next frame header\n"); + + if (this->free_bitrate_size == 0) { + this->free_bitrate_size = payload_size - this->cur_frame.padding; + } + + /* don't read the frame header twice */ + this->found_next_frame = 1; + memcpy(&this->next_header[0], &buf->content[payload_size], 4); + payload_size -= 4; + break; + } + } + this->cur_frame.size = payload_size + 4; + this->cur_frame.bitrate = 8000 * this->cur_frame.size / this->cur_frame.duration; + lprintf("free bitrate: bitrate: %d, frame size: %d\n", this->br, this->cur_frame.size); } if (this->check_vbr_header) { this->check_vbr_header = 0; this->mpg_frame_start = frame_pos; - this->xing_header = parse_xing_header(&this->cur_frame, buf->mem, this->cur_frame.size); + this->xing_header = parse_xing_header(&this->cur_frame, buf->content, this->cur_frame.size); if (this->xing_header) { buf->free_buffer(buf); + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + LOG_MODULE ": found Xing header at offset %"PRId64"\n", frame_pos); return 1; } - this->vbri_header = parse_vbri_header(&this->cur_frame, buf->mem, this->cur_frame.size); + this->vbri_header = parse_vbri_header(&this->cur_frame, buf->content, this->cur_frame.size); if (this->vbri_header) { buf->free_buffer(buf); + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + LOG_MODULE ": found Vbri header at offset %"PRId64"\n", frame_pos); return 1; } } - pts = (int64_t)(this->cur_time * 90.0f); @@ -551,8 +628,7 @@ static int parse_frame_payload(demux_mpgaudio_t *this, buf->extra_info->input_time = this->cur_time; buf->pts = pts; - buf->size = len + 4; - buf->content = buf->mem; + buf->size = this->cur_frame.size; buf->type = BUF_AUDIO_MPEG; buf->decoder_info[0] = 1; buf->decoder_flags = decoder_flags | BUF_FLAG_FRAME_END; @@ -572,8 +648,8 @@ static int parse_frame_payload(demux_mpgaudio_t *this, } } + lprintf("send buffer: size=%d, pts=%"PRId64"\n", buf->size, pts); this->audio_fifo->put(this->audio_fifo, buf); - lprintf("send buffer: pts=%"PRId64"\n", pts); this->cur_time += this->cur_frame.duration; return 1; } @@ -583,11 +659,12 @@ static int parse_frame_payload(demux_mpgaudio_t *this, * 32-bit MP3 frame header. * return 1 if found, 0 if not found */ -static int sniff_buffer_looks_like_mp3 (uint8_t *buf, int buflen) +static int sniff_buffer_looks_like_mp3 (uint8_t *buf, int buflen, int *version, int *layer) { int offset; mpg_audio_frame_t frame; + *version = *layer = 0; if (buf == NULL) return 0; @@ -596,20 +673,21 @@ static int sniff_buffer_looks_like_mp3 (uint8_t *buf, int buflen) if (parse_frame_header(&frame, buf + offset)) { size_t size = frame.size; - /* Since one frame is available, is there another frame - * just to be sure this is more likely to be a real MP3 - * buffer? */ - offset += size; - - if (offset + 4 >= buflen) { - return 0; - } + if (size > 0) { + /* Since one frame is available, is there another frame + * just to be sure this is more likely to be a real MP3 + * buffer? */ + if (offset + size + 4 >= buflen) { + return 0; + } - if (parse_frame_header(&frame, buf + offset)) { - lprintf("mpeg audio frame detected\n"); - return 1; + if (parse_frame_header(&frame, buf + offset + size)) { + *version = frame.version_idx + 1; + *layer = frame.layer; + lprintf("frame detected, mpeg %d layer %d\n", *version, *layer); + return 1; + } } - break; } } return 0; @@ -621,7 +699,7 @@ static int sniff_buffer_looks_like_mp3 (uint8_t *buf, int buflen) static int read_frame_header(demux_mpgaudio_t *this, uint8_t *header_buf, int bytes) { off_t len; int i; - + for (i = 0; i < (4 - bytes); i++) { header_buf[i] = header_buf[i + bytes]; } @@ -637,40 +715,51 @@ static int read_frame_header(demux_mpgaudio_t *this, uint8_t *header_buf, int by * Parse next mp3 frame */ static int demux_mpgaudio_next (demux_mpgaudio_t *this, int decoder_flags, int send_header) { - uint8_t header_buf[4]; - int bytes = 4; - - for (;;) { - - if (read_frame_header(this, header_buf, bytes)) { - - if (parse_frame_header(&this->cur_frame, header_buf)) { - - /* send header buffer */ - if ( send_header ) { - buf_element_t *buf; - - buf = this->audio_fifo->buffer_pool_alloc(this->audio_fifo); - - buf->type = BUF_AUDIO_MPEG; - buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAME_END; - - buf->decoder_info[0] = 0; - buf->decoder_info[1] = this->cur_frame.freq; - buf->decoder_info[2] = 0; /* bits_per_sample */ - - /* Only for channel_mode == 3 (mono) there is one channel, for any other case, there are 2 */ - buf->decoder_info[3] = ( this->cur_frame.channel_mode == 3 ) ? 1 : 2; - - buf->size = 0; /* No extra header data */ - - this->audio_fifo->put(this->audio_fifo, buf); + uint8_t buffer[4]; + uint8_t *header = buffer; + + if (this->found_next_frame) { + lprintf("skip header reading\n"); + header = this->next_header; + memcpy(&this->cur_frame, &this->next_frame, sizeof(mpg_audio_frame_t)); + } else { + int bytes = 4; + int loose_sync = 0; + + for (;;) { + if (!read_frame_header(this, header, bytes)) + return 0; + if (parse_frame_header(&this->cur_frame, header)) { + lprintf("frame found\n"); + + /* additionnal checks */ + if ((this->mpg_version == (this->cur_frame.version_idx + 1)) && + (this->mpg_layer == this->cur_frame.layer)) { + this->valid_frames++; + break; + } else { + if (this->valid_frames >= NUM_VALID_FRAMES) { + lprintf("invalid frame. expected mpeg %d, layer %d\n", this->mpg_version, this->mpg_layer); + } else { + this->mpg_version = this->cur_frame.version_idx + 1; + this->mpg_layer = this->cur_frame.layer; + this->valid_frames = 0; + break; + } } - - return parse_frame_payload(this, header_buf, decoder_flags); - - } else if ( id3v2_istag(header_buf) ) { - if (!id3v2_parse_tag(this->input, this->stream, header_buf)) { + } + + if (!loose_sync) { + off_t frame_pos = this->input->get_current_pos(this->input) - 4; + loose_sync = 1; + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + LOG_MODULE ": loose mp3 sync at offset %"PRId64"\n", frame_pos); + } + /* the stream is broken, don't keep info about previous frames */ + this->free_bitrate_size = 0; + + if ( id3v2_istag(header) ) { + if (!id3v2_parse_tag(this->input, this->stream, header)) { xprintf(this->stream->xine, XINE_VERBOSITY_LOG, LOG_MODULE ": ID3V2 tag parsing error\n"); bytes = 1; /* resync */ @@ -681,12 +770,31 @@ static int demux_mpgaudio_next (demux_mpgaudio_t *this, int decoder_flags, int s /* skip */ bytes = 1; } - - } else { - lprintf("read error\n"); - return 0; } } + + /* send header buffer */ + if ( send_header ) { + buf_element_t *buf; + + buf = this->audio_fifo->buffer_pool_alloc(this->audio_fifo); + + buf->type = BUF_AUDIO_MPEG; + buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAME_END; + + buf->decoder_info[0] = 0; + buf->decoder_info[1] = this->cur_frame.freq; + buf->decoder_info[2] = 0; /* bits_per_sample */ + + /* Only for channel_mode == 3 (mono) there is one channel, for any other case, there are 2 */ + buf->decoder_info[3] = ( this->cur_frame.channel_mode == 3 ) ? 1 : 2; + + buf->size = 0; /* No extra header data */ + + this->audio_fifo->put(this->audio_fifo, buf); + } + + return parse_frame_payload(this, header, decoder_flags); } static int demux_mpgaudio_send_chunk (demux_plugin_t *this_gen) { @@ -742,12 +850,13 @@ static int demux_mpgaudio_read_head(input_plugin_t *input, uint8_t *buf) { * mp3 stream detection * return 1 if detected, 0 otherwise */ -static int detect_mpgaudio_file(input_plugin_t *input) { - mpg_audio_frame_t frame; +static int detect_mpgaudio_file(input_plugin_t *input, + int *version, int *layer) { uint8_t buf[MAX_PREVIEW_SIZE]; int preview_len; uint32_t head; + *version = *layer = 0; preview_len = demux_mpgaudio_read_head(input, buf); if (preview_len < 4) return 0; @@ -774,15 +883,15 @@ static int detect_mpgaudio_file(input_plugin_t *input) { lprintf("cannot read mp3 frame header\n"); return 0; } - if (!parse_frame_header(&frame, &buf[10 + tag_size])) { - lprintf ("invalid mp3 frame header\n"); + if (!sniff_buffer_looks_like_mp3(&buf[10 + tag_size], preview_len - 10 - tag_size, version, layer)) { + lprintf ("sniff_buffer_looks_like_mp3 failed\n"); return 0; } else { lprintf ("a valid mp3 frame follows the id3v2 tag\n"); } } else if (head == MPEG_MARKER) { return 0; - } else if (!sniff_buffer_looks_like_mp3(buf, preview_len)) { + } else if (!sniff_buffer_looks_like_mp3(buf, preview_len, version, layer)) { lprintf ("sniff_buffer_looks_like_mp3 failed\n"); return 0; } @@ -821,11 +930,12 @@ static void demux_mpgaudio_send_headers (demux_plugin_t *this_gen) { */ this->check_vbr_header = 1; for (i = 0; i < NUM_PREVIEW_BUFFERS; i++) { + lprintf("preview buffer number %d / %d\n", i + 1, NUM_PREVIEW_BUFFERS); if (!demux_mpgaudio_next (this, BUF_FLAG_PREVIEW, i == 0)) { break; } } - + if (this->xing_header) { xing_header_t *xing = this->xing_header; @@ -836,7 +946,7 @@ static void demux_mpgaudio_send_headers (demux_plugin_t *this_gen) { if (this->stream_length) { this->br = ((uint64_t)xing->stream_size * 8 * 1000) / this->stream_length; } - + } else if (this->vbri_header) { vbri_header_t *vbri = this->vbri_header; @@ -848,7 +958,7 @@ static void demux_mpgaudio_send_headers (demux_plugin_t *this_gen) { this->br = ((uint64_t)vbri->stream_size * 8 * 1000) / this->stream_length; } } - + /* Set to default if Vbr header is incomplete or not present */ if (!this->br) { /* assume CBR */ @@ -879,7 +989,7 @@ static void demux_mpgaudio_send_headers (demux_plugin_t *this_gen) { { char scratch_buf[256]; char *mpeg_ver[3] = {"1", "2", "2.5"}; - + snprintf(scratch_buf, 256, "MPEG %s Layer %1d%s", mpeg_ver[this->cur_frame.version_idx], this->cur_frame.layer, (this->xing_header)? " VBR" : " CBR" ); @@ -1007,7 +1117,8 @@ static int demux_mpgaudio_seek (demux_plugin_t *this_gen, /* assume seeking is always perfect... */ this->cur_time = start_time; this->input->seek (this->input, seek_pos, SEEK_SET); - + this->found_next_frame = 0; + if (playing) { _x_demux_flush_engine(this->stream); } @@ -1039,21 +1150,23 @@ static uint32_t demux_mpgaudio_get_capabilities(demux_plugin_t *this_gen) { } static int demux_mpgaudio_get_optional_data(demux_plugin_t *this_gen, - void *data, int data_type) { + void *data, int data_type) { return DEMUX_OPTIONAL_UNSUPPORTED; -} +} static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *stream, input_plugin_t *input) { demux_mpgaudio_t *this; + int version = 0; + int layer = 0; lprintf("trying to open %s...\n", input->get_mrl(input)); switch (stream->content_detection_method) { case METHOD_BY_CONTENT: { - if (!detect_mpgaudio_file(input)) + if (!detect_mpgaudio_file(input, &version, &layer)) return NULL; } break; @@ -1061,23 +1174,23 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str case METHOD_BY_EXTENSION: { 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); - + if (!_x_demux_check_extension (mrl, extensions)) return NULL; - + } break; case METHOD_EXPLICIT: break; - + default: return NULL; } - - this = xine_xmalloc (sizeof (demux_mpgaudio_t)); + + this = calloc(1, sizeof(demux_mpgaudio_t)); this->demux_plugin.send_headers = demux_mpgaudio_send_headers; this->demux_plugin.send_chunk = demux_mpgaudio_send_chunk; @@ -1088,12 +1201,17 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str this->demux_plugin.get_capabilities = demux_mpgaudio_get_capabilities; this->demux_plugin.get_optional_data = demux_mpgaudio_get_optional_data; this->demux_plugin.demux_class = class_gen; - - this->input = input; - this->audio_fifo = stream->audio_fifo; - this->status = DEMUX_FINISHED; - this->stream = stream; - + + this->input = input; + this->audio_fifo = stream->audio_fifo; + this->status = DEMUX_FINISHED; + this->stream = stream; + + this->mpg_version = version; + this->mpg_layer = layer; + if (version || layer) { + this->valid_frames = NUM_VALID_FRAMES; + } return &this->demux_plugin; } @@ -1111,7 +1229,7 @@ static const char *get_identifier (demux_class_t *this_gen) { static const char *get_extensions (demux_class_t *this_gen) { demux_mpgaudio_class_t *this = (demux_mpgaudio_class_t *) this_gen; - + if( _x_decoder_available(this->xine, BUF_AUDIO_MPEG) ) return "mp3 mp2 mpa mpega"; else @@ -1144,10 +1262,10 @@ static void class_dispose (demux_class_t *this_gen) { } void *demux_mpgaudio_init_class (xine_t *xine, void *data) { - + demux_mpgaudio_class_t *this; - - this = xine_xmalloc (sizeof (demux_mpgaudio_class_t)); + + this = calloc(1, sizeof(demux_mpgaudio_class_t)); this->xine = xine; this->demux_class.open_plugin = open_plugin; diff --git a/src/demuxers/demux_nsf.c b/src/demuxers/demux_nsf.c index 81f42044f..40aeae9da 100644 --- a/src/demuxers/demux_nsf.c +++ b/src/demuxers/demux_nsf.c @@ -22,7 +22,7 @@ * NSF File "Demuxer" by Mike Melanson (melanson@pcisys.net) * This is really just a loader for NES Music File Format (extension NSF) * which loads an entire NSF file and passes it over to the NSF audio - * decoder. + * decoder. * * After the file is sent over, the demuxer controls the playback by * sending empty buffers with incrementing pts values. @@ -97,18 +97,14 @@ static int open_nsf_file(demux_nsf_t *this) { return 0; /* check for the signature */ - if ((header[0] != 'N') || - (header[1] != 'E') || - (header[2] != 'S') || - (header[3] != 'M') || - (header[4] != 0x1A)) + if (memcmp(header, "NESM\x1A", 5) != 0) return 0; this->total_songs = header[6]; this->current_song = header[7]; - this->title = strdup(&header[0x0E]); - this->artist = strdup(&header[0x2E]); - this->copyright = strdup(&header[0x4E]); + this->title = strndup((char*)&header[0x0E], 0x20); + this->artist = strndup((char*)&header[0x2E], 0x20); + this->copyright = strndup((char*)&header[0x4E], 0x20); this->filesize = this->input->get_length(this->input); @@ -128,7 +124,7 @@ static int demux_nsf_send_chunk(demux_plugin_t *this_gen) { buf->type = BUF_AUDIO_NSF; bytes_read = this->input->read(this->input, buf->content, buf->max_size); - if (bytes_read == 0) { + if (bytes_read <= 0) { /* the file has been completely loaded, free the buffer and start * sending control buffers */ buf->free_buffer(buf); @@ -170,7 +166,7 @@ static int demux_nsf_send_chunk(demux_plugin_t *this_gen) { buf->decoder_info[1] = 0; buf->type = BUF_AUDIO_NSF; - if(this->total_songs) + if(this->total_songs) buf->extra_info->input_normpos = (this->current_song - 1) * 65535 / this->total_songs; buf->extra_info->input_time = this->current_pts / 90; buf->pts = this->current_pts; @@ -303,7 +299,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str return NULL; } - this = xine_xmalloc (sizeof (demux_nsf_t)); + this = calloc(1, sizeof(demux_nsf_t)); this->stream = stream; this->input = input; @@ -377,7 +373,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_nsf_init_plugin (xine_t *xine, void *data) { demux_nsf_class_t *this; - this = xine_xmalloc (sizeof (demux_nsf_class_t)); + this = calloc(1, sizeof(demux_nsf_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_nsv.c b/src/demuxers/demux_nsv.c index 44bb18c79..8017d3d3f 100644 --- a/src/demuxers/demux_nsv.c +++ b/src/demuxers/demux_nsv.c @@ -50,7 +50,6 @@ #define FOURCC_TAG BE_FOURCC #define NSVf_TAG FOURCC_TAG('N', 'S', 'V', 'f') #define NSVs_TAG FOURCC_TAG('N', 'S', 'V', 's') -#define NONE_TAG FOURCC_TAG('N', 'O', 'N', 'E') #define BEEF 0xEFBE @@ -107,17 +106,17 @@ static void nsv_parse_framerate(demux_nsv_t *this, uint8_t framerate) /* 29.97 fps */ this->frame_pts_inc = 3003; break; - + case 3: /* 23.976 fps */ this->frame_pts_inc = 3753; break; - + case 5: /* 14.98 fps */ this->frame_pts_inc = 6006; break; - + default: lprintf("unknown framerate: 0x%02X\n", this->fps); this->frame_pts_inc = 90000; @@ -125,7 +124,7 @@ static void nsv_parse_framerate(demux_nsv_t *this, uint8_t framerate) } } else this->frame_pts_inc = 90000 / this->fps; - + lprintf("frame_pts_inc=%d\n", this->frame_pts_inc); } @@ -139,7 +138,7 @@ static off_t nsv_read(demux_nsv_t *this, uint8_t *buffer, off_t len) { int ultravox_rest; int buffer_pos = 0; - + /* ultravox stuff */ while (len) { ultravox_rest = this->ultravox_size - this->ultravox_pos; @@ -195,7 +194,7 @@ static off_t nsv_seek(demux_nsv_t *this, off_t offset, int origin) { /* ultravox stuff */ if (origin == SEEK_CUR) { uint8_t buffer[1024]; - + while (offset) { if (offset > sizeof(buffer)) { if (nsv_read(this, buffer, sizeof(buffer)) != sizeof(buffer)) @@ -222,7 +221,7 @@ static int nsv_resync(demux_nsv_t *this) { for (i = 0; i < NSV_MAX_RESYNC; i++) { uint8_t byte; - + if (nsv_read(this, &byte, 1) != 1) return NSV_RESYNC_ERROR; @@ -256,17 +255,11 @@ static int open_nsv_file(demux_nsv_t *this) { return 0; /* check for a 'NSV' signature */ - if ((preview[0] != 'N') || - (preview[1] != 'S') || - (preview[2] != 'V')) - { - if ((preview[0] != 'Z') || - (preview[1] != 0) || - (preview[2] != '9')) - return 0; + if ( memcmp(preview, "Z\09", 3) == 0) { this->is_ultravox = preview[3]; this->ultravox_first = 1; - } + } else if ( memcmp(preview, "NSV", 3) != 0 ) + return 0; lprintf("NSV file detected, ultravox=%d\n", this->is_ultravox); @@ -274,11 +267,11 @@ static int open_nsv_file(demux_nsv_t *this) { while (!NSVs_found) { switch (nsv_resync(this)) { - + case NSV_RESYNC_NSVf: { uint32_t chunk_size; - + /* if there is a NSVs tag, load 24 more header bytes; load starting at * offset 4 in buffer to keep header data in line with document */ if (nsv_read(this, &preview[4], 24) != 24) @@ -287,41 +280,41 @@ static int open_nsv_file(demux_nsv_t *this) { lprintf("found NSVf chunk\n"); /* this->data_size = _X_LE_32(&preview[8]);*/ /*lprintf("data_size: %lld\n", this->data_size);*/ - + /* skip the rest of the data */ chunk_size = _X_LE_32(&preview[4]); nsv_seek(this, chunk_size - 28, SEEK_CUR); } break; - + case NSV_RESYNC_NSVs: - - /* fetch the remaining 15 header bytes of the first chunk to get the + + /* fetch the remaining 15 header bytes of the first chunk to get the * relevant information */ if (nsv_read(this, &preview[4], 15) != 15) return 0; - + this->video_fourcc = _X_ME_32(&preview[4]); - if (_X_BE_32(&preview[4]) == NONE_TAG) + if (_x_is_fourcc(&preview[4], "NONE")) this->video_type = 0; else this->video_type = _x_fourcc_to_buf_video(this->video_fourcc); - + this->audio_fourcc = _X_ME_32(&preview[8]); - if (_X_BE_32(&preview[8]) == NONE_TAG) + if (_x_is_fourcc(&preview[8], "NONE")) this->audio_type = 0; else this->audio_type = _x_formattag_to_buf_audio(this->audio_fourcc); - + this->bih.biSize = sizeof(this->bih); this->bih.biWidth = _X_LE_16(&preview[12]); this->bih.biHeight = _X_LE_16(&preview[14]); this->bih.biCompression = this->video_fourcc; this->video_pts = 0; - + /* may not be true, but set it for the time being */ this->frame_pts_inc = 3003; - + lprintf("video: %c%c%c%c, buffer type %08X, %dx%d\n", preview[4], preview[5], @@ -340,10 +333,10 @@ static int open_nsv_file(demux_nsv_t *this) { nsv_parse_framerate(this, preview[16]); NSVs_found = 1; break; - + case NSV_RESYNC_ERROR: return 0; - + } } @@ -465,27 +458,27 @@ static int demux_nsv_send_chunk(demux_plugin_t *this_gen) { current_file_pos = this->input->get_current_pos(this->input); lprintf("dispatching video & audio chunks...\n"); - + if (this->is_first_chunk) { chunk_type = NSV_RESYNC_BEEF; this->is_first_chunk = 0; } else { chunk_type = nsv_resync(this); } - + switch (chunk_type) { case NSV_RESYNC_NSVf: /* do nothing */ break; - + case NSV_RESYNC_NSVs: /* skip header */ if (nsv_read(this, buffer, 15) != 15) return 0; nsv_parse_framerate(this, buffer[12]); - + /* fall thru */ - + case NSV_RESYNC_BEEF: if (nsv_read(this, buffer, 5) != 5) { this->status = DEMUX_FINISHED; @@ -495,15 +488,15 @@ static int demux_nsv_send_chunk(demux_plugin_t *this_gen) { video_size >>= 4; video_size &= 0xFFFFF; audio_size = _X_LE_16(&buffer[3]); - + nsv_parse_payload(this, video_size, audio_size); break; - + case NSV_RESYNC_ERROR: this->status = DEMUX_FINISHED; break; } - + return this->status; } @@ -594,7 +587,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str demux_nsv_t *this; - this = xine_xmalloc (sizeof (demux_nsv_t)); + this = calloc(1, sizeof(demux_nsv_t)); this->stream = stream; this->input = input; @@ -668,7 +661,7 @@ static void class_dispose (demux_class_t *this_gen) { static void *demux_nsv_init_plugin (xine_t *xine, void *data) { demux_nsv_class_t *this; - this = xine_xmalloc (sizeof (demux_nsv_class_t)); + this = calloc(1, sizeof(demux_nsv_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_ogg.c b/src/demuxers/demux_ogg.c index 9ed39f12d..3fc5ec9e1 100644 --- a/src/demuxers/demux_ogg.c +++ b/src/demuxers/demux_ogg.c @@ -1,18 +1,18 @@ /* * Copyright (C) 2000-2004 the xine project - * + * * This file is part of xine, a free video player. - * + * * xine is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * xine is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA @@ -194,7 +194,7 @@ static int get_stream (demux_ogg_t *this, int serno) { static int new_stream_info (demux_ogg_t *this, const int cur_serno) { int stream_num; - this->si[this->num_streams] = (stream_info_t *)xine_xmalloc(sizeof(stream_info_t)); + this->si[this->num_streams] = (stream_info_t *)calloc(1, sizeof(stream_info_t)); ogg_stream_init(&this->si[this->num_streams]->oss, cur_serno); stream_num = this->num_streams; this->si[stream_num]->buf_types = 0; @@ -237,7 +237,7 @@ static int read_ogg_packet (demux_ogg_t *this) { while (ogg_sync_pageout(&this->oy,&this->og)!=1) { buffer = ogg_sync_buffer(&this->oy, CHUNKSIZE); bytes = this->input->read(this->input, buffer, CHUNKSIZE); - if (bytes == 0) { + if (bytes <= 0) { if (total == 0) { lprintf("read_ogg_packet read nothing\n"); return 0; @@ -304,10 +304,10 @@ static void send_ogg_packet (demux_ogg_t *this, buf_element_t *buf; int done=0,todo=op->bytes; - int op_size = sizeof(ogg_packet); + const size_t op_size = sizeof(ogg_packet); while (done<todo) { - int offset=0; + size_t offset=0; buf = fifo->buffer_pool_alloc (fifo); buf->decoder_flags = decoder_flags; if (done==0) { @@ -329,7 +329,7 @@ static void send_ogg_packet (demux_ogg_t *this, buf->pts = pts; if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * + buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * 65535 / this->input->get_length (this->input) ); buf->extra_info->input_time = buf->pts / 90 ; buf->type = this->si[stream_num]->buf_types; @@ -498,7 +498,7 @@ static void read_chapter_comment (demux_ogg_t *this, ogg_packet *op) { lprintf("time: %d %d %d %d\n", hour, min,sec,msec); if (!this->chapter_info) { - this->chapter_info = (chapter_info_t *)xine_xmalloc(sizeof(chapter_info_t)); + this->chapter_info = (chapter_info_t *)calloc(1, sizeof(chapter_info_t)); this->chapter_info->current_chapter = -1; } this->chapter_info->max_chapter = chapter_no; @@ -531,34 +531,34 @@ static void update_chapter_display (demux_ogg_t *this, int stream_num, ogg_packe chapter--; if (chapter != this->chapter_info->current_chapter){ - xine_event_t uevent; - xine_ui_data_t data; - int title_len; - char *title; + xine_ui_data_t data = { + .str = { 0, }, + .str_len = 0 + }; + xine_event_t uevent = { + .type = XINE_EVENT_UI_SET_TITLE, + .stream = this->stream, + .data = &data, + .data_length = sizeof(data) + }; this->chapter_info->current_chapter = chapter; - if (chapter >= 0) { - char t_title[256]; + if (chapter >= 0) { if (this->title) { - snprintf(t_title, sizeof (t_title), "%s / %s", this->title, this->chapter_info->entries[chapter].name); + data.str_len = snprintf(data.str, sizeof(data.str), "%s / %s", this->title, this->chapter_info->entries[chapter].name); } else { - snprintf(t_title, sizeof (t_title), "%s", this->chapter_info->entries[chapter].name); + strncpy(data.str, this->chapter_info->entries[chapter].name, sizeof(data.str)-1); } - title = t_title; } else { - title = this->title; + strncpy(data.str, this->title, sizeof(data.str)); } - _x_meta_info_set(this->stream, XINE_META_INFO_TITLE, title); - lprintf("new TITLE: %s\n", title); - - uevent.type = XINE_EVENT_UI_SET_TITLE; - uevent.stream = this->stream; - uevent.data = &data; - uevent.data_length = sizeof(data); - title_len = strlen(title) + 1; - memcpy(data.str, title, title_len); - data.str_len = title_len; + if ( data.str_len == 0 ) + data.str_len = strlen(data.str); + + _x_meta_info_set(this->stream, XINE_META_INFO_TITLE, data.str); + lprintf("new TITLE: %s\n", data.str); + xine_event_send(this->stream, &uevent); } } @@ -578,10 +578,10 @@ static void send_ogg_buf (demux_ogg_t *this, int normpos = 0; if( this->input->get_length (this->input) ) - normpos = (int)( (double) this->input->get_current_pos (this->input) * + normpos = (int)( (double) this->input->get_current_pos (this->input) * 65535 / this->input->get_length (this->input) ); - + hdrlen = (*op->packet & PACKET_LEN_BITS01) >> 6; hdrlen |= (*op->packet & PACKET_LEN_BITS2) << 1; @@ -686,7 +686,7 @@ static void send_ogg_buf (demux_ogg_t *this, check_newpts( this, pts, PTS_VIDEO, decoder_flags ); } else pts = 0; - + llprintf(DEBUG_VIDEO_PACKETS, "videostream %d op-gpos %" PRId64 " hdr-gpos %" PRId64 " pts %" PRId64 " \n", stream_num, @@ -1020,7 +1020,7 @@ static void decode_dshow_header (demux_ogg_t *this, const int stream_num, ogg_pa this->si[stream_num]->headers = 0; /* header is sent below */ - if ( (_X_LE_32(&op->packet[96]) == 0x05589f80) && (op->bytes >= 184)) { + if ( _x_is_fourcc(&op->packet[96], "\x05\x58\x9f\x80") && (op->bytes >= 184)) { buf_element_t *buf; xine_bmiheader bih; @@ -1079,7 +1079,7 @@ static void decode_dshow_header (demux_ogg_t *this, const int stream_num, ogg_pa this->ignore_keyframes = 1; - } else if (_X_LE_32(&op->packet[96]) == 0x05589F81) { + } else if (_x_is_fourcc(&op->packet[96], "\x05\x58\x9f\x81")) { #if 0 /* FIXME: no test streams */ @@ -1194,27 +1194,27 @@ static void decode_theora_header (demux_ogg_t *this, const int stream_num, ogg_p static void decode_flac_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { xine_flac_metadata_header header; - xine_flac_streaminfo_block streaminfo; + xine_flac_streaminfo_block streaminfo = {}; buf_element_t *buf; xine_waveformatex wave; - /* Packet type */ - _x_assert(op->packet[0] == 0x7F); - - /* OggFLAC signature */ - _x_assert(op->packet[1] == 'F'); _x_assert(op->packet[2] == 'L'); - _x_assert(op->packet[3] == 'A'); _x_assert(op->packet[4] == 'C'); + static const uint8_t flac_signature_1[] = + { + /* Packet type */ + 0x7F, + /* OggFLAC signature */ + 'F', 'L', 'A', 'C', + /* Version: only 1.0 supported */ + 1, 0 + }; + static const uint8_t flac_signature_2[] = "fLaC"; - /* Version: supported only 1.0 */ - _x_assert(op->packet[5] == 1); _x_assert(op->packet[6] == 0); + _x_assert(memcmp(&op->packet[0], flac_signature_1, sizeof(flac_signature_1)) == 0); + _x_assert(memcmp(&op->packet[9], flac_signature_2, sizeof(flac_signature_2)) == 0); /* Header count */ this->si[stream_num]->headers = 0/*_X_BE_16(&op->packet[7]) +1*/; - /* fLaC signature */ - _x_assert(op->packet[9] == 'f'); _x_assert(op->packet[10] == 'L'); - _x_assert(op->packet[11] == 'a'); _x_assert(op->packet[12] == 'C'); - _x_parse_flac_metadata_header(&op->packet[13], &header); switch ( header.blocktype ) { @@ -1267,8 +1267,8 @@ static void decode_annodex_header (demux_ogg_t *this, const int stream_num, ogg_ static void decode_anxdata_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { int64_t granule_rate_n, granule_rate_d; uint32_t secondary_headers; - char content_type[1024]; - int content_type_length; + const char *content_type = ""; + size_t content_type_length = 0; lprintf("AnxData stream detected\n"); @@ -1280,11 +1280,16 @@ static void decode_anxdata_header (demux_ogg_t *this, const int stream_num, ogg_ lprintf("granule_rate %" PRId64 "/%" PRId64 ", %d secondary headers\n", granule_rate_n, granule_rate_d, secondary_headers); - /* read "Content-Tyoe" MIME header */ - sscanf(&op->packet[28], "Content-Type: %1023s\r\n", content_type); - content_type_length = strlen(content_type); + /* read "Content-Type" MIME header */ + const char *startline = &op->packet[28]; + const char *endline; + if ( strcmp(&op->packet[28], "Content-Type: ") == 0 && + (endline = strstr(startline, "\r\n")) ) { + content_type = startline + sizeof("Content-Type: "); + content_type_length = startline - endline; + } - lprintf("Content-Type: %s (length:%d)\n", content_type, content_type_length); + lprintf("Content-Type: %s (length:%td)\n", content_type, content_type_length); /* how many header packets in the AnxData stream? */ this->si[stream_num]->headers = secondary_headers + 1; @@ -1323,7 +1328,7 @@ static void decode_anxdata_header (demux_ogg_t *this, const int stream_num, ogg_ } else { this->si[stream_num]->buf_types = BUF_CONTROL_NOP; } - + } static void decode_cmml_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { @@ -1352,7 +1357,7 @@ static void send_header (demux_ogg_t *this) { this->ignore_keyframes = 0; while (!done) { - if (!read_ogg_packet(this)) { + if (!read_ogg_packet(this) || !this->og.header || !this->og.body) { return; } /* now we've got at least one new page */ @@ -1478,6 +1483,12 @@ static int demux_ogg_send_chunk (demux_plugin_t *this_gen) { return this->status; } + if (!this->og.header || !this->og.body) { + this->status = DEMUX_FINISHED; + lprintf ("EOF\n"); + return this->status; + } + /* now we've got one new page */ cur_serno = ogg_page_serialno (&this->og); @@ -1592,10 +1603,10 @@ static int demux_ogg_send_chunk (demux_plugin_t *this_gen) { if (ogg_page_eos(&this->og)) { int i; int finished_streams = 0; - + lprintf("end of stream, serialnumber %d\n", cur_serno); this->si[stream_num]->delivered_eos = 1; - + /* check if all logical streams are finished */ for (i = 0; i < this->num_streams; i++) { finished_streams += this->si[i]->delivered_eos; @@ -1617,12 +1628,12 @@ static int demux_ogg_send_chunk (demux_plugin_t *this_gen) { this->unhandled_video_streams = 0; this->num_spu_streams = 0; this->avg_bitrate = 1; - + /* try to read a chained stream */ this->send_newpts = 1; this->last_pts[0] = 0; this->last_pts[1] = 0; - + /* send control buffer to avoid buffer leak */ _x_demux_control_end(this->stream, 0); _x_demux_control_start(this->stream); @@ -1751,7 +1762,7 @@ static int demux_ogg_seek (demux_plugin_t *this_gen, hasn` changed its length, otherwise no seek to "new" data is possible*/ lprintf ("seek to time %d called\n",start_time); - lprintf ("current time is %d\n",current_time); + lprintf ("current time is %d\n",current_time); if (current_time > start_time) { /*seek between beginning and current_pos*/ @@ -1771,7 +1782,7 @@ static int demux_ogg_seek (demux_plugin_t *this_gen, } lprintf ("current_pos is %" PRId64 "\n",current_pos); - lprintf ("new_pos is %" PRId64 "\n",start_pos); + lprintf ("new_pos is %" PRId64 "\n",start_pos); } else { /*seek using avg_bitrate*/ @@ -1790,9 +1801,9 @@ static int demux_ogg_seek (demux_plugin_t *this_gen, ogg_stream_reset(&this->si[i]->oss); } - /*some strange streams have no syncpoint flag set at the beginning*/ - if (start_pos == 0) - this->keyframe_needed = 0; + /*some strange streams have no syncpoint flag set at the beginning*/ + if (start_pos == 0) + this->keyframe_needed = 0; lprintf ("seek to %" PRId64 " called\n",start_pos); @@ -1803,7 +1814,7 @@ static int demux_ogg_seek (demux_plugin_t *this_gen, /* fixme - this would be a nice position to do the following tasks 1. adjust an ogg videostream to a keyframe 2. compare the keyframe_pts with start_time. if the difference is to - high (e.g. larger than max keyframe_intervall, do a new seek or + high (e.g. larger than max keyframe_intervall, do a new seek or continue reading 3. adjust the audiostreams in such a way, that the difference is not to high. @@ -1811,12 +1822,12 @@ static int demux_ogg_seek (demux_plugin_t *this_gen, In short words, do all the cleanups necessary to continue playback without further actions */ - + this->send_newpts = 1; this->status = DEMUX_OK; - + if( !playing ) { - + this->buf_flag_seek = 0; } else { @@ -1833,13 +1844,13 @@ static int demux_ogg_seek (demux_plugin_t *this_gen, _x_demux_flush_engine(this->stream); } - + return this->status; } static int demux_ogg_get_stream_length (demux_plugin_t *this_gen) { - demux_ogg_t *this = (demux_ogg_t *) this_gen; + demux_ogg_t *this = (demux_ogg_t *) this_gen; if (this->time_length==-1){ if (this->avg_bitrate) { @@ -1854,7 +1865,7 @@ static int demux_ogg_get_stream_length (demux_plugin_t *this_gen) { } static uint32_t demux_ogg_get_capabilities(demux_plugin_t *this_gen) { - demux_ogg_t *this = (demux_ogg_t *) this_gen; + demux_ogg_t *this = (demux_ogg_t *) this_gen; int cap_chapter = 0; if (this->chapter_info) @@ -1884,8 +1895,8 @@ static int format_lang_string (demux_ogg_t * this, uint32_t buf_mask, uint32_t b static int demux_ogg_get_optional_data(demux_plugin_t *this_gen, void *data, int data_type) { - - demux_ogg_t *this = (demux_ogg_t *) this_gen; + + demux_ogg_t *this = (demux_ogg_t *) this_gen; char *str=(char *) data; int channel = *((int *)data); @@ -1924,11 +1935,7 @@ static int detect_ogg_content (int detection_method, demux_class_t *class_gen, if (_x_demux_read_header(input, buf, 4) != 4) return 0; - if ((buf[0] == 'O') && (buf[1] == 'g') && (buf[2] == 'g') && - (buf[3] == 'S')) - return 1; - else - return 0; + return _x_is_fourcc(buf, "OggS"); } case METHOD_BY_EXTENSION: { @@ -2014,7 +2021,7 @@ static int detect_anx_content (int detection_method, demux_class_t *class_gen, } static demux_plugin_t *anx_open_plugin (demux_class_t *class_gen, - xine_stream_t *stream, + xine_stream_t *stream, input_plugin_t *input) { demux_ogg_t *this; @@ -2026,8 +2033,7 @@ static demux_plugin_t *anx_open_plugin (demux_class_t *class_gen, * if we reach this point, the input has been accepted. */ - this = xine_xmalloc (sizeof (demux_ogg_t)); - memset (this, 0, sizeof(demux_ogg_t)); + this = calloc(1, sizeof(demux_ogg_t)); this->stream = stream; this->input = input; @@ -2044,13 +2050,13 @@ static demux_plugin_t *anx_open_plugin (demux_class_t *class_gen, this->demux_plugin.get_capabilities = demux_ogg_get_capabilities; this->demux_plugin.get_optional_data = demux_ogg_get_optional_data; this->demux_plugin.demux_class = class_gen; - + this->status = DEMUX_FINISHED; #ifdef HAVE_THEORA theora_info_init (&this->t_info); theora_comment_init (&this->t_comment); -#endif +#endif this->chapter_info = 0; this->title = 0; @@ -2060,7 +2066,7 @@ static demux_plugin_t *anx_open_plugin (demux_class_t *class_gen, } static demux_plugin_t *ogg_open_plugin (demux_class_t *class_gen, - xine_stream_t *stream, + xine_stream_t *stream, input_plugin_t *input) { demux_ogg_t *this; @@ -2072,8 +2078,7 @@ static demux_plugin_t *ogg_open_plugin (demux_class_t *class_gen, * if we reach this point, the input has been accepted. */ - this = xine_xmalloc (sizeof (demux_ogg_t)); - memset (this, 0, sizeof(demux_ogg_t)); + this = calloc(1, sizeof(demux_ogg_t)); this->stream = stream; this->input = input; @@ -2086,13 +2091,13 @@ static demux_plugin_t *ogg_open_plugin (demux_class_t *class_gen, this->demux_plugin.get_capabilities = demux_ogg_get_capabilities; this->demux_plugin.get_optional_data = demux_ogg_get_optional_data; this->demux_plugin.demux_class = class_gen; - + this->status = DEMUX_FINISHED; #ifdef HAVE_THEORA theora_info_init (&this->t_info); theora_comment_init (&this->t_comment); -#endif +#endif this->chapter_info = 0; this->title = 0; @@ -2108,7 +2113,7 @@ static demux_plugin_t *ogg_open_plugin (demux_class_t *class_gen, static const char *anx_get_description (demux_class_t *this_gen) { return "Annodex demux plugin"; } - + static const char *anx_get_identifier (demux_class_t *this_gen) { return "Annodex"; } @@ -2118,7 +2123,12 @@ static const char *anx_get_extensions (demux_class_t *this_gen) { } static const char *anx_get_mimetypes (demux_class_t *this_gen) { - return "application/x-annodex: ogg: Annodex media;"; + return "application/annodex: anx: Annodex media;" + "application/x-annodex: anx: Annodex media;" + "audio/annodex: axa: Annodex audio;" + "audio/x-annodex: axa: Annodex audio;" + "video/annodex: axv: Annodex video;" + "video/x-annodex: axv: Annodex video;"; } static void anx_class_dispose (demux_class_t *this_gen) { @@ -2130,7 +2140,7 @@ static void anx_class_dispose (demux_class_t *this_gen) { static void *anx_init_class (xine_t *xine, void *data) { demux_anx_class_t *this; - this = xine_xmalloc (sizeof (demux_anx_class_t)); + this = calloc(1, sizeof(demux_anx_class_t)); this->demux_class.open_plugin = anx_open_plugin; this->demux_class.get_description = anx_get_description; @@ -2149,20 +2159,25 @@ static void *anx_init_class (xine_t *xine, void *data) { static const char *ogg_get_description (demux_class_t *this_gen) { return "OGG demux plugin"; } - + static const char *ogg_get_identifier (demux_class_t *this_gen) { return "OGG"; } static const char *ogg_get_extensions (demux_class_t *this_gen) { - return "ogg ogm spx"; + return "ogx ogv oga ogg spx ogm"; } static const char *ogg_get_mimetypes (demux_class_t *this_gen) { - return "audio/x-ogg: ogg: OggVorbis Audio;" - "audio/x-speex: ogg: Speex Audio;" - "application/x-ogg: ogg: Ogg Stream;" - "application/ogg: ogg: Ogg Stream;"; + return "application/ogg: ogx: Ogg Stream;" + "application/x-ogg: ogx: Ogg Stream;" + "application/x-ogm: ogx: Ogg Stream;" + "application/x-ogm-audio: oga: Ogg Audio;" + "application/x-ogm-video: ogv: Ogg Video;" + "audio/ogg: oga: Ogg Audio;" + "audio/x-ogg: oga: Ogg Audio;" + "video/ogg: ogv: Ogg Video;" + "video/x-ogg: ogv: Ogg Video;"; } static void ogg_class_dispose (demux_class_t *this_gen) { @@ -2174,7 +2189,7 @@ static void ogg_class_dispose (demux_class_t *this_gen) { static void *ogg_init_class (xine_t *xine, void *data) { demux_ogg_class_t *this; - this = xine_xmalloc (sizeof (demux_ogg_class_t)); + this = calloc(1, sizeof(demux_ogg_class_t)); this->demux_class.open_plugin = ogg_open_plugin; this->demux_class.get_description = ogg_get_description; @@ -2198,7 +2213,7 @@ static const demuxer_info_t demux_info_ogg = { }; const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ + /* type, API, "name", version, special_info, init_function */ { PLUGIN_DEMUX, 26, "ogg", XINE_VERSION_CODE, &demux_info_ogg, ogg_init_class }, { PLUGIN_DEMUX, 26, "anx", XINE_VERSION_CODE, &demux_info_anx, anx_init_class }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } diff --git a/src/demuxers/demux_pva.c b/src/demuxers/demux_pva.c index 298d936b5..e2b61dcf0 100644 --- a/src/demuxers/demux_pva.c +++ b/src/demuxers/demux_pva.c @@ -148,7 +148,7 @@ static int demux_pva_send_chunk(demux_plugin_t *this_gen) { current_file_pos = this->input->get_current_pos(this->input); if (preamble[2] == 1) { - + /* video */ /* load the pts if it is the first thing in the chunk */ @@ -253,7 +253,7 @@ static int demux_pva_send_chunk(demux_plugin_t *this_gen) { buf->pts = pts; if( this->data_size ) - buf->extra_info->input_normpos = (int) ((double) this->input->get_current_pos(this->input) * + buf->extra_info->input_normpos = (int) ((double) this->input->get_current_pos(this->input) * 65535 / this->data_size); this->audio_fifo->put (this->audio_fifo, buf); @@ -302,7 +302,7 @@ static void demux_pva_send_headers(demux_plugin_t *this_gen) { buf->pts = 0; if( this->data_size ) - buf->extra_info->input_normpos = (int) ((double) this->input->get_current_pos(this->input) * + buf->extra_info->input_normpos = (int) ((double) this->input->get_current_pos(this->input) * 65535 / this->data_size); buf->type = BUF_VIDEO_MPEG; @@ -329,7 +329,7 @@ static void demux_pva_send_headers(demux_plugin_t *this_gen) { buf->pts = 0; if( this->data_size ) - buf->extra_info->input_normpos = (int) ((double) this->input->get_current_pos(this->input) * + buf->extra_info->input_normpos = (int) ((double) this->input->get_current_pos(this->input) * 65535 / this->data_size); buf->type = BUF_AUDIO_MPEG; @@ -347,7 +347,7 @@ static int demux_pva_seek (demux_plugin_t *this_gen, unsigned char seek_buffer[SEEK_BUFFER_SIZE]; int found = 0; int i; - + start_pos = (off_t) ( (double) start_pos / 65535 * this->data_size ); @@ -430,7 +430,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str return NULL; } - this = xine_xmalloc (sizeof (demux_pva_t)); + this = calloc(1, sizeof(demux_pva_t)); this->stream = stream; this->input = input; @@ -503,7 +503,7 @@ static void class_dispose (demux_class_t *this_gen) { static void *init_plugin (xine_t *xine, void *data) { demux_pva_class_t *this; - this = xine_xmalloc (sizeof (demux_pva_class_t)); + this = calloc(1, sizeof(demux_pva_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_qt.c b/src/demuxers/demux_qt.c index a55a0aef3..8e00d73a4 100644 --- a/src/demuxers/demux_qt.c +++ b/src/demuxers/demux_qt.c @@ -134,7 +134,7 @@ typedef unsigned int qt_atom; #define MAX_PTS_DIFF 100000 /* network bandwidth, cribbed from src/input/input_mms.c */ -const int64_t bandwidths[]={14400,19200,28800,33600,34430,57600, +static const int64_t bandwidths[]={14400,19200,28800,33600,34430,57600, 115200,262200,393216,524300,1544000,10485800}; /* these are things that can go wrong */ @@ -262,10 +262,10 @@ typedef struct { /* flags that indicate how a trak is supposed to be used */ unsigned int flags; - + /* formattag-like field that specifies codec in mp4 files */ unsigned int object_type_id; - + /* decoder data pass information to the decoder */ void *decoder_config; int decoder_config_len; @@ -307,7 +307,7 @@ typedef struct { unsigned int modification_time; unsigned int timescale; /* base clock frequency is Hz */ unsigned int duration; - + int64_t moov_first_offset; int trak_count; @@ -381,7 +381,7 @@ typedef struct { * lazyqt special debugging functions **********************************************************************/ -/* define DEBUG_ATOM_LOAD as 1 to get a verbose parsing of the relevant +/* define DEBUG_ATOM_LOAD as 1 to get a verbose parsing of the relevant * atoms */ #define DEBUG_ATOM_LOAD 0 @@ -403,7 +403,7 @@ typedef struct { /* Define DEBUG_DUMP_MOOV as 1 to dump the raw moov atom to disk. This is * particularly useful in debugging a file with a compressed moov (cmov) - * atom. The atom will be dumped to the filename specified as + * atom. The atom will be dumped to the filename specified as * RAW_MOOV_FILENAME. */ #define DEBUG_DUMP_MOOV 0 #define RAW_MOOV_FILENAME "moovatom.raw" @@ -502,7 +502,7 @@ static void find_moov_atom(input_plugin_t *input, off_t *moov_offset, atom = _X_BE_32(&atom_preamble[4]); /* Special case alert: 'free' atoms sometimes masquerade as 'moov' - * atoms. If this is a free atom, check for 'cmov' or 'mvhd' immediately + * atoms. If this is a free atom, check for 'cmov' or 'mvhd' immediately * following. QT Player can handle it, so xine should too. */ if (atom == FREE_ATOM) { @@ -533,7 +533,7 @@ static void find_moov_atom(input_plugin_t *input, off_t *moov_offset, /* if this atom is not the moov atom, make sure that it is at least one * of the other top-level QT atom. - * However, allow a configurable amount ( currently 1 ) atom be a + * However, allow a configurable amount ( currently 1 ) atom be a * non known atom, in hopes a known atom will be found */ if ((atom != FREE_ATOM) && (atom != JUNK_ATOM) && @@ -581,7 +581,7 @@ static void find_moov_atom(input_plugin_t *input, off_t *moov_offset, static qt_info *create_qt_info(void) { qt_info *info; - info = (qt_info *)xine_xmalloc(sizeof(qt_info)); + info = (qt_info *)calloc(1, sizeof(qt_info)); if (!info) return NULL; @@ -712,7 +712,7 @@ static int is_qt_file(input_plugin_t *qt_file) { return 0; } else { /* check that the next atom in the chunk contains alphanumeric - * characters in the atom type field; if not, disqualify the file + * characters in the atom type field; if not, disqualify the file * as a QT file */ qt_file->seek(qt_file, moov_atom_offset + ATOM_PREAMBLE_SIZE, SEEK_SET); if (qt_file->read(qt_file, atom_preamble, ATOM_PREAMBLE_SIZE) != @@ -738,39 +738,67 @@ static void parse_meta_atom(qt_info *info, unsigned char *meta_atom) { if (current_atom == ART_ATOM) { string_size = _X_BE_32(&meta_atom[i + 4]) - 16 + 1; + if (string_size <= 0) + continue; info->artist = xine_xmalloc(string_size); - strncpy(info->artist, &meta_atom[i + 20], string_size - 1); - info->artist[string_size - 1] = 0; + if (info->artist) { + strncpy(info->artist, &meta_atom[i + 20], string_size - 1); + info->artist[string_size - 1] = 0; + } } else if (current_atom == NAM_ATOM) { string_size = _X_BE_32(&meta_atom[i + 4]) - 16 + 1; + if (string_size <= 0) + continue; info->name = xine_xmalloc(string_size); - strncpy(info->name, &meta_atom[i + 20], string_size - 1); - info->name[string_size - 1] = 0; + if (info->name) { + strncpy(info->name, &meta_atom[i + 20], string_size - 1); + info->name[string_size - 1] = 0; + } } else if (current_atom == ALB_ATOM) { string_size = _X_BE_32(&meta_atom[i + 4]) - 16 + 1; + if (string_size <= 0) + continue; info->album = xine_xmalloc(string_size); - strncpy(info->album, &meta_atom[i + 20], string_size - 1); - info->album[string_size - 1] = 0; + if (info->album) { + strncpy(info->album, &meta_atom[i + 20], string_size - 1); + info->album[string_size - 1] = 0; + } } else if (current_atom == GEN_ATOM) { string_size = _X_BE_32(&meta_atom[i + 4]) - 16 + 1; + if (string_size <= 0) + continue; info->genre = xine_xmalloc(string_size); - strncpy(info->genre, &meta_atom[i + 20], string_size - 1); - info->genre[string_size - 1] = 0; + if (info->genre) { + strncpy(info->genre, &meta_atom[i + 20], string_size - 1); + info->genre[string_size - 1] = 0; + } } else if (current_atom == TOO_ATOM) { string_size = _X_BE_32(&meta_atom[i + 4]) - 16 + 1; + if (string_size <= 0) + continue; info->comment = xine_xmalloc(string_size); - strncpy(info->comment, &meta_atom[i + 20], string_size - 1); - info->comment[string_size - 1] = 0; + if (info->comment) { + strncpy(info->comment, &meta_atom[i + 20], string_size - 1); + info->comment[string_size - 1] = 0; + } } else if (current_atom == WRT_ATOM) { string_size = _X_BE_32(&meta_atom[i + 4]) - 16 + 1; + if (string_size <= 0) + continue; info->composer = xine_xmalloc(string_size); - strncpy(info->composer, &meta_atom[i + 20], string_size - 1); - info->composer[string_size - 1] = 0; + if (info->composer) { + strncpy(info->composer, &meta_atom[i + 20], string_size - 1); + info->composer[string_size - 1] = 0; + } } else if (current_atom == DAY_ATOM) { string_size = _X_BE_32(&meta_atom[i + 4]) - 16 + 1; + if (string_size <= 0) + continue; info->year = xine_xmalloc(string_size); - strncpy(info->year, &meta_atom[i + 20], string_size - 1); - info->year[string_size - 1] = 0; + if (info->year) { + strncpy(info->year, &meta_atom[i + 20], string_size - 1); + info->year[string_size - 1] = 0; + } } } @@ -793,7 +821,7 @@ static void parse_mvhd_atom(qt_info *info, unsigned char *mvhd_atom) { static int mp4_read_descr_len(unsigned char *s, uint32_t *length) { uint8_t b; uint8_t numBytes = 0; - + *length = 0; do { @@ -872,14 +900,14 @@ static qt_error parse_trak_atom (qt_trak *trak, break; } } - + debug_atom_load(" qt: parsing %s trak atom\n", (trak->type == MEDIA_VIDEO) ? "video" : (trak->type == MEDIA_AUDIO) ? "audio" : "other"); /* search for the useful atoms */ for (i = ATOM_PREAMBLE_SIZE; i < trak_atom_size - 4; i++) { - current_atom_size = _X_BE_32(&trak_atom[i - 4]); + current_atom_size = _X_BE_32(&trak_atom[i - 4]); current_atom = _X_BE_32(&trak_atom[i]); if (current_atom == TKHD_ATOM) { @@ -897,8 +925,8 @@ static qt_error parse_trak_atom (qt_trak *trak, debug_atom_load(" qt elst atom (edit list atom): %d entries\n", trak->edit_list_count); - trak->edit_list_table = (edit_list_table_t *)xine_xmalloc( - trak->edit_list_count * sizeof(edit_list_table_t)); + trak->edit_list_table = (edit_list_table_t *)calloc( + trak->edit_list_count, sizeof(edit_list_table_t)); if (!trak->edit_list_table) { last_error = QT_NO_MEMORY; goto free_trak; @@ -919,7 +947,7 @@ static qt_error parse_trak_atom (qt_trak *trak, } else if (current_atom == MDHD_ATOM) { int version; debug_atom_load ("demux_qt: mdhd atom\n"); - + version = trak_atom[i+4]; if ( version > 1 ) continue; /* unsupported, undocumented */ @@ -933,18 +961,25 @@ static qt_error parse_trak_atom (qt_trak *trak, /* allocate space for each of the properties unions */ trak->stsd_atoms_count = _X_BE_32(&trak_atom[i + 8]); - trak->stsd_atoms = xine_xmalloc(trak->stsd_atoms_count * sizeof(properties_t)); + if (trak->stsd_atoms_count <= 0) { + last_error = QT_HEADER_TROUBLE; + goto free_trak; + } + trak->stsd_atoms = calloc(trak->stsd_atoms_count, sizeof(properties_t)); if (!trak->stsd_atoms) { last_error = QT_NO_MEMORY; goto free_trak; } - memset(trak->stsd_atoms, 0, trak->stsd_atoms_count * sizeof(properties_t)); atom_pos = i + 0x10; properties_offset = 0x0C; for (k = 0; k < trak->stsd_atoms_count; k++) { - current_stsd_atom_size = _X_BE_32(&trak_atom[atom_pos - 4]); + current_stsd_atom_size = _X_BE_32(&trak_atom[atom_pos - 4]); + if (current_stsd_atom_size < 4) { + last_error = QT_HEADER_TROUBLE; + goto free_trak; + } if (trak->type == MEDIA_VIDEO) { @@ -953,8 +988,12 @@ static qt_error parse_trak_atom (qt_trak *trak, /* copy the properties atom */ trak->stsd_atoms[k].video.properties_atom_size = current_stsd_atom_size - 4; - trak->stsd_atoms[k].video.properties_atom = + trak->stsd_atoms[k].video.properties_atom = xine_xmalloc(trak->stsd_atoms[k].video.properties_atom_size); + if (!trak->stsd_atoms[k].video.properties_atom) { + last_error = QT_NO_MEMORY; + goto free_trak; + } memcpy(trak->stsd_atoms[k].video.properties_atom, &trak_atom[atom_pos], trak->stsd_atoms[k].video.properties_atom_size); @@ -967,7 +1006,7 @@ static qt_error parse_trak_atom (qt_trak *trak, trak->stsd_atoms[k].video.palette_count = 0; /* fetch video parameters */ - if( _X_BE_16(&trak_atom[atom_pos + 0x1C]) && + if( _X_BE_16(&trak_atom[atom_pos + 0x1C]) && _X_BE_16(&trak_atom[atom_pos + 0x1E]) ) { trak->stsd_atoms[k].video.width = _X_BE_16(&trak_atom[atom_pos + 0x1C]); @@ -995,9 +1034,9 @@ static qt_error parse_trak_atom (qt_trak *trak, /* compute the greyscale palette */ color_index = 255; - color_dec = 256 / + color_dec = 256 / (trak->stsd_atoms[k].video.palette_count - 1); - for (j = 0; + for (j = 0; j < trak->stsd_atoms[k].video.palette_count; j++) { @@ -1022,7 +1061,7 @@ static qt_error parse_trak_atom (qt_trak *trak, else color_table = qt_default_palette_256; - for (j = 0; + for (j = 0; j < trak->stsd_atoms[k].video.palette_count; j++) { @@ -1049,7 +1088,7 @@ static qt_error parse_trak_atom (qt_trak *trak, color_index = _X_BE_16(&trak_atom[atom_pos + 0x5A + j * 8]); if (color_count & 0x8000) color_index = j; - if (color_index < + if (color_index < trak->stsd_atoms[k].video.palette_count) { trak->stsd_atoms[k].video.palette[color_index].r = trak_atom[atom_pos + 0x5A + j * 8 + 2]; @@ -1092,8 +1131,12 @@ static qt_error parse_trak_atom (qt_trak *trak, /* copy the properties atom */ trak->stsd_atoms[k].audio.properties_atom_size = current_stsd_atom_size - 4; - trak->stsd_atoms[k].audio.properties_atom = + trak->stsd_atoms[k].audio.properties_atom = xine_xmalloc(trak->stsd_atoms[k].audio.properties_atom_size); + if (!trak->stsd_atoms[k].audio.properties_atom) { + last_error = QT_NO_MEMORY; + goto free_trak; + } memcpy(trak->stsd_atoms[k].audio.properties_atom, &trak_atom[atom_pos], trak->stsd_atoms[k].audio.properties_atom_size); @@ -1110,12 +1153,12 @@ static qt_error parse_trak_atom (qt_trak *trak, trak->stsd_atoms[k].audio.bits / 8; trak->stsd_atoms[k].audio.samples_per_frame = trak->stsd_atoms[k].audio.channels; - trak->stsd_atoms[k].audio.bytes_per_frame = - trak->stsd_atoms[k].audio.bytes_per_sample * + trak->stsd_atoms[k].audio.bytes_per_frame = + trak->stsd_atoms[k].audio.bytes_per_sample * trak->stsd_atoms[k].audio.samples_per_frame; - trak->stsd_atoms[k].audio.samples_per_packet = + trak->stsd_atoms[k].audio.samples_per_packet = trak->stsd_atoms[k].audio.samples_per_frame; - trak->stsd_atoms[k].audio.bytes_per_packet = + trak->stsd_atoms[k].audio.bytes_per_packet = trak->stsd_atoms[k].audio.bytes_per_sample; /* special case time: A lot of CBR audio codecs stored in the @@ -1123,7 +1166,7 @@ static qt_error parse_trak_atom (qt_trak *trak, if (trak->stsd_atoms[k].audio.codec_fourcc == IMA4_FOURCC) { trak->stsd_atoms[k].audio.samples_per_packet = 64; trak->stsd_atoms[k].audio.bytes_per_packet = 34; - trak->stsd_atoms[k].audio.bytes_per_frame = 34 * + trak->stsd_atoms[k].audio.bytes_per_frame = 34 * trak->stsd_atoms[k].audio.channels; trak->stsd_atoms[k].audio.bytes_per_sample = 2; trak->stsd_atoms[k].audio.samples_per_frame = 64 * @@ -1139,7 +1182,7 @@ static qt_error parse_trak_atom (qt_trak *trak, } else if (trak->stsd_atoms[k].audio.codec_fourcc == MAC6_FOURCC) { trak->stsd_atoms[k].audio.samples_per_packet = 6; trak->stsd_atoms[k].audio.bytes_per_packet = 1; - trak->stsd_atoms[k].audio.bytes_per_frame = 1 * + trak->stsd_atoms[k].audio.bytes_per_frame = 1 * trak->stsd_atoms[k].audio.channels; trak->stsd_atoms[k].audio.bytes_per_sample = 1; trak->stsd_atoms[k].audio.samples_per_frame = 6 * @@ -1147,7 +1190,7 @@ static qt_error parse_trak_atom (qt_trak *trak, } else if (trak->stsd_atoms[k].audio.codec_fourcc == ALAW_FOURCC) { trak->stsd_atoms[k].audio.samples_per_packet = 1; trak->stsd_atoms[k].audio.bytes_per_packet = 1; - trak->stsd_atoms[k].audio.bytes_per_frame = 1 * + trak->stsd_atoms[k].audio.bytes_per_frame = 1 * trak->stsd_atoms[k].audio.channels; trak->stsd_atoms[k].audio.bytes_per_sample = 2; trak->stsd_atoms[k].audio.samples_per_frame = 2 * @@ -1155,7 +1198,7 @@ static qt_error parse_trak_atom (qt_trak *trak, } else if (trak->stsd_atoms[k].audio.codec_fourcc == ULAW_FOURCC) { trak->stsd_atoms[k].audio.samples_per_packet = 1; trak->stsd_atoms[k].audio.bytes_per_packet = 1; - trak->stsd_atoms[k].audio.bytes_per_frame = 1 * + trak->stsd_atoms[k].audio.bytes_per_frame = 1 * trak->stsd_atoms[k].audio.channels; trak->stsd_atoms[k].audio.bytes_per_sample = 2; trak->stsd_atoms[k].audio.samples_per_frame = 2 * @@ -1174,21 +1217,22 @@ static qt_error parse_trak_atom (qt_trak *trak, (trak->stsd_atoms[k].audio.codec_fourcc != RAW_FOURCC)) { if (_X_BE_32(&trak_atom[atom_pos + 0x20])) - trak->stsd_atoms[k].audio.samples_per_packet = + trak->stsd_atoms[k].audio.samples_per_packet = _X_BE_32(&trak_atom[atom_pos + 0x20]); if (_X_BE_32(&trak_atom[atom_pos + 0x24])) - trak->stsd_atoms[k].audio.bytes_per_packet = + trak->stsd_atoms[k].audio.bytes_per_packet = _X_BE_32(&trak_atom[atom_pos + 0x24]); if (_X_BE_32(&trak_atom[atom_pos + 0x28])) - trak->stsd_atoms[k].audio.bytes_per_frame = + trak->stsd_atoms[k].audio.bytes_per_frame = _X_BE_32(&trak_atom[atom_pos + 0x28]); if (_X_BE_32(&trak_atom[atom_pos + 0x2C])) - trak->stsd_atoms[k].audio.bytes_per_sample = + trak->stsd_atoms[k].audio.bytes_per_sample = _X_BE_32(&trak_atom[atom_pos + 0x2C]); - trak->stsd_atoms[k].audio.samples_per_frame = - (trak->stsd_atoms[k].audio.bytes_per_frame / - trak->stsd_atoms[k].audio.bytes_per_packet) * - trak->stsd_atoms[k].audio.samples_per_packet; + if (trak->stsd_atoms[k].audio.bytes_per_packet) + trak->stsd_atoms[k].audio.samples_per_frame = + (trak->stsd_atoms[k].audio.bytes_per_frame / + trak->stsd_atoms[k].audio.bytes_per_packet) * + trak->stsd_atoms[k].audio.samples_per_packet; } /* see if the trak deserves a promotion to VBR */ @@ -1208,9 +1252,13 @@ static qt_error parse_trak_atom (qt_trak *trak, trak->stsd_atoms[k].audio.vbr = 1; /* further, FFmpeg's ALAC decoder requires 36 out-of-band bytes */ trak->stsd_atoms[k].audio.properties_atom_size = 36; - trak->stsd_atoms[k].audio.properties_atom = + trak->stsd_atoms[k].audio.properties_atom = xine_xmalloc(trak->stsd_atoms[k].audio.properties_atom_size); - memcpy(trak->stsd_atoms[k].audio.properties_atom, + if (!trak->stsd_atoms[k].audio.properties_atom) { + last_error = QT_NO_MEMORY; + goto free_trak; + } + memcpy(trak->stsd_atoms[k].audio.properties_atom, &trak_atom[atom_pos + 0x20], trak->stsd_atoms[k].audio.properties_atom_size); } @@ -1226,11 +1274,15 @@ static qt_error parse_trak_atom (qt_trak *trak, (_X_BE_32(&trak_atom[atom_pos + 0x3C]) == FRMA_ATOM) && (_X_ME_32(&trak_atom[atom_pos + 0x48]) == trak->stsd_atoms[k].audio.codec_fourcc)) { int wave_size = _X_BE_32(&trak_atom[atom_pos + 0x44]) - 8; - + if ((wave_size >= sizeof(xine_waveformatex)) && (current_atom_size >= (0x4C + wave_size))) { trak->stsd_atoms[k].audio.wave_size = wave_size; trak->stsd_atoms[k].audio.wave = xine_xmalloc(wave_size); + if (!trak->stsd_atoms[k].audio.wave) { + last_error = QT_NO_MEMORY; + goto free_trak; + } memcpy(trak->stsd_atoms[k].audio.wave, &trak_atom[atom_pos + 0x4C], wave_size); _x_waveformatex_le2me(trak->stsd_atoms[k].audio.wave); @@ -1279,12 +1331,12 @@ static qt_error parse_trak_atom (qt_trak *trak, } else if (current_atom == ESDS_ATOM) { uint32_t len; - + debug_atom_load(" qt/mpeg-4 esds atom\n"); - if ((trak->type == MEDIA_VIDEO) || + if ((trak->type == MEDIA_VIDEO) || (trak->type == MEDIA_AUDIO)) { - + j = i + 8; if( trak_atom[j++] == 0x03 ) { j += mp4_read_descr_len( &trak_atom[j], &len ); @@ -1300,21 +1352,29 @@ static qt_error parse_trak_atom (qt_trak *trak, j += mp4_read_descr_len( &trak_atom[j], &len ); debug_atom_load(" decoder config is %d (0x%X) bytes long\n", len, len); + if (len > current_atom_size - (j - i)) { + last_error = QT_NOT_A_VALID_FILE; + goto free_trak; + } trak->decoder_config = realloc(trak->decoder_config, len); trak->decoder_config_len = len; + if (!trak->decoder_config) { + last_error = QT_NO_MEMORY; + goto free_trak; + } memcpy(trak->decoder_config,&trak_atom[j],len); } } } } else if (current_atom == AVCC_ATOM) { - + debug_atom_load(" avcC atom\n"); - + trak->decoder_config_len = current_atom_size - 8; trak->decoder_config = realloc(trak->decoder_config, trak->decoder_config_len); memcpy(trak->decoder_config, &trak_atom[i + 4], trak->decoder_config_len); - + } else if (current_atom == STSZ_ATOM) { /* there should only be one of these atoms */ @@ -1331,8 +1391,8 @@ static qt_error parse_trak_atom (qt_trak *trak, /* allocate space and load table only if sample size is 0 */ if (trak->sample_size == 0) { - trak->sample_size_table = (unsigned int *)malloc( - trak->sample_size_count * sizeof(unsigned int)); + trak->sample_size_table = (unsigned int *)calloc( + trak->sample_size_count, sizeof(unsigned int)); if (!trak->sample_size_table) { last_error = QT_NO_MEMORY; goto free_trak; @@ -1362,8 +1422,8 @@ static qt_error parse_trak_atom (qt_trak *trak, debug_atom_load(" qt stss atom (sample sync atom): %d sync samples\n", trak->sync_sample_count); - trak->sync_sample_table = (unsigned int *)malloc( - trak->sync_sample_count * sizeof(unsigned int)); + trak->sync_sample_table = (unsigned int *)calloc( + trak->sync_sample_count, sizeof(unsigned int)); if (!trak->sync_sample_table) { last_error = QT_NO_MEMORY; goto free_trak; @@ -1391,8 +1451,8 @@ static qt_error parse_trak_atom (qt_trak *trak, debug_atom_load(" qt stco atom (32-bit chunk offset atom): %d chunk offsets\n", trak->chunk_offset_count); - trak->chunk_offset_table = (int64_t *)malloc( - trak->chunk_offset_count * sizeof(int64_t)); + trak->chunk_offset_table = (int64_t *)calloc( + trak->chunk_offset_count, sizeof(int64_t)); if (!trak->chunk_offset_table) { last_error = QT_NO_MEMORY; goto free_trak; @@ -1419,8 +1479,8 @@ static qt_error parse_trak_atom (qt_trak *trak, debug_atom_load(" qt co64 atom (64-bit chunk offset atom): %d chunk offsets\n", trak->chunk_offset_count); - trak->chunk_offset_table = (int64_t *)malloc( - trak->chunk_offset_count * sizeof(int64_t)); + trak->chunk_offset_table = (int64_t *)calloc( + trak->chunk_offset_count, sizeof(int64_t)); if (!trak->chunk_offset_table) { last_error = QT_NO_MEMORY; goto free_trak; @@ -1450,8 +1510,8 @@ static qt_error parse_trak_atom (qt_trak *trak, debug_atom_load(" qt stsc atom (sample-to-chunk atom): %d entries\n", trak->sample_to_chunk_count); - trak->sample_to_chunk_table = (sample_to_chunk_table_t *)malloc( - trak->sample_to_chunk_count * sizeof(sample_to_chunk_table_t)); + trak->sample_to_chunk_table = (sample_to_chunk_table_t *)calloc( + trak->sample_to_chunk_count, sizeof(sample_to_chunk_table_t)); if (!trak->sample_to_chunk_table) { last_error = QT_NO_MEMORY; goto free_trak; @@ -1475,7 +1535,8 @@ static qt_error parse_trak_atom (qt_trak *trak, } else if (current_atom == STTS_ATOM) { /* there should only be one of these atoms */ - if (trak->time_to_sample_table) { + if (trak->time_to_sample_table + || current_atom_size < 12 || current_atom_size >= UINT_MAX) { last_error = QT_HEADER_TROUBLE; goto free_trak; } @@ -1485,8 +1546,13 @@ static qt_error parse_trak_atom (qt_trak *trak, debug_atom_load(" qt stts atom (time-to-sample atom): %d entries\n", trak->time_to_sample_count); - trak->time_to_sample_table = (time_to_sample_table_t *)malloc( - (trak->time_to_sample_count+1) * sizeof(time_to_sample_table_t)); + if (trak->time_to_sample_count > (current_atom_size - 12) / 8) { + last_error = QT_HEADER_TROUBLE; + goto free_trak; + } + + trak->time_to_sample_table = (time_to_sample_table_t *)calloc( + trak->time_to_sample_count+1, sizeof(time_to_sample_table_t)); if (!trak->time_to_sample_table) { last_error = QT_NO_MEMORY; goto free_trak; @@ -1537,44 +1603,51 @@ static qt_error parse_reference_atom (reference_t *ref, qt_atom current_atom; unsigned int current_atom_size; + if (ref_atom_size >= 0x80000000) + return QT_NOT_A_VALID_FILE; + /* initialize reference atom */ ref->url = NULL; ref->data_rate = 0; ref->qtim_version = 0; /* traverse through the atom looking for the key atoms */ - for (i = ATOM_PREAMBLE_SIZE; i < ref_atom_size - 4; i++) { + for (i = ATOM_PREAMBLE_SIZE; i + 4 < ref_atom_size; i++) { current_atom_size = _X_BE_32(&ref_atom[i - 4]); current_atom = _X_BE_32(&ref_atom[i]); if (current_atom == RDRF_ATOM) { + size_t string_size = _X_BE_32(&ref_atom[i + 12]); + size_t url_offset = 0; + int http = 0; + + if (string_size >= current_atom_size || string_size >= ref_atom_size - i) + return QT_NOT_A_VALID_FILE; /* if the URL starts with "http://", copy it */ - if (strncmp(&ref_atom[i + 16], "http://", 7) == 0 - || strncmp(&ref_atom[i + 16], "rtsp://", 7) == 0) { + if ( memcmp(&ref_atom[i + 16], "http://", 7) && + memcmp(&ref_atom[i + 16], "rtsp://", 7) && + base_mrl ) + { + /* We need a "qt" prefix hack for Apple trailers */ + http = !strncasecmp (base_mrl, "http://", 7); + url_offset = strlen(base_mrl) + 2 * http; + } + if (url_offset >= 0x80000000) + return QT_NOT_A_VALID_FILE; - /* URL is spec'd to terminate with a NULL; don't trust it */ - ref->url = xine_xmalloc(_X_BE_32(&ref_atom[i + 12]) + 1); - strncpy(ref->url, &ref_atom[i + 16], _X_BE_32(&ref_atom[i + 12])); - ref->url[_X_BE_32(&ref_atom[i + 12]) - 1] = '\0'; + /* otherwise, append relative URL to base MRL */ + string_size += url_offset; - } else { + ref->url = xine_xmalloc(string_size + 1); - int string_size; + if ( url_offset ) + sprintf (ref->url, "%s%s", http ? "qt" : "", base_mrl); - if (base_mrl) - string_size = strlen(base_mrl) + _X_BE_32(&ref_atom[i + 12]) + 1; - else - string_size = _X_BE_32(&ref_atom[i + 12]) + 1; + memcpy(ref->url + url_offset, &ref_atom[i + 16], _X_BE_32(&ref_atom[i + 12])); - /* otherwise, append relative URL to base MRL */ - ref->url = xine_xmalloc(string_size); - if (base_mrl) - strcpy(ref->url, base_mrl); - strncat(ref->url, &ref_atom[i + 16], _X_BE_32(&ref_atom[i + 12])); - ref->url[string_size - 1] = '\0'; - } + ref->url[string_size] = '\0'; debug_atom_load(" qt rdrf URL reference:\n %s\n", ref->url); @@ -1609,9 +1682,9 @@ static qt_error parse_reference_atom (reference_t *ref, /* This is a little support function used to process the edit list when * building a frame table. */ #define MAX_DURATION 0x7FFFFFFFFFFFFFFFLL -static void get_next_edit_list_entry(qt_trak *trak, +static void get_next_edit_list_entry(qt_trak *trak, int *edit_list_index, - unsigned int *edit_list_media_time, + unsigned int *edit_list_media_time, int64_t *edit_list_duration, unsigned int global_timescale) { @@ -1628,9 +1701,9 @@ static void get_next_edit_list_entry(qt_trak *trak, /* otherwise, find an edit list entries whose media time != -1 */ if (trak->edit_list_table[*edit_list_index].media_time != -1) { - *edit_list_media_time = + *edit_list_media_time = trak->edit_list_table[*edit_list_index].media_time; - *edit_list_duration = + *edit_list_duration = trak->edit_list_table[*edit_list_index].track_duration; /* duration is in global timescale units; convert to trak timescale */ @@ -1644,8 +1717,8 @@ static void get_next_edit_list_entry(qt_trak *trak, *edit_list_index = *edit_list_index + 1; } - /* on the way out, check if this is the last edit list entry; if so, - * don't let the duration expire (so set it to an absurdly large value) + /* on the way out, check if this is the last edit list entry; if so, + * don't let the duration expire (so set it to an absurdly large value) */ if (*edit_list_index == trak->edit_list_count) *edit_list_duration = MAX_DURATION; @@ -1680,14 +1753,13 @@ static qt_error build_frame_table(qt_trak *trak, /* AUDIO and OTHER frame types follow the same rules; VIDEO and vbr audio * frame types follow a different set */ - if ((trak->type == MEDIA_VIDEO) || + if ((trak->type == MEDIA_VIDEO) || (trak->properties->audio.vbr)) { /* in this case, the total number of frames is equal to the number of * entries in the sample size table */ trak->frame_count = trak->sample_size_count; - trak->frames = (qt_frame *)malloc( - trak->frame_count * sizeof(qt_frame)); + trak->frames = (qt_frame *)calloc(trak->frame_count, sizeof(qt_frame)); if (!trak->frames) return QT_NO_MEMORY; trak->current_frame = 0; @@ -1699,10 +1771,9 @@ static qt_error build_frame_table(qt_trak *trak, pts_index_countdown = trak->time_to_sample_table[pts_index].count; - media_id_counts = xine_xmalloc(trak->stsd_atoms_count * sizeof(int)); + media_id_counts = calloc(trak->stsd_atoms_count, sizeof(int)); if (!media_id_counts) return QT_NO_MEMORY; - memset(media_id_counts, 0, trak->stsd_atoms_count * sizeof(int)); /* iterate through each start chunk in the stsc table */ for (i = 0; i < trak->sample_to_chunk_count; i++) { @@ -1732,7 +1803,7 @@ static qt_error build_frame_table(qt_trak *trak, trak->stsd_atoms_count); trak->frames[frame_counter].media_id = 0; } else { - trak->frames[frame_counter].media_id = + trak->frames[frame_counter].media_id = trak->sample_to_chunk_table[i].media_id; media_id_counts[trak->sample_to_chunk_table[i].media_id - 1]++; } @@ -1792,11 +1863,11 @@ static qt_error build_frame_table(qt_trak *trak, debug_edit_list(" %d: (before) pts = %"PRId64"...", i, trak->frames[i].pts); - if (trak->frames[i].pts < edit_list_media_time) + if (trak->frames[i].pts < edit_list_media_time) trak->frames[i].pts = edit_list_pts_counter; else { if (i < trak->frame_count - 1) - frame_duration = + frame_duration = (trak->frames[i + 1].pts - trak->frames[i].pts); debug_edit_list("duration = %"PRId64"...", frame_duration); @@ -1837,8 +1908,7 @@ static qt_error build_frame_table(qt_trak *trak, /* in this case, the total number of frames is equal to the number of * chunks */ trak->frame_count = trak->chunk_offset_count; - trak->frames = (qt_frame *)malloc( - trak->frame_count * sizeof(qt_frame)); + trak->frames = (qt_frame *)calloc(trak->frame_count, sizeof(qt_frame)); if (!trak->frames) return QT_NO_MEMORY; @@ -1876,7 +1946,7 @@ static qt_error build_frame_table(qt_trak *trak, trak->stsd_atoms_count); trak->frames[j].media_id = 0; } else { - trak->frames[j].media_id = + trak->frames[j].media_id = trak->sample_to_chunk_table[i].media_id; } @@ -1941,10 +2011,10 @@ static void parse_moov_atom(qt_info *info, unsigned char *moov_atom, /* create a new trak structure */ info->trak_count++; - info->traks = (qt_trak *)realloc(info->traks, + info->traks = (qt_trak *)realloc(info->traks, info->trak_count * sizeof(qt_trak)); - info->last_error = parse_trak_atom (&info->traks[info->trak_count - 1], + info->last_error = parse_trak_atom (&info->traks[info->trak_count - 1], &moov_atom[i - 4]); if (info->last_error != QT_OK) { info->trak_count--; @@ -1993,8 +2063,12 @@ static void parse_moov_atom(qt_info *info, unsigned char *moov_atom, info->references = (reference_t *)realloc(info->references, info->reference_count * sizeof(reference_t)); - parse_reference_atom(&info->references[info->reference_count - 1], - &moov_atom[i - 4], info->base_mrl); + error = parse_reference_atom(&info->references[info->reference_count - 1], + &moov_atom[i - 4], info->base_mrl); + if (error != QT_OK) { + info->last_error = error; + return; + } } else { debug_atom_load(" qt: unknown atom into the moov atom (0x%08X)\n", current_atom); @@ -2049,11 +2123,11 @@ static void parse_moov_atom(qt_info *info, unsigned char *moov_atom, /* iterate through 1..n-1 reference entries and decide on the right one */ for (i = 1; i < info->reference_count; i++) { - if (info->references[i].qtim_version > + if (info->references[i].qtim_version > info->references[info->chosen_reference].qtim_version) info->chosen_reference = i; else if ((info->references[i].data_rate <= bandwidth) && - (info->references[i].data_rate > + (info->references[i].data_rate > info->references[info->chosen_reference].data_rate)) info->chosen_reference = i; } @@ -2137,7 +2211,7 @@ static qt_error open_qt_file(qt_info *info, input_plugin_t *input, info->last_error = QT_FILE_READ_ERROR; return info->last_error; } - if (input->read(input, moov_atom, moov_atom_size) != + if (input->read(input, moov_atom, moov_atom_size) != moov_atom_size) { free(moov_atom); info->last_error = QT_FILE_READ_ERROR; @@ -2145,7 +2219,7 @@ static qt_error open_qt_file(qt_info *info, input_plugin_t *input, } /* check if moov is compressed */ - if (_X_BE_32(&moov_atom[12]) == CMOV_ATOM) { + if (_X_BE_32(&moov_atom[12]) == CMOV_ATOM && moov_atom_size >= 0x28) { info->compressed_header = 1; @@ -2268,12 +2342,12 @@ static int demux_qt_send_chunk(demux_plugin_t *this_gen) { /* if audio is present, send pts of current audio frame, otherwise * send current video frame pts */ if (audio_trak) - _x_demux_control_newpts(this->stream, - audio_trak->frames[audio_trak->current_frame].pts, + _x_demux_control_newpts(this->stream, + audio_trak->frames[audio_trak->current_frame].pts, BUF_FLAG_SEEK); else - _x_demux_control_newpts(this->stream, - video_trak->frames[video_trak->current_frame].pts, + _x_demux_control_newpts(this->stream, + video_trak->frames[video_trak->current_frame].pts, BUF_FLAG_SEEK); } @@ -2380,7 +2454,7 @@ static int demux_qt_send_chunk(demux_plugin_t *this_gen) { frame_duration); debug_video_demux(" qt: sending off video frame %d from offset 0x%"PRIX64", %d bytes, media id %d, %"PRId64" pts\n", - i, + i, video_trak->frames[i].offset, video_trak->frames[i].size, video_trak->frames[i].media_id, @@ -2438,7 +2512,7 @@ static int demux_qt_send_chunk(demux_plugin_t *this_gen) { SEEK_SET); debug_audio_demux(" qt: sending off audio frame %d from offset 0x%"PRIX64", %d bytes, media id %d, %"PRId64" pts\n", - i, + i, audio_trak->frames[i].offset, audio_trak->frames[i].size, audio_trak->frames[i].media_id, @@ -2457,8 +2531,8 @@ static int demux_qt_send_chunk(demux_plugin_t *this_gen) { * turns around and sends out audio buffers as soon as they are * received. If 2 or more consecutive audio buffers are dispatched to * the audio out unit, the engine will compensate with pops. */ - if ((buf->type == BUF_AUDIO_LPCM_BE) || - (buf->type == BUF_AUDIO_LPCM_LE)) { + if ((buf->type == BUF_AUDIO_LPCM_BE) || + (buf->type == BUF_AUDIO_LPCM_LE)) { if (first_buf) { buf->extra_info->input_time = audio_trak->frames[i].pts / 90; buf->pts = audio_trak->frames[i].pts; @@ -2487,7 +2561,7 @@ static int demux_qt_send_chunk(demux_plugin_t *this_gen) { /* Special case alert: If this is signed, 8-bit data, transform * the data to unsigned. */ - if ((audio_trak->properties->audio.bits == 8) && + if ((audio_trak->properties->audio.bits == 8) && ((audio_trak->properties->audio.codec_fourcc == TWOS_FOURCC) || (audio_trak->properties->audio.codec_fourcc == SOWT_FOURCC))) for (j = 0; j < buf->size; j++) @@ -2556,7 +2630,7 @@ static void demux_qt_send_headers(demux_plugin_t *this_gen) { this->bih.biBitCount = video_trak->properties->video.depth; this->bih.biCompression = video_trak->properties->video.codec_fourcc; - video_trak->properties->video.codec_buftype = + video_trak->properties->video.codec_buftype = _x_fourcc_to_buf_video(this->bih.biCompression); /* hack: workaround a fourcc clash! 'mpg4' is used by MS and Sorenson @@ -2564,13 +2638,13 @@ static void demux_qt_send_headers(demux_plugin_t *this_gen) { */ if( video_trak->properties->video.codec_buftype == BUF_VIDEO_MSMPEG4_V1 ) video_trak->properties->video.codec_buftype = BUF_VIDEO_MPEG4; - - if( !video_trak->properties->video.codec_buftype && + + if( !video_trak->properties->video.codec_buftype && video_trak->properties->video.codec_fourcc ) video_trak->properties->video.codec_buftype = BUF_VIDEO_UNKNOWN; _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, 1); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, + _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, this->bih.biWidth); _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, this->bih.biHeight); @@ -2603,7 +2677,7 @@ static void demux_qt_send_headers(demux_plugin_t *this_gen) { break; } } else { - audio_trak->properties->audio.codec_buftype = + audio_trak->properties->audio.codec_buftype = _x_formattag_to_buf_audio(audio_trak->properties->audio.codec_fourcc); } @@ -2618,7 +2692,7 @@ static void demux_qt_send_headers(demux_plugin_t *this_gen) { audio_trak->properties->audio.sample_rate); _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITS, audio_trak->properties->audio.bits); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_FOURCC, + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_FOURCC, audio_trak->properties->audio.codec_fourcc); } else { @@ -2659,17 +2733,17 @@ static void demux_qt_send_headers(demux_plugin_t *this_gen) { (video_trak->properties->video.codec_buftype)) { buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAME_END; - + memcpy(buf->content, &this->bih, sizeof(this->bih)); buf->size = sizeof(this->bih); buf->type = video_trak->properties->video.codec_buftype; this->video_fifo->put (this->video_fifo, buf); - + /* send header info to decoder. some mpeg4 streams need this */ if( video_trak->decoder_config ) { buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); buf->type = video_trak->properties->video.codec_buftype; - + if (video_trak->properties->video.codec_fourcc == AVC1_FOURCC) { buf->size = 0; buf->decoder_flags = BUF_FLAG_SPECIAL|BUF_FLAG_HEADER; @@ -2713,9 +2787,9 @@ static void demux_qt_send_headers(demux_plugin_t *this_gen) { /* set the audio bitrate field (only for CBR audio) */ if (!audio_trak->properties->audio.vbr) { - audio_bitrate = + audio_bitrate = audio_trak->properties->audio.sample_rate / - audio_trak->properties->audio.samples_per_frame * + audio_trak->properties->audio.samples_per_frame * audio_trak->properties->audio.bytes_per_frame * audio_trak->properties->audio.channels * 8; @@ -2730,7 +2804,7 @@ static void demux_qt_send_headers(demux_plugin_t *this_gen) { buf->decoder_info[1] = audio_trak->properties->audio.sample_rate; buf->decoder_info[2] = audio_trak->properties->audio.bits; buf->decoder_info[3] = audio_trak->properties->audio.channels; - + if( audio_trak->properties->audio.wave_size ) { if( audio_trak->properties->audio.wave_size > buf->max_size ) buf->size = buf->max_size; @@ -2741,9 +2815,9 @@ static void demux_qt_send_headers(demux_plugin_t *this_gen) { buf->size = 0; buf->content = NULL; } - + this->audio_fifo->put (this->audio_fifo, buf); - + if( audio_trak->decoder_config ) { buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); buf->type = audio_trak->properties->audio.codec_buftype; @@ -2836,7 +2910,7 @@ static int demux_qt_seek (demux_plugin_t *this_gen, qt_trak *video_trak = NULL; qt_trak *audio_trak = NULL; int64_t keyframe_pts; - + start_pos = (off_t) ( (double) start_pos / 65535 * this->data_size ); @@ -2944,7 +3018,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str return NULL; } - this = xine_xmalloc (sizeof (demux_qt_t)); + this = calloc(1, sizeof(demux_qt_t)); this->stream = stream; this->input = input; @@ -3059,7 +3133,9 @@ static const char *get_mimetypes (demux_class_t *this_gen) { return "video/quicktime: mov,qt: Quicktime animation;" "video/x-quicktime: mov,qt: Quicktime animation;" "audio/x-m4a: m4a,m4b: MPEG-4 audio;" - "application/x-quicktimeplayer: qtl: Quicktime list;"; + "application/x-quicktimeplayer: qtl: Quicktime list;" + "video/mp4: mp4,mpg4: MPEG-4 video;" + "audio/mp4: mp4,mpg4: MPEG-4 audio;"; } static void class_dispose (demux_class_t *this_gen) { @@ -3073,7 +3149,7 @@ static void *init_plugin (xine_t *xine, void *data) { demux_qt_class_t *this; - this = xine_xmalloc (sizeof (demux_qt_class_t)); + this = calloc(1, sizeof(demux_qt_class_t)); this->config = xine->config; this->xine = xine; @@ -3095,7 +3171,7 @@ static const demuxer_info_t demux_info_qt = { }; const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ + /* type, API, "name", version, special_info, init_function */ { PLUGIN_DEMUX, 26, "quicktime", XINE_VERSION_CODE, &demux_info_qt, init_plugin }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; diff --git a/src/demuxers/demux_rawdv.c b/src/demuxers/demux_rawdv.c index 2d21f080d..968542057 100644 --- a/src/demuxers/demux_rawdv.c +++ b/src/demuxers/demux_rawdv.c @@ -1,18 +1,18 @@ /* * Copyright (C) 2000-2003 the xine project - * + * * This file is part of xine, a free video player. - * + * * xine is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * xine is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA @@ -89,17 +89,17 @@ static int demux_raw_dv_next (demux_raw_dv_t *this) { /* TODO: duplicate data and send to audio fifo. * however we don't have dvaudio decoder yet. */ - + buf->pts = this->pts; buf->extra_info->input_time = this->pts/90; if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * + buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * 65535 / this->input->get_length (this->input) ); buf->extra_info->frame_number = this->cur_frame; buf->type = BUF_VIDEO_DV; - + this->video_fifo->put(this->video_fifo, buf); - + if (this->audio_fifo) { abuf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); abuf->content = abuf->mem; @@ -213,11 +213,11 @@ static void demux_raw_dv_send_headers (demux_plugin_t *this_gen) { bih->biSizeImage = bih->biWidth*bih->biHeight; this->video_fifo->put(this->video_fifo, buf); - + this->pts = 0; this->cur_frame = 0; this->bytes_left = this->frame_size; - + this->status = DEMUX_OK; _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, 1); @@ -302,20 +302,21 @@ static int demux_raw_dv_seek (demux_plugin_t *this_gen, } if( !start_pos && start_time ) { - start_pos = (start_time * 90 / this->duration) * this->frame_size; + /* Upcast start_time in case sizeof(off_t) > sizeof(int) */ + start_pos = ((off_t) start_time * 90 / this->duration) * this->frame_size; } - - start_pos = start_pos - (start_pos % this->frame_size); + + start_pos = start_pos - (start_pos % this->frame_size); this->input->seek(this->input, start_pos, SEEK_SET); this->cur_frame = start_pos / this->frame_size; this->pts = this->cur_frame * this->duration; this->bytes_left = this->frame_size; - + _x_demux_flush_engine (this->stream); _x_demux_control_newpts (this->stream, this->pts, BUF_FLAG_SEEK); - + this->status = DEMUX_OK; return this->status; } @@ -347,7 +348,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str demux_raw_dv_t *this; - this = xine_xmalloc (sizeof (demux_raw_dv_t)); + this = calloc(1, sizeof(demux_raw_dv_t)); this->stream = stream; this->input = input; @@ -367,15 +368,14 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str case METHOD_BY_CONTENT: { uint8_t buf[8]; - + if (_x_demux_read_header(input, buf, 8) != 8) { free (this); return NULL; } /* DIF (DV) movie file */ - if (!((buf[0] == 0x1f) && (buf[1] == 0x07) && (buf[2] == 00) && - (buf[4] ^ 0x01))) { + if (memcmp(buf, "\x1F\x07\x00", 3) != 0 || !(buf[4] ^ 0x01)) { free (this); return NULL; } @@ -436,7 +436,7 @@ static void class_dispose (demux_class_t *this_gen) { static void *init_plugin (xine_t *xine, void *data) { demux_raw_dv_class_t *this; - this = xine_xmalloc (sizeof (demux_raw_dv_class_t)); + this = calloc(1, sizeof(demux_raw_dv_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_real.c b/src/demuxers/demux_real.c index 85d7dc5a3..340083221 100644 --- a/src/demuxers/demux_real.c +++ b/src/demuxers/demux_real.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000-2005 the xine project + * Copyright (C) 2000-2008 the xine project * * This file is part of xine, a free video player. * @@ -26,9 +26,9 @@ * * video packet sub-demuxer ported from mplayer code (www.mplayerhq.hu): * Real parser & demuxer - * + * * (C) Alex Beregszaszi <alex@naxine.org> - * + * * Based on FFmpeg's libav/rm.c. */ @@ -42,6 +42,9 @@ #include <string.h> #include <stdlib.h> #include <ctype.h> +#ifdef HAVE_MALLOC_H +#include <malloc.h> +#endif #define LOG_MODULE "demux_real" #define LOG_VERBOSE @@ -55,13 +58,13 @@ #include "demux.h" #include "bswap.h" +#include "real_common.h" + #define FOURCC_TAG BE_FOURCC -#define RMF_TAG FOURCC_TAG('.', 'R', 'M', 'F') #define PROP_TAG FOURCC_TAG('P', 'R', 'O', 'P') #define MDPR_TAG FOURCC_TAG('M', 'D', 'P', 'R') #define CONT_TAG FOURCC_TAG('C', 'O', 'N', 'T') #define DATA_TAG FOURCC_TAG('D', 'A', 'T', 'A') -#define INDX_TAG FOURCC_TAG('I', 'N', 'D', 'X') #define RA_TAG FOURCC_TAG('.', 'r', 'a', 0xfd) #define VIDO_TAG FOURCC_TAG('V', 'I', 'D', 'O') @@ -90,11 +93,11 @@ typedef struct { uint32_t start_time; uint32_t preroll; uint32_t duration; - char stream_name_size; + size_t stream_name_size; char *stream_name; - char mime_type_size; + size_t mime_type_size; char *mime_type; - uint32_t type_specific_len; + size_t type_specific_len; char *type_specific_data; } mdpr_t; @@ -108,11 +111,17 @@ typedef struct { uint32_t fourcc; uint32_t buf_type; uint32_t format; - + real_index_entry_t *index; int index_entries; - + mdpr_t *mdpr; + int sps, cfs, w, h; + int block_align; + size_t frame_size; + uint8_t *frame_buffer; + uint32_t frame_num_bytes; + uint32_t sub_packet_cnt; } real_stream_t; typedef struct { @@ -150,7 +159,7 @@ typedef struct { int64_t last_pts[2]; int send_newpts; int buf_flag_seek; - + uint32_t last_ts; uint32_t next_ts; int last_seq; @@ -168,16 +177,14 @@ typedef struct { demux_class_t demux_class; } demux_real_class_t; - static void real_parse_index(demux_real_t *this) { off_t next_index_chunk = this->index_start; off_t original_pos = this->input->get_current_pos(this->input); unsigned char index_chunk_header[INDEX_CHUNK_HEADER_SIZE]; unsigned char index_record[INDEX_RECORD_SIZE]; - int i, entries, stream_num; - real_index_entry_t **index; - + int i; + while(next_index_chunk) { lprintf("reading index chunk at %"PRIX64"\n", next_index_chunk); @@ -192,69 +199,68 @@ static void real_parse_index(demux_real_t *this) { } /* Check chunk is actually an index chunk */ - if(_X_BE_32(&index_chunk_header[0]) == INDX_TAG) { - unsigned short version; + if(!_x_is_fourcc(&index_chunk_header[0], "INDX")) { + lprintf("expected index chunk found chunk type: %.4s\n", &index_chunk_header[0]); + break; + } - /* Check version */ - version = _X_BE_16(&index_chunk_header[8]); - if(version != 0) { - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_real: unknown object version in INDX: 0x%04x\n", version); - break; - } + /* Check version */ + const uint16_t version = _X_BE_16(&index_chunk_header[8]); + if(version != 0) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_real: unknown object version in INDX: 0x%04x\n", version); + break; + } - /* Read data from header */ - entries = _X_BE_32(&index_chunk_header[10]); - stream_num = _X_BE_16(&index_chunk_header[14]); - next_index_chunk = _X_BE_32(&index_chunk_header[16]); - - /* Find which stream this index is for */ - index = NULL; - for(i = 0; i < this->num_video_streams; i++) { - if(stream_num == this->video_streams[i].mdpr->stream_number) { - index = &this->video_streams[i].index; - this->video_streams[i].index_entries = entries; - lprintf("found index chunk for video stream with num %d\n", stream_num); - break; - } + /* Read data from header */ + const uint32_t entries = _X_BE_32(&index_chunk_header[10]); + const uint16_t stream_num = _X_BE_16(&index_chunk_header[14]); + next_index_chunk = _X_BE_32(&index_chunk_header[16]); + + /* Find which stream this index is for */ + real_index_entry_t **index = NULL; + for(i = 0; i < this->num_video_streams; i++) { + if(stream_num == this->video_streams[i].mdpr->stream_number) { + index = &this->video_streams[i].index; + this->video_streams[i].index_entries = entries; + lprintf("found index chunk for video stream with num %d\n", stream_num); + break; } + } - if(!index) { - for(i = 0; i < this->num_audio_streams; i++) { - if(stream_num == this->audio_streams[i].mdpr->stream_number) { - index = &this->audio_streams[i].index; - this->audio_streams[i].index_entries = entries; - lprintf("found index chunk for audio stream with num %d\n", stream_num); - break; - } - } + if(!index) { + for(i = 0; i < this->num_audio_streams; i++) { + if(stream_num == this->audio_streams[i].mdpr->stream_number) { + index = &this->audio_streams[i].index; + this->audio_streams[i].index_entries = entries; + lprintf("found index chunk for audio stream with num %d\n", stream_num); + break; + } } + } - if(index && entries) { - /* Allocate memory for index */ - *index = xine_xmalloc(entries * sizeof(real_index_entry_t)); - - /* Read index */ - for(i = 0; i < entries; i++) { - if(this->input->read(this->input, index_record, INDEX_RECORD_SIZE) - != INDEX_RECORD_SIZE) { - lprintf("index record not read\n"); - free(*index); - *index = NULL; - break; - } - - (*index)[i].timestamp = _X_BE_32(&index_record[2]); - (*index)[i].offset = _X_BE_32(&index_record[6]); - (*index)[i].packetno = _X_BE_32(&index_record[10]); - } - } else { - lprintf("unused index chunk with %d entries for stream num %d\n", - entries, stream_num); + if(index && entries) + /* Allocate memory for index */ + *index = calloc(entries, sizeof(real_index_entry_t)); + + if(index && entries && *index) { + /* Read index */ + for(i = 0; i < entries; i++) { + if(this->input->read(this->input, index_record, INDEX_RECORD_SIZE) + != INDEX_RECORD_SIZE) { + lprintf("index record not read\n"); + free(*index); + *index = NULL; + break; + } + + (*index)[i].timestamp = _X_BE_32(&index_record[2]); + (*index)[i].offset = _X_BE_32(&index_record[6]); + (*index)[i].packetno = _X_BE_32(&index_record[10]); } } else { - lprintf("expected index chunk found chunk type: %.4s\n", &index_chunk_header[0]); - break; + lprintf("unused index chunk with %d entries for stream num %d\n", + entries, stream_num); } } @@ -262,8 +268,12 @@ static void real_parse_index(demux_real_t *this) { this->input->seek(this->input, original_pos, SEEK_SET); } -static mdpr_t *real_parse_mdpr(const char *data) { - mdpr_t *mdpr=malloc(sizeof(mdpr_t)); +static mdpr_t *real_parse_mdpr(const char *data, const unsigned int size) +{ + if (size < 38) + return NULL; + + mdpr_t *mdpr=calloc(sizeof(mdpr_t), 1); mdpr->stream_number=_X_BE_16(&data[2]); mdpr->max_bit_rate=_X_BE_32(&data[4]); @@ -275,17 +285,29 @@ static mdpr_t *real_parse_mdpr(const char *data) { mdpr->duration=_X_BE_32(&data[28]); mdpr->stream_name_size=data[32]; - mdpr->stream_name=malloc(sizeof(char)*(mdpr->stream_name_size+1)); + if (size < 38 + mdpr->stream_name_size) + goto fail; + mdpr->stream_name=malloc(mdpr->stream_name_size+1); + if (!mdpr->stream_name) + goto fail; memcpy(mdpr->stream_name, &data[33], mdpr->stream_name_size); mdpr->stream_name[(int)mdpr->stream_name_size]=0; mdpr->mime_type_size=data[33+mdpr->stream_name_size]; - mdpr->mime_type=malloc(sizeof(char)*(mdpr->mime_type_size+1)); + if (size < 38 + mdpr->stream_name_size + mdpr->mime_type_size) + goto fail; + mdpr->mime_type=malloc(mdpr->mime_type_size+1); + if (!mdpr->mime_type) + goto fail; memcpy(mdpr->mime_type, &data[34+mdpr->stream_name_size], mdpr->mime_type_size); mdpr->mime_type[(int)mdpr->mime_type_size]=0; mdpr->type_specific_len=_X_BE_32(&data[34+mdpr->stream_name_size+mdpr->mime_type_size]); - mdpr->type_specific_data=malloc(sizeof(char)*(mdpr->type_specific_len)); + if (size < 38 + mdpr->stream_name_size + mdpr->mime_type_size + mdpr->type_specific_data) + goto fail; + mdpr->type_specific_data=malloc(mdpr->type_specific_len); + if (!mdpr->type_specific_data) + goto fail; memcpy(mdpr->type_specific_data, &data[38+mdpr->stream_name_size+mdpr->mime_type_size], mdpr->type_specific_len); @@ -305,6 +327,13 @@ static mdpr_t *real_parse_mdpr(const char *data) { #endif return mdpr; + +fail: + free (mdpr->stream_name); + free (mdpr->mime_type); + free (mdpr->type_specific_data); + free (mdpr); + return NULL; } static void real_free_mdpr (mdpr_t *mdpr) { @@ -314,43 +343,109 @@ static void real_free_mdpr (mdpr_t *mdpr) { free (mdpr); } +static void real_parse_audio_specific_data (demux_real_t *this, + real_stream_t * stream) +{ + if (stream->mdpr->type_specific_len < 46) { + xprintf (this->stream->xine, XINE_VERBOSITY_LOG, + "demux_real: audio data size smaller than header length!\n"); + return; + } + + uint8_t * data = stream->mdpr->type_specific_data; + const uint32_t coded_frame_size = _X_BE_32 (data+24); + const uint16_t codec_data_length = _X_BE_16 (data+40); + const uint16_t coded_frame_size2 = _X_BE_16 (data+42); + const uint16_t subpacket_size = _X_BE_16 (data+44); + + stream->sps = subpacket_size; + stream->w = coded_frame_size2; + stream->h = codec_data_length; + stream->block_align = coded_frame_size2; + stream->cfs = coded_frame_size; + + switch (stream->buf_type) { + case BUF_AUDIO_COOK: + case BUF_AUDIO_ATRK: + stream->block_align = subpacket_size; + break; + + case BUF_AUDIO_14_4: + break; + + case BUF_AUDIO_28_8: + stream->block_align = stream->cfs; + break; + + case BUF_AUDIO_SIPRO: + /* this->block_align = 19; */ + break; + + default: + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_real: error, i don't handle buf type 0x%08x\n", stream->buf_type); + } + + /* + * when stream->sps is set it used to do this: + * stream->frame_size = stream->w / stream->sps * stream->h * stream->sps; + * but it looks pointless? the compiler will probably optimise it away, I suppose? + */ + if (stream->w < 32768 && stream->h < 32768) { + stream->frame_size = stream->w * stream->h; + stream->frame_buffer = calloc(stream->frame_size, 1); + } else { + stream->frame_size = 0; + stream->frame_buffer = NULL; + } + + stream->frame_num_bytes = 0; + stream->sub_packet_cnt = 0; + + if (!stream->frame_buffer) + xprintf (this->stream->xine, XINE_VERBOSITY_LOG, + "demux_real: failed to allocate the audio frame buffer!\n"); + + xprintf (this->stream->xine, XINE_VERBOSITY_LOG, + "demux_real: buf type 0x%08x frame size %zu block align %d\n", stream->buf_type, + stream->frame_size, stream->block_align); + +} static void real_parse_headers (demux_real_t *this) { char preamble[PREAMBLE_SIZE]; unsigned int chunk_type = 0; unsigned int chunk_size; - unsigned short version; - unsigned char *chunk_buffer; - int field_size; - int stream_ptr; - unsigned char data_chunk_header[DATA_CHUNK_HEADER_SIZE]; - unsigned char signature[REAL_SIGNATURE_SIZE]; - - this->data_start = 0; - this->data_size = 0; - this->num_video_streams = 0; - this->num_audio_streams = 0; if (INPUT_IS_SEEKABLE(this->input)) this->input->seek (this->input, 0, SEEK_SET); - if (this->input->read(this->input, signature, REAL_SIGNATURE_SIZE) != - REAL_SIGNATURE_SIZE) { + { + uint8_t signature[REAL_SIGNATURE_SIZE]; + if (this->input->read(this->input, signature, REAL_SIGNATURE_SIZE) != + REAL_SIGNATURE_SIZE) { - lprintf ("signature not read\n"); - this->status = DEMUX_FINISHED; - return; - } + lprintf ("signature not read\n"); + this->status = DEMUX_FINISHED; + return; + } - if (_X_BE_32(signature) != RMF_TAG) { - this->status = DEMUX_FINISHED; - lprintf ("signature not found '%.4s'\n", signature); - return; + if ( !_x_is_fourcc(signature, ".RMF") ) { + this->status = DEMUX_FINISHED; + lprintf ("signature not found '%.4s'\n", signature); + return; + } + + /* skip to the start of the first chunk and start traversing */ + chunk_size = _X_BE_32(&signature[4]); } - /* skip to the start of the first chunk and start traversing */ - chunk_size = _X_BE_32(&signature[4]); + this->data_start = 0; + this->data_size = 0; + this->num_video_streams = 0; + this->num_audio_streams = 0; + this->input->seek(this->input, chunk_size-8, SEEK_CUR); /* iterate through chunks and gather information until the first DATA @@ -371,179 +466,198 @@ static void real_parse_headers (demux_real_t *this) { case PROP_TAG: case MDPR_TAG: case CONT_TAG: + { + if (chunk_size < PREAMBLE_SIZE+1) { + this->status = DEMUX_FINISHED; + return; + } + chunk_size -= PREAMBLE_SIZE; + uint8_t *const chunk_buffer = malloc(chunk_size); + if (! chunk_buffer || + this->input->read(this->input, chunk_buffer, chunk_size) != + chunk_size) { + free (chunk_buffer); + this->status = DEMUX_FINISHED; + return; + } - chunk_size -= PREAMBLE_SIZE; - chunk_buffer = xine_xmalloc(chunk_size); - if (this->input->read(this->input, chunk_buffer, chunk_size) != - chunk_size) { - free (chunk_buffer); - this->status = DEMUX_FINISHED; - return; - } - - version = _X_BE_16(&chunk_buffer[0]); - - if (chunk_type == PROP_TAG) { - - if(version != 0) { - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "demuxe_real: unknown object version in PROP: 0x%04x\n", version); - free(chunk_buffer); - this->status = DEMUX_FINISHED; - return; - } - - this->duration = _X_BE_32(&chunk_buffer[22]); - this->index_start = _X_BE_32(&chunk_buffer[30]); - this->data_start = _X_BE_32(&chunk_buffer[34]); - this->avg_bitrate = _X_BE_32(&chunk_buffer[6]); - - lprintf("PROP: duration: %d ms\n", this->duration); - lprintf("PROP: index start: %"PRIX64"\n", this->index_start); - lprintf("PROP: data start: %"PRIX64"\n", this->data_start); - lprintf("PROP: average bit rate: %"PRId64"\n", this->avg_bitrate); - - if (this->avg_bitrate<1) - this->avg_bitrate = 1; - - _x_stream_info_set(this->stream, XINE_STREAM_INFO_BITRATE, - this->avg_bitrate); - - } else if (chunk_type == MDPR_TAG) { + uint16_t version = _X_BE_16(&chunk_buffer[0]); - mdpr_t *mdpr; - uint32_t fourcc; + if (chunk_type == PROP_TAG) { - if (version != 0) { - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_real: unknown object version in MDPR: 0x%04x\n", version); - free(chunk_buffer); - continue; - } - - mdpr = real_parse_mdpr (chunk_buffer); + if(version != 0) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demuxe_real: unknown object version in PROP: 0x%04x\n", version); + free(chunk_buffer); + this->status = DEMUX_FINISHED; + return; + } - lprintf ("parsing type specific data...\n"); + this->duration = _X_BE_32(&chunk_buffer[22]); + this->index_start = _X_BE_32(&chunk_buffer[30]); + this->data_start = _X_BE_32(&chunk_buffer[34]); + this->avg_bitrate = _X_BE_32(&chunk_buffer[6]); - if(_X_BE_32(mdpr->type_specific_data) == RA_TAG) { - int version, len; + lprintf("PROP: duration: %d ms\n", this->duration); + lprintf("PROP: index start: %"PRIX64"\n", this->index_start); + lprintf("PROP: data start: %"PRIX64"\n", this->data_start); + lprintf("PROP: average bit rate: %"PRId64"\n", this->avg_bitrate); - if(this->num_audio_streams == MAX_AUDIO_STREAMS) { - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_real: maximum number of audio stream exceeded\n"); - goto unknown; - } - - version = _X_BE_16(mdpr->type_specific_data + 4); + if (this->avg_bitrate<1) + this->avg_bitrate = 1; - lprintf("audio version %d detected\n", version); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_BITRATE, + this->avg_bitrate); - switch(version) { + } else if (chunk_type == MDPR_TAG) { + if (version != 0) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_real: unknown object version in MDPR: 0x%04x\n", version); + free(chunk_buffer); + continue; + } + + mdpr_t *const mdpr = real_parse_mdpr (chunk_buffer, chunk_size); + + lprintf ("parsing type specific data...\n"); + if (!mdpr) { + free (chunk_buffer); + this->status = DEMUX_FINISHED; + return; + } + if(!strcmp(mdpr->mime_type, "audio/X-MP3-draft-00")) { + lprintf ("mpeg layer 3 audio detected...\n"); + + static const uint32_t fourcc = ME_FOURCC('a', 'd', 'u', 0x55); + this->audio_streams[this->num_audio_streams].fourcc = fourcc; + this->audio_streams[this->num_audio_streams].buf_type = _x_formattag_to_buf_audio(fourcc); + this->audio_streams[this->num_audio_streams].index = NULL; + this->audio_streams[this->num_audio_streams].mdpr = mdpr; + this->num_audio_streams++; + } else if(_X_BE_32(mdpr->type_specific_data) == RA_TAG && + mdpr->type_specific_len >= 6) { + if(this->num_audio_streams == MAX_AUDIO_STREAMS) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_real: maximum number of audio stream exceeded\n"); + goto unknown; + } + + const uint16_t version = _X_BE_16(mdpr->type_specific_data + 4); + + lprintf("audio version %d detected\n", version); + + char *fourcc_ptr = "\0\0\0"; + switch(version) { case 3: - /* Version 3 header stores fourcc after meta info - cheat by reading backwards from the + /* Version 3 header stores fourcc after meta info - cheat by reading backwards from the * end of the header instead of having to parse it all */ - fourcc = _X_ME_32(mdpr->type_specific_data + mdpr->type_specific_len - 5); + if (mdpr->type_specific_len >= 5) + fourcc_ptr = mdpr->type_specific_data + mdpr->type_specific_len - 5; break; - case 4: - len = *(mdpr->type_specific_data + 56); - fourcc = _X_ME_32(mdpr->type_specific_data + 58 + len); + case 4: { + if (mdpr->type_specific_len >= 57) { + const uint8_t len = *(mdpr->type_specific_data + 56); + if (mdpr->type_specific_len >= 62 + len) + fourcc_ptr = mdpr->type_specific_data + 58 + len; + } + } break; case 5: - fourcc = _X_ME_32(mdpr->type_specific_data + 66); + if (mdpr->type_specific_len >= 70) + fourcc_ptr = mdpr->type_specific_data + 66; break; default: lprintf("unsupported audio header version %d\n", version); goto unknown; - } - - lprintf("fourcc = %.4s\n", (char *) &fourcc); - - this->audio_streams[this->num_audio_streams].fourcc = fourcc; - this->audio_streams[this->num_audio_streams].buf_type = _x_formattag_to_buf_audio(fourcc); - this->audio_streams[this->num_audio_streams].index = NULL; - this->audio_streams[this->num_audio_streams].mdpr = mdpr; - - this->num_audio_streams++; - - } else if(_X_BE_32(mdpr->type_specific_data + 4) == VIDO_TAG) { - - if(this->num_video_streams == MAX_VIDEO_STREAMS) { - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_real: maximum number of video stream exceeded\n"); - goto unknown; - } - - lprintf ("video detected\n"); - fourcc = _X_ME_32(mdpr->type_specific_data + 8); - lprintf("fourcc = %.4s\n", (char *) &fourcc); - - this->video_streams[this->num_video_streams].fourcc = fourcc; - this->video_streams[this->num_video_streams].buf_type = _x_fourcc_to_buf_video(fourcc); - this->video_streams[this->num_video_streams].format = _X_BE_32(mdpr->type_specific_data + 30); - this->video_streams[this->num_video_streams].index = NULL; - this->video_streams[this->num_video_streams].mdpr = mdpr; - - this->num_video_streams++; - - } else { - lprintf("unrecognised type specific data\n"); - -unknown: - real_free_mdpr(mdpr); - } - - } else if (chunk_type == CONT_TAG) { - - if(version != 0) { - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_real: unknown object version in CONT: 0x%04x\n", version); - free(chunk_buffer); - continue; - } + } + lprintf("fourcc = %.4s\n", fourcc_ptr); + + const uint32_t fourcc = _X_ME_32(fourcc_ptr); + + this->audio_streams[this->num_audio_streams].fourcc = fourcc; + this->audio_streams[this->num_audio_streams].buf_type = _x_formattag_to_buf_audio(fourcc); + this->audio_streams[this->num_audio_streams].index = NULL; + this->audio_streams[this->num_audio_streams].mdpr = mdpr; + + real_parse_audio_specific_data (this, + &this->audio_streams[this->num_audio_streams]); + this->num_audio_streams++; + + } else if(_X_BE_32(mdpr->type_specific_data + 4) == VIDO_TAG && + mdpr->type_specific_len >= 34) { + + if(this->num_video_streams == MAX_VIDEO_STREAMS) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_real: maximum number of video stream exceeded\n"); + goto unknown; + } + + lprintf ("video detected\n"); + const uint32_t fourcc = _X_ME_32(mdpr->type_specific_data + 8); + lprintf("fourcc = %.4s\n", (char *) &fourcc); + + this->video_streams[this->num_video_streams].fourcc = fourcc; + this->video_streams[this->num_video_streams].buf_type = _x_fourcc_to_buf_video(fourcc); + this->video_streams[this->num_video_streams].format = _X_BE_32(mdpr->type_specific_data + 30); + this->video_streams[this->num_video_streams].index = NULL; + this->video_streams[this->num_video_streams].mdpr = mdpr; + + this->num_video_streams++; + + } else { + lprintf("unrecognised type specific data\n"); + + unknown: + real_free_mdpr(mdpr); + } + + } else if (chunk_type == CONT_TAG) { + + if(version != 0) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_real: unknown object version in CONT: 0x%04x\n", version); + free(chunk_buffer); + continue; + } + + int stream_ptr = 2; +#define SET_METADATA_STRING(type) \ + do { \ + const uint16_t field_size = _X_BE_16(&chunk_buffer[stream_ptr]); \ + stream_ptr += 2; \ + _x_meta_info_n_set(this->stream, type, \ + &chunk_buffer[stream_ptr], field_size); \ + stream_ptr += field_size; \ + } while(0) + + /* load the title string */ + SET_METADATA_STRING(XINE_META_INFO_TITLE); + + /* load the author string */ + SET_METADATA_STRING(XINE_META_INFO_ARTIST); + + /* load the copyright string as the year */ + SET_METADATA_STRING(XINE_META_INFO_YEAR); + + /* load the comment string */ + SET_METADATA_STRING(XINE_META_INFO_COMMENT); + } - stream_ptr = 2; - - /* load the title string */ - field_size = _X_BE_16(&chunk_buffer[stream_ptr]); - stream_ptr += 2; - _x_meta_info_n_set(this->stream, XINE_META_INFO_TITLE, - &chunk_buffer[stream_ptr], field_size); - stream_ptr += field_size; - - /* load the author string */ - field_size = _X_BE_16(&chunk_buffer[stream_ptr]); - stream_ptr += 2; - _x_meta_info_n_set(this->stream, XINE_META_INFO_ARTIST, - &chunk_buffer[stream_ptr], field_size); - stream_ptr += field_size; - - /* load the copyright string as the year */ - field_size = _X_BE_16(&chunk_buffer[stream_ptr]); - stream_ptr += 2; - _x_meta_info_n_set(this->stream, XINE_META_INFO_YEAR, - &chunk_buffer[stream_ptr], field_size); - stream_ptr += field_size; - - /* load the comment string */ - field_size = _X_BE_16(&chunk_buffer[stream_ptr]); - stream_ptr += 2; - _x_meta_info_n_set(this->stream, XINE_META_INFO_COMMENT, - &chunk_buffer[stream_ptr], field_size); - stream_ptr += field_size; + free(chunk_buffer); } - - free(chunk_buffer); break; - case DATA_TAG: - if (this->input->read(this->input, data_chunk_header, + case DATA_TAG: { + uint8_t data_chunk_header[DATA_CHUNK_HEADER_SIZE]; + + if (this->input->read(this->input, data_chunk_header, DATA_CHUNK_HEADER_SIZE) != DATA_CHUNK_HEADER_SIZE) { this->status = DEMUX_FINISHED; return ; } - + /* check version */ - version = _X_BE_16(&data_chunk_header[0]); + const uint16_t version = _X_BE_16(&data_chunk_header[0]); if(version != 0) { xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_real: unknown object version in DATA: 0x%04x\n", version); @@ -554,7 +668,8 @@ unknown: this->current_data_chunk_packet_count = _X_BE_32(&data_chunk_header[2]); this->next_data_chunk_offset = _X_BE_32(&data_chunk_header[6]); this->data_chunk_size = chunk_size; - break; + } + break; default: /* this should not occur, but in case it does, skip the chunk */ @@ -568,17 +683,10 @@ unknown: /* Read index tables */ if(INPUT_IS_SEEKABLE(this->input)) real_parse_index(this); - + /* Simple stream selection case - 0/1 audio/video streams */ - if(this->num_video_streams == 1) - this->video_stream = &this->video_streams[0]; - else - this->video_stream = NULL; - - if(this->num_audio_streams == 1) - this->audio_stream = &this->audio_streams[0]; - else - this->audio_stream = NULL; + this->video_stream = (this->num_video_streams == 1) ? &this->video_streams[0] : NULL; + this->audio_stream = (this->num_audio_streams == 1) ? &this->audio_streams[0] : NULL; /* In the case of multiple audio/video streams select the first streams found in the file */ @@ -590,23 +698,23 @@ unknown: /* Get data to search through for stream chunks */ if(INPUT_IS_SEEKABLE(this->input)) { original_pos = this->input->get_current_pos(this->input); - + if((len = this->input->read(this->input, search_buffer, MAX_PREVIEW_SIZE)) <= 0) { - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_real: failed to read header\n"); this->status = DEMUX_FINISHED; return; } - + offset = 0; } else if((this->input->get_capabilities(this->input) & INPUT_CAP_PREVIEW) != 0) { if((len = this->input->get_optional_data(this->input, search_buffer, INPUT_OPTIONAL_DATA_PREVIEW)) <= 0) { - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_real: failed to read header\n"); this->status = DEMUX_FINISHED; return; } - + /* Preview data starts at the beginning of the file */ offset = this->data_start + 18; } else { @@ -615,19 +723,17 @@ unknown: this->status = DEMUX_FINISHED; return; } - + while((offset < len) && ((!this->video_stream && (this->num_video_streams > 0)) || (!this->audio_stream && (this->num_audio_streams > 0)))) { - uint32_t id; - int i, stream; - + int i; + /* Check for end of the data chunk */ - if(((id = _X_BE_32(&search_buffer[offset])) == DATA_TAG) || - (id == INDX_TAG)) - break; - - stream = _X_BE_16(&search_buffer[offset + 4]); + if (_x_is_fourcc(&search_buffer[offset], "INDX") || _x_is_fourcc(&search_buffer[offset], "DATA")) + break; + + const int stream = _X_BE_16(&search_buffer[offset + 4]); for(i = 0; !this->video_stream && (i < this->num_video_streams); i++) { if(stream == this->video_streams[i].mdpr->stream_number) { @@ -635,7 +741,7 @@ unknown: lprintf("selecting video stream: %d\n", stream); } } - + for(i = 0; !this->audio_stream && (i < this->num_audio_streams); i++) { if(stream == this->audio_streams[i].mdpr->stream_number) { this->audio_stream = &this->audio_streams[i]; @@ -645,11 +751,11 @@ unknown: offset += _X_BE_16(&search_buffer[offset + 2]); } - + if(INPUT_IS_SEEKABLE(this->input)) this->input->seek(this->input, original_pos, SEEK_SET); } - + /* Let the user know if we haven't managed to detect what streams to play */ if((!this->video_stream && this->num_video_streams) || (!this->audio_stream && this->num_audio_streams)) { @@ -658,19 +764,17 @@ unknown: this->status = DEMUX_FINISHED; return; } - + /* Send headers and set meta info */ if(this->video_stream) { - buf_element_t *buf; - /* Check for recognised codec*/ if(!this->video_stream->buf_type) this->video_stream->buf_type = BUF_VIDEO_UNKNOWN; - + /* Send header */ - buf = this->video_fifo->buffer_pool_alloc(this->video_fifo); + buf_element_t *const buf = this->video_fifo->buffer_pool_alloc(this->video_fifo); buf->content = buf->mem; - + memcpy(buf->content, this->video_stream->mdpr->type_specific_data, this->video_stream->mdpr->type_specific_len); @@ -688,9 +792,9 @@ unknown: this->video_stream->fourcc); _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_BITRATE, this->video_stream->mdpr->avg_bit_rate); - + /* Allocate fragment offset table */ - this->fragment_tab = xine_xmalloc(FRAGMENT_TAB_SIZE*sizeof(uint32_t)); + this->fragment_tab = calloc(FRAGMENT_TAB_SIZE, sizeof(uint32_t)); this->fragment_tab_max = FRAGMENT_TAB_SIZE; } @@ -698,31 +802,30 @@ unknown: /* Check for recognised codec */ if(!this->audio_stream->buf_type) this->audio_stream->buf_type = BUF_AUDIO_UNKNOWN; - + /* Send headers */ if(this->audio_fifo) { - mdpr_t *mdpr = this->audio_stream->mdpr; - buf_element_t *buf; + mdpr_t *const mdpr = this->audio_stream->mdpr; - buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); + buf_element_t *buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); buf->type = this->audio_stream->buf_type; buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_FRAME_END; - + /* For AAC we send two header buffers, the first is a standard audio * header giving bits per sample, sample rate and number of channels. * The second is the codec initialisation data found at the end of * the type specific data for the audio stream */ if(buf->type == BUF_AUDIO_AAC) { - int version = _X_BE_16(mdpr->type_specific_data + 4); - + const uint16_t version = _X_BE_16(mdpr->type_specific_data + 4); + if(version != 5) { xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_real: unsupported audio header version for AAC: %d\n", version); buf->free_buffer(buf); goto unsupported; } - + buf->decoder_info[1] = _X_BE_16(mdpr->type_specific_data + 54); buf->decoder_info[2] = _X_BE_16(mdpr->type_specific_data + 58); buf->decoder_info[3] = _X_BE_16(mdpr->type_specific_data + 60); @@ -730,21 +833,28 @@ unknown: buf->decoder_flags |= BUF_FLAG_STDHEADER; buf->content = NULL; buf->size = 0; - + this->audio_fifo->put (this->audio_fifo, buf); - + buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); - + buf->type = this->audio_stream->buf_type; buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_FRAME_END|BUF_FLAG_SPECIAL; buf->decoder_info[1] = BUF_SPECIAL_DECODER_CONFIG; buf->decoder_info[2] = _X_BE_32(mdpr->type_specific_data + 74) - 1; buf->decoder_info_ptr[2] = buf->content; buf->size = 0; - + memcpy(buf->content, mdpr->type_specific_data + 79, buf->decoder_info[2]); + } else if(buf->type == BUF_AUDIO_MP3ADU) { + buf->decoder_flags |= BUF_FLAG_STDHEADER | BUF_FLAG_FRAME_END; + buf->size = 0; + buf->decoder_info[0] = 0; + buf->decoder_info[1] = 0; + buf->decoder_info[2] = 0; + buf->decoder_info[3] = 0; } else { memcpy(buf->content, mdpr->type_specific_data, mdpr->type_specific_len); @@ -782,7 +892,7 @@ static int demux_real_parse_references( demux_real_t *this) { lprintf("parsing references\n"); - + /* read file to memory. * warning: dumb code, but hopefuly ok since reference file is small */ do { @@ -801,17 +911,27 @@ static int demux_real_parse_references( demux_real_t *this) { if(buf_used) buf[buf_used] = '\0'; - + lprintf("received %d bytes [%s]\n", buf_used, buf); if (!strncmp(buf,"http://",7)) { - for (i = 0; buf[i] && !isspace(buf[i]); ++i) - /**/; - buf[i] = 0; - lprintf("reference [%s] found\n", buf); - - _x_demux_send_mrl_reference (this->stream, 0, buf, NULL, 0, 0); + i = 0; + while (buf[i]) + { + j = i; + while (buf[i] && !isspace(buf[i])) + ++i; /* skip non-space */ + len = buf[i]; + buf[i] = 0; + if (strncmp (buf + j, "http://", 7) || (i - j) < 8) + break; /* stop at the first non-http reference */ + lprintf("reference [%s] found\n", buf + j); + _x_demux_send_mrl_reference (this->stream, 0, buf + j, NULL, 0, 0); + buf[i] = (char) len; + while (buf[i] && isspace(buf[i])) + ++i; /* skip spaces */ + } } else for (i = 0; i < buf_used; ++i) { @@ -825,10 +945,10 @@ static int demux_real_parse_references( demux_real_t *this) { /* rpm files can contain comments which should be skipped */ if( !strncmp(&buf[i],"<!--",4) ) comment = 1; - + if( !strncmp(&buf[i],"-->",3) ) comment = 0; - + if( (!strncmp(&buf[i],"pnm://",6) || !strncmp(&buf[i],"rtsp://",7)) && !comment ) { for(j=i; buf[j] && buf[j] != '"' && !isspace(buf[j]); j++ ) @@ -841,14 +961,14 @@ static int demux_real_parse_references( demux_real_t *this) { i = j; } - } - + } + free(buf); - + this->status = DEMUX_FINISHED; return this->status; } - + /* redefine abs as macro to handle 64-bit diffs. i guess llabs may not be available everywhere */ #define abs(x) ( ((x)<0) ? -(x) : (x) ) @@ -858,9 +978,7 @@ static int demux_real_parse_references( demux_real_t *this) { #define PTS_VIDEO 1 static void check_newpts (demux_real_t *this, int64_t pts, int video, int preview) { - int64_t diff; - - diff = pts - this->last_pts[video]; + const int64_t diff = pts - this->last_pts[video]; lprintf ("check_newpts %"PRId64"\n", pts); if (!preview && pts && @@ -886,7 +1004,7 @@ static uint32_t real_fix_timestamp (demux_real_t *this, uint8_t *hdr, uint32_t t int pict_type; int seq; uint32_t ts_out; - + switch(this->video_stream->buf_type) { case BUF_VIDEO_RV20: pict_type = (hdr[0] & 0xC0) >> 6; @@ -901,35 +1019,35 @@ static uint32_t real_fix_timestamp (demux_real_t *this, uint8_t *hdr, uint32_t t seq = ((hdr[1] & 0x07) << 10) + (hdr[2] << 2) + ((hdr[3] & 0xC0) >> 6); break; default: - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_real: can't fix timestamp for buf type 0x%08x\n", + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_real: can't fix timestamp for buf type 0x%08x\n", this->video_stream->buf_type); return ts_in; break; } - + switch (pict_type) { case 0: - case 1: + case 1: /* I frame */ ts_out = this->next_ts; - + this->last_ts = this->next_ts; this->next_ts = ts_in; - + this->last_seq = this->next_seq; this->next_seq = seq; break; case 2: /* P frame */ ts_out = this->next_ts; - + this->last_ts = this->next_ts; if (seq < this->next_seq) this->next_ts += seq + 8192 - this->next_seq; else this->next_ts += seq - this->next_seq; - + this->last_seq = this->next_seq; this->next_seq = seq; break; @@ -946,8 +1064,8 @@ static uint32_t real_fix_timestamp (demux_real_t *this, uint8_t *hdr, uint32_t t ts_out = 0; break; } - - return ts_out; + + return ts_out; } static int stream_read_char (demux_real_t *this) { @@ -966,18 +1084,14 @@ static int demux_real_send_chunk(demux_plugin_t *this_gen) { demux_real_t *this = (demux_real_t *) this_gen; char header[DATA_PACKET_HEADER_SIZE]; - int stream, size, keyframe, input_time = 0; - unsigned short version; - uint32_t id, timestamp; - int64_t pts; - off_t offset, input_length = 0; + int keyframe, input_time = 0; int normpos = 0; if(this->reference_mode) return demux_real_parse_references(this); - + /* load a header from wherever the stream happens to be pointing */ - if ( (size=this->input->read(this->input, header, DATA_PACKET_HEADER_SIZE)) != + if ( this->input->read(this->input, header, DATA_PACKET_HEADER_SIZE) != DATA_PACKET_HEADER_SIZE) { xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, @@ -988,29 +1102,28 @@ static int demux_real_send_chunk(demux_plugin_t *this_gen) { } /* Check to see if we've gone past the end of the data chunk */ - if(((id = _X_BE_32(&header[0])) == DATA_TAG) || - (id == INDX_TAG)) { + if (_x_is_fourcc(&header[0], "INDX") || _x_is_fourcc(&header[0], "DATA")) { lprintf("finished reading data chunk\n"); this->status = DEMUX_FINISHED; return this->status; } /* check version */ - version = _X_BE_16(&header[0]); + const uint16_t version = _X_BE_16(&header[0]); if(version > 1) { xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_real: unknown object version in data packet: 0x%04x\n", version); this->status = DEMUX_FINISHED; return this->status; } - + /* read the packet information */ - stream = _X_BE_16(&header[4]); - offset = this->input->get_current_pos(this->input); - size = _X_BE_16(&header[2]) - DATA_PACKET_HEADER_SIZE; - timestamp= _X_BE_32(&header[6]); - pts = (int64_t) timestamp * 90; - + const uint16_t stream = _X_BE_16(&header[4]); + const off_t offset __attr_unused = this->input->get_current_pos(this->input); + uint16_t size = _X_BE_16(&header[2]) - DATA_PACKET_HEADER_SIZE; + const uint32_t timestamp= _X_BE_32(&header[6]); + int64_t pts = (int64_t) timestamp * 90; + /* Data packet header with version 1 contains 1 extra byte */ if(version == 0) keyframe = header[11] & PN_KEYFRAME_FLAG; @@ -1024,11 +1137,9 @@ static int demux_real_send_chunk(demux_plugin_t *this_gen) { if (this->video_stream && (stream == this->video_stream->mdpr->stream_number)) { - int vpkg_header, vpkg_length, vpkg_offset; int vpkg_seqnum = -1; int vpkg_subseq = 0; buf_element_t *buf; - int n, fragment_size; uint32_t decoder_flags; lprintf ("video chunk detected.\n"); @@ -1043,21 +1154,20 @@ static int demux_real_send_chunk(demux_plugin_t *this_gen) { * bit 6: 1=short header (only one block?) */ - vpkg_header = stream_read_char (this); size--; + const int vpkg_header = stream_read_char (this); size--; lprintf ("vpkg_hdr: %02x (size=%d)\n", vpkg_header, size); + int vpkg_length, vpkg_offset; if (0x40==(vpkg_header&0xc0)) { /* * seems to be a very short header * 2 bytes, purpose of the second byte yet unknown */ - int bummer; - - bummer = stream_read_char (this); size--; + const int bummer __attr_unused = stream_read_char (this); lprintf ("bummer == %02X\n",bummer); vpkg_offset = 0; - vpkg_length = size; + vpkg_length = --size; } else { @@ -1115,23 +1225,22 @@ static int demux_real_send_chunk(demux_plugin_t *this_gen) { if(this->video_stream->index) input_time = timestamp; else - input_time = (int)((int64_t) this->input->get_current_pos(this->input) + input_time = (int)((int64_t) this->input->get_current_pos(this->input) * 8 * 1000 / this->avg_bitrate); - if(this->data_start && this->data_chunk_size) - input_length = this->data_start + 18 + this->data_chunk_size; - if( input_length ) + const off_t input_length = this->data_start + 18 + this->data_chunk_size; + if( input_length > 18 ) normpos = (int)((double) this->input->get_current_pos(this->input) * 65535 / input_length); - + check_newpts (this, pts, PTS_VIDEO, 0); if (this->fragment_size == 0) { lprintf ("new packet starting\n"); - + /* send fragment offset table */ if(this->fragment_count) { lprintf("sending fragment offset table\n"); - + buf = this->video_fifo->buffer_pool_alloc(this->video_fifo); buf->decoder_flags = BUF_FLAG_SPECIAL | BUF_FLAG_FRAME_END; @@ -1144,18 +1253,18 @@ static int demux_real_send_chunk(demux_plugin_t *this_gen) { xine_fast_memcpy(buf->decoder_info_ptr[2], this->fragment_tab, this->fragment_count*8); - + this->video_fifo->put(this->video_fifo, buf); - + this->fragment_count = 0; } - + decoder_flags = BUF_FLAG_FRAME_START; } else { lprintf ("continuing packet \n"); decoder_flags = 0; } - + /* add entry to fragment offset table */ this->fragment_tab[2*this->fragment_count] = 1; this->fragment_tab[2*this->fragment_count+1] = this->fragment_size; @@ -1165,46 +1274,47 @@ static int demux_real_send_chunk(demux_plugin_t *this_gen) { * calc size of fragment */ - if ((vpkg_header & 0xc0) == 0x080) + int fragment_size; + switch(vpkg_header & 0xc0) { + case 0x80: fragment_size = vpkg_offset; - else { - if (0x00 == (vpkg_header&0xc0)) - fragment_size = size; - else - fragment_size = vpkg_length; + break; + case 0x00: + fragment_size = size; + break; + default: + fragment_size = vpkg_length; + break; } lprintf ("fragment size is %d\n", fragment_size); /* * read fragment_size bytes of data */ - - n = fragment_size; + + int n = fragment_size; while(n) { buf = this->video_fifo->buffer_pool_alloc(this->video_fifo); - - if(n>buf->max_size) - buf->size = buf->max_size; - else - buf->size = n; + + buf->size = MIN(n, buf->max_size); buf->decoder_flags = decoder_flags; decoder_flags &= ~BUF_FLAG_FRAME_START; - + buf->type = this->video_stream->buf_type; - + if(this->input->read(this->input, buf->content, buf->size) < buf->size) { - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_real: failed to read video fragment"); buf->free_buffer(buf); this->status = DEMUX_FINISHED; return this->status; } - - /* RV30 and RV40 streams contain some fragments that shouldn't be passed - * to the decoder. The purpose of these fragments is unknown, but - * realplayer doesn't appear to pass them to the decoder either */ - if((n == fragment_size) && + + /* RV30 and RV40 streams contain some fragments that shouldn't be passed + * to the decoder. The purpose of these fragments is unknown, but + * realplayer doesn't appear to pass them to the decoder either */ + if((n == fragment_size) && (((buf->type == BUF_VIDEO_RV30) && (buf->content[0] & 0x20)) || ((buf->type == BUF_VIDEO_RV40) && (buf->content[0] & 0x80)))) { lprintf("ignoring fragment\n"); @@ -1216,12 +1326,12 @@ static int demux_real_send_chunk(demux_plugin_t *this_gen) { break; } - + /* if the video stream has b-frames fix the timestamps */ if((this->video_stream->format >= 0x20200002) && (buf->decoder_flags & BUF_FLAG_FRAME_START)) pts = (int64_t) real_fix_timestamp(this, buf->content, timestamp) * 90; - + /* this test was moved from ffmpeg video decoder. * fixme: is pts only valid on frame start? */ if( buf->decoder_flags & BUF_FLAG_FRAME_START ) @@ -1229,13 +1339,13 @@ static int demux_real_send_chunk(demux_plugin_t *this_gen) { else buf->pts = 0; pts = 0; - + buf->extra_info->input_normpos = normpos; buf->extra_info->input_time = input_time; buf->extra_info->total_time = this->duration; - + this->video_fifo->put(this->video_fifo, buf); - + n -= buf->size; } @@ -1260,71 +1370,131 @@ static int demux_real_send_chunk(demux_plugin_t *this_gen) { goto discard; else this->audio_need_keyframe = 0; - + /* if we have a seekable stream then use the timestamp for the data * packet for more accurate seeking - if not then estimate time using * average bitrate */ if(this->audio_stream->index) input_time = timestamp; else - input_time = (int)((int64_t) this->input->get_current_pos(this->input) - * 8 * 1000 / this->avg_bitrate); - - if(this->data_start && this->data_chunk_size) - input_length = this->data_start + 18 + this->data_chunk_size; - else - input_length = 0; - - if( input_length ) + input_time = (int)((int64_t) this->input->get_current_pos(this->input) + * 8 * 1000 / this->avg_bitrate); + + const off_t input_length = this->data_start + 18 + this->data_chunk_size; + + if( input_length > 18 ) normpos = (int)((double) this->input->get_current_pos(this->input) * 65535 / input_length); - + check_newpts (this, pts, PTS_AUDIO, 0); - + /* Each packet of AAC is made up of several AAC frames preceded by a * header defining the size of the frames */ if(this->audio_stream->buf_type == BUF_AUDIO_AAC) { - int i, frames, *sizes; - + int i; + /* Upper 4 bits of second byte is frame count */ - frames = (stream_read_word(this) & 0xf0) >> 4; - + const int frames = (stream_read_word(this) & 0xf0) >> 4; + /* 2 bytes per frame size */ - sizes = xine_xmalloc(frames*sizeof(int)); + int sizes[frames]; + for(i = 0; i < frames; i++) sizes[i] = stream_read_word(this); - + for(i = 0; i < frames; i++) { - if(_x_demux_read_send_data(this->audio_fifo, this->input, sizes[i], pts, - this->audio_stream->buf_type, 0, normpos, + if(_x_demux_read_send_data(this->audio_fifo, this->input, sizes[i], pts, + this->audio_stream->buf_type, 0, normpos, input_time, this->duration, 0) < 0) { - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_real: failed to read AAC frame\n"); - free(sizes); this->status = DEMUX_FINISHED; return this->status; } - + pts = 0; /* Only set pts on first frame */ } - - free(sizes); + } else if (this->audio_stream->buf_type == BUF_AUDIO_COOK || + this->audio_stream->buf_type == BUF_AUDIO_ATRK || + this->audio_stream->buf_type == BUF_AUDIO_28_8 || + this->audio_stream->buf_type == BUF_AUDIO_SIPRO) { + /* reorder */ + uint8_t * buffer = this->audio_stream->frame_buffer; + int sps = this->audio_stream->sps; + int sph = this->audio_stream->h; + int cfs = this->audio_stream->cfs; + int w = this->audio_stream->w; + int spc = this->audio_stream->sub_packet_cnt; + int x; + off_t pos; + const size_t fs = this->audio_stream->frame_size; + + if (!buffer) { + this->status = DEMUX_FINISHED; + return this->status; + } + + switch (this->audio_stream->buf_type) { + case BUF_AUDIO_28_8: + for (x = 0; x < sph / 2; x++) { + pos = x * 2 * w + spc * cfs; + if(pos + cfs > fs || this->input->read(this->input, buffer + pos, cfs) < cfs) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_real: failed to read audio chunk\n"); + + this->status = DEMUX_FINISHED; + return this->status; + } + } + break; + case BUF_AUDIO_COOK: + case BUF_AUDIO_ATRK: + for (x = 0; x < w / sps; x++) { + pos = sps * (sph * x + ((sph + 1) / 2) * (spc & 1) + (spc >> 1)); + if(pos + sps > fs || this->input->read(this->input, buffer + pos, sps) < sps) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_real: failed to read audio chunk\n"); + + this->status = DEMUX_FINISHED; + return this->status; + } + } + break; + case BUF_AUDIO_SIPRO: + pos = spc * w; + if(pos + w > fs || this->input->read(this->input, buffer + pos, w) < w) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_real: failed to read audio chunk\n"); + + this->status = DEMUX_FINISHED; + return this->status; + } + if (spc == sph - 1) + demux_real_sipro_swap (buffer, sph * w * 2 / 96); + break; + } + if(++this->audio_stream->sub_packet_cnt == sph) { + this->audio_stream->sub_packet_cnt = 0; + _x_demux_send_data(this->audio_fifo, buffer, this->audio_stream->frame_size, + pts, this->audio_stream->buf_type, 0, normpos, input_time, + this->duration, 0); + } } else { - if(_x_demux_read_send_data(this->audio_fifo, this->input, size, pts, + if(_x_demux_read_send_data(this->audio_fifo, this->input, size, pts, this->audio_stream->buf_type, 0, normpos, input_time, this->duration, 0) < 0) { - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_real: failed to read audio chunk\n"); this->status = DEMUX_FINISHED; return this->status; } - + /* FIXME: dp->flags = (flags & 0x2) ? 0x10 : 0; */ } - + } else { /* discard */ @@ -1342,18 +1512,10 @@ discard: /* check if it's time to reload */ if (!this->current_data_chunk_packet_count && this->next_data_chunk_offset) { - char preamble[PREAMBLE_SIZE]; unsigned char data_chunk_header[DATA_CHUNK_HEADER_SIZE]; /* seek to the next DATA chunk offset */ - this->input->seek(this->input, this->next_data_chunk_offset, SEEK_SET); - - /* load the DATA chunk preamble */ - if (this->input->read(this->input, preamble, PREAMBLE_SIZE) != - PREAMBLE_SIZE) { - this->status = DEMUX_FINISHED; - return this->status; - } + this->input->seek(this->input, this->next_data_chunk_offset + PREAMBLE_SIZE, SEEK_SET); /* load the rest of the DATA chunk header */ if (this->input->read(this->input, data_chunk_header, @@ -1415,14 +1577,14 @@ static int demux_real_seek (demux_plugin_t *this_gen, demux_real_t *this = (demux_real_t *) this_gen; real_index_entry_t *index, *other_index = NULL; int i = 0, entries; - + lprintf("seek start_pos=%d, start_time=%d, playing=%d\n", (int)start_pos, start_time, playing); if((this->input->get_capabilities(this->input) & INPUT_CAP_SEEKABLE) && ((this->audio_stream && this->audio_stream->index) || (this->video_stream && this->video_stream->index))) { - + start_pos = (off_t) ( (double) start_pos / 65535 * this->input->get_length (this->input) ); @@ -1459,6 +1621,9 @@ static int demux_real_seek (demux_plugin_t *this_gen, this->input->seek(this->input, index[i].offset, SEEK_SET); if(playing) { + if(this->audio_stream) + this->audio_stream->sub_packet_cnt = 0; + this->buf_flag_seek = 1; _x_demux_flush_engine(this->stream); } @@ -1467,14 +1632,14 @@ static int demux_real_seek (demux_plugin_t *this_gen, /* RTSP supports only time based seek */ if (start_pos && !start_time) start_time = (int64_t) this->duration * start_pos / 65535; - + this->input->seek_time(this->input, start_time, SEEK_SET); } this->send_newpts = 1; this->old_seqnum = -1; this->fragment_size = 0; - + this->next_ts = 0; this->next_seq = 0; @@ -1489,19 +1654,16 @@ static void demux_real_dispose (demux_plugin_t *this_gen) { for(i = 0; i < this->num_video_streams; i++) { real_free_mdpr(this->video_streams[i].mdpr); - if(this->video_streams[i].index) - free(this->video_streams[i].index); + free(this->video_streams[i].index); } - + for(i = 0; i < this->num_audio_streams; i++) { real_free_mdpr(this->audio_streams[i].mdpr); - if(this->audio_streams[i].index) - free(this->audio_streams[i].index); + free(this->audio_streams[i].index); + free(this->audio_streams[i].frame_buffer); } - - if(this->fragment_tab) - free(this->fragment_tab); - + + free(this->fragment_tab); free(this); } @@ -1528,21 +1690,27 @@ static int demux_real_get_optional_data(demux_plugin_t *this_gen, } /* help function to discover stream type. returns: + * -1 if couldn't read * 0 if not known. * 1 if normal stream. * 2 if reference stream. */ -static int real_check_stream_type(uint8_t *buf, int len) +static int real_check_stream_type(input_plugin_t *input) { - if ((buf[0] == 0x2e) - && (buf[1] == 'R') - && (buf[2] == 'M') - && (buf[3] == 'F')) + uint8_t buf[1024]; + off_t len = _x_demux_read_header(input, buf, sizeof(buf)); + + if ( len < 4 ) + return -1; + + if ( memcmp(buf, "\x2eRMF", 4) == 0 ) return 1; - buf[len] = '\0'; - if( strstr(buf,"pnm://") || strstr(buf,"rtsp://") || strstr(buf,"<smil>") || - !strncmp(buf,"http://",7) ) +#define my_strnstr(haystack, haystacklen, needle) \ + memmem(haystack, haystacklen, needle, sizeof(needle)) + + if( my_strnstr(buf, len, "pnm://") || my_strnstr(buf, len, "rtsp://") || + my_strnstr(buf, len, "<smil>") || !strncmp(buf, "http://", MIN(7, len)) ) return 2; return 0; @@ -1551,32 +1719,24 @@ static int real_check_stream_type(uint8_t *buf, int len) static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *stream, input_plugin_t *input) { - demux_real_t *this; - uint8_t buf[1024+1]; - int len, stream_type=0; - - switch (stream->content_detection_method) { - - case METHOD_BY_CONTENT:{ + /* discover stream type */ + const int stream_type = real_check_stream_type(input); - if (! (len = _x_demux_read_header(input, buf, 1024)) ) - return NULL; + if ( stream_type < 0 ) + return NULL; - lprintf ("read 4 bytes: %02x %02x %02x %02x\n", - buf[0], buf[1], buf[2], buf[3]); + switch (stream->content_detection_method) { - if (!(stream_type = real_check_stream_type(buf,len))) + case METHOD_BY_CONTENT: + if ( stream_type < 1 ) return NULL; - } - lprintf ("by content accepted.\n"); - break; + lprintf ("by content accepted.\n"); + break; case METHOD_BY_EXTENSION: { - const char *extensions, *mrl; - - mrl = input->get_mrl (input); - extensions = class_gen->get_extensions (class_gen); + const char *const mrl = input->get_mrl (input); + const char *const extensions = class_gen->get_extensions (class_gen); lprintf ("by extension '%s'\n", mrl); @@ -1595,17 +1755,11 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str return NULL; } - - this = xine_xmalloc (sizeof (demux_real_t)); + demux_real_t *this = calloc(1, sizeof(demux_real_t)); this->stream = stream; this->input = input; - /* discover stream type */ - if(!stream_type) - if ( (len = _x_demux_read_header(this->input, buf, 1024)) ) - stream_type = real_check_stream_type(buf,len); - if(stream_type == 2){ this->reference_mode = 1; lprintf("reference stream detected\n"); @@ -1642,7 +1796,7 @@ static const char *get_mimetypes (demux_class_t *this_gen) { return "audio/x-pn-realaudio: ra, rm, ram: Real Media file;" "audio/x-pn-realaudio-plugin: rpm: Real Media plugin file;" "audio/x-real-audio: ra, rm, ram: Real Media file;" - "application/vnd.rn-realmedia: ra, rm, ram: Real Media file;"; + "application/vnd.rn-realmedia: ra, rm, ram: Real Media file;"; } static void class_dispose (demux_class_t *this_gen) { @@ -1652,9 +1806,7 @@ static void class_dispose (demux_class_t *this_gen) { } static void *init_class (xine_t *xine, void *data) { - demux_real_class_t *this; - - this = xine_xmalloc (sizeof (demux_real_class_t)); + demux_real_class_t *const this = calloc(1, sizeof(demux_real_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_realaudio.c b/src/demuxers/demux_realaudio.c index 70c9b310a..3c18f7ec3 100644 --- a/src/demuxers/demux_realaudio.c +++ b/src/demuxers/demux_realaudio.c @@ -41,6 +41,8 @@ #include "bswap.h" #include "group_audio.h" +#include "real_common.h" + #define RA_FILE_HEADER_PREV_SIZE 22 typedef struct { @@ -61,7 +63,13 @@ typedef struct { off_t data_start; off_t data_size; - + + uint32_t cfs; + uint16_t w, h; + int frame_len; + size_t frame_size; + uint8_t *frame_buffer; + unsigned char *header; unsigned int header_size; } demux_ra_t; @@ -70,26 +78,24 @@ typedef struct { demux_class_t demux_class; } demux_ra_class_t; +/* Map flavour to bytes per second */ +static const int sipr_fl2bps[4] = {813, 1062, 625, 2000}; // 6.5, 8.5, 5, 16 kbit per second + /* returns 1 if the RealAudio file was opened successfully, 0 otherwise */ static int open_ra_file(demux_ra_t *this) { - unsigned char file_header[RA_FILE_HEADER_PREV_SIZE], len; - unsigned short version; - off_t offset; - + uint8_t file_header[RA_FILE_HEADER_PREV_SIZE]; /* check the signature */ if (_x_demux_read_header(this->input, file_header, RA_FILE_HEADER_PREV_SIZE) != RA_FILE_HEADER_PREV_SIZE) return 0; - if ((file_header[0] != '.') || - (file_header[1] != 'r') || - (file_header[2] != 'a')) + if ( memcmp(file_header, ".ra", 3) != 0 ) return 0; /* read version */ - version = _X_BE_16(&file_header[0x04]); - + const uint16_t version = _X_BE_16(&file_header[0x04]); + /* read header size according to version */ if (version == 3) this->header_size = _X_BE_16(&file_header[0x06]) + 8; @@ -99,86 +105,121 @@ static int open_ra_file(demux_ra_t *this) { xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_realaudio: unknown version number %d\n", version); return 0; } - + /* allocate for and read header data */ - this->header = xine_xmalloc(this->header_size); - - if (_x_demux_read_header(this->input, this->header, this->header_size) != this->header_size) { + this->header = malloc(this->header_size); + + if (!this->header || _x_demux_read_header(this->input, this->header, this->header_size) != this->header_size) { xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_realaudio: unable to read header\n"); free(this->header); return 0; } - + + off_t offset; /* read header data according to version */ if((version == 3) && (this->header_size >= 32)) { this->data_size = _X_BE_32(&this->header[0x12]); - + this->block_align = 240; - + offset = 0x16; } else if(this->header_size >= 72) { - this->data_size = _X_BE_32(&this->header[0x1C]); - + this->data_size = _X_BE_32(&this->header[0x1C]); + this->block_align = _X_BE_16(&this->header[0x2A]); - + if(this->header[0x3D] == 4) this->fourcc = _X_ME_32(&this->header[0x3E]); else { - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_realaudio: invalid fourcc size %d\n", this->header[0x3D]); free(this->header); return 0; } - + offset = 0x45; } else { xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_realaudio: header too small\n"); free(this->header); return 0; } - + /* Read title */ - len = this->header[offset]; - if(len && ((offset+len+2) < this->header_size)) { - _x_meta_info_n_set(this->stream, XINE_META_INFO_TITLE, - &this->header[offset+1], len); - offset += len+1; - } else - offset++; - + { + const uint8_t len = this->header[offset]; + if(len && ((offset+len+2) < this->header_size)) { + _x_meta_info_n_set(this->stream, XINE_META_INFO_TITLE, + &this->header[offset+1], len); + offset += len+1; + } else + offset++; + } + /* Author */ - len = this->header[offset]; - if(len && ((offset+len+1) < this->header_size)) { - _x_meta_info_n_set(this->stream, XINE_META_INFO_ARTIST, - &this->header[offset+1], len); - offset += len+1; - } else - offset++; - + { + const uint8_t len = this->header[offset]; + if(len && ((offset+len+1) < this->header_size)) { + _x_meta_info_n_set(this->stream, XINE_META_INFO_ARTIST, + &this->header[offset+1], len); + offset += len+1; + } else + offset++; + } + /* Copyright/Date */ - len = this->header[offset]; - if(len && ((offset+len) <= this->header_size)) { - _x_meta_info_n_set(this->stream, XINE_META_INFO_YEAR, - &this->header[offset+1], len); - offset += len+1; - } else - offset++; - + { + const uint8_t len = this->header[offset]; + if(len && ((offset+len) <= this->header_size)) { + _x_meta_info_n_set(this->stream, XINE_META_INFO_YEAR, + &this->header[offset+1], len); + offset += len+1; + } else + offset++; + } + /* Fourcc for version 3 comes after meta info */ - if((version == 3) && ((offset+7) <= this->header_size)) { - if(this->header[offset+2] == 4) - this->fourcc = _X_ME_32(&this->header[offset+3]); - else { - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_realaudio: invalid fourcc size %d\n", this->header[offset+2]); - free(this->header); - return 0; + if(version == 3) { + if (((offset+7) <= this->header_size)) { + if(this->header[offset+2] == 4) + this->fourcc = _X_ME_32(&this->header[offset+3]); + else { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_realaudio: invalid fourcc size %d\n", this->header[offset+2]); + free(this->header); + return 0; + } + } else { + this->fourcc = ME_FOURCC('l', 'p', 'c', 'J'); } } - + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_FOURCC, this->fourcc); this->audio_type = _x_formattag_to_buf_audio(this->fourcc); + if (version == 4) { + const uint16_t sps = _X_BE_16 (this->header+44) ? : 1; + this->w = _X_BE_16 (this->header+42); + this->h = _X_BE_16 (this->header+40); + this->cfs = _X_BE_32 (this->header+24); + + if (this->w < 0x8000 && this->h < 0x8000) { + uint64_t fs; + this->frame_len = this->w * this->h; + fs = (uint64_t) this->frame_len * sps; + if (fs < 0x80000000) { + this->frame_size = fs; + this->frame_buffer = calloc(this->frame_size, 1); + } + } + if (! this->frame_buffer) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_realaudio: malloc failed\n"); + return 0; + } + + if (this->audio_type == BUF_AUDIO_28_8 || this->audio_type == BUF_AUDIO_SIPRO) + this->block_align = this->cfs; + } + /* seek to start of data */ this->data_start = this->header_size; if (this->input->seek(this->input, this->data_start, SEEK_SET) != @@ -197,27 +238,57 @@ static int demux_ra_send_chunk(demux_plugin_t *this_gen) { demux_ra_t *this = (demux_ra_t *) this_gen; off_t current_normpos = 0; - int64_t current_pts; /* just load data chunks from wherever the stream happens to be * pointing; issue a DEMUX_FINISHED status if EOF is reached */ if( this->input->get_length (this->input) ) - current_normpos = (int)( (double) (this->input->get_current_pos (this->input) - this->data_start) * + current_normpos = (int)( (double) (this->input->get_current_pos (this->input) - this->data_start) * 65535 / this->data_size ); - current_pts = 0; /* let the engine sort out the pts for now */ + const int64_t current_pts = 0; /* let the engine sort out the pts for now */ if (this->seek_flag) { _x_demux_control_newpts(this->stream, current_pts, BUF_FLAG_SEEK); this->seek_flag = 0; } - if(_x_demux_read_send_data(this->audio_fifo, this->input, this->block_align, - current_pts, this->audio_type, 0, current_normpos, + if (this->audio_type == BUF_AUDIO_28_8 || this->audio_type == BUF_AUDIO_SIPRO) { + if (this->audio_type == BUF_AUDIO_SIPRO) { + if(this->input->read(this->input, this->frame_buffer, this->frame_len) < this->frame_len) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_realaudio: failed to read audio chunk\n"); + + this->status = DEMUX_FINISHED; + return this->status; + } + demux_real_sipro_swap (this->frame_buffer, this->frame_len * 2 / 96); + } else { + int x, y; + + for (y = 0; y < this->h; y++) + for (x = 0; x < this->h / 2; x++) { + const int pos = x * 2 * this->w + y * this->cfs; + if(this->input->read(this->input, this->frame_buffer + pos, + this->cfs) < this->cfs) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_realaudio: failed to read audio chunk\n"); + + this->status = DEMUX_FINISHED; + return this->status; + } + } + } + + _x_demux_send_data(this->audio_fifo, + this->frame_buffer, this->frame_size, + current_pts, this->audio_type, 0, + current_normpos, current_pts / 90, 0, 0); + } else if(_x_demux_read_send_data(this->audio_fifo, this->input, this->block_align, + current_pts, this->audio_type, 0, current_normpos, current_pts / 90, 0, 0) < 0) { - this->status = DEMUX_FINISHED; + this->status = DEMUX_FINISHED; } - + return this->status; } @@ -243,12 +314,9 @@ static void demux_ra_send_headers(demux_plugin_t *this_gen) { buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); buf->type = this->audio_type; buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_FRAME_END; - - if(this->header_size > buf->max_size) - buf->size = buf->max_size; - else - buf->size = this->header_size; - + + buf->size = MIN(this->header_size, buf->max_size); + memcpy(buf->content, this->header, buf->size); this->audio_fifo->put (this->audio_fifo, buf); @@ -296,9 +364,11 @@ static int demux_ra_seek (demux_plugin_t *this_gen, static void demux_ra_dispose (demux_plugin_t *this_gen) { demux_ra_t *this = (demux_ra_t *) this_gen; - + if(this->header) free(this->header); + if (this->frame_buffer) + free(this->frame_buffer); free(this); } @@ -311,8 +381,6 @@ static int demux_ra_get_status (demux_plugin_t *this_gen) { /* return the approximate length in miliseconds */ static int demux_ra_get_stream_length (demux_plugin_t *this_gen) { - demux_ra_t *this = (demux_ra_t *) this_gen; - return 0; } @@ -330,9 +398,10 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str demux_ra_t *this; - this = xine_xmalloc (sizeof (demux_ra_t)); + this = calloc(1, sizeof(demux_ra_t)); this->stream = stream; this->input = input; + this->frame_buffer = NULL; this->demux_plugin.send_headers = demux_ra_send_headers; this->demux_plugin.send_chunk = demux_ra_send_chunk; @@ -370,7 +439,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str } break; - + default: free (this); return NULL; @@ -404,7 +473,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_realaudio_init_plugin (xine_t *xine, void *data) { demux_ra_class_t *this; - this = xine_xmalloc (sizeof (demux_ra_class_t)); + this = calloc(1, sizeof(demux_ra_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_roq.c b/src/demuxers/demux_roq.c index 18edaea87..346d487aa 100644 --- a/src/demuxers/demux_roq.c +++ b/src/demuxers/demux_roq.c @@ -47,7 +47,6 @@ #include "bswap.h" #include "group_games.h" -#define RoQ_MAGIC_NUMBER 0x1084 #define RoQ_CHUNK_PREAMBLE_SIZE 8 #define RoQ_AUDIO_SAMPLE_RATE 22050 @@ -93,10 +92,11 @@ static int open_roq_file(demux_roq_t *this) { return 0; /* check for the RoQ magic numbers */ - if ((_X_LE_16(&preamble[0]) != RoQ_MAGIC_NUMBER) || - (_X_LE_32(&preamble[2]) != 0xFFFFFFFF)) + static const uint8_t RoQ_MAGIC_STRING[] = + { 0x10, 0x84, 0xFF, 0xFF, 0xFF, 0xFF }; + if( memcmp(preamble, RoQ_MAGIC_STRING, sizeof(RoQ_MAGIC_STRING)) != 0 ) return 0; - + this->bih.biSize = sizeof(xine_bmiheader); this->bih.biWidth = this->bih.biHeight = 0; this->wave.nChannels = 0; /* assume no audio at first */ @@ -119,7 +119,7 @@ static int open_roq_file(demux_roq_t *this) { while (i-- > 0) { /* if this read fails, then maybe it's just a really small RoQ file * (even less than 2 seconds) */ - if (this->input->read(this->input, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != + if (this->input->read(this->input, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != RoQ_CHUNK_PREAMBLE_SIZE) break; chunk_type = _X_LE_16(&preamble[0]); @@ -181,7 +181,7 @@ static int demux_roq_send_chunk(demux_plugin_t *this_gen) { off_t current_file_pos; /* fetch the next preamble */ - if (this->input->read(this->input, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != + if (this->input->read(this->input, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != RoQ_CHUNK_PREAMBLE_SIZE) { this->status = DEMUX_FINISHED; return this->status; @@ -193,21 +193,21 @@ static int demux_roq_send_chunk(demux_plugin_t *this_gen) { if ((chunk_type == RoQ_SOUND_MONO) || (chunk_type == RoQ_SOUND_STEREO)) { if( this->audio_fifo ) { - + /* do this calculation carefully because I can't trust the * 64-bit numerical manipulation */ audio_pts = this->audio_byte_count; audio_pts *= 90000; audio_pts /= (RoQ_AUDIO_SAMPLE_RATE * this->wave.nChannels); this->audio_byte_count += chunk_size - 8; /* do not count the preamble */ - + current_file_pos = this->input->get_current_pos(this->input); /* send out the preamble */ buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); buf->type = BUF_AUDIO_ROQ; if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = (int)( (double) (current_file_pos - RoQ_CHUNK_PREAMBLE_SIZE) * + buf->extra_info->input_normpos = (int)( (double) (current_file_pos - RoQ_CHUNK_PREAMBLE_SIZE) * 65535 / this->input->get_length (this->input) ); buf->pts = 0; buf->size = RoQ_CHUNK_PREAMBLE_SIZE; @@ -219,7 +219,7 @@ static int demux_roq_send_chunk(demux_plugin_t *this_gen) { buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); buf->type = BUF_AUDIO_ROQ; if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = (int)( (double) current_file_pos * + buf->extra_info->input_normpos = (int)( (double) current_file_pos * 65535 / this->input->get_length (this->input) ); buf->pts = audio_pts; @@ -256,7 +256,7 @@ static int demux_roq_send_chunk(demux_plugin_t *this_gen) { buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); buf->type = BUF_VIDEO_ROQ; if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = (int)( (double) (current_file_pos - RoQ_CHUNK_PREAMBLE_SIZE) * + buf->extra_info->input_normpos = (int)( (double) (current_file_pos - RoQ_CHUNK_PREAMBLE_SIZE) * 65535 / this->input->get_length (this->input) ); buf->pts = this->video_pts_counter; buf->size = RoQ_CHUNK_PREAMBLE_SIZE; @@ -267,7 +267,7 @@ static int demux_roq_send_chunk(demux_plugin_t *this_gen) { buf = this->video_fifo->buffer_pool_alloc (this->audio_fifo); buf->type = BUF_VIDEO_ROQ; if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = (int)( (double) current_file_pos * + buf->extra_info->input_normpos = (int)( (double) current_file_pos * 65535 / this->input->get_length (this->input) ); buf->pts = this->video_pts_counter; @@ -411,7 +411,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str return NULL; } - this = xine_xmalloc (sizeof (demux_roq_t)); + this = calloc(1, sizeof(demux_roq_t)); this->stream = stream; this->input = input; @@ -485,7 +485,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_roq_init_plugin (xine_t *xine, void *data) { demux_roq_class_t *this; - this = xine_xmalloc (sizeof (demux_roq_class_t)); + this = calloc(1, sizeof(demux_roq_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_shn.c b/src/demuxers/demux_shn.c index 87324ab45..b4f7c764b 100644 --- a/src/demuxers/demux_shn.c +++ b/src/demuxers/demux_shn.c @@ -83,16 +83,16 @@ static int demux_shn_send_chunk(demux_plugin_t *this_gen) { buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); buf->type = BUF_AUDIO_SHORTEN; if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * + buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * 65535 / this->input->get_length (this->input) ); buf->pts = 0; bytes_read = this->input->read(this->input, buf->content, buf->max_size); - if (bytes_read == 0) { + if (bytes_read <= 0) { buf->free_buffer(buf); this->status = DEMUX_FINISHED; return this->status; - } else + } else buf->size = bytes_read; /* each buffer stands on its own */ @@ -182,7 +182,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str demux_shn_t *this; - this = xine_xmalloc (sizeof (demux_shn_t)); + this = calloc(1, sizeof(demux_shn_t)); this->stream = stream; this->input = input; @@ -253,7 +253,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_shn_init_plugin (xine_t *xine, void *data) { demux_shn_class_t *this; - this = xine_xmalloc (sizeof (demux_shn_class_t)); + this = calloc(1, sizeof(demux_shn_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_slave.c b/src/demuxers/demux_slave.c index 436d37579..de530f224 100644 --- a/src/demuxers/demux_slave.c +++ b/src/demuxers/demux_slave.c @@ -2,19 +2,19 @@ * Copyright (C) 2000-2003 the xine project * May 2003 - Miguel Freitas * This plugin was sponsored by 1Control - * + * * This file is part of xine, a free video player. - * + * * xine is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * xine is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA @@ -51,7 +51,7 @@ #define CHECK_VPTS_INTERVAL 2*90000 #define NETWORK_PREBUFFER 90000 -typedef struct { +typedef struct { demux_plugin_t demux_plugin; xine_stream_t *stream; @@ -86,14 +86,15 @@ static int demux_slave_next (demux_slave_t *this) { char fifo_name[11]; uint8_t *p, *s; int64_t curvpts; - + /* fill the scratch buffer */ n = this->input->read(this->input, &this->scratch[this->scratch_used], SCRATCH_SIZE - this->scratch_used); - this->scratch_used += n; + if (n > 0) + this->scratch_used += n; this->scratch[this->scratch_used] = '\0'; - if( !n ) { + if (n <= 0) { lprintf("connection closed\n"); this->status = DEMUX_FINISHED; return 0; @@ -186,10 +187,8 @@ static int demux_slave_next (demux_slave_t *this) { buf->decoder_flags = decoder_flags; /* set decoder info */ - for( i = 0; i < BUF_NUM_DEC_INFO; i++ ) { - buf->decoder_info[i] = this->decoder_info[i]; - buf->decoder_info_ptr[i] = this->decoder_info_ptr[i]; - } + memcpy(buf->decoder_info, this->decoder_info, sizeof(this->decoder_info)); + memcpy(buf->decoder_info_ptr, this->decoder_info_ptr, sizeof(this->decoder_info)); memset(this->decoder_info, 0, sizeof(this->decoder_info)); memset(this->decoder_info_ptr, 0, sizeof(this->decoder_info_ptr)); @@ -331,7 +330,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str demux_slave_t *this; static char slave_id_str[] = "master xine v1\n"; - this = xine_xmalloc (sizeof (demux_slave_t)); + this = calloc(1, sizeof(demux_slave_t)); switch (stream->content_detection_method) { @@ -414,7 +413,7 @@ static void class_dispose (demux_class_t *this_gen) { static void *init_plugin (xine_t *xine, void *data) { demux_slave_class_t *this; - this = xine_xmalloc (sizeof (demux_slave_class_t)); + this = calloc(1, sizeof(demux_slave_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; @@ -434,7 +433,7 @@ static const demuxer_info_t demux_info_slave = { }; const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ + /* type, API, "name", version, special_info, init_function */ { PLUGIN_DEMUX, 26, "slave", XINE_VERSION_CODE, &demux_info_slave, init_plugin }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; diff --git a/src/demuxers/demux_smjpeg.c b/src/demuxers/demux_smjpeg.c index 899fbf7e3..04a46fa78 100644 --- a/src/demuxers/demux_smjpeg.c +++ b/src/demuxers/demux_smjpeg.c @@ -55,7 +55,6 @@ #define vidD_TAG FOURCC_TAG('v', 'i', 'd', 'D') #define APCM_TAG FOURCC_TAG('A', 'P', 'C', 'M') -#define SMJPEG_SIGNATURE_SIZE 8 /* 16 is the max size of a header chunk (the video header) */ #define SMJPEG_VIDEO_HEADER_SIZE 16 #define SMJPEG_AUDIO_HEADER_SIZE 12 @@ -98,27 +97,22 @@ static int open_smjpeg_file(demux_smjpeg_t *this) { unsigned char header_chunk[SMJPEG_HEADER_CHUNK_MAX_SIZE]; unsigned int audio_codec = 0; - if (_x_demux_read_header(this->input, signature, SMJPEG_SIGNATURE_SIZE) != - SMJPEG_SIGNATURE_SIZE) + static const uint8_t SMJPEG_SIGNATURE[8] = + { 0x00, 0x0A, 'S', 'M', 'J', 'P', 'E', 'G' }; + + if (_x_demux_read_header(this->input, signature, sizeof(SMJPEG_SIGNATURE)) != + sizeof(SMJPEG_SIGNATURE)) return 0; - /* check for the SMJPEG signature */ - if ((signature[0] != 0x00) || - (signature[1] != 0x0A) || - (signature[2] != 'S') || - (signature[3] != 'M') || - (signature[4] != 'J') || - (signature[5] != 'P') || - (signature[6] != 'E') || - (signature[7] != 'G')) + if (memcmp(signature, SMJPEG_SIGNATURE, sizeof(SMJPEG_SIGNATURE)) != 0) return 0; /* file is qualified; jump over the header + version to the duration */ - this->input->seek(this->input, SMJPEG_SIGNATURE_SIZE + 4, SEEK_SET); + this->input->seek(this->input, sizeof(SMJPEG_SIGNATURE) + 4, SEEK_SET); if (this->input->read(this->input, header_chunk, 4) != 4) return 0; this->duration = _X_BE_32(&header_chunk[0]); - + /* initial state: no video and no audio (until headers found) */ this->video_type = this->audio_type = 0; this->input_length = this->input->get_length (this->input); @@ -400,7 +394,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str return NULL; } - this = xine_xmalloc (sizeof (demux_smjpeg_t)); + this = calloc(1, sizeof(demux_smjpeg_t)); this->stream = stream; this->input = input; @@ -474,7 +468,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_smjpeg_init_plugin (xine_t *xine, void *data) { demux_smjpeg_class_t *this; - this = xine_xmalloc (sizeof (demux_smjpeg_class_t)); + this = calloc(1, sizeof(demux_smjpeg_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_snd.c b/src/demuxers/demux_snd.c index 0965a75ae..66e2bd543 100644 --- a/src/demuxers/demux_snd.c +++ b/src/demuxers/demux_snd.c @@ -42,8 +42,6 @@ #define SND_HEADER_SIZE 24 #define PCM_BLOCK_ALIGN 1024 -/* this is the big-endian hex value '.snd' */ -#define snd_TAG 0x2E736E64 typedef struct { demux_plugin_t demux_plugin; @@ -83,7 +81,7 @@ static int open_snd_file(demux_snd_t *this) { return 0; /* check the signature */ - if (_X_BE_32(&header[0]) != snd_TAG) + if ( !_x_is_fourcc(&header[0], ".snd") ) return 0; /* file is qualified; skip over the header bytes in the stream */ @@ -112,11 +110,11 @@ static int open_snd_file(demux_snd_t *this) { this->audio_bytes_per_second = this->audio_channels * this->audio_sample_rate; break; - + case 2: this->audio_type = BUF_AUDIO_LPCM_BE; this->audio_bits = 8; - this->audio_frames = this->data_size / + this->audio_frames = this->data_size / (this->audio_channels * this->audio_bits / 8); this->audio_block_align = PCM_BLOCK_ALIGN; this->audio_bytes_per_second = this->audio_channels * @@ -126,7 +124,7 @@ static int open_snd_file(demux_snd_t *this) { case 3: this->audio_type = BUF_AUDIO_LPCM_BE; this->audio_bits = 16; - this->audio_frames = this->data_size / + this->audio_frames = this->data_size / (this->audio_channels * this->audio_bits / 8); this->audio_block_align = PCM_BLOCK_ALIGN; this->audio_bytes_per_second = this->audio_channels * @@ -165,7 +163,7 @@ static int demux_snd_send_chunk(demux_plugin_t *this_gen) { /* just load data chunks from wherever the stream happens to be * pointing; issue a DEMUX_FINISHED status if EOF is reached */ remaining_sample_bytes = this->audio_block_align; - current_file_pos = + current_file_pos = this->input->get_current_pos(this->input) - this->data_start; current_pts = current_file_pos; @@ -207,7 +205,7 @@ static int demux_snd_send_chunk(demux_plugin_t *this_gen) { for (i = 0; i < buf->size; i++) buf->content[i] += 0x80; } - + this->audio_fifo->put (this->audio_fifo, buf); } return this->status; @@ -253,11 +251,11 @@ static int demux_snd_seek (demux_plugin_t *this_gen, off_t start_pos, int start_ demux_snd_t *this = (demux_snd_t *) this_gen; start_pos = (off_t) ( (double) start_pos / 65535 * this->data_size ); - + this->seek_flag = 1; this->status = DEMUX_OK; _x_demux_flush_engine (this->stream); - + /* if input is non-seekable, do not proceed with the rest of this * seek function */ if (!INPUT_IS_SEEKABLE(this->input)) @@ -318,7 +316,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str demux_snd_t *this; - this = xine_xmalloc (sizeof (demux_snd_t)); + this = calloc(1, sizeof(demux_snd_t)); this->stream = stream; this->input = input; @@ -348,7 +346,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str } } /* falling through is intended */ - + case METHOD_BY_CONTENT: case METHOD_EXPLICIT: @@ -382,7 +380,7 @@ static const char *get_extensions (demux_class_t *this_gen) { static const char *get_mimetypes (demux_class_t *this_gen) { return "audio/basic: snd,au: ULAW (Sun) audio;" "audio/x-basic: snd,au: ULAW (Sun) audio;" - "audio/x-pn-au: snd,au: ULAW (Sun) audio;"; + "audio/x-pn-au: snd,au: ULAW (Sun) audio;"; } @@ -395,7 +393,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_snd_init_plugin (xine_t *xine, void *data) { demux_snd_class_t *this; - this = xine_xmalloc (sizeof (demux_snd_class_t)); + this = calloc(1, sizeof(demux_snd_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_str.c b/src/demuxers/demux_str.c index 2cf542014..d88432817 100644 --- a/src/demuxers/demux_str.c +++ b/src/demuxers/demux_str.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000-2003 the xine project + * Copyright (C) 2000-2008 the xine project * * This file is part of xine, a free video player. * @@ -102,7 +102,7 @@ * - then follows 16-bit RLE data until the EOD * - RLE format: bits 15-10: # of 0s preceding this value (unsigned) * bits 9-0: this value (signed) - * - e.g. 3 bytes (2,10)(0,20)(3,30) -> 0 0 10 20 0 0 0 30 + * - e.g. 3 bytes (2,10)(0,20)(3,30) -> 0 0 10 20 0 0 0 30 * - 16 bits: EOD (0xFE00) * - 16 bits: 0xFE00 end-of-data footer */ @@ -139,20 +139,15 @@ #define CD_RAW_SECTOR_SIZE 2352 +#define STR_MAGIC "\x60\x01\x01\x80" #define STR_MAX_CHANNELS 32 -#define STR_MAGIC (0x80010160) - #define CDXA_TYPE_MASK 0x0E #define CDXA_TYPE_DATA 0x08 #define CDXA_TYPE_AUDIO 0x04 #define CDXA_TYPE_VIDEO 0x02 #define CDXA_SUBMODE_EOF 0x80 /* set if EOF */ -#define FOURCC_TAG BE_FOURCC -#define RIFF_TAG FOURCC_TAG('R', 'I', 'F', 'F') -#define CDXA_TAG FOURCC_TAG('C', 'D', 'X', 'A') - /* FIXME */ #define FRAME_DURATION 45000 @@ -188,9 +183,7 @@ static int open_str_file(demux_str_t *this) { unsigned char check_bytes[STR_CHECK_BYTES]; int local_offset, sector, channel; - for (channel = 0; channel < STR_MAX_CHANNELS; channel++) { - this->channel_type[channel] = 0; - } + memset(this->channel_type, 0, sizeof(this->channel_type)); this->input->seek(this->input, 0, SEEK_SET); if (this->input->read(this->input, check_bytes, STR_CHECK_BYTES) != @@ -200,8 +193,8 @@ static int open_str_file(demux_str_t *this) { } /* check for STR with a RIFF header */ - if ((_X_BE_32(&check_bytes[0]) == RIFF_TAG) && - (_X_BE_32(&check_bytes[8]) == CDXA_TAG)) + if ( _x_is_fourcc(&check_bytes[0], "RIFF") && + _x_is_fourcc(&check_bytes[8], "CDXA") ) local_offset = 0x2C; else local_offset = 0; @@ -218,16 +211,20 @@ static int open_str_file(demux_str_t *this) { check_bytes[local_offset + 0x13]); /* check for 12-byte sync marker */ - if ((_X_BE_32(&check_bytes[local_offset + 0]) != 0x00FFFFFF) || - (_X_BE_32(&check_bytes[local_offset + 4]) != 0xFFFFFFFF) || - (_X_BE_32(&check_bytes[local_offset + 8]) != 0xFFFFFF00)) { + static const uint8_t sync_marker[12] = + { 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0xFF, 0xFF, 0X00 + }; + if ( memcmp(&check_bytes[local_offset], + sync_marker, sizeof(sync_marker)) != 0 ) { lprintf("sector %d sync error\n", sector); return 0; } /* the 32 bits starting at 0x10 and at 0x14 should be the same */ - if (_X_BE_32(&check_bytes[local_offset + 0x10]) != - _X_BE_32(&check_bytes[local_offset + 0x14])) { + if (memcmp(&check_bytes[local_offset + 0x10], + &check_bytes[local_offset + 0x14], 4) != 0) { lprintf("sector %d control bits copy error\n", sector); return 0; } @@ -246,7 +243,7 @@ static int open_str_file(demux_str_t *this) { case CDXA_TYPE_VIDEO: /* first time we have seen video/data in this channel? */ if ((!(this->channel_type[channel] & CDXA_TYPE_DATA)) && - (_X_LE_32(&check_bytes[local_offset + 0x18]) == STR_MAGIC)) { + (_x_is_fourcc(&check_bytes[local_offset + 0x18], STR_MAGIC))) { /* mark this channel as having video data */ this->channel_type[channel] |= CDXA_TYPE_VIDEO; @@ -347,7 +344,7 @@ static int demux_str_send_chunk(demux_plugin_t *this_gen) { case CDXA_TYPE_DATA: /* video chunk */ - if (_X_LE_32(§or[0x18]) != STR_MAGIC || + if (!_x_is_fourcc(§or[0x18], STR_MAGIC) || channel != this->default_video_channel) { return 0; } @@ -370,7 +367,7 @@ static int demux_str_send_chunk(demux_plugin_t *this_gen) { */ if( this->data_size ) - buf->extra_info->input_normpos = (int)( (double) current_pos * + buf->extra_info->input_normpos = (int)( (double) current_pos * 65535 / this->data_size ); buf->extra_info->input_time = (current_pos*1000)/(CD_RAW_SECTOR_SIZE*75); @@ -408,7 +405,7 @@ static int demux_str_send_chunk(demux_plugin_t *this_gen) { } if( this->data_size ) - buf->extra_info->input_normpos = (int)( (double) current_pos * + buf->extra_info->input_normpos = (int)( (double) current_pos * 65535 / this->data_size ); buf->extra_info->input_time = (current_pos*1000)/(CD_RAW_SECTOR_SIZE*75); @@ -532,7 +529,7 @@ static int demux_str_get_status (demux_plugin_t *this_gen) { static int demux_str_get_stream_length (demux_plugin_t *this_gen) { demux_str_t *this = (demux_str_t *) this_gen; - return (int)((int64_t) this->input->get_length(this->input) + return (int)((int64_t) this->input->get_length(this->input) * 1000 / (CD_RAW_SECTOR_SIZE * 75)); } @@ -555,7 +552,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str return NULL; } - this = xine_xmalloc (sizeof (demux_str_t)); + this = calloc(1, sizeof(demux_str_t)); this->stream = stream; this->input = input; @@ -578,7 +575,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str mrl = input->get_mrl (input); extensions = class_gen->get_extensions (class_gen); - + if (!_x_demux_check_extension (mrl, extensions)) { free (this); return NULL; @@ -628,7 +625,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_str_init_plugin (xine_t *xine, void *data) { demux_str_class_t *this; - this = xine_xmalloc (sizeof (demux_str_class_t)); + this = calloc(1, sizeof(demux_str_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_ts.c b/src/demuxers/demux_ts.c index 86a14f019..1a19340f3 100644 --- a/src/demuxers/demux_ts.c +++ b/src/demuxers/demux_ts.c @@ -1,3 +1,4 @@ + /* * Copyright (C) 2000-2003 the xine project * @@ -33,8 +34,13 @@ * Date Author * ---- ------ * + * 8-Apr-2009 Petri Hintukainen <phi@sdf-eu.org> + * - support for 192-byte packets (HDMV/BluRay) + * - support for audio inside PES PID 0xfd (HDMV/BluRay) + * - demux HDMV/BluRay bitmap subtitles + * * 28-Nov-2004 Mike Lampard <mlampard> - * - Added support for PMT sections larger than 1 ts packet + * - Added support for PMT sections larger than 1 ts packet * * 28-Aug-2004 James Courtier-Dutton <jcdutton> * - Improve PAT and PMT handling. Added some FIXME comments. @@ -52,7 +58,7 @@ * - dynamic allocation leaks fixes * * 27-May-2002 Giovanni Baronetti and Mauro Borghi <mauro.borghi@tilab.com> - * - fill buffers before putting them in fifos + * - fill buffers before putting them in fifos * - force PMT reparsing when PMT PID changes * - accept non seekable input plugins -- FIX? * - accept dvb as input plugin @@ -167,14 +173,14 @@ #define PKT_SIZE 188 #define BODY_SIZE (188 - 4) /* more PIDS are needed due "auto-detection". 40 spare media entries */ -#define MAX_PIDS ((BODY_SIZE - 1 - 13) / 4) + 40 +#define MAX_PIDS ((BODY_SIZE - 1 - 13) / 4) + 40 #define MAX_PMTS ((BODY_SIZE - 1 - 13) / 4) + 10 #define SYNC_BYTE 0x47 #define MIN_SYNCS 3 -#define NPKT_PER_READ 100 +#define NPKT_PER_READ 96 // 96*188 = 94*192 -#define BUF_SIZE (NPKT_PER_READ * PKT_SIZE) +#define BUF_SIZE (NPKT_PER_READ * (PKT_SIZE + 4)) #define MAX_PES_BUF_SIZE 2048 @@ -185,9 +191,6 @@ #define INVALID_PROGRAM ((unsigned int)(-1)) #define INVALID_CC ((unsigned int)(-1)) -#define MIN(a,b) (((a)<(b))?(a):(b)) -#define MAX(a,b) (((a)>(b))?(a):(b)) - #define PROG_STREAM_MAP 0xBC #define PRIVATE_STREAM1 0xBD #define PADDING_STREAM 0xBE @@ -220,7 +223,23 @@ ISO_13818_PART7_AUDIO = 0x0f, /* ISO/IEC 13818-7 Audio with ADTS transport sytax */ ISO_14496_PART2_VIDEO = 0x10, /* ISO/IEC 14496-2 Visual (MPEG-4) */ ISO_14496_PART3_AUDIO = 0x11, /* ISO/IEC 14496-3 Audio with LATM transport syntax */ - ISO_14496_PART10_VIDEO = 0x1b /* ISO/IEC 14496-10 Video (MPEG-4 part 10/AVC, aka H.264) */ + ISO_14496_PART10_VIDEO = 0x1b, /* ISO/IEC 14496-10 Video (MPEG-4 part 10/AVC, aka H.264) */ + STREAM_VIDEO_MPEG = 0x80, + STREAM_AUDIO_AC3 = 0x81, + + STREAM_VIDEO_VC1 = 0xea, /* VC-1 Video */ + + HDMV_AUDIO_80_PCM = 0x80, /* BluRay PCM */ + HDMV_AUDIO_82_DTS = 0x82, /* DTS */ + HDMV_AUDIO_83_TRUEHD = 0x83, /* Dolby TrueHD, primary audio */ + HDMV_AUDIO_84_EAC3 = 0x84, /* Dolby Digital plus, primary audio */ + HDMV_AUDIO_85_DTS_HRA = 0x85, /* DTS-HRA */ + HDMV_AUDIO_86_DTS_HD_MA = 0x86, /* DTS-HD Master audio */ + + HDMV_SPU_BITMAP = 0x90, + HDMV_SPU_INTERACTIVE = 0x91, + HDMV_SPU_TEXT = 0x92, + } streamType; #define WRAP_THRESHOLD 270000 @@ -228,6 +247,11 @@ #define PTS_AUDIO 0 #define PTS_VIDEO 1 +#undef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +#undef MAX +#define MAX(a,b) ((a)>(b)?(a):(b)) + /* ** ** DATA STRUCTURES @@ -246,24 +270,25 @@ typedef struct { int64_t pts; buf_element_t *buf; unsigned int counter; - uint8_t descriptor_tag; + uint16_t descriptor_tag; /* +0x100 for PES stream IDs (no available TS descriptor tag?) */ int64_t packet_count; int corrupted_pes; uint32_t buffered_bytes; + int autodetected; } demux_ts_media; /* DVBSUB */ -#define MAX_SPU_LANGS 16 +#define MAX_SPU_LANGS 32 typedef struct { spu_dvb_descriptor_t desc; int pid; int media_index; } demux_ts_spu_lang; - + /* Audio Channels */ -#define MAX_AUDIO_TRACKS 16 +#define MAX_AUDIO_TRACKS 32 typedef struct { int pid; @@ -288,6 +313,10 @@ typedef struct { int status; + int hdmv; /* -1 = unknown, 0 = mpeg-ts, 1 = hdmv/m2ts */ + int pkt_size; /* TS packet size */ + int pkt_offset; /* TS packet offset */ + int blockSize; int rate; int media_num; @@ -309,10 +338,10 @@ typedef struct { unsigned int pid_count; unsigned int videoPid; unsigned int videoMedia; - + demux_ts_audio_track audio_tracks[MAX_AUDIO_TRACKS]; int audio_tracks_count; - + int send_end_buffers; int64_t last_pts[2]; int send_newpts; @@ -340,7 +369,7 @@ typedef struct { int32_t npkt_read; uint8_t buf[BUF_SIZE]; /* == PKT_SIZE * NPKT_PER_READ */ - + int numPreview; } demux_ts_t; @@ -368,7 +397,7 @@ static void demux_ts_build_crc32_table(demux_ts_t*this) { } } -static uint32_t demux_ts_compute_crc32(demux_ts_t*this, uint8_t *data, +static uint32_t demux_ts_compute_crc32(demux_ts_t*this, uint8_t *data, int32_t length, uint32_t crc32) { int32_t i; @@ -413,7 +442,7 @@ static void check_newpts( demux_ts_t *this, int64_t pts, int video ) The original code worked well when the wrap happend like this: V7 A7 V8 V9 A9 Dv V0 V1 da A1 V2 V3 A3 V4 - + Legend: Vn = video packet with timestamp n An = audio packet with timestamp n @@ -431,27 +460,27 @@ static void check_newpts( demux_ts_t *this, int64_t pts, int video ) a delay of almoust 26.5 hours! The new code gives the following sequences for the above examples: - + V7 A7 V8 V9 A9 Dv V0 V1 A1 V2 V3 A3 V4 V7 V8 A7 V9 Dv V0 Da A9 Dv V1 V2 A1 V3 V4 A3 After proving this code it should be cleaned up to use just a single variable "last_pts". */ - + /* this->last_pts[video] = pts; -*/ +*/ this->last_pts[video] = this->last_pts[1-video] = pts; } } /* Send a BUF_SPU_DVB to let xine know of that channel. */ -static void demux_send_special_spu_buf( demux_ts_t *this, int spu_channel ) +static void demux_send_special_spu_buf( demux_ts_t *this, uint32_t spu_type, int spu_channel ) { buf_element_t *buf; buf = this->video_fifo->buffer_pool_alloc( this->video_fifo ); - buf->type = BUF_SPU_DVB|spu_channel; + buf->type = spu_type|spu_channel; buf->content = buf->mem; buf->size = 0; this->video_fifo->put( this->video_fifo, buf ); @@ -466,7 +495,7 @@ static void demux_send_special_spu_buf( demux_ts_t *this, int spu_channel ) static void demux_ts_update_spu_channel(demux_ts_t *this) { buf_element_t *buf; - + this->current_spu_channel = this->stream->spu_channel; buf = this->video_fifo->buffer_pool_alloc(this->video_fifo); @@ -475,7 +504,7 @@ static void demux_ts_update_spu_channel(demux_ts_t *this) buf->decoder_flags = BUF_FLAG_SPECIAL; buf->decoder_info[1] = BUF_SPECIAL_SPU_DVB_DESCRIPTOR; buf->size = 0; - + if (this->current_spu_channel >= 0 && this->current_spu_channel < this->spu_langs_count) { @@ -504,6 +533,10 @@ static void demux_ts_update_spu_channel(demux_ts_t *this) #endif } + if ((this->media[this->spu_media].type & BUF_MAJOR_MASK) == BUF_SPU_HDMV) { + buf->type = BUF_SPU_HDMV; + } + this->video_fifo->put(this->video_fifo, buf); } @@ -540,7 +573,7 @@ static void demux_ts_parse_pat (demux_ts_t*this, unsigned char *original_pkt, * indicator set. */ if (!pusi) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: demux error! PAT without payload unit start indicator\n"); return; } @@ -550,7 +583,7 @@ static void demux_ts_parse_pat (demux_ts_t*this, unsigned char *original_pkt, */ pkt += pkt[4]; if (pkt - original_pkt > PKT_SIZE) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: demux error! PAT with invalid pointer\n"); return; } @@ -584,13 +617,13 @@ static void demux_ts_parse_pat (demux_ts_t*this, unsigned char *original_pkt, } if (pkt - original_pkt > BODY_SIZE - 1 - 3 - section_length) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: FIXME: (unsupported )PAT spans multiple TS packets\n"); return; } if ((section_number != 0) || (last_section_number != 0)) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: FIXME: (unsupported) PAT consists of multiple (%d) sections\n", last_section_number); return; } @@ -599,11 +632,11 @@ static void demux_ts_parse_pat (demux_ts_t*this, unsigned char *original_pkt, calc_crc32 = demux_ts_compute_crc32 (this, pkt+5, section_length+3-4, 0xffffffff); if (crc32 != calc_crc32) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: demux error! PAT with invalid CRC32: packet_crc32: %.8x calc_crc32: %.8x\n", crc32,calc_crc32); return; - } + } #ifdef TS_PAT_LOG else { printf ("demux_ts: PAT CRC32 ok.\n"); @@ -647,13 +680,12 @@ static void demux_ts_parse_pat (demux_ts_t*this, unsigned char *original_pkt, this->last_pmt_crc = 0; this->videoPid = INVALID_PID; this->spu_pid = INVALID_PID; - } - this->pmt_pid[program_count] = pmt_pid; - if (this->pmt[program_count] != NULL) { - free(this->pmt[program_count]); - this->pmt[program_count] = NULL; - this->pmt_write_ptr[program_count] = NULL; + if (this->pmt[program_count] != NULL) { + free(this->pmt[program_count]); + this->pmt[program_count] = NULL; + this->pmt_write_ptr[program_count] = NULL; + } } #ifdef TS_PAT_LOG if (this->program_number[program_count] != INVALID_PROGRAM) @@ -682,7 +714,7 @@ static int demux_ts_parse_pes_header (xine_t *xine, demux_ts_media *m, /* we should have a PES packet here */ if (p[0] || p[1] || (p[2] != 1)) { - xprintf (xine, XINE_VERBOSITY_DEBUG, + xprintf (xine, XINE_VERBOSITY_DEBUG, "demux_ts: error %02x %02x %02x (should be 0x000001) \n", p[0], p[1], p[2]); return 0 ; } @@ -733,7 +765,7 @@ static int demux_ts_parse_pes_header (xine_t *xine, demux_ts_media *m, /* sometimes corruption on header_len causes segfault in memcpy below */ if (header_len + 9 > pkt_len) { - xprintf (xine, XINE_VERBOSITY_DEBUG, + xprintf (xine, XINE_VERBOSITY_DEBUG, "demux_ts: illegal value for PES_header_data_length (0x%x)\n", header_len); return 0; } @@ -741,10 +773,28 @@ static int demux_ts_parse_pes_header (xine_t *xine, demux_ts_media *m, p += header_len + 9; packet_len -= header_len + 3; - if (stream_id == 0xbd) { + if (m->descriptor_tag == STREAM_VIDEO_VC1) { + m->content = p; + m->size = packet_len; + m->type = BUF_VIDEO_VC1; + return 1; + } + + if (m->descriptor_tag == HDMV_SPU_BITMAP) { + long payload_len = ((buf[4] << 8) | buf[5]) - header_len - 3; + + m->content = p; + m->size = packet_len; + m->type |= BUF_SPU_HDMV; + m->buf->decoder_info[2] = payload_len; + return 1; + + } else + + if (stream_id == 0xbd || stream_id == 0xfd /* HDMV */) { int spu_id; - + lprintf ("audio buf = %02X %02X %02X %02X %02X %02X %02X %02X\n", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); @@ -752,15 +802,42 @@ static int demux_ts_parse_pes_header (xine_t *xine, demux_ts_media *m, * we check the descriptor tag first because some stations * do not include any of the ac3 header info in their audio tracks * these "raw" streams may begin with a byte that looks like a stream type. + * For audio streams, m->type already contains the stream no. */ - if((m->descriptor_tag == 0x81) || /* ac3 - raw */ + if((m->descriptor_tag == STREAM_AUDIO_AC3) || /* ac3 - raw */ (p[0] == 0x0B && p[1] == 0x77)) { /* ac3 - syncword */ m->content = p; m->size = packet_len; m->type |= BUF_AUDIO_A52; return 1; - } else if (m->descriptor_tag == 0x06 + } else if (m->descriptor_tag == HDMV_AUDIO_83_TRUEHD) { + /* TODO: separate AC3 and TrueHD streams ... */ + m->content = p; + m->size = packet_len; + m->type |= BUF_AUDIO_A52; + return 1; + + } else if (m->descriptor_tag == HDMV_AUDIO_82_DTS || + m->descriptor_tag == HDMV_AUDIO_86_DTS_HD_MA ) { + m->content = p; + m->size = packet_len; + m->type |= BUF_AUDIO_DTS; + return 1; + + } else if (m->descriptor_tag == HDMV_AUDIO_80_PCM) { + + m->content = p + 4; + m->size = packet_len - 4; + m->type |= BUF_AUDIO_LPCM_BE; + + m->buf->decoder_flags |= BUF_FLAG_SPECIAL; + m->buf->decoder_info[1] = BUF_SPECIAL_LPCM_CONFIG; + m->buf->decoder_info[2] = (p[3]<<24) | (p[2]<<16) | (p[1]<<8) | p[0]; + + return 1; + + } else if (m->descriptor_tag == ISO_13818_PES_PRIVATE && p[0] == 0x20 && p[1] == 0x00) { /* DVBSUB */ long payload_len = ((buf[4] << 8) | buf[5]) - header_len - 3; @@ -808,6 +885,7 @@ static int demux_ts_parse_pes_header (xine_t *xine, demux_ts_media *m, switch (m->descriptor_tag) { case ISO_11172_VIDEO: case ISO_13818_VIDEO: + case STREAM_VIDEO_MPEG: lprintf ("demux_ts: found MPEG video type.\n"); m->type = BUF_VIDEO_MPEG; break; @@ -831,7 +909,7 @@ static int demux_ts_parse_pes_header (xine_t *xine, demux_ts_media *m, m->content = p; m->size = packet_len; switch (m->descriptor_tag) { - case ISO_11172_AUDIO: + case ISO_11172_AUDIO: case ISO_13818_AUDIO: lprintf ("demux_ts: found MPEG audio track.\n"); m->type |= BUF_AUDIO_MPEG; @@ -880,7 +958,7 @@ static void demux_ts_buffer_pes(demux_ts_t*this, unsigned char *ts, case (i.e. adaptation field only) when it does not get bumped. */ if (m->counter != INVALID_CC) { if ((m->counter & 0x0f) != cc) { - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: PID 0x%.4x: unexpected cc %d (expected %d)\n", m->pid, cc, m->counter); } } @@ -906,13 +984,13 @@ static void demux_ts_buffer_pes(demux_ts_t*this, unsigned char *ts, else if ( this->numPreview<5 ) m->buf->decoder_flags=BUF_FLAG_PREVIEW; else - m->buf->decoder_flags=BUF_FLAG_FRAME_END; + m->buf->decoder_flags |= BUF_FLAG_FRAME_END; } m->buf->pts = m->pts; m->buf->decoder_info[0] = 1; - + if( this->input->get_length (this->input) ) - m->buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * + m->buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * 65535 / this->input->get_length (this->input) ); if (this->rate) m->buf->extra_info->input_time = (int)((int64_t)this->input->get_current_pos (this->input) @@ -930,13 +1008,15 @@ static void demux_ts_buffer_pes(demux_ts_t*this, unsigned char *ts, if (!demux_ts_parse_pes_header(this->stream->xine, m, ts, len, this->stream)) { m->buf->free_buffer(m->buf); m->buf = NULL; - - if (m->corrupted_pes > CORRUPT_PES_THRESHOLD) { - if (this->videoPid == m->pid) + + if (m->corrupted_pes > CORRUPT_PES_THRESHOLD && m->autodetected) { + if (this->videoPid == m->pid) { this->videoPid = INVALID_PID; + this->last_pmt_crc = 0; + } } else { m->corrupted_pes++; - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: PID 0x%.4x: corrupted pes encountered\n", m->pid); } } else { @@ -955,7 +1035,7 @@ static void demux_ts_buffer_pes(demux_ts_t*this, unsigned char *ts, m->buf->pts = m->pts; m->buf->decoder_info[0] = 1; if( this->input->get_length (this->input) ) - m->buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * + m->buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * 65535 / this->input->get_length (this->input) ); if (this->rate) m->buf->extra_info->input_time = (int)((int64_t)this->input->get_current_pos (this->input) @@ -982,7 +1062,7 @@ static void demux_ts_pes_new(demux_ts_t*this, unsigned int mediaIndex, unsigned int pid, fifo_buffer_t *fifo, - uint8_t descriptor) { + uint16_t descriptor) { demux_ts_media *m = &this->media[mediaIndex]; @@ -1040,7 +1120,7 @@ static void demux_ts_get_reg_desc(demux_ts_t *this, uint32_t *dest, { *dest = (d[2] << 24) | (d[3] << 16) | (d[4] << 8) | d[5]; - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: found registration format identifier: 0x%.4x\n", *dest); return; } @@ -1062,7 +1142,7 @@ static inline int ts_payloadsize(unsigned char * tsp) } return 184; } - + /* * NAME demux_ts_parse_pmt @@ -1092,14 +1172,14 @@ static void demux_ts_parse_pmt (demux_ts_t *this, uint32_t crc32; uint32_t calc_crc32; uint32_t coded_length; - unsigned int pid; + unsigned int pid; unsigned char *stream; - unsigned int i; - int count; - char *ptr = NULL; + unsigned int i; + int count; + char *ptr = NULL; unsigned char len; - unsigned int offset=0; - + unsigned int offset=0; + /* * A new section should start with the payload unit start * indicator set. We allocate some mem (max. allowed for a PM section) @@ -1108,7 +1188,7 @@ static void demux_ts_parse_pmt (demux_ts_t *this, if (pusi) { pkt+=pkt[4]; /* pointer to start of section */ offset=1; - + if (this->pmt[program_count] != NULL) free(this->pmt[program_count]); this->pmt[program_count] = (uint8_t *) calloc(4096, sizeof(unsigned char)); this->pmt_write_ptr[program_count] = this->pmt[program_count]; @@ -1152,7 +1232,7 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num } if ((section_number != 0) || (last_section_number != 0)) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: FIXME (unsupported) PMT consists of multiple (%d) sections\n", last_section_number); return; } @@ -1178,7 +1258,7 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num len = count-offset; memcpy (this->pmt_write_ptr[program_count], ptr, len); this->pmt_write_ptr[program_count] +=len; - + #ifdef TS_PMT_LOG printf ("ts_demux: wr_ptr: %p, will be %p when finished\n", this->pmt_write_ptr[program_count], @@ -1193,6 +1273,15 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num return; } + if (!section_length) { + free (this->pmt[program_count]); + this->pmt[program_count] = NULL; +#ifdef TS_PMT_LOG + printf ("ts_demux: eek, zero-length section?\n"); +#endif + return; + } + #ifdef TS_PMT_LOG printf ("ts_demux: have all TS packets for the PMT section\n"); #endif @@ -1207,9 +1296,9 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num this->pmt[program_count], section_length+3-4, 0xffffffff); if (crc32 != calc_crc32) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: demux error! PMT with invalid CRC32: packet_crc32: %#.8x calc_crc32: %#.8x\n", - crc32,calc_crc32); + crc32,calc_crc32); return; } else { @@ -1230,6 +1319,15 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num } } + /* + * Forget the current video, audio and subtitle PIDs; if the PMT has not + * changed, we'll pick them up again when we parse this PMT, while if the + * PMT has changed (e.g. an IPTV streamer that's just changed its source), + * we'll get new PIDs that we should follow. + */ + this->audio_tracks_count = 0; + this->videoPid = INVALID_PID; + this->spu_pid = INVALID_PID; /* * ES definitions start here...we are going to learn upto one video @@ -1247,7 +1345,7 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num stream = &this->pmt[program_count][12] + program_info_length; coded_length = 13 + program_info_length; if (coded_length > section_length) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux error! PMT with inconsistent progInfo length\n"); return; } @@ -1264,7 +1362,7 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num stream_info_length = ((stream[3] << 8) | stream[4]) & 0x0fff; coded_length = 5 + stream_info_length; if (coded_length > section_length) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux error! PMT with inconsistent streamInfo length\n"); return; } @@ -1278,6 +1376,7 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num case ISO_13818_VIDEO: case ISO_14496_PART2_VIDEO: case ISO_14496_PART10_VIDEO: + case STREAM_VIDEO_VC1: if (this->videoPid == INVALID_PID) { #ifdef TS_PMT_LOG printf ("demux_ts: PMT video pid 0x%.4x type %2.2x\n", pid, stream[0]); @@ -1331,7 +1430,6 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num case ISO_13818_PES_PRIVATE: for (i = 5; i < coded_length; i += stream[i+1] + 2) { if ((stream[i] == 0x6a) && (this->audio_tracks_count < MAX_AUDIO_TRACKS)) { - uint32_t format_identifier=0; int i, found = 0; for(i = 0; i < this->audio_tracks_count; i++) { if(this->audio_tracks[i].pid == pid) { @@ -1344,7 +1442,7 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num printf ("demux_ts: PMT AC3 audio pid 0x%.4x type %2.2x\n", pid, stream[0]); #endif demux_ts_pes_new(this, this->media_num, pid, - this->audio_fifo, 0x81); + this->audio_fifo, STREAM_AUDIO_AC3); this->audio_tracks[this->audio_tracks_count].pid = pid; this->audio_tracks[this->audio_tracks_count].media_index = this->media_num; @@ -1379,9 +1477,9 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num { int no = this->spu_langs_count; demux_ts_spu_lang *lang = &this->spu_langs[no]; - + this->spu_langs_count++; - + memcpy(lang->desc.lang, &stream[pos], 3); lang->desc.lang[3] = 0; lang->desc.comp_page_id = @@ -1392,7 +1490,7 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num lang->media_index = this->media_num; this->media[this->media_num].type = no; demux_ts_pes_new(this, this->media_num, pid, this->video_fifo, stream[0]); - demux_send_special_spu_buf( this, no ); + demux_send_special_spu_buf( this, BUF_SPU_DVB, no ); #ifdef TS_LOG printf("demux_ts: DVBSUB: pid 0x%.4x: %s page %ld %ld type %2.2x\n", pid, lang->desc.lang, @@ -1405,6 +1503,46 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num } break; + case HDMV_SPU_INTERACTIVE: + case HDMV_SPU_TEXT: + if (this->hdmv > 0) { + printf("demux_ts: Skipping unsupported HDMV subtitle stream_type: 0x%.2x pid: 0x%.4x\n", + stream[0], pid); + break; + } + /* fall thru */ + + case HDMV_SPU_BITMAP: + if (this->hdmv > 0) { + if (pid >= 0x1200 && pid < 0x1300) { + /* HDMV Presentation Graphics / SPU */ + + if (this->spu_langs_count >= MAX_SPU_LANGS) { + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_ts: too many SPU tracks! ignoring pid 0x%.4x\n", + pid); + break; + } + + demux_ts_spu_lang *lang = &this->spu_langs[this->spu_langs_count]; + + memset(lang->desc.lang, 0, sizeof(lang->desc.lang)); + /*memcpy(lang->desc.lang, &stream[pos], 3);*/ + /*lang->desc.lang[3] = 0;*/ + lang->pid = pid; + lang->media_index = this->media_num; + this->media[this->media_num].type = this->spu_langs_count; + demux_ts_pes_new(this, this->media_num, pid, this->video_fifo, stream[0]); + demux_send_special_spu_buf( this, BUF_SPU_HDMV, this->spu_langs_count ); + this->spu_langs_count++; +#ifdef TS_PMT_LOG + printf("demux_ts: HDMV subtitle stream_type: 0x%.2x pid: 0x%.4x\n", + stream[0], pid); +#endif + break; + } + } + /* fall thru */ default: /* This following section handles all the cases where the audio track info is stored in PMT user info with stream id >= 0x80 @@ -1412,7 +1550,7 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num * then we check the registration format identifier to see if it holds "AC-3" (0x41432d33) and * if is does, we tag this as an audio stream. * FIXME: This will need expanding if we ever see a DTS or other media format here. - */ + */ if ((this->audio_tracks_count < MAX_AUDIO_TRACKS) && (stream[0] >= 0x80) ) { int i, found = 0; for(i = 0; i < this->audio_tracks_count; i++) { @@ -1426,7 +1564,10 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num demux_ts_get_reg_desc(this, &format_identifier, stream + 5, stream_info_length); /* If no format identifier, assume A52 */ - if ((format_identifier == 0x41432d33) || (format_identifier == 0)) { + if (( format_identifier == 0x41432d33) || + ( format_identifier == 0) || + ((format_identifier == 0x48444d56 || this->hdmv>0) && stream[0] == HDMV_AUDIO_80_PCM) /* BluRay PCM */) { + demux_ts_pes_new(this, this->media_num, pid, this->audio_fifo, stream[0]); this->audio_tracks[this->audio_tracks_count].pid = pid; this->audio_tracks[this->audio_tracks_count].media_index = this->media_num; @@ -1491,10 +1632,10 @@ static int sync_correct(demux_ts_t*this, uint8_t *buf, int32_t npkt_read) { xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: about to resync!\n"); for (p=0; p < npkt_read; p++) { - for(n=0; n < PKT_SIZE; n++) { + for(n=0; n < this->pkt_size; n++) { sync_ok = 1; for (i=0; i < MIN(MIN_SYNCS, npkt_read - p); i++) { - if (buf[n + ((i+p) * PKT_SIZE)] != SYNC_BYTE) { + if (buf[this->pkt_offset + n + ((i+p) * this->pkt_size)] != SYNC_BYTE) { sync_ok = 0; break; } @@ -1506,14 +1647,14 @@ static int sync_correct(demux_ts_t*this, uint8_t *buf, int32_t npkt_read) { if (sync_ok) { /* Found sync, fill in */ - memmove(&buf[0], &buf[n + p * PKT_SIZE], - ((PKT_SIZE * (npkt_read - p)) - n)); + memmove(&buf[0], &buf[n + p * this->pkt_size], + ((this->pkt_size * (npkt_read - p)) - n)); read_length = this->input->read(this->input, - &buf[(PKT_SIZE * (npkt_read - p)) - n], - n + p * PKT_SIZE); + &buf[(this->pkt_size * (npkt_read - p)) - n], + n + p * this->pkt_size); /* FIXME: when read_length is not as required... we now stop demuxing */ - if (read_length != (n + p * PKT_SIZE)) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + if (read_length != (n + p * this->pkt_size)) { + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts_tsync_correct: sync found, but read failed\n"); return 0; } @@ -1531,6 +1672,32 @@ static int sync_detect(demux_ts_t*this, uint8_t *buf, int32_t npkt_read) { sync_ok = 1; + if (this->hdmv) { + this->pkt_size = PKT_SIZE + 4; + this->pkt_offset = 4; + for (i=0; i < MIN(MIN_SYNCS, npkt_read - 3); i++) { + if (buf[this->pkt_offset + i * this->pkt_size] != SYNC_BYTE) { + sync_ok = 0; + break; + } + } + if (sync_ok) { + if (this->hdmv < 0) { + /* fix npkt_read (packet size is 192, not 188) */ + this->npkt_read = npkt_read * PKT_SIZE / this->pkt_size; + } + this->hdmv = 1; + return sync_ok; + } + if (this->hdmv > 0) + return sync_correct(this, buf, npkt_read); + + /* plain ts */ + this->hdmv = 0; + this->pkt_size = PKT_SIZE; + this->pkt_offset = 0; + } + for (i=0; i < MIN(MIN_SYNCS, npkt_read); i++) { if (buf[i * PKT_SIZE] != SYNC_BYTE) { sync_ok = 0; @@ -1554,15 +1721,15 @@ static unsigned char * demux_synchronise(demux_ts_t* this) { /* NEW: handle read returning less packets than NPKT_PER_READ... */ do { read_length = this->input->read(this->input, this->buf, - PKT_SIZE * NPKT_PER_READ); - if (read_length % PKT_SIZE) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + this->pkt_size * NPKT_PER_READ); + if (read_length < 0 || read_length % this->pkt_size) { + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: read returned %d bytes (not a multiple of %d!)\n", - read_length, PKT_SIZE); + read_length, this->pkt_size); this->status = DEMUX_FINISHED; return NULL; } - this->npkt_read = read_length / PKT_SIZE; + this->npkt_read = read_length / this->pkt_size; #ifdef TS_READ_STATS this->rstat[this->npkt_read]++; @@ -1589,13 +1756,13 @@ static unsigned char * demux_synchronise(demux_ts_t* this) { return NULL; } } - return_pointer = &(this->buf)[PKT_SIZE * this->packet_number]; + return_pointer = &(this->buf)[this->pkt_offset + this->pkt_size * this->packet_number]; this->packet_number++; return return_pointer; } -static int64_t demux_ts_adaptation_field_parse(uint8_t *data, +static int64_t demux_ts_adaptation_field_parse(uint8_t *data, uint32_t adaptation_field_length) { uint32_t discontinuity_indicator=0; @@ -1717,7 +1884,7 @@ static void demux_ts_parse_packet (demux_ts_t*this) { transport_error_indicator = (originalPkt[1] >> 7) & 0x01; payload_unit_start_indicator = (originalPkt[1] >> 6) & 0x01; transport_priority = (originalPkt[1] >> 5) & 0x01; - pid = ((originalPkt[1] << 8) | + pid = ((originalPkt[1] << 8) | originalPkt[2]) & 0x1fff; transport_scrambling_control = (originalPkt[3] >> 6) & 0x03; adaptation_field_control = (originalPkt[3] >> 4) & 0x03; @@ -1737,8 +1904,8 @@ static void demux_ts_parse_packet (demux_ts_t*this) { /* * Discard packets that are obviously bad. */ - if (sync_byte != 0x47) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + if (sync_byte != SYNC_BYTE) { + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux error! invalid ts sync byte %.2x\n", sync_byte); return; } @@ -1753,7 +1920,7 @@ static void demux_ts_parse_packet (demux_ts_t*this) { if (transport_scrambling_control) { if (this->videoPid == pid) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: selected videoPid is scrambled; skipping...\n"); } for (i=0; i < this->scrambled_npids; i++) { @@ -1778,7 +1945,7 @@ static void demux_ts_parse_packet (demux_ts_t*this) { */ data_offset += adaptation_field_length + 1; } - + if (! (adaptation_field_control & 0x1)) { return; } @@ -1790,10 +1957,10 @@ static void demux_ts_parse_packet (demux_ts_t*this) { */ program_count=0; if(this->media_num<MAX_PMTS) - while ((this->program_number[program_count] != INVALID_PROGRAM) && - (program_count < MAX_PMTS)) { + while ((this->program_number[program_count] != INVALID_PROGRAM) && + (program_count < MAX_PMTS)) { if (pid == this->pmt_pid[program_count]) { - + #ifdef TS_LOG printf ("demux_ts: PMT prog: 0x%.4x pid: 0x%.4x\n", this->program_number[program_count], @@ -1806,7 +1973,7 @@ static void demux_ts_parse_packet (demux_ts_t*this) { } program_count++; } - + if (payload_unit_start_indicator && this->media_num < MAX_PIDS){ int pes_stream_id; if (pid == 0) { @@ -1820,7 +1987,7 @@ static void demux_ts_parse_packet (demux_ts_t*this) { #ifdef TS_HEADER_LOG printf("demux_ts:ts_pes_header:stream_id=0x%.2x\n",pes_stream_id); #endif - + if ( (pes_stream_id >= VIDEO_STREAM_S) && (pes_stream_id <= VIDEO_STREAM_E) ) { if ( this->videoPid == INVALID_PID) { int i, found = 0; @@ -1830,20 +1997,21 @@ static void demux_ts_parse_packet (demux_ts_t*this) { break; } } - + if (found && (this->media[i].corrupted_pes == 0)) { this->videoPid = pid; this->videoMedia = i; } else if (!found) { this->videoPid = pid; this->videoMedia = this->media_num; - demux_ts_pes_new(this, this->media_num++, pid, this->video_fifo, pes_stream_id); + this->media[this->videoMedia].autodetected = 1; + demux_ts_pes_new(this, this->media_num++, pid, this->video_fifo, 0x100 + pes_stream_id); } - + if (this->videoPid != INVALID_PID) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: auto-detected video pid 0x%.4x\n", pid); - } + } } } else if ( (pes_stream_id >= AUDIO_STREAM_S) && (pes_stream_id <= AUDIO_STREAM_E) ) { if (this->audio_tracks_count < MAX_AUDIO_TRACKS) { @@ -1859,20 +2027,21 @@ static void demux_ts_parse_packet (demux_ts_t*this) { xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: auto-detected audio pid 0x%.4x\n", pid); #endif + /* store PID, index and stream no. */ this->audio_tracks[this->audio_tracks_count].pid = pid; this->audio_tracks[this->audio_tracks_count].media_index = this->media_num; this->media[this->media_num].type = this->audio_tracks_count; demux_ts_pes_new(this, this->media_num++, pid, - this->audio_fifo,pes_stream_id); + this->audio_fifo, 0x100 + pes_stream_id); this->audio_tracks_count++; } } } } - + if (data_len > PKT_SIZE) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: demux error! invalid payload size %d\n", data_len); } else { @@ -1946,7 +2115,7 @@ static void demux_ts_event_handler (demux_ts_t *this) { this->last_pmt_crc = 0; _x_demux_control_start (this->stream); break; - + } xine_event_free (event); @@ -1985,7 +2154,7 @@ static void demux_ts_dispose (demux_plugin_t *this_gen) { } } for (i=0; i < MAX_PIDS; i++) { - if (this->media[i].buf != NULL) { + if (this->media[i].buf != NULL) { this->media[i].buf->free_buffer(this->media[i].buf); this->media[i].buf = NULL; } @@ -2022,23 +2191,23 @@ static void demux_ts_send_headers (demux_plugin_t *this_gen) { this->last_pmt_crc = 0; _x_demux_control_start (this->stream); - + this->input->seek (this->input, 0, SEEK_SET); this->send_newpts = 1; - + demux_ts_build_crc32_table (this); - + this->status = DEMUX_OK ; this->send_end_buffers = 1; this->scrambled_npids = 0; - + /* DVBSUB */ this->spu_pid = INVALID_PID; this->spu_langs_count = 0; this->current_spu_channel = -1; - + /* FIXME ? */ _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, 1); _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, 1); @@ -2065,11 +2234,11 @@ static int demux_ts_seek (demux_plugin_t *this_gen, } this->send_newpts = 1; - + for (i=0; i<MAX_PIDS; i++) { demux_ts_media *m = &this->media[i]; - if (m->buf != NULL) + if (m->buf != NULL) m->buf->free_buffer(m->buf); m->buf = NULL; m->counter = INVALID_CC; @@ -2078,7 +2247,7 @@ static int demux_ts_seek (demux_plugin_t *this_gen, } if( !playing ) { - + this->status = DEMUX_OK; this->buf_flag_seek = 0; @@ -2088,7 +2257,7 @@ static int demux_ts_seek (demux_plugin_t *this_gen, _x_demux_flush_engine(this->stream); } - + return this->status; } @@ -2097,7 +2266,7 @@ static int demux_ts_get_stream_length (demux_plugin_t *this_gen) { demux_ts_t*this = (demux_ts_t*)this_gen; if (this->rate) - return (int)((int64_t) this->input->get_length (this->input) + return (int)((int64_t) this->input->get_length (this->input) * 1000 / (this->rate * 50)); else return 0; @@ -2119,7 +2288,7 @@ static int demux_ts_get_optional_data(demux_plugin_t *this_gen, /* be a bit paranoid */ if (this == NULL || this->stream == NULL) return DEMUX_OPTIONAL_UNSUPPORTED; - + switch (data_type) { case DEMUX_OPTIONAL_DATA_AUDIOLANG: @@ -2138,7 +2307,7 @@ static int demux_ts_get_optional_data(demux_plugin_t *this_gen, if (channel>=0 && channel<this->spu_langs_count) { memcpy(str, this->spu_langs[channel].desc.lang, 3); str[3] = 0;} - else + else strcpy(str, "none"); return DEMUX_OPTIONAL_SUCCESS; @@ -2147,45 +2316,54 @@ static int demux_ts_get_optional_data(demux_plugin_t *this_gen, } } +static int detect_ts(uint8_t *buf, size_t len, int ts_size) +{ + int i, j; + int try_again, ts_detected = 0; + size_t packs = len / ts_size - 2; + + for (i = 0; i < ts_size; i++) { + try_again = 0; + if (buf[i] == SYNC_BYTE) { + for (j = 1; j < packs; j++) { + if (buf[i + j*ts_size] != SYNC_BYTE) { + try_again = 1; + break; + } + } + if (try_again == 0) { +#ifdef TS_LOG + printf ("demux_ts: found 0x47 pattern at offset %d\n", i); +#endif + ts_detected = 1; + } + } + } -static demux_plugin_t *open_plugin (demux_class_t *class_gen, - xine_stream_t *stream, + return ts_detected; +} + +static demux_plugin_t *open_plugin (demux_class_t *class_gen, + xine_stream_t *stream, input_plugin_t *input) { - + demux_ts_t *this; int i; + int hdmv = -1; switch (stream->content_detection_method) { case METHOD_BY_CONTENT: { uint8_t buf[2069]; - int i, j; - int try_again, ts_detected; - if (!_x_demux_read_header(input, buf, 2069)) + if (!_x_demux_read_header(input, buf, sizeof(buf))) return NULL; - ts_detected = 0; - - for (i = 0; i < 188; i++) { - try_again = 0; - if (buf[i] == 0x47) { - for (j = 1; j <= 10; j++) { - if (buf[i + j*188] != 0x47) { - try_again = 1; - break; - } - } - if (try_again == 0) { -#ifdef TS_LOG - printf ("demux_ts: found 0x47 pattern at offset %d\n", i); -#endif - ts_detected = 1; - } - } - } - - if (!ts_detected) + if (detect_ts(buf, sizeof(buf), PKT_SIZE)) + hdmv = 0; + else if (detect_ts(buf, sizeof(buf), PKT_SIZE+4)) + hdmv = 1; + else return NULL; } break; @@ -2193,6 +2371,11 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, case METHOD_BY_EXTENSION: { const char *const mrl = input->get_mrl (input); + if (_x_demux_check_extension (mrl, "m2ts mts")) + hdmv = 1; + else + hdmv = 0; + /* check extension */ const char *const extensions = class_gen->get_extensions (class_gen); @@ -2229,7 +2412,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, * if we reach this point, the input has been accepted. */ - this = xine_xmalloc(sizeof(*this)); + this = calloc(1, sizeof(*this)); this->stream = stream; this->input = input; this->blockSize = PKT_SIZE; @@ -2243,13 +2426,14 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, this->demux_plugin.get_capabilities = demux_ts_get_capabilities; this->demux_plugin.get_optional_data = demux_ts_get_optional_data; this->demux_plugin.demux_class = class_gen; - + /* * Initialise our specialised data. */ for (i = 0; i < MAX_PIDS; i++) { this->media[i].pid = INVALID_PID; this->media[i].buf = NULL; + this->media[i].autodetected = 0; } for (i = 0; i < MAX_PMTS; i++) { @@ -2267,14 +2451,8 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, this->last_pmt_crc = 0; this->rate = 16000; /* FIXME */ - - this->status = DEMUX_FINISHED; -#ifdef TS_READ_STATS - for (i=0; i<=NPKT_PER_READ; i++) { - this->rstat[i] = 0; - } -#endif + this->status = DEMUX_FINISHED; /* DVBSUB */ this->spu_pid = INVALID_PID; @@ -2283,9 +2461,14 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, /* dvb */ this->event_queue = xine_event_new_queue (this->stream); - + + /* HDMV */ + this->hdmv = hdmv; + this->pkt_offset = (hdmv > 0) ? 4 : 0; + this->pkt_size = PKT_SIZE + this->pkt_offset; + this->numPreview=0; - + return &this->demux_plugin; } @@ -2296,7 +2479,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, static const char *get_description (demux_class_t *this_gen) { return "MPEG Transport Stream demuxer"; } - + static const char *get_identifier (demux_class_t *this_gen) { return "MPEG_TS"; } @@ -2317,10 +2500,10 @@ static void class_dispose (demux_class_t *this_gen) { } static void *init_class (xine_t *xine, void *data) { - + demux_ts_class_t *this; - - this = xine_xmalloc (sizeof (demux_ts_class_t)); + + this = calloc(1, sizeof(demux_ts_class_t)); this->config = xine->config; this->xine = xine; @@ -2343,7 +2526,7 @@ static const demuxer_info_t demux_info_ts = { }; const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ + /* type, API, "name", version, special_info, init_function */ { PLUGIN_DEMUX, 26, "mpeg-ts", XINE_VERSION_CODE, &demux_info_ts, init_class }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; diff --git a/src/demuxers/demux_tta.c b/src/demuxers/demux_tta.c index f6eadd652..7462cd874 100644 --- a/src/demuxers/demux_tta.c +++ b/src/demuxers/demux_tta.c @@ -19,11 +19,21 @@ * * True Audio demuxer by Diego Pettenò <flameeyes@gentoo.org> * Inspired by tta libavformat demuxer by Alex Beregszaszi + * + * Seek + time support added by Kelvie Wong <kelvie@ieee.org> */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #define LOG_MODULE "demux_tta" #define LOG_VERBOSE +// This is from the TTA spec, the length (in seconds) of a frame +// http://www.true-audio.com/TTA_Lossless_Audio_Codec_-_Format_Description +#define FRAME_TIME 1.04489795918367346939 + #include "xine_internal.h" #include "xineutils.h" #include "demux.h" @@ -43,6 +53,8 @@ typedef struct { uint32_t totalframes; uint32_t currentframe; + off_t datastart; + int status; union { @@ -52,9 +64,9 @@ typedef struct { uint16_t channels; uint16_t bits_per_sample; uint32_t samplerate; - uint32_t data_length; + uint32_t data_length; /* Number of samples */ uint32_t crc32; - } __attribute__((__packed__)) tta; + } XINE_PACKED tta; uint8_t buffer[22]; /* This is the size of the header */ } header; } demux_tta_t; @@ -72,13 +84,13 @@ static int open_tta_file(demux_tta_t *this) { if (_x_demux_read_header(this->input, peek, 4) != 4) return 0; - if ( _X_BE_32(peek) != FOURCC_32('T', 'T', 'A', '1') ) + if ( !_x_is_fourcc(peek, "TTA1") ) return 0; if ( this->input->read(this->input, this->header.buffer, sizeof(this->header)) != sizeof(this->header) ) return 0; - framelen = 1.04489795918367346939 * le2me_32(this->header.tta.samplerate); + framelen = (uint32_t)(FRAME_TIME * le2me_32(this->header.tta.samplerate)); this->totalframes = le2me_32(this->header.tta.data_length) / framelen + ((le2me_32(this->header.tta.data_length) % framelen) ? 1 : 0); this->currentframe = 0; @@ -87,12 +99,15 @@ static int open_tta_file(demux_tta_t *this) { return 0; } - this->seektable = xine_xmalloc(sizeof(uint32_t)*this->totalframes); + this->seektable = calloc(this->totalframes, sizeof(uint32_t)); this->input->read(this->input, this->seektable, sizeof(uint32_t)*this->totalframes); /* Skip the CRC32 */ this->input->seek(this->input, 4, SEEK_CUR); + /* Store the offset after the header for seeking */ + this->datastart = this->input->get_current_pos(this->input); + return 1; } @@ -100,7 +115,7 @@ static int demux_tta_send_chunk(demux_plugin_t *this_gen) { demux_tta_t *this = (demux_tta_t *) this_gen; uint32_t bytes_to_read; - if ( this->currentframe > this->totalframes ) { + if ( this->currentframe >= this->totalframes ) { this->status = DEMUX_FINISHED; return this->status; } @@ -115,7 +130,7 @@ static int demux_tta_send_chunk(demux_plugin_t *this_gen) { buf = this->audio_fifo->buffer_pool_alloc(this->audio_fifo); buf->type = BUF_AUDIO_TTA; buf->pts = 0; - buf->extra_info->total_time = this->totalframes; + buf->extra_info->total_time = (int)(le2me_32(this->header.tta.data_length) * 1000.0 / le2me_32(this->header.tta.samplerate)); /* milliseconds */ buf->decoder_flags = 0; /* Set normalised position */ @@ -123,9 +138,13 @@ static int demux_tta_send_chunk(demux_plugin_t *this_gen) { (int) ((double) this->currentframe * 65535 / this->totalframes); /* Set time */ - /* buf->extra_info->input_time = this->current_sample / this->samplerate; */ + buf->extra_info->input_time = (int)(FRAME_TIME * this->currentframe)*1000; bytes_read = this->input->read(this->input, buf->content, ( bytes_to_read > buf->max_size ) ? buf->max_size : bytes_to_read); + if (bytes_read < 0) { + this->status = DEMUX_FINISHED; + break; + } buf->size = bytes_read; @@ -133,7 +152,7 @@ static int demux_tta_send_chunk(demux_plugin_t *this_gen) { if ( bytes_to_read <= 0 ) buf->decoder_flags |= BUF_FLAG_FRAME_END; - + this->audio_fifo->put(this->audio_fifo, buf); } @@ -145,6 +164,12 @@ static int demux_tta_send_chunk(demux_plugin_t *this_gen) { static void demux_tta_send_headers(demux_plugin_t *this_gen) { demux_tta_t *this = (demux_tta_t *) this_gen; buf_element_t *buf; + xine_waveformatex wave; + uint32_t total_size = sizeof(xine_waveformatex) + sizeof(this->header) + + sizeof(uint32_t)*this->totalframes; + unsigned char *header; + + header = malloc(total_size); this->audio_fifo = this->stream->audio_fifo; @@ -162,32 +187,51 @@ static void demux_tta_send_headers(demux_plugin_t *this_gen) { /* send start buffers */ _x_demux_control_start(this->stream); - /* send init info to decoders */ - if (this->audio_fifo) { - xine_waveformatex wave; - - buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); - buf->type = BUF_AUDIO_TTA; - buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAME_END; - buf->decoder_info[0] = 0; - buf->decoder_info[1] = le2me_32(this->header.tta.samplerate); - buf->decoder_info[2] = le2me_16(this->header.tta.bits_per_sample); - buf->decoder_info[3] = le2me_16(this->header.tta.channels); - - buf->size = sizeof(xine_waveformatex) + sizeof(this->header) + sizeof(uint32_t)*this->totalframes; - memcpy(buf->content+sizeof(xine_waveformatex), this->header.buffer, sizeof(this->header)); - memcpy(buf->content+sizeof(xine_waveformatex)+sizeof(this->header), this->seektable, sizeof(uint32_t)*this->totalframes); + /* create header */ + wave.cbSize = total_size - sizeof(xine_waveformatex); - wave.cbSize = buf->size - sizeof(xine_waveformatex); - memcpy(buf->content, &wave, sizeof(wave)); + memcpy(header, &wave, sizeof(wave)); + memcpy(header+sizeof(xine_waveformatex), this->header.buffer, sizeof(this->header)); + memcpy(header+sizeof(xine_waveformatex)+sizeof(this->header), this->seektable, sizeof(uint32_t)*this->totalframes); - this->audio_fifo->put (this->audio_fifo, buf); + /* send init info to decoders */ + if (this->audio_fifo) { + uint32_t bytes_left = total_size; + + /* We are sending the seektable as well, and this may be larger than + buf->max_size */ + while (bytes_left) { + buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); + buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER; + buf->type = BUF_AUDIO_TTA; + + /* Copy min(bytes_left, max_size) bytes */ + buf->size = bytes_left < buf->max_size ? bytes_left : buf->max_size; + memcpy(buf->content, header+(total_size-bytes_left), buf->size); + + bytes_left -= buf->size; + + /* The decoder information only needs the decoder information on the last + buffer element. */ + if (!bytes_left) { + buf->decoder_flags |= BUF_FLAG_FRAME_END; + buf->decoder_info[0] = 0; + buf->decoder_info[1] = le2me_32(this->header.tta.samplerate); + buf->decoder_info[2] = le2me_16(this->header.tta.bits_per_sample); + buf->decoder_info[3] = le2me_16(this->header.tta.channels); + } + this->audio_fifo->put (this->audio_fifo, buf); + } } + free(header); } static int demux_tta_seek (demux_plugin_t *this_gen, off_t start_pos, int start_time, int playing) { demux_tta_t *this = (demux_tta_t *) this_gen; + uint32_t start_frame; + uint32_t frame_index; + off_t start_off = this->datastart; /* if thread is not running, initialize demuxer */ if( !playing ) { @@ -196,6 +240,27 @@ static int demux_tta_seek (demux_plugin_t *this_gen, _x_demux_control_newpts(this->stream, 0, 0); this->status = DEMUX_OK; + + } else { + + /* Get the starting frame */ + if( start_pos ) + start_frame = start_pos * this->totalframes / 65535; + else + start_frame = (uint32_t)((double)start_time/ 1000.0 / FRAME_TIME); + + /* Now we find the offset */ + for( frame_index = 0; frame_index < start_frame; frame_index++ ) + start_off += le2me_32(this->seektable[frame_index]); + + /* Let's seek! We store the current frame internally, so let's update that + * as well */ + _x_demux_flush_engine(this->stream); + this->input->seek(this->input, start_off, SEEK_SET); + this->currentframe = start_frame; + _x_demux_control_newpts(this->stream, (int)(FRAME_TIME * start_frame) * 90000, BUF_FLAG_SEEK); + + this->status = DEMUX_OK; } return this->status; @@ -204,6 +269,7 @@ static int demux_tta_seek (demux_plugin_t *this_gen, static void demux_tta_dispose (demux_plugin_t *this_gen) { demux_tta_t *this = (demux_tta_t *) this_gen; + free(this->seektable); free(this); } @@ -214,9 +280,8 @@ static int demux_tta_get_status (demux_plugin_t *this_gen) { } static int demux_tta_get_stream_length (demux_plugin_t *this_gen) { -// demux_tta_t *this = (demux_tta_t *) this_gen; - - return 0; + demux_tta_t *this = (demux_tta_t *) this_gen; + return le2me_32(this->header.tta.data_length) * 1000.0 / le2me_32(this->header.tta.samplerate); /* milliseconds */ } static uint32_t demux_tta_get_capabilities(demux_plugin_t *this_gen) { @@ -233,7 +298,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str demux_tta_t *this; - this = xine_xmalloc (sizeof (demux_tta_t)); + this = calloc(1, sizeof(demux_tta_t)); this->stream = stream; this->input = input; @@ -295,7 +360,8 @@ static const char *get_extensions (demux_class_t *this_gen) { } static const char *get_mimetypes (demux_class_t *this_gen) { - return NULL; + return "audio/x-tta: tta: True Audio;" + "audio/tta: tta: True Audio;"; } static void class_dispose (demux_class_t *this_gen) { @@ -307,7 +373,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_tta_init_plugin (xine_t *xine, void *data) { demux_tta_class_t *this; - this = xine_xmalloc (sizeof (demux_tta_class_t)); + this = calloc(1, sizeof(demux_tta_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_vmd.c b/src/demuxers/demux_vmd.c index 8b0087417..6aec12580 100644 --- a/src/demuxers/demux_vmd.c +++ b/src/demuxers/demux_vmd.c @@ -19,7 +19,7 @@ */ /* - * Sierra Video and Music Data (.vmd) File Demuxer + * Sierra Video and Music Data (.vmd) File Demuxer * by Mike Melanson (melanson@pcisys.net) * For more information on the VMD file format, visit: * http://www.pcisys.net/~melanson/codecs/ @@ -109,7 +109,7 @@ static int open_vmd_file(demux_vmd_t *this) { unsigned int total_frames; int64_t current_video_pts = 0; - if (_x_demux_read_header(this->input, vmd_header, VMD_HEADER_SIZE) != + if (_x_demux_read_header(this->input, vmd_header, VMD_HEADER_SIZE) != VMD_HEADER_SIZE) return 0; @@ -168,7 +168,7 @@ static int open_vmd_file(demux_vmd_t *this) { return 0; } - this->frame_table = xine_xmalloc(this->frame_count * sizeof(vmd_frame_t)); + this->frame_table = calloc(this->frame_count, sizeof(vmd_frame_t)); current_offset = this->data_start = _X_LE_32(&vmd_header[20]); this->data_size = toc_offset - this->data_start; @@ -234,7 +234,7 @@ static int demux_vmd_send_chunk(demux_plugin_t *this_gen) { buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); buf->type = BUF_VIDEO_VMD; if( this->data_size ) - buf->extra_info->input_normpos = (int)( (double) (frame->frame_offset - this->data_start) * + buf->extra_info->input_normpos = (int)( (double) (frame->frame_offset - this->data_start) * 65535 / this->data_size); memcpy(buf->content, frame->frame_record, BYTES_PER_FRAME_RECORD); buf->size = BYTES_PER_FRAME_RECORD; @@ -246,7 +246,7 @@ static int demux_vmd_send_chunk(demux_plugin_t *this_gen) { buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); buf->type = BUF_VIDEO_VMD; if( this->data_size ) - buf->extra_info->input_normpos = (int)( (double) (frame->frame_offset - this->data_start) * + buf->extra_info->input_normpos = (int)( (double) (frame->frame_offset - this->data_start) * 65535 / this->data_size); if (remaining_bytes > buf->max_size) @@ -277,7 +277,7 @@ static int demux_vmd_send_chunk(demux_plugin_t *this_gen) { buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); buf->type = BUF_AUDIO_VMD; if( this->data_size ) - buf->extra_info->input_normpos = (int)( (double) (frame->frame_offset - this->data_start) * + buf->extra_info->input_normpos = (int)( (double) (frame->frame_offset - this->data_start) * 65535 / this->data_size); memcpy(buf->content, frame->frame_record, BYTES_PER_FRAME_RECORD); buf->size = BYTES_PER_FRAME_RECORD; @@ -289,7 +289,7 @@ static int demux_vmd_send_chunk(demux_plugin_t *this_gen) { buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); buf->type = BUF_AUDIO_VMD; if( this->data_size ) - buf->extra_info->input_normpos = (int)( (double) (frame->frame_offset - this->data_start) * + buf->extra_info->input_normpos = (int)( (double) (frame->frame_offset - this->data_start) * 65535 / this->data_size); if (remaining_bytes > buf->max_size) @@ -421,7 +421,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str demux_vmd_t *this; - this = xine_xmalloc (sizeof (demux_vmd_t)); + this = calloc(1, sizeof(demux_vmd_t)); this->stream = stream; this->input = input; @@ -495,7 +495,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_vmd_init_plugin (xine_t *xine, void *data) { demux_vmd_class_t *this; - this = xine_xmalloc (sizeof (demux_vmd_class_t)); + this = calloc(1, sizeof(demux_vmd_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_voc.c b/src/demuxers/demux_voc.c index 0439980f8..1ddbc1727 100644 --- a/src/demuxers/demux_voc.c +++ b/src/demuxers/demux_voc.c @@ -85,7 +85,7 @@ static int open_voc_file(demux_voc_t *this) { return 0; /* check the signature */ - if (strncmp(header, VOC_SIGNATURE, strlen(VOC_SIGNATURE)) != 0) + if (memcmp(header, VOC_SIGNATURE, sizeof(VOC_SIGNATURE)-1) != 0) return 0; /* file is qualified */ @@ -93,7 +93,7 @@ static int open_voc_file(demux_voc_t *this) { this->input->seek(this->input, first_block_offset, SEEK_SET); /* load the block preamble */ - if (this->input->read(this->input, preamble, BLOCK_PREAMBLE_SIZE) != + if (this->input->read(this->input, preamble, BLOCK_PREAMBLE_SIZE) != BLOCK_PREAMBLE_SIZE) return 0; @@ -106,7 +106,7 @@ static int open_voc_file(demux_voc_t *this) { } /* assemble 24-bit, little endian length */ - this->data_size = preamble[1] | (preamble[2] << 8) | (preamble[3] << 16); + this->data_size = _X_LE_24(&preamble[1]); /* get the next 2 bytes (re-use preamble bytes) */ if (this->input->read(this->input, preamble, 2) != 2) @@ -142,7 +142,7 @@ static int demux_voc_send_chunk(demux_plugin_t *this_gen) { /* just load data chunks from wherever the stream happens to be * pointing; issue a DEMUX_FINISHED status if EOF is reached */ remaining_sample_bytes = PCM_BLOCK_ALIGN; - current_file_pos = + current_file_pos = this->input->get_current_pos(this->input) - this->data_start; current_pts = current_file_pos; @@ -231,7 +231,7 @@ static int demux_voc_seek (demux_plugin_t *this_gen, off_t start_pos, int start_ start_pos = (off_t) ( (double) start_pos / 65535 * this->data_size ); - + this->seek_flag = 1; this->status = DEMUX_OK; _x_demux_flush_engine (this->stream); @@ -296,7 +296,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str demux_voc_t *this; - this = xine_xmalloc (sizeof (demux_voc_t)); + this = calloc(1, sizeof(demux_voc_t)); this->stream = stream; this->input = input; @@ -370,7 +370,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_voc_init_plugin (xine_t *xine, void *data) { demux_voc_class_t *this; - this = xine_xmalloc (sizeof (demux_voc_class_t)); + this = calloc(1, sizeof(demux_voc_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_vox.c b/src/demuxers/demux_vox.c index 3ce2ad705..ccf9bf877 100644 --- a/src/demuxers/demux_vox.c +++ b/src/demuxers/demux_vox.c @@ -77,7 +77,7 @@ static int demux_vox_send_chunk (demux_plugin_t *this_gen) { buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); buf->type = BUF_AUDIO_DIALOGIC_IMA; bytes_read = this->input->read(this->input, buf->content, buf->max_size); - if (bytes_read == 0) { + if (bytes_read <= 0) { buf->free_buffer(buf); this->status = DEMUX_FINISHED; return this->status; @@ -87,7 +87,7 @@ static int demux_vox_send_chunk (demux_plugin_t *this_gen) { buf->size = buf->max_size; if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = (int)( (double) current_file_pos * + buf->extra_info->input_normpos = (int)( (double) current_file_pos * 65535 / this->input->get_length (this->input) ); buf->extra_info->input_time = audio_pts / 90; buf->pts = audio_pts; @@ -166,7 +166,7 @@ static int demux_vox_get_status (demux_plugin_t *this_gen) { static int demux_vox_get_stream_length (demux_plugin_t *this_gen) { demux_vox_t *this = (demux_vox_t *) this_gen; - return (int)((int64_t)this->input->get_length(this->input) + return (int)((int64_t)this->input->get_length(this->input) * 2 * 1000 / DIALOGIC_SAMPLERATE); } @@ -203,7 +203,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str return NULL; } - this = xine_xmalloc (sizeof (demux_vox_t)); + this = calloc(1, sizeof(demux_vox_t)); this->stream = stream; this->input = input; @@ -247,7 +247,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_vox_init_plugin (xine_t *xine, void *data) { demux_vox_class_t *this; - this = xine_xmalloc (sizeof (demux_vox_class_t)); + this = calloc(1, sizeof(demux_vox_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_vqa.c b/src/demuxers/demux_vqa.c index 40242476b..578be14ee 100644 --- a/src/demuxers/demux_vqa.c +++ b/src/demuxers/demux_vqa.c @@ -25,7 +25,7 @@ * * Quick technical note: VQA files begin with a header that includes a * frame index. This ought to be useful for seeking within a VQA file. - * However, seeking is infeasible due to the audio encoding: Each audio + * However, seeking is infeasible due to the audio encoding: Each audio * block needs information from the previous audio block in order to be * decoded, thus making random seeking difficult. */ @@ -96,8 +96,8 @@ static int open_vqa_file(demux_vqa_t *this) { return 0; /* check for the VQA signatures */ - if ((_X_BE_32(&scratch[0]) != FORM_TAG) || - (_X_BE_32(&scratch[8]) != WVQA_TAG)) + if (!_x_is_fourcc(&scratch[0], "FORM") || + !_x_is_fourcc(&scratch[8], "WVQA") ) return 0; /* file is qualified; skip to the start of the VQA header */ @@ -108,7 +108,7 @@ static int open_vqa_file(demux_vqa_t *this) { this->filesize = 1; /* load the VQA header */ - if (this->input->read(this->input, vqa_header, VQA_HEADER_SIZE) != + if (this->input->read(this->input, vqa_header, VQA_HEADER_SIZE) != VQA_HEADER_SIZE) return 0; @@ -334,7 +334,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str demux_vqa_t *this; - this = xine_xmalloc (sizeof (demux_vqa_t)); + this = calloc(1, sizeof(demux_vqa_t)); this->stream = stream; this->input = input; @@ -408,7 +408,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_vqa_init_plugin (xine_t *xine, void *data) { demux_vqa_class_t *this; - this = xine_xmalloc (sizeof (demux_vqa_class_t)); + this = calloc(1, sizeof(demux_vqa_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_wav.c b/src/demuxers/demux_wav.c index 33baaf973..99c50ad67 100644 --- a/src/demuxers/demux_wav.c +++ b/src/demuxers/demux_wav.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001-2005 the xine project + * Copyright (C) 2001-2008 the xine project * * This file is part of xine, a free video player. * @@ -41,9 +41,11 @@ #include "bswap.h" #include "group_audio.h" -#define WAV_SIGNATURE_SIZE 16 +#define WAV_SIGNATURE_SIZE 12 /* this is the hex value for 'data' */ #define data_TAG 0x61746164 +/* this is the hex value for 'fmt ' */ +#define fmt_TAG 0x20746D66 #define PCM_BLOCK_ALIGN 1024 #define PREFERED_BLOCK_SIZE 4096 @@ -74,31 +76,62 @@ typedef struct { static int demux_wav_get_stream_length (demux_plugin_t *this_gen); -/* returns 1 if the WAV file was opened successfully, 0 otherwise */ -static int open_wav_file(demux_wav_t *this) { - uint8_t signature[WAV_SIGNATURE_SIZE]; +/* searches for the chunk with the given tag from the beginning of WAV file + * returns 1 if chunk was found, 0 otherwise, + * fills chunk_size and chunk_pos if chunk was found + * NOTE: chunk_pos is set to the position of the first byte of chunk data */ +static int find_chunk_by_tag(demux_wav_t *this, const uint32_t given_chunk_tag, + uint32_t *found_chunk_size, off_t *found_chunk_pos) { uint32_t chunk_tag; uint32_t chunk_size; uint8_t chunk_preamble[8]; + /* search for the chunks from the start of the WAV file */ + this->input->seek(this->input, WAV_SIGNATURE_SIZE, SEEK_SET); + + while (1) { + if (this->input->read(this->input, chunk_preamble, 8) != 8) { + return 0; + } + + chunk_tag = _X_LE_32(&chunk_preamble[0]); + chunk_size = _X_LE_32(&chunk_preamble[4]); + + if (chunk_tag == given_chunk_tag) { + if (found_chunk_size) + *found_chunk_size = _X_LE_32(&chunk_preamble[4]); + if (found_chunk_pos) + *found_chunk_pos = this->input->get_current_pos(this->input); + return 1; + } else { + this->input->seek(this->input, chunk_size, SEEK_CUR); + } + } +} + +/* returns 1 if the WAV file was opened successfully, 0 otherwise */ +static int open_wav_file(demux_wav_t *this) { + uint8_t signature[WAV_SIGNATURE_SIZE]; + off_t wave_pos; + uint32_t wave_size; + /* check the signature */ if (_x_demux_read_header(this->input, signature, WAV_SIGNATURE_SIZE) != WAV_SIGNATURE_SIZE) return 0; - if (memcmp(signature, "RIFF", 4) || memcmp(&signature[8], "WAVEfmt ", 8) ) + if (memcmp(signature, "RIFF", 4) || memcmp(&signature[8], "WAVE", 4) ) return 0; - /* file is qualified; skip over the header bytes in the stream */ - this->input->seek(this->input, WAV_SIGNATURE_SIZE, SEEK_SET); - - /* go after the format structure */ - if (this->input->read(this->input, - (unsigned char *)&this->wave_size, 4) != 4) + /* search for the 'fmt ' chunk first */ + wave_pos = 0; + if (find_chunk_by_tag(this, fmt_TAG, &wave_size, &wave_pos)==0) return 0; - this->wave_size = le2me_32(this->wave_size); - this->wave = xine_xmalloc( this->wave_size ); - - if (this->input->read(this->input, (void *)this->wave, this->wave_size) != + this->wave_size = wave_size; + + this->input->seek(this->input, wave_pos, SEEK_SET); + this->wave = malloc( this->wave_size ); + + if (!this->wave || this->input->read(this->input, (void *)this->wave, this->wave_size) != this->wave_size) { free (this->wave); return 0; @@ -114,28 +147,21 @@ static int open_wav_file(demux_wav_t *this) { return 0; } - /* traverse through the chunks to find the 'data' chunk */ + /* search for the 'data' chunk */ this->data_start = this->data_size = 0; - while (this->data_start == 0) { - - if (this->input->read(this->input, chunk_preamble, 8) != 8) { - free (this->wave); - return 0; - } - chunk_tag = _X_LE_32(&chunk_preamble[0]); - chunk_size = _X_LE_32(&chunk_preamble[4]); - - if (chunk_tag == data_TAG) { - this->data_start = this->input->get_current_pos(this->input); - /* Get the data length from the file itself, instead of the data - * TAG, for broken files */ - this->data_size = this->input->get_length(this->input); - } else { - this->input->seek(this->input, chunk_size, SEEK_CUR); - } + if (find_chunk_by_tag(this, data_TAG, NULL, &this->data_start)==0) + { + free (this->wave); + return 0; + } + else + { + /* Get the data length from the file itself, instead of the data + * TAG, for broken files */ + this->input->seek(this->input, this->data_start, SEEK_SET); + this->data_size = this->input->get_length(this->input); + return 1; } - - return 1; } static int demux_wav_send_chunk(demux_plugin_t *this_gen) { @@ -184,11 +210,16 @@ static int demux_wav_send_chunk(demux_plugin_t *this_gen) { buf->size = remaining_sample_bytes; remaining_sample_bytes -= buf->size; - if (this->input->read(this->input, buf->content, buf->size) != + off_t read; + if ((read = this->input->read(this->input, buf->content, buf->size)) != buf->size) { - buf->free_buffer(buf); - this->status = DEMUX_FINISHED; - break; + if (read == 0) { + buf->free_buffer(buf); + this->status = DEMUX_FINISHED; + break; + } else { + buf->size = read; + } } #if 0 @@ -337,7 +368,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str demux_wav_t *this; uint32_t align; - this = xine_xmalloc (sizeof (demux_wav_t)); + this = calloc(1, sizeof(demux_wav_t)); this->stream = stream; this->input = input; @@ -423,7 +454,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_wav_init_plugin (xine_t *xine, void *data) { demux_wav_class_t *this; - this = xine_xmalloc (sizeof (demux_wav_class_t)); + this = calloc(1, sizeof(demux_wav_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_wc3movie.c b/src/demuxers/demux_wc3movie.c index 596d47f4a..36cc4eabb 100644 --- a/src/demuxers/demux_wc3movie.c +++ b/src/demuxers/demux_wc3movie.c @@ -102,7 +102,7 @@ typedef struct { } demux_mve_class_t; /* bizarre palette lookup table */ -const unsigned char wc3_pal_lookup[] = { +static const unsigned char wc3_pal_lookup[] = { 0x00, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0E, 0x10, 0x12, 0x13, 0x15, 0x16, 0x18, 0x19, 0x1A, 0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x23, 0x24, 0x25, 0x27, 0x28, 0x29, 0x2A, 0x2C, @@ -177,7 +177,7 @@ static int demux_mve_send_chunk(demux_plugin_t *this_gen) { } } this->current_shot++; - + /* this is the start of a new shot; send a new palette */ if (this->input->read(this->input, preamble, 4) != 4) { this->status = DEMUX_FINISHED; @@ -205,7 +205,7 @@ static int demux_mve_send_chunk(demux_plugin_t *this_gen) { } else if (chunk_tag == AUDI_TAG) { if( this->audio_fifo ) { audio_pts = this->video_pts - WC3_PTS_INC; - + while (chunk_size) { buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); buf->type = BUF_AUDIO_LPCM_LE; @@ -213,23 +213,23 @@ static int demux_mve_send_chunk(demux_plugin_t *this_gen) { buf->extra_info->input_normpos = (int)( (double) current_file_pos * 65535 / this->data_size); buf->extra_info->input_time = audio_pts / 90; buf->pts = audio_pts; - + if (chunk_size > buf->max_size) buf->size = buf->max_size; else buf->size = chunk_size; chunk_size -= buf->size; - + if (this->input->read(this->input, buf->content, buf->size) != buf->size) { buf->free_buffer(buf); this->status = DEMUX_FINISHED; break; } - + if (!chunk_size) buf->decoder_flags |= BUF_FLAG_FRAME_END; - + this->audio_fifo->put (this->audio_fifo, buf); } }else{ @@ -293,7 +293,7 @@ static void demux_mve_send_headers(demux_plugin_t *this_gen) { /* load stream information */ _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, 1); - /* this is not strictly correct-- some WC3 MVE files do not contain + /* this is not strictly correct-- some WC3 MVE files do not contain * audio, but I'm too lazy to check if that is the case */ _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, 1); _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, @@ -357,9 +357,9 @@ static int open_mve_file(demux_mve_t *this) { if (_x_demux_read_header(this->input, header, WC3_HEADER_SIZE) != WC3_HEADER_SIZE) return 0; - if ((_X_BE_32(&header[0]) != FORM_TAG) || - (_X_BE_32(&header[8]) != MOVE_TAG) || - (_X_BE_32(&header[12]) != PC_TAG)) + if ( !_x_is_fourcc(&header[0], "FORM") || + !_x_is_fourcc(&header[8], "MOVE") || + !_x_is_fourcc(&header[12], "_PC_") ) return 0; /* file is qualified */ @@ -376,19 +376,23 @@ static int open_mve_file(demux_mve_t *this) { if (this->input->read(this->input, preamble, 4) != 4) return 0; this->number_of_shots = _X_LE_32(&preamble[0]); - + /* allocate space for the shot offset index and set offsets to 0 */ - this->shot_offsets = xine_xmalloc(this->number_of_shots * sizeof(off_t)); + this->shot_offsets = calloc(this->number_of_shots, sizeof(off_t)); this->current_shot = 0; - for (i = 0; i < this->number_of_shots; i++) - this->shot_offsets[i] = 0; /* skip the SOND chunk */ this->input->seek(this->input, 12, SEEK_CUR); /* load the palette chunks */ - this->palettes = xine_xmalloc(this->number_of_shots * PALETTE_SIZE * + this->palettes = calloc(this->number_of_shots, PALETTE_SIZE * sizeof(palette_entry_t)); + + if (!this->shot_offsets || !this->palettes) { + free (this->shot_offsets); + return 0; + } + for (i = 0; i < this->number_of_shots; i++) { /* make sure there was a valid palette chunk preamble */ if (this->input->read(this->input, preamble, PREAMBLE_SIZE) != @@ -398,8 +402,8 @@ static int open_mve_file(demux_mve_t *this) { return 0; } - if ((_X_BE_32(&preamble[0]) != PALT_TAG) || - (_X_BE_32(&preamble[4]) != PALETTE_CHUNK_SIZE)) { + if ( !_x_is_fourcc(&preamble[0], "PALT") || + (_X_BE_32(&preamble[4]) != PALETTE_CHUNK_SIZE)) { xine_log(this->stream->xine, XINE_LOG_MSG, _("demux_wc3movie: There was a problem while loading palette chunks\n")); free (this->palettes); @@ -460,8 +464,9 @@ static int open_mve_file(demux_mve_t *this) { case BNAM_TAG: /* load the name into the stream attributes */ - title = realloc (title, chunk_size); - if (this->input->read(this->input, title, chunk_size) != chunk_size) { + free (title); + title = malloc (chunk_size); + if (!title || this->input->read(this->input, title, chunk_size) != chunk_size) { free (title); free (this->palettes); free (this->shot_offsets); @@ -535,13 +540,13 @@ static int demux_mve_seek (demux_plugin_t *this_gen, start_time /= 1000; start_pos = (off_t) ( (double) start_pos / 65535 * this->data_size ); - + this->status = DEMUX_OK; _x_demux_flush_engine(this->stream); this->seek_flag = 1; /* if input is non-seekable, do not proceed with the rest of this - * seek function */ + * seek function */ if (!INPUT_IS_SEEKABLE(this->input)) return this->status; @@ -561,7 +566,7 @@ static int demux_mve_seek (demux_plugin_t *this_gen, chunk_size = (_X_BE_32(&preamble[4]) + 1) & (~1); if (chunk_tag == SHOT_TAG) { - this->shot_offsets[0] = + this->shot_offsets[0] = this->input->get_current_pos(this->input) - PREAMBLE_SIZE; /* skip the four SHOT data bytes (palette index) */ this->input->seek(this->input, 4, SEEK_CUR); @@ -576,7 +581,7 @@ static int demux_mve_seek (demux_plugin_t *this_gen, start_pos += this->data_start; for (i = 0; i < this->number_of_shots - 1; i++) { - /* if the next shot offset has not been recorded, traverse through the + /* if the next shot offset has not been recorded, traverse through the * file until it is found */ if (this->shot_offsets[i + 1] == 0) { off_t current_pos; @@ -602,7 +607,7 @@ static int demux_mve_seek (demux_plugin_t *this_gen, chunk_size = (_X_BE_32(&preamble[4]) + 1) & (~1); if (chunk_tag == SHOT_TAG) { - this->shot_offsets[i + 1] = + this->shot_offsets[i + 1] = this->input->get_current_pos(this->input) - PREAMBLE_SIZE; /* skip the four SHOT data bytes (palette index) */ this->input->seek(this->input, 4, SEEK_CUR); @@ -615,7 +620,7 @@ static int demux_mve_seek (demux_plugin_t *this_gen, /* check if the seek-to offset falls in between this shot offset and * the next one */ - if ((start_pos >= this->shot_offsets[i]) && + if ((start_pos >= this->shot_offsets[i]) && (start_pos < this->shot_offsets[i + 1])) { new_shot = i; @@ -667,7 +672,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str demux_mve_t *this; - this = xine_xmalloc (sizeof (demux_mve_t)); + this = calloc(1, sizeof(demux_mve_t)); this->stream = stream; this->input = input; @@ -741,7 +746,7 @@ static void class_dispose (demux_class_t *this_gen) { void *demux_wc3movie_init_plugin (xine_t *xine, void *data) { demux_mve_class_t *this; - this = xine_xmalloc (sizeof (demux_mve_class_t)); + this = calloc(1, sizeof(demux_mve_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_yuv4mpeg2.c b/src/demuxers/demux_yuv4mpeg2.c index 9c5856710..aa1a4dff6 100644 --- a/src/demuxers/demux_yuv4mpeg2.c +++ b/src/demuxers/demux_yuv4mpeg2.c @@ -69,7 +69,7 @@ typedef struct { int aspect_d; int progressive; int top_field_first; - + unsigned int frame_pts_inc; unsigned int frame_size; @@ -86,7 +86,7 @@ static int open_yuv4mpeg2_file(demux_yuv4mpeg2_t *this) { char *header_ptr, *header_endptr, *header_end; this->bih.biWidth = this->bih.biHeight = this->fps_n = this->fps_d = - this->aspect_n = this->aspect_d = this->progressive = + this->aspect_n = this->aspect_d = this->progressive = this->top_field_first = this->data_start = 0; if (_x_demux_read_header(this->input, header, Y4M_HEADER_BYTES) != Y4M_HEADER_BYTES) @@ -98,11 +98,11 @@ static int open_yuv4mpeg2_file(demux_yuv4mpeg2_t *this) { /* null terminate the read data */ header[Y4M_HEADER_BYTES] = '\0'; - + /* check for stream header terminator */ if ((header_end = strchr(header, '\n')) == NULL) return 0; - + /* read tagged fields in stream header */ header_ptr = &header[Y4M_SIGNATURE_SIZE]; while (header_ptr < header_end) { @@ -111,7 +111,7 @@ static int open_yuv4mpeg2_file(demux_yuv4mpeg2_t *this) { break; else header_ptr++; - + switch (*header_ptr) { case 'W': /* read the width */ @@ -153,31 +153,31 @@ static int open_yuv4mpeg2_file(demux_yuv4mpeg2_t *this) { return 0; else header_ptr = header_endptr; - + /* denominator */ this->fps_d = strtol(header_ptr + 1, &header_endptr, 10); if (header_endptr == header_ptr + 1) return 0; else header_ptr = header_endptr; - + break; case 'A': - /* read aspect ratio - stored as a ratio(!) + /* read aspect ratio - stored as a ratio(!) * numerator */ this->aspect_n = strtol(header_ptr + 1, &header_endptr, 10); if ((header_endptr == header_ptr + 1) || (*header_endptr != ':')) return 0; else header_ptr = header_endptr; - + /* denominator */ this->aspect_d = strtol(header_ptr + 1, &header_endptr, 10); if (header_endptr == header_ptr + 1) return 0; else header_ptr = header_endptr; - + break; default: /* skip whatever this is */ @@ -185,7 +185,7 @@ static int open_yuv4mpeg2_file(demux_yuv4mpeg2_t *this) { header_ptr++; } } - + /* make sure all the data was found */ if (!this->bih.biWidth || !this->bih.biHeight || !this->fps_n || !this->fps_d) return 0; @@ -194,25 +194,17 @@ static int open_yuv4mpeg2_file(demux_yuv4mpeg2_t *this) { this->frame_size = this->bih.biWidth * this->bih.biHeight * 3 / 2; /* pts difference between frames */ - this->frame_pts_inc = (90000 * this->fps_d) / this->fps_n; - + this->frame_pts_inc = (90000 * this->fps_d) / this->fps_n; + /* finally, look for the first frame */ - while ((header_ptr - header) < (Y4M_HEADER_BYTES - 4)) { - if((header_ptr[0] == 'F') && - (header_ptr[1] == 'R') && - (header_ptr[2] == 'A') && - (header_ptr[3] == 'M') && - (header_ptr[4] == 'E')) { - this->data_start = header_ptr - header; - break; - } else - header_ptr++; - } - + char *data_start_ptr = memmem(header_ptr, Y4M_HEADER_BYTES, "FRAME", 5); + /* make sure the first frame was found */ - if(!this->data_start) + if ( !data_start_ptr ) return 0; - + + this->data_start = data_start_ptr - header; + /* compute size of all frames */ if (INPUT_IS_SEEKABLE(this->input)) { this->data_size = this->input->get_length(this->input) - @@ -228,29 +220,26 @@ static int open_yuv4mpeg2_file(demux_yuv4mpeg2_t *this) { static int demux_yuv4mpeg2_send_chunk(demux_plugin_t *this_gen) { demux_yuv4mpeg2_t *this = (demux_yuv4mpeg2_t *) this_gen; - buf_element_t *buf = NULL; - unsigned char preamble[Y4M_FRAME_SIGNATURE_SIZE]; - int bytes_remaining; - off_t current_file_pos; - int64_t pts; - /* validate that this is an actual frame boundary */ - if (this->input->read(this->input, preamble, Y4M_FRAME_SIGNATURE_SIZE) != - Y4M_FRAME_SIGNATURE_SIZE) { - this->status = DEMUX_FINISHED; - return this->status; - } - if (memcmp(preamble, Y4M_FRAME_SIGNATURE, Y4M_FRAME_SIGNATURE_SIZE) != - 0) { - this->status = DEMUX_FINISHED; - return this->status; + { + uint8_t preamble[Y4M_FRAME_SIGNATURE_SIZE]; + if (this->input->read(this->input, preamble, Y4M_FRAME_SIGNATURE_SIZE) != + Y4M_FRAME_SIGNATURE_SIZE) { + this->status = DEMUX_FINISHED; + return this->status; + } + if (memcmp(preamble, Y4M_FRAME_SIGNATURE, Y4M_FRAME_SIGNATURE_SIZE) != + 0) { + this->status = DEMUX_FINISHED; + return this->status; + } } /* load and dispatch the raw frame */ - bytes_remaining = this->frame_size; - current_file_pos = + int bytes_remaining = this->frame_size; + off_t current_file_pos = this->input->get_current_pos(this->input) - this->data_start; - pts = current_file_pos; + int64_t pts = current_file_pos; pts /= (this->frame_size + Y4M_FRAME_SIGNATURE_SIZE); pts *= this->frame_pts_inc; @@ -261,17 +250,14 @@ static int demux_yuv4mpeg2_send_chunk(demux_plugin_t *this_gen) { } while(bytes_remaining) { - buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); + buf_element_t *buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); buf->type = BUF_VIDEO_I420; if( this->data_size ) buf->extra_info->input_normpos = (int)((double) current_file_pos * 65535 / this->data_size); buf->extra_info->input_time = pts / 90; buf->pts = pts; - if (bytes_remaining > buf->max_size) - buf->size = buf->max_size; - else - buf->size = bytes_remaining; + buf->size = MIN(bytes_remaining, buf->max_size); bytes_remaining -= buf->size; if (this->input->read(this->input, buf->content, buf->size) != @@ -285,13 +271,12 @@ static int demux_yuv4mpeg2_send_chunk(demux_plugin_t *this_gen) { buf->decoder_flags |= BUF_FLAG_FRAME_END; this->video_fifo->put(this->video_fifo, buf); } - + return this->status; -} +} static void demux_yuv4mpeg2_send_headers(demux_plugin_t *this_gen) { demux_yuv4mpeg2_t *this = (demux_yuv4mpeg2_t *) this_gen; - buf_element_t *buf; this->video_fifo = this->stream->video_fifo; this->audio_fifo = this->stream->audio_fifo; @@ -310,17 +295,17 @@ static void demux_yuv4mpeg2_send_headers(demux_plugin_t *this_gen) { _x_demux_control_start(this->stream); /* send init info to decoders */ - buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); + buf_element_t *buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAMERATE| BUF_FLAG_FRAME_END; buf->decoder_info[0] = this->frame_pts_inc; /* initial video step */ - + if(this->aspect_n && this->aspect_d) { buf->decoder_flags |= BUF_FLAG_ASPECT; buf->decoder_info[1] = this->bih.biWidth * this->aspect_n; buf->decoder_info[2] = this->bih.biHeight * this->aspect_d; } - + buf->decoder_info[3] = this->progressive; buf->decoder_info[4] = this->top_field_first; @@ -342,7 +327,7 @@ static int demux_yuv4mpeg2_seek (demux_plugin_t *this_gen, /* YUV4MPEG2 files are essentially constant bit-rate video. Seek along * the calculated frame boundaries. Divide the requested seek offset - * by the frame size integer-wise to obtain the desired frame number + * by the frame size integer-wise to obtain the desired frame number * and then multiply the frame number by the frame size to get the * starting offset. Add the data_start offset to obtain the final * offset. */ @@ -385,7 +370,7 @@ static int demux_yuv4mpeg2_get_status (demux_plugin_t *this_gen) { static int demux_yuv4mpeg2_get_stream_length (demux_plugin_t *this_gen) { demux_yuv4mpeg2_t *this = (demux_yuv4mpeg2_t *) this_gen; - return (int)(((int64_t) this->data_size * 1000 * this->fps_d) / + return (int)(((int64_t) this->data_size * 1000 * this->fps_d) / ((this->frame_size + Y4M_FRAME_SIGNATURE_SIZE) * this->fps_n)); } @@ -400,10 +385,7 @@ static int demux_yuv4mpeg2_get_optional_data(demux_plugin_t *this_gen, static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *stream, input_plugin_t *input) { - - demux_yuv4mpeg2_t *this; - - this = xine_xmalloc (sizeof (demux_yuv4mpeg2_t)); + demux_yuv4mpeg2_t *this = calloc(1, sizeof(demux_yuv4mpeg2_t)); this->stream = stream; this->input = input; @@ -422,10 +404,8 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str switch (stream->content_detection_method) { case METHOD_BY_EXTENSION: { - const char *extensions, *mrl; - - mrl = input->get_mrl (input); - extensions = class_gen->get_extensions (class_gen); + const char *const mrl = input->get_mrl (input); + const char *const extensions = class_gen->get_extensions (class_gen); if (!_x_demux_check_extension (mrl, extensions)) { free (this); @@ -477,7 +457,7 @@ static void class_dispose (demux_class_t *this_gen) { static void *init_plugin (xine_t *xine, void *data) { demux_yuv4mpeg2_class_t *this; - this = xine_xmalloc (sizeof (demux_yuv4mpeg2_class_t)); + this = calloc(1, sizeof(demux_yuv4mpeg2_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/demux_yuv_frames.c b/src/demuxers/demux_yuv_frames.c index 774329c05..81dd2b03a 100644 --- a/src/demuxers/demux_yuv_frames.c +++ b/src/demuxers/demux_yuv_frames.c @@ -1,19 +1,19 @@ /* * Copyright (C) 2003-2004 the xine project * Copyright (C) 2003 Jeroen Asselman <j.asselman@itsec-ps.nl> - * + * * This file is part of xine, a free video player. - * + * * xine is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * xine is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA @@ -70,8 +70,6 @@ static int demux_yuv_frames_get_status (demux_plugin_t *this_gen) { } static int switch_buf(demux_yuv_frames_t *this , buf_element_t *buf){ - int result = 0; - if (!buf) return 0; @@ -88,8 +86,7 @@ static int switch_buf(demux_yuv_frames_t *this , buf_element_t *buf){ case BUF_VIDEO_I420: case BUF_VIDEO_YUY2: this->video_fifo->put(this->video_fifo, buf); - result = 1; /* 1, we still should read audio */ - break; + return 1; /* 1, we still should read audio */ case BUF_AUDIO_LPCM_LE: if (!_x_stream_info_get(this->stream, XINE_STREAM_INFO_HAS_VIDEO)) _x_demux_control_newpts(this->stream, buf->pts, 0); @@ -100,7 +97,7 @@ static int switch_buf(demux_yuv_frames_t *this , buf_element_t *buf){ buf->free_buffer(buf); } - return result; + return 0; } static int demux_yuv_frames_send_chunk (demux_plugin_t *this_gen){ @@ -123,21 +120,27 @@ static void demux_yuv_frames_send_headers (demux_plugin_t *this_gen){ this->video_fifo = this->stream->video_fifo; this->audio_fifo = this->stream->audio_fifo; - + _x_demux_control_start(this->stream); if(_x_stream_info_get(this->stream, XINE_STREAM_INFO_HAS_AUDIO)) { buf = this->input->read_block(this->input, this->audio_fifo, 0); - - this->audio_fifo->put(this->audio_fifo, buf); + + if (buf) + this->audio_fifo->put(this->audio_fifo, buf); + else + this->status = DEMUX_FINISHED; } - + if(_x_stream_info_get(this->stream, XINE_STREAM_INFO_HAS_VIDEO)) { buf = this->input->read_block(this->input, this->video_fifo, 0); - - this->video_fifo->put(this->video_fifo, buf); + + if (buf) + this->video_fifo->put(this->video_fifo, buf); + else + this->status = DEMUX_FINISHED; } - + this->status = DEMUX_OK; } @@ -203,7 +206,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, * if we reach this point, the input has been accepted. */ - this = xine_xmalloc (sizeof (demux_yuv_frames_t)); + this = calloc(1, sizeof(demux_yuv_frames_t)); this->stream = stream; this->input = input; @@ -253,7 +256,7 @@ static void class_dispose (demux_class_t *this_gen) { static void *init_class (xine_t *xine, void *data) { demux_yuv_frames_class_t *this; - this = xine_xmalloc (sizeof (demux_yuv_frames_class_t)); + this = calloc(1, sizeof(demux_yuv_frames_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; diff --git a/src/demuxers/ebml.c b/src/demuxers/ebml.c index ac44aecd7..75fbfde75 100644 --- a/src/demuxers/ebml.c +++ b/src/demuxers/ebml.c @@ -40,7 +40,7 @@ ebml_parser_t *new_ebml_parser (xine_t *xine, input_plugin_t *input) { ebml_parser_t *ebml; - + ebml = malloc(sizeof(ebml_parser_t)); ebml->xine = xine; ebml->input = input; @@ -52,15 +52,15 @@ ebml_parser_t *new_ebml_parser (xine_t *xine, input_plugin_t *input) { ebml->doctype = NULL; ebml->doctype_version = 0; ebml->doctype_read_version = 0; - + ebml->level = 0; - + return ebml; } void dispose_ebml_parser(ebml_parser_t *ebml) { - free(ebml); + free(ebml); } @@ -132,7 +132,7 @@ static int ebml_read_elem_len(ebml_parser_t *ebml, uint64_t *len) { int ff_bytes; uint64_t value; int i; - + if (ebml->input->read(ebml->input, data, 1) != 1) { off_t pos = ebml->input->get_current_pos(ebml->input); xprintf(ebml->xine, XINE_VERBOSITY_LOG, @@ -162,7 +162,7 @@ static int ebml_read_elem_len(ebml_parser_t *ebml, uint64_t *len) { ff_bytes = 1; else ff_bytes = 0; - + /* read the rest of the len */ if (ebml->input->read(ebml->input, data + 1, size - 1) != (size - 1)) { off_t pos = ebml->input->get_current_pos(ebml->input); @@ -231,7 +231,7 @@ int ebml_read_uint(ebml_parser_t *ebml, ebml_elem_t *elem, uint64_t *num) { "ebml: Invalid integer element size %" PRIu64 "\n", size); return 0; } - + if (!ebml_read_elem_data (ebml, data, size)) return 0; @@ -253,7 +253,7 @@ int ebml_read_sint (ebml_parser_t *ebml, ebml_elem_t *elem, int64_t *num) { "ebml: Invalid integer element size %" PRIu64 "\n", size); return 0; } - + if (!ebml_read_elem_data(ebml, data, size)) return 0; @@ -262,7 +262,7 @@ int ebml_read_sint (ebml_parser_t *ebml, ebml_elem_t *elem, int64_t *num) { *num = -1; else *num = 0; - + while (size > 0) { *num = (*num << 8) | data[elem->len - size]; size--; @@ -310,7 +310,7 @@ int ebml_read_ascii(ebml_parser_t *ebml, ebml_elem_t *elem, char *str) { if (!ebml_read_elem_data(ebml, str, size)) return 0; - + return 1; } @@ -318,6 +318,22 @@ int ebml_read_utf8 (ebml_parser_t *ebml, ebml_elem_t *elem, char *str) { return ebml_read_ascii (ebml, elem, str); } +char *ebml_alloc_read_ascii (ebml_parser_t *ebml, ebml_elem_t *elem) +{ + char *text; + if (elem->len >= 4096) + return NULL; + text = malloc(elem->len + 1); + if (text) + { + text[elem->len] = '\0'; + if (ebml_read_ascii (ebml, elem, text)) + return text; + free (text); + } + return NULL; +} + int ebml_read_date (ebml_parser_t *ebml, ebml_elem_t *elem, int64_t *date) { return ebml_read_sint (ebml, elem, date); } @@ -330,7 +346,7 @@ int ebml_read_master (ebml_parser_t *ebml, ebml_elem_t *elem) { top_elem->start = elem->start; top_elem->len = elem->len; top_elem->id = elem->id; - + ebml->level++; lprintf("id: 0x%x, len: %" PRIu64 ", level: %d\n", elem->id, elem->len, ebml->level); if (ebml->level >= EBML_STACK_SIZE) { @@ -362,20 +378,20 @@ int ebml_check_header(ebml_parser_t *ebml) { "ebml: invalid master element\n"); return 0; } - + if (master.id != EBML_ID_EBML) { xprintf(ebml->xine, XINE_VERBOSITY_LOG, "ebml: invalid master element\n"); return 0; } - + if (!ebml_read_master (ebml, &master)) return 0; next_level = 1; while (next_level == 1) { ebml_elem_t elem; - + if (!ebml_read_elem_head(ebml, &elem)) return 0; @@ -389,7 +405,7 @@ int ebml_check_header(ebml_parser_t *ebml) { ebml->version = num; break; } - + case EBML_ID_EBMLREADVERSION: { uint64_t num; @@ -423,10 +439,8 @@ int ebml_check_header(ebml_parser_t *ebml) { } case EBML_ID_DOCTYPE: { - char *text = malloc(elem.len + 1); - - text[elem.len] = '\0'; - if (!ebml_read_ascii (ebml, &elem, text)) + char *text = ebml_alloc_read_ascii (ebml, &elem); + if (!text) return 0; lprintf("doctype: %s\n", text); diff --git a/src/demuxers/ebml.h b/src/demuxers/ebml.h index 35078c502..6d750a98c 100644 --- a/src/demuxers/ebml.h +++ b/src/demuxers/ebml.h @@ -48,7 +48,7 @@ typedef struct ebml_parser_s { /* xine stuff */ xine_t *xine; input_plugin_t *input; - + /* EBML Parser Stack Management */ ebml_elem_t elem_stack[EBML_STACK_SIZE]; int level; @@ -61,11 +61,11 @@ typedef struct ebml_parser_s { char *doctype; uint64_t doctype_version; uint64_t doctype_read_version; - + } ebml_parser_t; -ebml_parser_t *new_ebml_parser (xine_t *xine, input_plugin_t *input); +ebml_parser_t *new_ebml_parser (xine_t *xine, input_plugin_t *input) XINE_MALLOC; void dispose_ebml_parser (ebml_parser_t *ebml); @@ -91,6 +91,8 @@ int ebml_read_ascii(ebml_parser_t *ebml, ebml_elem_t *elem, char *str); int ebml_read_utf8(ebml_parser_t *ebml, ebml_elem_t *elem, char *str); +char *ebml_alloc_read_ascii(ebml_parser_t *ebml, ebml_elem_t *elem); + int ebml_read_date(ebml_parser_t *ebml, ebml_elem_t *elem, int64_t *date); int ebml_read_master(ebml_parser_t *ebml, ebml_elem_t *elem); diff --git a/src/demuxers/group_audio.c b/src/demuxers/group_audio.c index 2643a8b80..f405d0292 100644 --- a/src/demuxers/group_audio.c +++ b/src/demuxers/group_audio.c @@ -110,7 +110,7 @@ static const demuxer_info_t demux_info_mod = { #endif const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ + /* type, API, "name", version, special_info, init_function */ { PLUGIN_DEMUX, 26, "aac", XINE_VERSION_CODE, &demux_info_aac, demux_aac_init_plugin }, { PLUGIN_DEMUX, 26, "ac3", XINE_VERSION_CODE, &demux_info_ac3, demux_ac3_init_plugin }, { PLUGIN_DEMUX, 26, "aud", XINE_VERSION_CODE, &demux_info_aud, demux_aud_init_plugin }, diff --git a/src/demuxers/group_audio.h b/src/demuxers/group_audio.h index 424e5c8e0..d2cd91875 100644 --- a/src/demuxers/group_audio.h +++ b/src/demuxers/group_audio.h @@ -1,18 +1,18 @@ -/* +/* * Copyright (C) 2000-2005 the xine project - * + * * This file is part of xine, a free video player. - * + * * xine is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * xine is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA diff --git a/src/demuxers/group_games.c b/src/demuxers/group_games.c index ad257c2fb..f08e8477d 100644 --- a/src/demuxers/group_games.c +++ b/src/demuxers/group_games.c @@ -78,7 +78,7 @@ static const demuxer_info_t demux_info_vmd = { }; const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ + /* type, API, "name", version, special_info, init_function */ { PLUGIN_DEMUX, 26, "wve", XINE_VERSION_CODE, &demux_info_eawve, demux_eawve_init_plugin}, { PLUGIN_DEMUX, 26, "idcin", XINE_VERSION_CODE, &demux_info_idcin, demux_idcin_init_plugin }, { PLUGIN_DEMUX, 26, "ipmovie", XINE_VERSION_CODE, &demux_info_ipmovie, demux_ipmovie_init_plugin }, diff --git a/src/demuxers/group_games.h b/src/demuxers/group_games.h index f93d4bb07..ea6b00e75 100644 --- a/src/demuxers/group_games.h +++ b/src/demuxers/group_games.h @@ -1,18 +1,18 @@ -/* +/* * Copyright (C) 2000-2003 the xine project - * + * * This file is part of xine, a free video player. - * + * * xine is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * xine is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA diff --git a/src/demuxers/id3.c b/src/demuxers/id3.c index 6b36cc666..15599ffea 100644 --- a/src/demuxers/id3.c +++ b/src/demuxers/id3.c @@ -29,7 +29,7 @@ * * ID3v2 specs: http://www.id3.org/ */ - + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -84,7 +84,7 @@ static const char* const id3_encoding[] = { "UTF-16", /* 0x01 */ "UTF-16BE", /* 0x02 */ "UTF-8"}; /* 0x03 */ - + int id3v1_parse_tag (input_plugin_t *input, xine_stream_t *stream) { off_t len; @@ -113,7 +113,7 @@ int id3v1_parse_tag (input_plugin_t *input, xine_stream_t *stream) { if (tag.genre < ID3_GENRE_COUNT) { _x_meta_info_set(stream, XINE_META_INFO_GENRE, id3_genre[tag.genre]); } - + } return 1; } else { @@ -126,12 +126,12 @@ static int id3v2_parse_genre(char* dest, char *src, int len) { int state = 0; char *buf = dest; unsigned int index = 0; - + while (*src) { lprintf("state=%d\n", state); if ((buf - dest) >= len) return 0; - + switch (state) { case 0: /* initial state */ @@ -241,7 +241,7 @@ static int id3v2_parse_header(input_plugin_t *input, uint8_t *mp3_frame_header, lprintf("tag: ID3 v2.%d.%d\n", mp3_frame_header[3], tag_header->revision); lprintf("flags: %d\n", tag_header->flags); - lprintf("size: %d\n", tag_header->size); + lprintf("size: %zu\n", tag_header->size); return 1; } else { return 0; @@ -259,9 +259,9 @@ static int id3v22_parse_frame_header(input_plugin_t *input, if (len == ID3V22_FRAME_HEADER_SIZE) { frame_header->id = (buf[0] << 16) + (buf[1] << 8) + buf[2]; - frame_header->size = _X_BE_24_synchsafe(&buf[3]); + frame_header->size = _X_BE_24(&buf[3]); - lprintf("frame: %c%c%c: size: %d\n", buf[0], buf[1], buf[2], + lprintf("frame: %c%c%c: size: %zu\n", buf[0], buf[1], buf[2], frame_header->size); return 1; @@ -275,8 +275,11 @@ static int id3v22_interp_frame(input_plugin_t *input, id3v22_frame_header_t *frame_header) { char *buf; int enc; - - buf = malloc(frame_header->size + 1); + const size_t bufsize = frame_header->size + 2; + if ( bufsize < 3 ) /* frames has to be _at least_ 1 byte */ + return 0; + + buf = malloc(bufsize); if (buf == NULL) { lprintf("malloc error"); return 0; @@ -284,6 +287,7 @@ static int id3v22_interp_frame(input_plugin_t *input, if (input->read (input, buf, frame_header->size) == frame_header->size) { buf[frame_header->size] = 0; + buf[frame_header->size + 1] = 0; enc = buf[0]; if( enc >= ID3_ENCODING_COUNT ) enc = 0; @@ -292,7 +296,7 @@ static int id3v22_interp_frame(input_plugin_t *input, case ( FOURCC_TAG(0, 'T', 'C', 'O') ): { char tmp[1024]; - + if (id3v2_parse_genre(tmp, buf + 1, 1024)) { _x_meta_info_set(stream, XINE_META_INFO_GENRE, tmp); } @@ -337,9 +341,9 @@ static int id3v22_interp_frame(input_plugin_t *input, } -int id3v22_parse_tag(input_plugin_t *input, - xine_stream_t *stream, - int8_t *mp3_frame_header) { +static int id3v22_parse_tag(input_plugin_t *input, + xine_stream_t *stream, + int8_t *mp3_frame_header) { id3v2_header_t tag_header; id3v22_frame_header_t tag_frame_header; int pos = 0; @@ -348,22 +352,22 @@ int id3v22_parse_tag(input_plugin_t *input, if (tag_header.flags & ID3V22_ZERO_FLAG) { /* invalid flags */ - xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: invalid header flags (%02x)\n", tag_header.flags); + xprintf(stream->xine, XINE_VERBOSITY_DEBUG, + LOG_MODULE ": invalid header flags (%02x)\n", tag_header.flags); input->seek (input, tag_header.size - pos, SEEK_CUR); return 0; } if (tag_header.flags & ID3V22_COMPRESS_FLAG) { /* compressed tag: not supported */ - xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: compressed tags are not supported\n"); + xprintf(stream->xine, XINE_VERBOSITY_DEBUG, + LOG_MODULE ": compressed tags are not supported\n"); input->seek (input, tag_header.size - pos, SEEK_CUR); return 0; } if (tag_header.flags & ID3V22_UNSYNCH_FLAG) { /* unsynchronized tag: not supported */ - xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: unsynchronized tags are not supported\n"); + xprintf(stream->xine, XINE_VERBOSITY_DEBUG, + LOG_MODULE ": unsynchronized tags are not supported\n"); input->seek (input, tag_header.size - pos, SEEK_CUR); return 0; } @@ -371,15 +375,15 @@ int id3v22_parse_tag(input_plugin_t *input, while ((pos + ID3V22_FRAME_HEADER_SIZE) <= tag_header.size) { if (id3v22_parse_frame_header(input, &tag_frame_header)) { pos += ID3V22_FRAME_HEADER_SIZE; - if (tag_frame_header.id && tag_frame_header.size) { + if (tag_frame_header.id) { if ((pos + tag_frame_header.size) <= tag_header.size) { if (!id3v22_interp_frame(input, stream, &tag_frame_header)) { - xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: invalid frame content\n"); + xprintf(stream->xine, XINE_VERBOSITY_DEBUG, + LOG_MODULE ": invalid frame content\n"); } } else { - xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: invalid frame header\n"); + xprintf(stream->xine, XINE_VERBOSITY_DEBUG, + LOG_MODULE ": invalid frame header\n"); input->seek (input, tag_header.size - pos, SEEK_CUR); return 1; } @@ -390,14 +394,14 @@ int id3v22_parse_tag(input_plugin_t *input, return 1; } } else { - xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: id3v2_parse_frame_header problem\n"); + xprintf(stream->xine, XINE_VERBOSITY_DEBUG, + LOG_MODULE ": id3v2_parse_frame_header problem\n"); return 0; } } return 1; } else { - xprintf(stream->xine, XINE_VERBOSITY_DEBUG, "id3: id3v2_parse_header problem\n"); + xprintf(stream->xine, XINE_VERBOSITY_DEBUG, LOG_MODULE ": id3v2_parse_header problem\n"); return 0; } } @@ -415,7 +419,7 @@ static int id3v23_parse_frame_header(input_plugin_t *input, frame_header->size = _X_BE_32(&buf[4]); frame_header->flags = _X_BE_16(buf + 8); - lprintf("frame: %c%c%c%c, size: %d, flags: %X\n", buf[0], buf[1], buf[2], buf[3], + lprintf("frame: %c%c%c%c, size: %zu, flags: %X\n", buf[0], buf[1], buf[2], buf[3], frame_header->size, frame_header->flags); return 1; @@ -429,9 +433,9 @@ static int id3v23_parse_frame_ext_header(input_plugin_t *input, uint8_t buf[14]; if (input->read (input, buf, 4) == 4) { - - frame_ext_header->size = _X_BE_32_synchsafe(&buf[0]); - + + frame_ext_header->size = _X_BE_32(&buf[0]); + if (frame_ext_header->size == 6) { if (input->read (input, buf + 4, 6) == 6) { frame_ext_header->flags = _X_BE_16(buf + 4); @@ -439,7 +443,7 @@ static int id3v23_parse_frame_ext_header(input_plugin_t *input, frame_ext_header->crc = 0; } else { return 0; - } + } } else if (frame_ext_header->size == 10) { if (input->read (input, buf + 4, 10) == 10) { @@ -451,11 +455,11 @@ static int id3v23_parse_frame_ext_header(input_plugin_t *input, } } else { - lprintf("invalid ext header size: %d\n", frame_ext_header->size); + lprintf("invalid ext header size: %zu\n", frame_ext_header->size); return 0; } - lprintf("ext header: size: %d, flags: %X, padding_size: %d, crc: %d\n", + lprintf("ext header: size: %zu, flags: %X, padding_size: %d, crc: %d\n", frame_ext_header->size, frame_ext_header->flags, frame_ext_header->padding_size, frame_ext_header->crc); return 1; @@ -469,8 +473,11 @@ static int id3v23_interp_frame(input_plugin_t *input, id3v23_frame_header_t *frame_header) { char *buf; int enc; + const size_t bufsize = frame_header->size + 2; + if ( bufsize < 3 ) /* frames has to be _at least_ 1 byte */ + return 0; - buf = malloc(frame_header->size + 1); + buf = malloc(bufsize); if (buf == NULL) { lprintf("malloc error"); return 0; @@ -478,6 +485,7 @@ static int id3v23_interp_frame(input_plugin_t *input, if (input->read (input, buf, frame_header->size) == frame_header->size) { buf[frame_header->size] = 0; + buf[frame_header->size + 1] = 0; enc = buf[0]; if( enc >= ID3_ENCODING_COUNT ) enc = 0; @@ -486,7 +494,7 @@ static int id3v23_interp_frame(input_plugin_t *input, case ( FOURCC_TAG('T', 'C', 'O', 'N') ): { char tmp[1024]; - + if (id3v2_parse_genre(tmp, buf + 1, 1024)) { _x_meta_info_set(stream, XINE_META_INFO_GENRE, tmp); } @@ -530,9 +538,9 @@ static int id3v23_interp_frame(input_plugin_t *input, } } -int id3v23_parse_tag(input_plugin_t *input, - xine_stream_t *stream, - int8_t *mp3_frame_header) { +static int id3v23_parse_tag(input_plugin_t *input, + xine_stream_t *stream, + int8_t *mp3_frame_header) { id3v2_header_t tag_header; id3v23_frame_header_t tag_frame_header; id3v23_frame_ext_header_t tag_frame_ext_header; @@ -542,15 +550,15 @@ int id3v23_parse_tag(input_plugin_t *input, if (tag_header.flags & ID3V23_ZERO_FLAG) { /* invalid flags */ - xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: invalid header flags (%02x)\n", tag_header.flags); + xprintf(stream->xine, XINE_VERBOSITY_DEBUG, + LOG_MODULE ": invalid header flags (%02x)\n", tag_header.flags); input->seek (input, tag_header.size - pos, SEEK_CUR); return 0; } if (tag_header.flags & ID3V23_UNSYNCH_FLAG) { /* unsynchronized tag: not supported */ - xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: unsynchronized tags are not supported\n"); + xprintf(stream->xine, XINE_VERBOSITY_DEBUG, + LOG_MODULE ": unsynchronized tags are not supported\n"); input->seek (input, tag_header.size - pos, SEEK_CUR); return 0; } @@ -559,38 +567,40 @@ int id3v23_parse_tag(input_plugin_t *input, if (!id3v23_parse_frame_ext_header(input, &tag_frame_ext_header)) { return 0; } + pos += tag_frame_ext_header.size; } /* frame parsing */ while ((pos + ID3V23_FRAME_HEADER_SIZE) <= tag_header.size) { if (id3v23_parse_frame_header(input, &tag_frame_header)) { pos += ID3V23_FRAME_HEADER_SIZE; - if (tag_frame_header.id && tag_frame_header.size) { + if (tag_frame_header.id) { if ((pos + tag_frame_header.size) <= tag_header.size) { if (!id3v23_interp_frame(input, stream, &tag_frame_header)) { - xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: invalid frame content\n"); + xprintf(stream->xine, XINE_VERBOSITY_DEBUG, + LOG_MODULE ": invalid frame content\n"); } } else { - xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: invalid frame header\n"); + xprintf(stream->xine, XINE_VERBOSITY_DEBUG, + LOG_MODULE ": invalid frame header\n"); input->seek (input, tag_header.size - pos, SEEK_CUR); return 1; } pos += tag_frame_header.size; } else { /* end of frames, the rest is padding */ - input->seek (input, tag_header.size - pos, SEEK_CUR); + lprintf("skipping padding %zu bytes\n", tag_header.size - pos); + input->seek (input, tag_header.size - pos, SEEK_CUR); return 1; } } else { - xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: id3v2_parse_frame_header problem\n"); + xprintf(stream->xine, XINE_VERBOSITY_DEBUG, + LOG_MODULE ": id3v2_parse_frame_header problem\n"); return 0; } } return 1; } else { - xprintf(stream->xine, XINE_VERBOSITY_DEBUG, "id3v23: id3v2_parse_header problem\n"); + xprintf(stream->xine, XINE_VERBOSITY_DEBUG, LOG_MODULE ": id3v2_parse_header problem\n"); return 0; } } @@ -600,7 +610,7 @@ int id3v23_parse_tag(input_plugin_t *input, /* id3v2 "genre" parsing code. what a ugly format ! */ static int id3v24_parse_genre(char* dest, char *src, int len) { unsigned int index = 0; - + dest[0] = '\0'; if (sscanf(src, "%u", &index) == 1) { if (index < ID3_GENRE_COUNT) { @@ -621,10 +631,10 @@ static int id3v24_parse_frame_header(input_plugin_t *input, len = input->read (input, buf, ID3V24_FRAME_HEADER_SIZE); if (len == ID3V24_FRAME_HEADER_SIZE) { frame_header->id = _X_BE_32(buf); - frame_header->size = _X_BE_32_synchsafe(&buf[4]); + frame_header->size = _X_BE_32(&buf[4]); frame_header->flags = _X_BE_16(&buf[8]); - lprintf("frame: %c%c%c%c, size: %d, flags: %X\n", buf[0], buf[1], buf[2], buf[3], + lprintf("frame: %c%c%c%c, size: %zu, flags: %X\n", buf[0], buf[1], buf[2], buf[3], frame_header->size, frame_header->flags); return 1; @@ -638,8 +648,8 @@ static int id3v24_parse_ext_header(input_plugin_t *input, uint8_t buf[5]; if (input->read (input, buf, 4) == 4) { - - frame_ext_header->size = _X_BE_32_synchsafe(&buf[0]); + + frame_ext_header->size = _X_BE_32(&buf[0]); if (input->read (input, buf, 2) == 2) { uint8_t flags_size = buf[0]; @@ -704,7 +714,7 @@ static int id3v24_parse_ext_header(input_plugin_t *input, } else { return 0; } - lprintf("ext header: size: %d, flags: %X, crc: %d, restrictions: %8X\n", + lprintf("ext header: size: %zu, flags: %X, crc: %d, restrictions: %8X\n", frame_ext_header->size, frame_ext_header->flags, frame_ext_header->crc, frame_ext_header->restrictions); return 1; @@ -718,8 +728,11 @@ static int id3v24_interp_frame(input_plugin_t *input, id3v24_frame_header_t *frame_header) { char *buf; int enc; + const size_t bufsize = frame_header->size + 2; + if ( bufsize < 3 ) /* frames has to be _at least_ 1 byte */ + return 0; - buf = malloc(frame_header->size + 1); + buf = malloc(bufsize); if (buf == NULL) { lprintf("malloc error"); return 0; @@ -727,17 +740,18 @@ static int id3v24_interp_frame(input_plugin_t *input, if (input->read (input, buf, frame_header->size) == frame_header->size) { buf[frame_header->size] = 0; + buf[frame_header->size + 1] = 0; enc = buf[0]; if( enc >= ID3_ENCODING_COUNT ) enc = 0; - + lprintf("data: %s\n", buf+1); switch (frame_header->id) { case ( FOURCC_TAG('T', 'C', 'O', 'N') ): { char tmp[1024]; - + if (id3v24_parse_genre(tmp, buf + 1, 1024)) { _x_meta_info_set(stream, XINE_META_INFO_GENRE, tmp); } @@ -757,6 +771,7 @@ static int id3v24_interp_frame(input_plugin_t *input, break; case ( FOURCC_TAG('T', 'Y', 'E', 'R') ): + case ( FOURCC_TAG('T', 'D', 'R', 'C') ): _x_meta_info_set_generic(stream, XINE_META_INFO_YEAR, buf + 1, id3_encoding[enc]); break; @@ -781,9 +796,9 @@ static int id3v24_interp_frame(input_plugin_t *input, } } -int id3v24_parse_tag(input_plugin_t *input, - xine_stream_t *stream, - int8_t *mp3_frame_header) { +static int id3v24_parse_tag(input_plugin_t *input, + xine_stream_t *stream, + int8_t *mp3_frame_header) { id3v2_header_t tag_header; id3v24_frame_header_t tag_frame_header; id3v24_frame_ext_header_t tag_frame_ext_header; @@ -793,8 +808,8 @@ int id3v24_parse_tag(input_plugin_t *input, if (tag_header.flags & ID3V24_ZERO_FLAG) { /* invalid flags */ - xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: invalid header flags (%02x)\n", tag_header.flags); + xprintf(stream->xine, XINE_VERBOSITY_DEBUG, + LOG_MODULE ": invalid header flags (%02x)\n", tag_header.flags); input->seek (input, tag_header.size - pos, SEEK_CUR); return 0; } @@ -809,20 +824,21 @@ int id3v24_parse_tag(input_plugin_t *input, if (!id3v24_parse_ext_header(input, &tag_frame_ext_header)) { return 0; } + pos += tag_frame_ext_header.size; } /* frame parsing */ while ((pos + ID3V24_FRAME_HEADER_SIZE) <= tag_header.size) { if (id3v24_parse_frame_header(input, &tag_frame_header)) { pos += ID3V24_FRAME_HEADER_SIZE; - if (tag_frame_header.id && tag_frame_header.size) { + if (tag_frame_header.id) { if ((pos + tag_frame_header.size) <= tag_header.size) { if (!id3v24_interp_frame(input, stream, &tag_frame_header)) { - xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: invalid frame content\n"); + xprintf(stream->xine, XINE_VERBOSITY_DEBUG, + LOG_MODULE ": invalid frame content\n"); } } else { - xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: invalid frame header\n"); + xprintf(stream->xine, XINE_VERBOSITY_DEBUG, + LOG_MODULE ": invalid frame header\n"); input->seek (input, tag_header.size - pos, SEEK_CUR); return 1; } @@ -833,8 +849,8 @@ int id3v24_parse_tag(input_plugin_t *input, return 1; } } else { - xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: id3v2_parse_frame_header problem\n"); + xprintf(stream->xine, XINE_VERBOSITY_DEBUG, + LOG_MODULE ": id3v2_parse_frame_header problem\n"); return 0; } } @@ -844,7 +860,7 @@ int id3v24_parse_tag(input_plugin_t *input, } return 1; } else { - xprintf(stream->xine, XINE_VERBOSITY_DEBUG, "id3v23: id3v2_parse_header problem\n"); + xprintf(stream->xine, XINE_VERBOSITY_DEBUG, LOG_MODULE ": id3v2_parse_header problem\n"); return 0; } } @@ -858,22 +874,22 @@ int id3v2_parse_tag(input_plugin_t *input, switch(mp3_frame_header[3]) { case 2: - xprintf(stream->xine, XINE_VERBOSITY_LOG, "ID3V2.2 tag\n"); + xprintf(stream->xine, XINE_VERBOSITY_LOG, LOG_MODULE ": ID3V2.2 tag\n"); result = id3v22_parse_tag(input, stream, mp3_frame_header); break; - + case 3: - xprintf(stream->xine, XINE_VERBOSITY_LOG, "ID3V2.3 tag\n"); + xprintf(stream->xine, XINE_VERBOSITY_LOG, LOG_MODULE ": ID3V2.3 tag\n"); result = id3v23_parse_tag(input, stream, mp3_frame_header); break; case 4: - xprintf(stream->xine, XINE_VERBOSITY_LOG, "ID3V2.4 tag\n"); + xprintf(stream->xine, XINE_VERBOSITY_LOG, LOG_MODULE ": ID3V2.4 tag\n"); result = id3v24_parse_tag(input, stream, mp3_frame_header); break; default: - xprintf(stream->xine, XINE_VERBOSITY_LOG, "Unknown ID3v2 version: 0x%02x.\n", mp3_frame_header[3]); + xprintf(stream->xine, XINE_VERBOSITY_LOG, LOG_MODULE ": Unknown ID3v2 version: 0x%02x.\n", mp3_frame_header[3]); } return result; diff --git a/src/demuxers/id3.h b/src/demuxers/id3.h index b4ea4b6be..41babe2b4 100644 --- a/src/demuxers/id3.h +++ b/src/demuxers/id3.h @@ -103,22 +103,22 @@ typedef struct { uint32_t id; uint8_t revision; uint8_t flags; - uint32_t size; + size_t size; } id3v2_header_t; typedef struct { uint32_t id; - uint32_t size; + size_t size; } id3v22_frame_header_t; typedef struct { uint32_t id; - uint32_t size; + size_t size; uint16_t flags; } id3v23_frame_header_t; typedef struct { - uint32_t size; + size_t size; uint16_t flags; uint32_t padding_size; uint32_t crc; @@ -128,12 +128,12 @@ typedef id3v2_header_t id3v24_footer_t; typedef struct { uint32_t id; - uint32_t size; + size_t size; uint16_t flags; } id3v24_frame_header_t; typedef struct { - uint32_t size; + size_t size; uint8_t flags; uint32_t crc; uint8_t restrictions; @@ -151,19 +151,16 @@ typedef struct { int id3v1_parse_tag (input_plugin_t *input, xine_stream_t *stream); -int id3v22_parse_tag(input_plugin_t *input, - xine_stream_t *stream, - int8_t *mp3_frame_header); - -int id3v23_parse_tag(input_plugin_t *input, - xine_stream_t *stream, - int8_t *mp3_frame_header); - -int id3v24_parse_tag(input_plugin_t *input, - xine_stream_t *stream, - int8_t *mp3_frame_header); - -/* Generic function that switch between the three above */ +/** + * @brief Generic function for ID3v2 tags parsing. + * @param input Pointer to the input plugin used by the demuxer, used + * to access the tag's data. + * @param stream Pointer to the xine stream currently being read. + * @param mp3_frame_header Header of the MP3 frame carrying the tag. + * + * @note This function will take care of calling the proper function for + * parsing ID3v2.2, ID3v2.3 or ID3v2.4 tags. + */ int id3v2_parse_tag(input_plugin_t *input, xine_stream_t *stream, int8_t *mp3_frame_header); diff --git a/src/demuxers/iff.h b/src/demuxers/iff.h index 94830f69c..8ac24a697 100644 --- a/src/demuxers/iff.h +++ b/src/demuxers/iff.h @@ -27,8 +27,8 @@ #define IFFP_IFF_H #define IFF_OKAY 0L -#define CLIENT_ERROR 1L -#define NOFILE 5L +#define IFF_CLIENT_ERROR 1L +#define IFF_NOFILE 5L #define FOURCC_CHUNK BE_FOURCC #define IFF_16SV_CHUNK FOURCC_CHUNK('1', '6', 'S', 'V') diff --git a/src/demuxers/matroska.h b/src/demuxers/matroska.h index 6806c207d..0a8226319 100644 --- a/src/demuxers/matroska.h +++ b/src/demuxers/matroska.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000-2007 the xine project + * Copyright (C) 2000-2009 the xine project * * This file is part of xine, a free video player. * @@ -16,6 +16,8 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Matroska EBML stream handling */ #ifndef MATROSKA_H #define MATROSKA_H @@ -62,6 +64,7 @@ #define MATROSKA_ID_CL_BLOCKGROUP 0xA0 #define MATROSKA_ID_CL_BLOCK 0xA1 #define MATROSKA_ID_CL_BLOCKVIRTUAL 0xA2 +#define MATROSKA_ID_CL_SIMPLEBLOCK 0xA3 #define MATROSKA_ID_CL_BLOCKADDITIONS 0x75A1 #define MATROSKA_ID_CL_BLOCKMORE 0xA6 #define MATROSKA_ID_CL_BLOCKADDID 0xEE @@ -168,10 +171,16 @@ /* Chapters */ #define MATROSKA_ID_CHAPTERS 0x1043A770 #define MATROSKA_ID_CH_EDITIONENTRY 0x45B9 +#define MATROSKA_ID_CH_ED_UID 0x45BC +#define MATROSKA_ID_CH_ED_HIDDEN 0x45BD +#define MATROSKA_ID_CH_ED_DEFAULT 0x45DB +#define MATROSKA_ID_CH_ED_ORDERED 0x45DD #define MATROSKA_ID_CH_ATOM 0xB6 #define MATROSKA_ID_CH_UID 0x73C4 #define MATROSKA_ID_CH_TIMESTART 0x91 #define MATROSKA_ID_CH_TIMEEND 0x92 +#define MATROSKA_ID_CH_HIDDEN 0x98 +#define MATROSKA_ID_CH_ENABLED 0x4598 #define MATROSKA_ID_CH_TRACK 0x8F #define MATROSKA_ID_CH_TRACKNUMBER 0x89 #define MATROSKA_ID_CH_DISPLAY 0x80 @@ -182,6 +191,46 @@ /* Tags */ #define MATROSKA_ID_TAGS 0x1254C367 +/* Chapter (used in tracks) */ +typedef struct { + uint64_t uid; + uint64_t time_start; + uint64_t time_end; + /* if not 0, the chapter could e.g. be used for skipping, but not + * be shown in the chapter list */ + int hidden; + /* disabled chapters should be skipped during playback (using this + * would require parsing control blocks) */ + int enabled; + /* Tracks this chapter belongs to. + * Remember that elements can occur in any order, so in theory the + * chapters could become available before the tracks do. + * TODO: currently unused + */ + /* uint64_t* tracks; */ + /* Chapter titles and locale information + * TODO: chapters can have multiple sets of those, i.e. several tuples + * (title, language, country). The current implementation picks from + * those by the following rules: + * 1) remember the first element + * 2) overwrite with an element where language=="eng" + */ + char* title; + char* language; + char* country; +} matroska_chapter_t; + +/* Edition */ +typedef struct { + uint64_t uid; + unsigned int hidden; + unsigned int is_default; + unsigned int ordered; + + int num_chapters, cap_chapters; + matroska_chapter_t** chapters; +} matroska_edition_t; + /* Matroska Track */ typedef struct { int flag_interlaced; @@ -213,7 +262,8 @@ typedef struct { typedef struct matroska_track_s matroska_track_t; struct matroska_track_s { int track_num; - + uint64_t uid; + uint32_t track_type; uint64_t default_duration; char *language; @@ -222,7 +272,7 @@ struct matroska_track_s { uint32_t codec_private_len; int default_flag; uint32_t compress_algo; - + uint32_t buf_type; fifo_buffer_t *fifo; @@ -235,7 +285,7 @@ struct matroska_track_s { void (*handle_content) (demux_plugin_t *this_gen, matroska_track_t *track, int decoder_flags, - uint8_t *data, int data_len, + uint8_t *data, size_t data_len, int64_t data_pts, int data_duration, int input_normpos, int input_time); }; diff --git a/src/demuxers/qtpalette.h b/src/demuxers/qtpalette.h index a8a44e916..422b570a9 100644 --- a/src/demuxers/qtpalette.h +++ b/src/demuxers/qtpalette.h @@ -11,7 +11,7 @@ static const unsigned char qt_default_palette_4[4 * 4] = { 0x93, 0x65, 0x5E, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xDF, 0xD0, 0xAB, 0x00, - 0x00, 0x00, 0x00, 0x00 + 0x00, 0x00, 0x00, 0x00 }; static const unsigned char qt_default_palette_16[16 * 4] = { @@ -30,7 +30,7 @@ static const unsigned char qt_default_palette_16[16 * 4] = { 0xFF, 0xFB, 0xF9, 0x00, 0xE8, 0xCA, 0xC5, 0x00, 0x8A, 0x7C, 0x77, 0x00, - 0x00, 0x00, 0x00, 0x00 + 0x00, 0x00, 0x00, 0x00 }; static const unsigned char qt_default_palette_256[256 * 4] = { diff --git a/src/demuxers/real_common.h b/src/demuxers/real_common.h new file mode 100644 index 000000000..4945a65ff --- /dev/null +++ b/src/demuxers/real_common.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2008 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + */ + +static inline void demux_real_sipro_swap (char buffer[], int bs) +{ + /* bs = nybbles per subpacket */ + static const unsigned char sipr_swaps[38][2] = { + {0, 63}, {1, 22}, {2, 44}, {3, 90}, {5, 81}, {7, 31}, {8, 86}, {9, 58}, + {10, 36}, {12, 68}, {13, 39}, {14, 73}, {15, 53}, {16, 69}, {17, 57}, + {19, 88}, {20, 34}, {21, 71}, {24, 46}, {25, 94}, {26, 54}, {28, 75}, + {29, 50}, {32, 70}, {33, 92}, {35, 74}, {38, 85}, {40, 56}, {42, 87}, + {43, 65}, {45, 59}, {48, 79}, {49, 93}, {51, 89}, {55, 95}, {61, 76}, + {67, 83}, {77, 80} + }; + int n; + + for (n = 0; n < 38; ++n) + { + int j; + int i = bs * sipr_swaps[n][0]; + int o = bs * sipr_swaps[n][1]; + /* swap nibbles of block 'i' with 'o' TODO: optimize */ + for (j = 0; j < bs; ++j) + { + int x = (i & 1) ? (buffer[i >> 1] >> 4) : (buffer[i >> 1] & 0x0F); + int y = (o & 1) ? (buffer[o >> 1] >> 4) : (buffer[o >> 1] & 0x0F); + if (o & 1) + buffer[o >> 1] = (buffer[o >> 1] & 0x0F) | (x << 4); + else + buffer[o >> 1] = (buffer[o >> 1] & 0xF0) | x; + if (i & 1) + buffer[i >> 1] = (buffer[i >> 1] & 0x0F) | (y << 4); + else + buffer[i >> 1] = (buffer[i >> 1] & 0xF0) | y; + ++i; + ++o; + } + } +} |