summaryrefslogtreecommitdiff
path: root/src/demuxers
diff options
context:
space:
mode:
Diffstat (limited to 'src/demuxers')
-rw-r--r--src/demuxers/asfheader.c10
-rw-r--r--src/demuxers/demux_asf.c33
-rw-r--r--src/demuxers/demux_avi.c15
-rw-r--r--src/demuxers/demux_film.c4
-rw-r--r--src/demuxers/demux_flac.c19
-rw-r--r--src/demuxers/demux_flv.c40
-rw-r--r--src/demuxers/demux_matroska.c63
-rw-r--r--src/demuxers/demux_mpgaudio.c402
-rw-r--r--src/demuxers/demux_nsv.c8
-rw-r--r--src/demuxers/demux_qt.c8
-rw-r--r--src/demuxers/demux_real.c28
-rw-r--r--src/demuxers/demux_smjpeg.c4
-rw-r--r--src/demuxers/demux_ts.c9
-rw-r--r--src/demuxers/ebml.c4
-rw-r--r--src/demuxers/ebml.h4
-rw-r--r--src/demuxers/id3.c49
16 files changed, 494 insertions, 206 deletions
diff --git a/src/demuxers/asfheader.c b/src/demuxers/asfheader.c
index 97537c337..75ad11c75 100644
--- a/src/demuxers/asfheader.c
+++ b/src/demuxers/asfheader.c
@@ -140,9 +140,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;
@@ -596,6 +596,12 @@ static int asf_header_parse_content_description(asf_header_t *header_pub, uint8_
content->description = asf_reader_get_string(&reader, description_length, iconv_cd);
content->rating = asf_reader_get_string(&reader, rating_length, 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;
iconv_close(iconv_cd);
diff --git a/src/demuxers/demux_asf.c b/src/demuxers/demux_asf.c
index 1a97e12bf..73f70eeb3 100644
--- a/src/demuxers/demux_asf.c
+++ b/src/demuxers/demux_asf.c
@@ -379,10 +379,21 @@ static int asf_read_header (demux_asf_t *this) {
uint8_t *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,7 +406,11 @@ 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");
@@ -449,10 +464,9 @@ static int asf_read_header (demux_asf_t *this) {
demux_stream->buf_type = _x_formattag_to_buf_audio
( ((xine_waveformatex *)asf_stream->private_data)->wFormatTag );
if ( !demux_stream->buf_type ) {
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
- "demux_asf: unknown audio type 0x%x\n",
- ((xine_waveformatex *)asf_stream->private_data)->wFormatTag);
demux_stream->buf_type = BUF_AUDIO_UNKNOWN;
+ _x_report_audio_format_tag (this->stream->xine, LOG_MODULE,
+ ((xine_waveformatex *)asf_stream->private_data)->wFormatTag);
}
_x_meta_info_set(this->stream, XINE_META_INFO_AUDIOCODEC, _x_buf_audio_name(demux_stream->buf_type));
@@ -495,10 +509,8 @@ static int asf_read_header (demux_asf_t *this) {
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_report_video_fourcc (this->stream->xine, LOG_MODULE, bmiheader->biCompression);
}
_x_meta_info_set(this->stream, XINE_META_INFO_VIDEOCODEC, _x_buf_video_name(demux_stream->buf_type));
@@ -722,6 +734,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;
@@ -732,10 +747,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;
diff --git a/src/demuxers/demux_avi.c b/src/demuxers/demux_avi.c
index c6a73ebde..27dfce443 100644
--- a/src/demuxers/demux_avi.c
+++ b/src/demuxers/demux_avi.c
@@ -1871,7 +1871,12 @@ static void demux_avi_send_headers (demux_plugin_t *this_gen) {
if (!this->avi->bih->biCompression)
this->avi->video_type = BUF_VIDEO_RGB;
else
+ {
this->avi->video_type = _x_fourcc_to_buf_video(this->avi->bih->biCompression);
+ if (!this->avi->video_type)
+ _x_report_video_fourcc (this->stream->xine, LOG_MODULE,
+ this->avi->bih->biCompression);
+ }
for(i=0; i < this->avi->n_audio; i++) {
this->avi->audio[i]->audio_type = _x_formattag_to_buf_audio (this->avi->audio[i]->wavex->wFormatTag);
@@ -1884,10 +1889,10 @@ static void demux_avi_send_headers (demux_plugin_t *this_gen) {
}
if( !this->avi->audio[i]->audio_type ) {
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "unknown audio type 0x%x\n",
- this->avi->audio[i]->wavex->wFormatTag);
this->no_audio = 1;
this->avi->audio[i]->audio_type = BUF_AUDIO_UNKNOWN;
+ _x_report_audio_format_tag (this->stream->xine, LOG_MODULE,
+ this->avi->audio[i]->wavex->wFormatTag);
} else
xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_avi: audio type %s (wFormatTag 0x%x)\n",
_x_buf_audio_name(this->avi->audio[i]->audio_type),
@@ -1899,8 +1904,8 @@ static void demux_avi_send_headers (demux_plugin_t *this_gen) {
* however, at least for this case (compressor: xvid biCompression: DIVX), the
* xvid fourcc must prevail as it is used by ffmpeg to detect encoder bugs. [MF]
*/
- if( _x_fourcc_to_buf_video(this->avi->compressor) == BUF_VIDEO_XVID &&
- _x_fourcc_to_buf_video(this->avi->bih->biCompression) == BUF_VIDEO_MPEG4 ) {
+ if( this->avi->video_type == BUF_VIDEO_MPEG4 &&
+ _x_fourcc_to_buf_video(this->avi->compressor) == BUF_VIDEO_XVID ) {
this->avi->bih->biCompression = this->avi->compressor;
this->avi->video_type = BUF_VIDEO_XVID;
}
@@ -1949,6 +1954,8 @@ static void demux_avi_send_headers (demux_plugin_t *this_gen) {
this->avi->compressor = this->avi->bih->biCompression;
} else {
this->avi->video_type = _x_fourcc_to_buf_video(this->avi->compressor);
+ if (!this->avi->video_type)
+ _x_fourcc_to_buf_video(this->avi->bih->biCompression);
}
_x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_FOURCC,
diff --git a/src/demuxers/demux_film.c b/src/demuxers/demux_film.c
index cc9e90d66..193d8850b 100644
--- a/src/demuxers/demux_film.c
+++ b/src/demuxers/demux_film.c
@@ -201,7 +201,11 @@ static int open_film_file(demux_film_t *film) {
film->video_type = _x_fourcc_to_buf_video(*(uint32_t *)&film_header[i + 8]);
if( !film->video_type )
+ {
film->video_type = BUF_VIDEO_UNKNOWN;
+ _x_report_video_fourcc (film->stream->xine, LOG_MODULE,
+ *(uint32_t *)&film_header[i + 8]);
+ }
/* fetch the audio information if the chunk size checks out */
if (chunk_size == 32) {
diff --git a/src/demuxers/demux_flac.c b/src/demuxers/demux_flac.c
index b4c5427c5..ed974a69c 100644
--- a/src/demuxers/demux_flac.c
+++ b/src/demuxers/demux_flac.c
@@ -189,7 +189,7 @@ static int open_flac_file(demux_flac_t *flac) {
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, cn;
char *comment;
@@ -201,18 +201,25 @@ 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);
@@ -247,8 +254,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) {
@@ -520,7 +527,9 @@ void *demux_flac_init_plugin (xine_t *xine, void *data) {
this->demux_class.open_plugin = open_plugin;
this->demux_class.description = N_("Free Lossless Audio Codec (flac) demux plugin");
this->demux_class.identifier = "FLAC";
- this->demux_class.mimetypes = NULL;
+ this->demux_class.mimetypes =
+ "audio/x-flac: flac: FLAC Audio;"
+ "audio/flac: flac: FLAC Audio;";
this->demux_class.extensions = "flac";
this->demux_class.dispose = default_demux_class_dispose;
diff --git a/src/demuxers/demux_flv.c b/src/demuxers/demux_flv.c
index e6a7e234a..38855c027 100644
--- a/src/demuxers/demux_flv.c
+++ b/src/demuxers/demux_flv.c
@@ -306,9 +306,12 @@ static int parse_flv_var(demux_flv_t *this,
num = _X_BE_32(tmp);
tmp += 4;
if (key && keylen == 5 && !strncmp(key, "times", 5)) {
- free (this->index);
- this->index = xine_xcalloc(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 = xine_xcalloc(num, sizeof(flv_index_entry_t));
+ 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));
@@ -319,16 +322,20 @@ 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 = xine_xcalloc(num, sizeof(flv_index_entry_t));
+ 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);
@@ -501,9 +508,9 @@ static int read_flv_packet(demux_flv_t *this, int preview) {
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);
@@ -569,7 +576,9 @@ static int read_flv_packet(demux_flv_t *this, int preview) {
}
return this->status;
- }
+ }
+ /* no preview */
+ this->input->seek(this->input, remaining_bytes, SEEK_CUR);
continue;
default:
@@ -661,7 +670,7 @@ static void seek_flv_file(demux_flv_t *this, off_t seek_pos, int seek_pts) {
}
}
- if (seek_pos && this->videocodec) {
+ if (seek_pos && this->videocodec && abs(seek_pts-this->cur_pts) > 300000) {
off_t pos, size;
pos = this->input->get_current_pos(this->input);
@@ -899,4 +908,3 @@ const plugin_info_t xine_plugin_info[] EXPORTED = {
{ PLUGIN_DEMUX, 27, "flashvideo", XINE_VERSION_CODE, &demux_info_flv, init_plugin },
{ PLUGIN_NONE, 0, "", 0, NULL, NULL }
};
-
diff --git a/src/demuxers/demux_matroska.c b/src/demuxers/demux_matroska.c
index 4a99492ef..ec932aacb 100644
--- a/src/demuxers/demux_matroska.c
+++ b/src/demuxers/demux_matroska.c
@@ -1303,6 +1303,8 @@ static int parse_track_entry(demux_matroska_t *this, matroska_track_t *track) {
_x_bmiheader_le2me(bih);
track->buf_type = _x_fourcc_to_buf_video(bih->biCompression);
+ if (!track->buf_type)
+ _x_report_video_fourcc (this->stream->xine, LOG_MODULE, bih->biCompression);
init_codec = init_codec_video;
} else if (!strcmp(track->codec_id, MATROSKA_CODEC_ID_V_UNCOMPRESSED)) {
@@ -1413,6 +1415,8 @@ static int parse_track_entry(demux_matroska_t *this, matroska_track_t *track) {
_x_waveformatex_le2me(wfh);
track->buf_type = _x_formattag_to_buf_audio(wfh->wFormatTag);
+ if (!track->buf_type)
+ _x_report_audio_format_tag (this->stream->xine, LOG_MODULE, 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)) {
@@ -1829,11 +1833,20 @@ static int read_block_data (demux_matroska_t *this, int len) {
return 1;
}
+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, uint64_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;
@@ -1842,17 +1855,18 @@ static int parse_block (demux_matroska_t *this, uint64_t block_size,
int decoder_flags = 0;
data = this->block_data;
- if (!(num_len = parse_ebml_sint(this, data, &track_num)))
+ 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 = 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;
@@ -1860,7 +1874,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;
}
@@ -1969,24 +1983,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_sint(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];
}
diff --git a/src/demuxers/demux_mpgaudio.c b/src/demuxers/demux_mpgaudio.c
index 27ee7f56b..6eb4ee622 100644
--- a/src/demuxers/demux_mpgaudio.c
+++ b/src/demuxers/demux_mpgaudio.c
@@ -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
@@ -64,6 +64,7 @@
/* Xing header stuff */
#define XING_TAG FOURCC_TAG('X', 'i', 'n', 'g')
+#define INFO_TAG FOURCC_TAG('I', 'n', 'f', 'o')
#define XING_FRAMES_FLAG 0x0001
#define XING_BYTES_FLAG 0x0002
#define XING_TOC_FLAG 0x0004
@@ -76,16 +77,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 */
@@ -124,7 +125,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 */
@@ -134,7 +141,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 */
@@ -205,14 +220,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");
@@ -233,14 +248,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;
}
@@ -273,19 +288,27 @@ static int parse_frame_header(mpg_audio_frame_t *const frame, const uint8_t *con
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;
}
@@ -295,16 +318,8 @@ static int parse_frame_header(mpg_audio_frame_t *const frame, const uint8_t *con
*/
static xing_header_t* parse_xing_header(mpg_audio_frame_t *frame,
uint8_t *buf, int bufsize) {
-
-#ifdef LOG
- int i;
-#endif
uint8_t *ptr = buf;
- xing_header_t *xing;
-
- xing = xine_xmalloc (sizeof (xing_header_t));
- if (!xing)
- return NULL;
+ xing_header_t *xing = NULL;
/* offset of the Xing header */
if (frame->lsf_bit) {
@@ -319,52 +334,87 @@ static xing_header_t* parse_xing_header(mpg_audio_frame_t *frame,
ptr += (9 + 4);
}
- if (ptr >= (buf + bufsize - 4)) return 0;
+ if (ptr >= (buf + bufsize - 4)) goto exit_error;
lprintf("checking %08X\n", *ptr);
+
if (_X_BE_32(ptr) == XING_TAG) {
- lprintf("Xing header found\n");
+ int has_frames_flag = 0;
+ int has_bytes_flag = 0;
+
+ xing = xine_xmalloc (sizeof (xing_header_t));
+ if (!xing)
+ goto exit_error;
+
+ lprintf("found Xing header\n");
ptr += 4;
- if (ptr >= (buf + bufsize - 4)) return 0;
+ if (ptr >= (buf + bufsize - 4)) goto exit_error;
xing->flags = _X_BE_32(ptr); ptr += 4;
if (xing->flags & XING_FRAMES_FLAG) {
- if (ptr >= (buf + bufsize - 4)) return 0;
+ if (ptr >= (buf + bufsize - 4)) goto exit_error;
xing->stream_frames = _X_BE_32(ptr); ptr += 4;
lprintf("stream frames: %d\n", xing->stream_frames);
+ has_frames_flag = 1;
}
if (xing->flags & XING_BYTES_FLAG) {
- if (ptr >= (buf + bufsize - 4)) return 0;
+ if (ptr >= (buf + bufsize - 4)) goto exit_error;
xing->stream_size = _X_BE_32(ptr); ptr += 4;
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");
+ goto exit_error;
+ }
+
if (xing->flags & XING_TOC_FLAG) {
+ int i;
+
lprintf("toc found\n");
- if (ptr >= (buf + bufsize - XING_TOC_LENGTH)) return 0;
+ if (ptr >= (buf + bufsize - XING_TOC_LENGTH)) goto exit_error;
memcpy(xing->toc, ptr, XING_TOC_LENGTH);
#ifdef LOG
for (i = 0; i < XING_TOC_LENGTH; i++) {
- lprintf("%d ", xing->toc[i]);
+ printf("%d ", xing->toc[i]);
}
- lprintf("\n");
+ printf("\n");
#endif
+ /* check the table validity
+ * - MUST start with 0
+ * - values MUST increase
+ */
+ if (xing->toc[0] != 0) {
+ lprintf("invalid Xing toc\n");
+ goto exit_error;
+ }
+ for (i = 1; i < XING_TOC_LENGTH; i++) {
+ if (xing->toc[i] < xing->toc[i-1]) {
+ lprintf("invalid Xing toc\n");
+ goto exit_error;
+ }
+ }
ptr += XING_TOC_LENGTH;
}
xing->vbr_scale = -1;
if (xing->flags & XING_VBR_SCALE_FLAG) {
- if (ptr >= (buf + bufsize - 4)) return 0;
+ if (ptr >= (buf + bufsize - 4)) goto exit_error;
xing->vbr_scale = _X_BE_32(ptr);
lprintf("vbr_scale: %d\n", xing->vbr_scale);
}
-
- return xing;
} else {
lprintf("Xing header not found\n");
+ }
+ return xing;
+
+exit_error:
+ lprintf("Xing header parse error\n");
free(xing);
return NULL;
}
-}
/*
* Parse a Vbri header
@@ -386,7 +436,7 @@ static vbri_header_t* parse_vbri_header(mpg_audio_frame_t *frame,
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;
@@ -450,6 +500,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
@@ -460,43 +511,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);
@@ -505,14 +610,13 @@ 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;
+ 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;
}
@@ -522,11 +626,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;
@@ -535,20 +640,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;
@@ -576,40 +682,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);
- }
-
- return parse_frame_payload(this, header_buf, decoder_flags);
-
- } else if ( id3v2_istag(_X_ME_32(header_buf)) ) {
- if (!id3v2_parse_tag(this->input, this->stream, _X_ME_32(header_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;
+ }
+ }
+ }
+
+ 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(_X_ME_32(header)) ) {
+ if (!id3v2_parse_tag(this->input, this->stream, _X_ME_32(header))) {
xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
LOG_MODULE ": ID3V2 tag parsing error\n");
bytes = 1; /* resync */
@@ -620,12 +737,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) {
@@ -672,12 +808,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;
@@ -701,15 +838,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;
}
@@ -748,11 +885,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;
@@ -763,7 +901,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;
@@ -806,7 +944,7 @@ static void demux_mpgaudio_send_headers (demux_plugin_t *this_gen) {
{
char scratch_buf[256];
static const char mpeg_ver[3][4] = {"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" );
@@ -919,7 +1057,7 @@ static int demux_mpgaudio_seek (demux_plugin_t *this_gen,
if (this->stream_length > 0) {
if (this->xing_header &&
- (this->xing_header->flags & (XING_TOC_FLAG | XING_BYTES_FLAG))) {
+ (this->xing_header->flags & XING_TOC_FLAG)) {
seek_pos += xing_get_seek_point(this->xing_header, start_time, this->stream_length);
lprintf("time seek: xing: time=%d, pos=%"PRId64"\n", start_time, seek_pos);
} else if (this->vbri_header) {
@@ -934,7 +1072,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);
}
@@ -969,13 +1108,15 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str
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;
@@ -987,7 +1128,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str
default:
return NULL;
}
-
+
this = xine_xmalloc (sizeof (demux_mpgaudio_t));
this->demux_plugin.send_headers = demux_mpgaudio_send_headers;
@@ -999,12 +1140,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;
}
diff --git a/src/demuxers/demux_nsv.c b/src/demuxers/demux_nsv.c
index 74f98c7cd..43b1fbc88 100644
--- a/src/demuxers/demux_nsv.c
+++ b/src/demuxers/demux_nsv.c
@@ -305,13 +305,21 @@ static int open_nsv_file(demux_nsv_t *this) {
if (_X_BE_32(&preview[4]) == NONE_TAG)
this->video_type = 0;
else
+ {
this->video_type = _x_fourcc_to_buf_video(this->video_fourcc);
+ if (!this->video_type)
+ _x_report_video_fourcc (this->stream->xine, LOG_MODULE, this->video_fourcc);
+ }
this->audio_fourcc = _X_ME_32(&preview[8]);
if (_X_BE_32(&preview[8]) == NONE_TAG)
this->audio_type = 0;
else
+ {
this->audio_type = _x_formattag_to_buf_audio(this->audio_fourcc);
+ if (!this->audio_type)
+ _x_report_audio_format_tag (this->stream->xine, LOG_MODULE, this->audio_fourcc);
+ }
this->bih.biSize = sizeof(this->bih);
this->bih.biWidth = _X_LE_16(&preview[12]);
diff --git a/src/demuxers/demux_qt.c b/src/demuxers/demux_qt.c
index 6b2aa5eea..ecd2c319a 100644
--- a/src/demuxers/demux_qt.c
+++ b/src/demuxers/demux_qt.c
@@ -2628,7 +2628,11 @@ static void demux_qt_send_headers(demux_plugin_t *this_gen) {
if( !video_trak->properties->video.codec_buftype &&
video_trak->properties->video.codec_fourcc )
+ {
video_trak->properties->video.codec_buftype = BUF_VIDEO_UNKNOWN;
+ _x_report_video_fourcc (this->stream->xine, LOG_MODULE,
+ video_trak->properties->video.codec_fourcc);
+ }
_x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, 1);
_x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH,
@@ -2670,7 +2674,11 @@ static void demux_qt_send_headers(demux_plugin_t *this_gen) {
if( !audio_trak->properties->audio.codec_buftype &&
audio_trak->properties->audio.codec_fourcc )
+ {
audio_trak->properties->audio.codec_buftype = BUF_AUDIO_UNKNOWN;
+ _x_report_audio_format_tag (this->stream->xine, LOG_MODULE,
+ audio_trak->properties->audio.codec_fourcc);
+ }
_x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, 1);
_x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_CHANNELS,
diff --git a/src/demuxers/demux_real.c b/src/demuxers/demux_real.c
index 21308bd45..41c6fb4a2 100644
--- a/src/demuxers/demux_real.c
+++ b/src/demuxers/demux_real.c
@@ -459,6 +459,9 @@ static void real_parse_headers (demux_real_t *this) {
this->num_audio_streams++;
+ if (!this->audio_streams[this->num_audio_streams].buf_type)
+ _x_report_audio_format_tag (this->stream->xine, LOG_MODULE, fourcc);
+
} else if(_X_BE_32(mdpr->type_specific_data + 4) == VIDO_TAG) {
if(this->num_video_streams == MAX_VIDEO_STREAMS) {
@@ -479,6 +482,9 @@ static void real_parse_headers (demux_real_t *this) {
this->num_video_streams++;
+ if (!this->video_streams[this->num_video_streams].buf_type)
+ _x_report_video_fourcc (this->stream->xine, LOG_MODULE, fourcc);
+
} else {
lprintf("unrecognised type specific data\n");
@@ -800,12 +806,22 @@ static int demux_real_parse_references( demux_real_t *this) {
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)
{
diff --git a/src/demuxers/demux_smjpeg.c b/src/demuxers/demux_smjpeg.c
index 10cdf8120..d9b436032 100644
--- a/src/demuxers/demux_smjpeg.c
+++ b/src/demuxers/demux_smjpeg.c
@@ -147,6 +147,8 @@ static int open_smjpeg_file(demux_smjpeg_t *this) {
this->bih.biHeight = _X_BE_16(&header_chunk[10]);
this->bih.biCompression = *(uint32_t *)&header_chunk[12];
this->video_type = _x_fourcc_to_buf_video(this->bih.biCompression);
+ if (!this->video_type)
+ _x_report_video_fourcc (this->stream->xine, LOG_MODULE, this->bih.biCompression);
break;
case _SND_TAG:
@@ -166,6 +168,8 @@ static int open_smjpeg_file(demux_smjpeg_t *this) {
} else {
audio_codec = *(uint32_t *)&header_chunk[8];
this->audio_type = _x_formattag_to_buf_audio(audio_codec);
+ if (!this->audio_type)
+ _x_report_audio_format_tag (this->stream->xine, LOG_MODULE, audio_codec);
}
break;
diff --git a/src/demuxers/demux_ts.c b/src/demuxers/demux_ts.c
index 9de28aacc..5d85a5597 100644
--- a/src/demuxers/demux_ts.c
+++ b/src/demuxers/demux_ts.c
@@ -1175,6 +1175,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
diff --git a/src/demuxers/ebml.c b/src/demuxers/ebml.c
index 772b848eb..41a91371e 100644
--- a/src/demuxers/ebml.c
+++ b/src/demuxers/ebml.c
@@ -234,6 +234,7 @@ int ebml_read_uint(ebml_parser_t *ebml, ebml_elem_t *elem, uint64_t *num) {
return 1;
}
+#if 0
int ebml_read_sint (ebml_parser_t *ebml, ebml_elem_t *elem, int64_t *num) {
uint8_t data[8];
uint64_t size = elem->len;
@@ -260,6 +261,7 @@ int ebml_read_sint (ebml_parser_t *ebml, ebml_elem_t *elem, int64_t *num) {
return 1;
}
+#endif
int ebml_read_float (ebml_parser_t *ebml, ebml_elem_t *elem, double *num) {
@@ -304,6 +306,7 @@ int ebml_read_ascii(ebml_parser_t *ebml, ebml_elem_t *elem, char *str) {
return 1;
}
+#if 0
int ebml_read_utf8 (ebml_parser_t *ebml, ebml_elem_t *elem, char *str) {
return ebml_read_ascii (ebml, elem, str);
}
@@ -311,6 +314,7 @@ int ebml_read_utf8 (ebml_parser_t *ebml, ebml_elem_t *elem, char *str) {
int ebml_read_date (ebml_parser_t *ebml, ebml_elem_t *elem, int64_t *date) {
return ebml_read_sint (ebml, elem, date);
}
+#endif
int ebml_read_master (ebml_parser_t *ebml, ebml_elem_t *elem) {
ebml_elem_t *top_elem;
diff --git a/src/demuxers/ebml.h b/src/demuxers/ebml.h
index 7ebd68da2..31d825e35 100644
--- a/src/demuxers/ebml.h
+++ b/src/demuxers/ebml.h
@@ -83,15 +83,19 @@ int ebml_skip(ebml_parser_t *ebml, ebml_elem_t *elem);
/* EBML types */
int ebml_read_uint(ebml_parser_t *ebml, ebml_elem_t *elem, uint64_t *val);
+#if 0
int ebml_read_sint(ebml_parser_t *ebml, ebml_elem_t *elem, int64_t *val);
+#endif
int ebml_read_float(ebml_parser_t *ebml, ebml_elem_t *elem, double *val);
int ebml_read_ascii(ebml_parser_t *ebml, ebml_elem_t *elem, char *str);
+#if 0
int ebml_read_utf8(ebml_parser_t *ebml, ebml_elem_t *elem, char *str);
int ebml_read_date(ebml_parser_t *ebml, ebml_elem_t *elem, int64_t *date);
+#endif
int ebml_read_master(ebml_parser_t *ebml, ebml_elem_t *elem);
diff --git a/src/demuxers/id3.c b/src/demuxers/id3.c
index b9bb75744..71cb5e743 100644
--- a/src/demuxers/id3.c
+++ b/src/demuxers/id3.c
@@ -341,21 +341,21 @@ 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);
+ 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");
+ 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");
+ LOG_MODULE ": unsynchronized tags are not supported\n");
input->seek (input, tag_header.size - pos, SEEK_CUR);
return 0;
}
@@ -367,11 +367,11 @@ int id3v22_parse_tag(input_plugin_t *input,
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");
+ LOG_MODULE ": invalid frame content\n");
}
} else {
xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
- "id3: invalid frame header\n");
+ LOG_MODULE ": invalid frame header\n");
input->seek (input, tag_header.size - pos, SEEK_CUR);
return 1;
}
@@ -383,13 +383,13 @@ int id3v22_parse_tag(input_plugin_t *input,
}
} else {
xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
- "id3: id3v2_parse_frame_header problem\n");
+ 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;
}
}
@@ -527,14 +527,14 @@ 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);
+ 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");
+ LOG_MODULE ": unsynchronized tags are not supported\n");
input->seek (input, tag_header.size - pos, SEEK_CUR);
return 0;
}
@@ -543,6 +543,7 @@ 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) {
@@ -552,29 +553,30 @@ int id3v23_parse_tag(input_plugin_t *input,
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");
+ LOG_MODULE ": invalid frame content\n");
}
} else {
xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
- "id3: invalid frame header\n");
+ 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 %d 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");
+ 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;
}
}
@@ -770,7 +772,7 @@ 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);
+ LOG_MODULE ": invalid header flags (%02x)\n", tag_header.flags);
input->seek (input, tag_header.size - pos, SEEK_CUR);
return 0;
}
@@ -785,6 +787,7 @@ 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) {
@@ -794,11 +797,11 @@ int id3v24_parse_tag(input_plugin_t *input,
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");
+ LOG_MODULE ": invalid frame content\n");
}
} else {
xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
- "id3: invalid frame header\n");
+ LOG_MODULE ": invalid frame header\n");
input->seek (input, tag_header.size - pos, SEEK_CUR);
return 1;
}
@@ -810,7 +813,7 @@ int id3v24_parse_tag(input_plugin_t *input,
}
} else {
xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
- "id3: id3v2_parse_frame_header problem\n");
+ LOG_MODULE ": id3v2_parse_frame_header problem\n");
return 0;
}
}
@@ -820,7 +823,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;
}
}
@@ -832,19 +835,19 @@ int id3v2_parse_tag(input_plugin_t *input,
switch(id3_signature) {
case ID3V22_TAG:
- xprintf(stream->xine, XINE_VERBOSITY_LOG, "ID3V2.2 tag\n");
+ xprintf(stream->xine, XINE_VERBOSITY_LOG, LOG_MODULE ": ID3V2.2 tag\n");
return id3v22_parse_tag(input, stream, id3_signature);
case ID3V23_TAG:
- xprintf(stream->xine, XINE_VERBOSITY_LOG, "ID3V2.3 tag\n");
+ xprintf(stream->xine, XINE_VERBOSITY_LOG, LOG_MODULE ": ID3V2.3 tag\n");
return id3v23_parse_tag(input, stream, id3_signature);
case ID3V24_TAG:
- xprintf(stream->xine, XINE_VERBOSITY_LOG, "ID3V2.4 tag\n");
+ xprintf(stream->xine, XINE_VERBOSITY_LOG, LOG_MODULE ": ID3V2.4 tag\n");
return id3v24_parse_tag(input, stream, id3_signature);
default:
- xprintf(stream->xine, XINE_VERBOSITY_LOG, "Unknown ID3v2 signature: 0x%08x.\n", be2me_32(id3_signature));
+ xprintf(stream->xine, XINE_VERBOSITY_LOG, LOG_MODULE ": Unknown ID3v2 signature: 0x%08x.\n", be2me_32(id3_signature));
}
return 0;