summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThibaut Mattern <tmattern@users.sourceforge.net>2006-09-07 07:21:06 +0000
committerThibaut Mattern <tmattern@users.sourceforge.net>2006-09-07 07:21:06 +0000
commit045444a964c3b8d84142697bbcc98db3d959a0db (patch)
tree298c1254342efb5ee2c917cb44878c26b0b219a4 /src
parente2426a05a8fa7417093f8b2522210f635a0cbeca (diff)
downloadxine-lib-045444a964c3b8d84142697bbcc98db3d959a0db.tar.gz
xine-lib-045444a964c3b8d84142697bbcc98db3d959a0db.tar.bz2
Added common asf header parser.
Modified the mms input plugins and the asf demuxer to use the new parser. Added Asf Extended Header parsing, fixed best stream selection. CVS patchset: 8203 CVS date: 2006/09/07 07:21:06
Diffstat (limited to 'src')
-rw-r--r--src/demuxers/Makefile.am2
-rw-r--r--src/demuxers/asfheader.c806
-rw-r--r--src/demuxers/asfheader.h663
-rw-r--r--src/demuxers/demux_asf.c720
-rw-r--r--src/input/Makefile.am2
-rw-r--r--src/input/mms.c281
-rw-r--r--src/input/mmsh.c336
7 files changed, 1571 insertions, 1239 deletions
diff --git a/src/demuxers/Makefile.am b/src/demuxers/Makefile.am
index b7904e54b..228cb08e1 100644
--- a/src/demuxers/Makefile.am
+++ b/src/demuxers/Makefile.am
@@ -90,7 +90,7 @@ xineplug_dmx_qt_la_LIBADD = $(XINE_LIB) $(ZLIB_LIBS)
xineplug_dmx_qt_la_CFLAGS = $(VISIBILITY_FLAG) $(AM_CFLAGS)
xineplug_dmx_qt_la_LDFLAGS = -avoid-version -module
-xineplug_dmx_asf_la_SOURCES = demux_asf.c
+xineplug_dmx_asf_la_SOURCES = demux_asf.c asfheader.c
xineplug_dmx_asf_la_LIBADD = $(XINE_LIB)
xineplug_dmx_asf_la_CFLAGS = $(VISIBILITY_FLAG) $(AM_CFLAGS) -fno-strict-aliasing
xineplug_dmx_asf_la_LDFLAGS = -avoid-version -module
diff --git a/src/demuxers/asfheader.c b/src/demuxers/asfheader.c
new file mode 100644
index 000000000..62220e225
--- /dev/null
+++ b/src/demuxers/asfheader.c
@@ -0,0 +1,806 @@
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#define LOG_MODULE "asfheader"
+#define LOG_VERBOSE
+/*
+#define LOG
+*/
+#include "bswap.h"
+#include "asfheader.h"
+
+typedef struct asf_header_internal_s asf_header_internal_t;
+struct asf_header_internal_s {
+ asf_header_t pub;
+
+ /* private part */
+ int number_count;
+ uint16_t numbers[ASF_MAX_NUM_STREAMS];
+ iconv_t iconv_cd;
+ uint8_t *bitrate_pointers[ASF_MAX_NUM_STREAMS];
+};
+
+
+typedef struct asf_reader_s asf_reader_t;
+struct asf_reader_s {
+ uint8_t *buffer;
+ size_t pos;
+ size_t size;
+};
+
+
+static void asf_reader_init(asf_reader_t *reader, uint8_t *buffer, int size) {
+ reader->buffer = buffer;
+ reader->pos = 0;
+ reader->size = size;
+}
+
+static int asf_reader_get_8(asf_reader_t *reader, uint8_t *value) {
+ if ((reader->size - reader->pos) < 1)
+ return 0;
+ *value = *(reader->buffer + reader->pos);
+ reader->pos += 1;
+ return 1;
+}
+
+static int asf_reader_get_16(asf_reader_t *reader, uint16_t *value) {
+ if ((reader->size - reader->pos) < 2)
+ return 0;
+ *value = LE_16(reader->buffer + reader->pos);
+ reader->pos += 2;
+ return 1;
+}
+
+static int asf_reader_get_32(asf_reader_t *reader, uint32_t *value) {
+ if ((reader->size - reader->pos) < 4)
+ return 0;
+ *value = LE_32(reader->buffer + reader->pos);
+ reader->pos += 4;
+ return 1;
+}
+
+static int asf_reader_get_64(asf_reader_t *reader, uint64_t *value) {
+ if ((reader->size - reader->pos) < 8)
+ return 0;
+ *value = LE_64(reader->buffer + reader->pos);
+ reader->pos += 8;
+ return 1;
+}
+
+static int asf_reader_get_guid(asf_reader_t *reader, GUID *value) {
+ if ((reader->size - reader->pos) < 16)
+ return 0;
+
+ asf_get_guid(reader->buffer + reader->pos, value);
+ reader->pos += 16;
+ return 1;
+}
+
+static uint8_t *asf_reader_get_bytes(asf_reader_t *reader, size_t size) {
+ uint8_t *buffer;
+
+ if ((reader->size - reader->pos) < size)
+ return NULL;
+ buffer = malloc(size);
+ if (!buffer)
+ return NULL;
+ memcpy(buffer, reader->buffer + reader->pos, size);
+ reader->pos += size;
+ return buffer;
+}
+
+/* get an utf8 string */
+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];
+
+ if ((reader->size - reader->pos) < size)
+ return NULL;
+
+ inbuf = (char *)reader->buffer + reader->pos;
+ inbytesleft = size;
+ outbuf = scratch;
+ outbytesleft = sizeof(scratch);
+ reader->pos += size;
+ if (iconv (cd, (char **)&inbuf, &inbytesleft, &outbuf, &outbytesleft) != -1) {
+ return strdup(scratch);
+ } else {
+ lprintf("iconv error\n");
+ return NULL;
+ }
+}
+
+static int asf_reader_skip(asf_reader_t *reader, size_t size) {
+ if ((reader->size - reader->pos) < size) {
+ reader->pos = reader->size;
+ return 0;
+ }
+ reader->pos += size;
+ return size;
+}
+
+static uint8_t *asf_reader_get_buffer(asf_reader_t *reader) {
+ return (reader->buffer + reader->pos);
+}
+
+static int asf_reader_eos(asf_reader_t *reader) {
+ if (reader->pos < reader->size)
+ return 0;
+ else
+ return 1;
+}
+
+static size_t asf_reader_get_size(asf_reader_t *reader) {
+ return reader->size - reader->pos;
+}
+
+void asf_get_guid(uint8_t *buffer, GUID *value) {
+ int i;
+
+ value->Data1 = LE_32(buffer);
+ value->Data2 = LE_16(buffer + 4);
+ value->Data3 = LE_16(buffer + 6);
+ for(i = 0; i < 8; i++) {
+ value->Data4[i] = *(buffer + i + 8);
+ }
+}
+
+int asf_find_object_id (GUID *g) {
+ int i;
+
+ for (i = 1; i < GUID_END; i++) {
+ if (!memcmp(g, &guids[i].guid, sizeof(GUID))) {
+ lprintf ("asf_find_object_id: %s\n", guids[i].name);
+ return i;
+ }
+ }
+ lprintf ("asf_find_object_id: unknown GUID: 0x%04X, 0x%02X, 0x%02X, {0x%01X, 0x%01X, 0x%01X, 0x%01X, 0x%01X, 0x%01X, 0x%01X, 0x%01X}\n",
+ g->Data1, g->Data2, g->Data3, g->Data4[0], g->Data4[1], g->Data4[2], g->Data4[3], g->Data4[4], g->Data4[5], g->Data4[6], g->Data4[7]);
+ return GUID_ERROR;
+}
+
+/* Manage id mapping */
+int asf_header_get_stream_id(asf_header_t *header_pub, uint16_t stream_number) {
+ asf_header_internal_t *header = (asf_header_internal_t *)header_pub;
+ int i;
+
+ /* linear search */
+ for (i = 0; i < header->number_count; i++) {
+ if (stream_number == header->numbers[i]) {
+ lprintf("asf_header_get_stream_id: id found: %d\n", i);
+ return i;
+ }
+ }
+
+ /* not found */
+ if (header->number_count >= ASF_MAX_NUM_STREAMS)
+ return -1;
+
+ header->numbers[header->number_count] = stream_number;
+ header->number_count++;
+ return header->number_count - 1;
+}
+
+int asf_header_parse_file_properties(asf_header_t *header, uint8_t *buffer, int buffer_len) {
+ asf_reader_t reader;
+ asf_file_t *asf_file;
+ uint32_t flags;
+
+ if (buffer_len < 80) {
+ lprintf("invalid asf file properties object\n");
+ return 0;
+ }
+
+ asf_file = malloc(sizeof(asf_file_t));
+ if (!asf_file) {
+ lprintf("cannot allocate asf_file_struct\n");
+ return 0;
+ }
+
+ asf_reader_init(&reader, buffer, buffer_len);
+
+ asf_reader_get_guid(&reader, &asf_file->file_id);
+ asf_reader_get_64(&reader, &asf_file->file_size);
+
+ /* creation date */
+ asf_reader_skip(&reader, 8);
+ asf_reader_get_64(&reader, &asf_file->data_packet_count);
+ asf_reader_get_64(&reader, &asf_file->play_duration);
+ asf_reader_get_64(&reader, &asf_file->send_duration);
+ asf_reader_get_64(&reader, &asf_file->preroll);
+
+ asf_reader_get_32(&reader, &flags);
+ asf_reader_get_32(&reader, &asf_file->packet_size);
+
+ /* duplicated packet size */
+ asf_reader_skip(&reader, 4);
+ asf_reader_get_32(&reader, &asf_file->max_bitrate);
+
+ asf_file->broadcast_flag = flags & 0x1;
+ asf_file->seekable_flag = flags & 0x2;
+
+ header->file = asf_file;
+
+ lprintf("File properties\n");
+ lprintf(" file_id: %04X\n", asf_file->file_id.Data1);
+ lprintf(" file_size: %"PRIu64"\n", asf_file->file_size);
+ lprintf(" data_packet_count: %"PRIu64"\n", asf_file->data_packet_count);
+ lprintf(" play_duration: %"PRIu64"\n", asf_file->play_duration);
+ lprintf(" send_duration: %"PRIu64"\n", asf_file->send_duration);
+ lprintf(" preroll: %"PRIu64"\n", asf_file->preroll);
+ lprintf(" broadcast_flag: %d\n", asf_file->broadcast_flag);
+ lprintf(" seekable_flag: %d\n", asf_file->seekable_flag);
+ lprintf(" packet_size: %"PRIu32"\n", asf_file->packet_size);
+ lprintf(" max_bitrate: %"PRIu32"\n", asf_file->max_bitrate);
+ return 1;
+}
+
+int asf_header_parse_stream_properties(asf_header_t *header, uint8_t *buffer, int buffer_len) {
+ asf_reader_t reader;
+ uint16_t flags;
+ uint32_t junk;
+ GUID guid;
+ asf_stream_t *asf_stream = NULL;
+ int stream_id;
+
+ if (buffer_len < 54)
+ goto exit_error;
+
+ asf_stream = malloc(sizeof(asf_stream_t));
+ if (!asf_stream)
+ goto exit_error;
+
+ asf_reader_init(&reader, buffer, buffer_len);
+
+ asf_reader_get_guid(&reader, &guid);
+ asf_stream->stream_type = asf_find_object_id(&guid);
+ asf_reader_get_guid(&reader, &guid);
+ asf_stream->error_correction_type = asf_find_object_id(&guid);
+
+ asf_reader_get_64(&reader, &asf_stream->time_offset);
+ asf_reader_get_32(&reader, &asf_stream->private_data_length);
+ asf_reader_get_32(&reader, &asf_stream->error_correction_data_length);
+
+ asf_reader_get_16(&reader, &flags);
+ asf_stream->stream_number = flags & 0x7F;
+ asf_stream->encrypted_flag = flags >> 15;
+
+ asf_reader_get_32(&reader, &junk);
+
+ asf_stream->private_data = asf_reader_get_bytes(&reader, asf_stream->private_data_length);
+ if (!asf_stream->private_data)
+ goto exit_error;
+
+ asf_stream->error_correction_data = asf_reader_get_bytes(&reader, asf_stream->error_correction_data_length);
+ if (!asf_stream->error_correction_data)
+ goto exit_error;
+
+ lprintf("Stream_properties\n");
+ lprintf(" stream_number: %d\n", asf_stream->stream_number);
+ lprintf(" stream_type: %s\n", guids[asf_stream->stream_type].name);
+ lprintf(" error_correction_type: %s\n", guids[asf_stream->error_correction_type].name);
+ lprintf(" time_offset: %"PRIu64"\n", asf_stream->time_offset);
+ lprintf(" private_data_length: %"PRIu32"\n", asf_stream->private_data_length);
+ lprintf(" error_correction_data_length: %"PRIu32"\n", asf_stream->error_correction_data_length);
+ lprintf(" encrypted_flag: %d\n", asf_stream->encrypted_flag);
+
+ stream_id = asf_header_get_stream_id(header, asf_stream->stream_number);
+ if (stream_id >= 0) {
+ header->streams[stream_id] = asf_stream;
+ header->stream_count++;
+ }
+ return 1;
+
+exit_error:
+ if (asf_stream) {
+ if (asf_stream->private_data)
+ free(asf_stream->private_data);
+ if (asf_stream->error_correction_data)
+ free(asf_stream->error_correction_data);
+ free(asf_stream);
+ }
+ return 0;
+}
+
+int asf_header_parse_stream_extended_properties(asf_header_t *header, uint8_t *buffer, int buffer_len) {
+ asf_reader_t reader;
+ uint32_t flags;
+ uint16_t stream_number;
+ int i;
+ int stream_id;
+
+ if (buffer_len < 64)
+ return 0;
+
+ asf_stream_extension_t *asf_stream_extension = malloc(sizeof(asf_stream_extension_t));
+ if (!asf_stream_extension)
+ return 0;
+
+ asf_reader_init(&reader, buffer, buffer_len);
+
+ asf_reader_get_64(&reader, &asf_stream_extension->start_time);
+ asf_reader_get_64(&reader, &asf_stream_extension->end_time);
+
+ asf_reader_get_32(&reader, &asf_stream_extension->data_bitrate);
+ asf_reader_get_32(&reader, &asf_stream_extension->buffer_size);
+ asf_reader_get_32(&reader, &asf_stream_extension->initial_buffer_fullness);
+ asf_reader_get_32(&reader, &asf_stream_extension->alternate_data_bitrate);
+ asf_reader_get_32(&reader, &asf_stream_extension->alternate_buffer_size);
+ asf_reader_get_32(&reader, &asf_stream_extension->alternate_initial_buffer_fullness);
+ asf_reader_get_32(&reader, &asf_stream_extension->max_object_size);
+
+ /* 4 flags */
+ asf_reader_get_32(&reader, &flags);
+ asf_stream_extension->reliable_flag = flags & 1;
+ asf_stream_extension->seekable_flag = (flags >> 1) & 1;
+ asf_stream_extension->no_cleanpoints_flag = (flags >> 2) & 1;
+ asf_stream_extension->resend_live_cleanpoints_flag = (flags >> 3) & 1;
+
+ asf_reader_get_16(&reader, &stream_number);
+
+ asf_reader_get_16(&reader, &asf_stream_extension->language_id);
+ asf_reader_get_64(&reader, &asf_stream_extension->average_time_per_frame);
+
+ asf_reader_get_16(&reader, &asf_stream_extension->stream_name_count);
+ asf_reader_get_16(&reader, &asf_stream_extension->payload_extension_system_count);
+
+ /* get stream names */
+ 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;
+ 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 */
+ }
+ }
+
+ /* skip payload extensions */
+ if (asf_stream_extension->payload_extension_system_count) {
+ for (i = 0; i < asf_stream_extension->payload_extension_system_count; i++) {
+ GUID guid;
+ uint16_t data_size;
+ uint32_t length;
+ asf_reader_get_guid(&reader, &guid);
+ asf_reader_get_16(&reader, &data_size);
+ asf_reader_get_32(&reader, &length);
+ asf_reader_skip(&reader, length);
+ }
+ }
+
+ stream_id = asf_header_get_stream_id(header, stream_number);
+ if (stream_id >= 0) {
+ header->stream_extensions[stream_id] = asf_stream_extension;
+ }
+
+ /* embeded stream properties */
+ if (asf_reader_get_size(&reader) >= 24) {
+ GUID guid;
+ uint64_t object_length;
+
+ asf_reader_get_guid(&reader, &guid);
+ asf_reader_get_64(&reader, &object_length);
+
+ /* check length validity */
+ if (asf_reader_get_size(&reader) == (object_length - 24)) {
+ int object_id = asf_find_object_id(&guid);
+ switch (object_id) {
+ case GUID_ASF_STREAM_PROPERTIES:
+ asf_header_parse_stream_properties(header, asf_reader_get_buffer(&reader), object_length - 24);
+ break;
+ default:
+ lprintf ("unexpected object\n");
+ break;
+ }
+ } else {
+ lprintf ("invalid object length\n");
+ }
+ }
+
+ lprintf("Stream extension properties\n");
+ lprintf(" stream_number: %"PRIu16"\n", stream_number);
+ lprintf(" start_time: %"PRIu64"\n", asf_stream_extension->start_time);
+ lprintf(" end_time: %"PRIu64"\n", asf_stream_extension->end_time);
+ lprintf(" data_bitrate: %"PRIu32"\n", asf_stream_extension->data_bitrate);
+ lprintf(" buffer_size: %"PRIu32"\n", asf_stream_extension->buffer_size);
+ lprintf(" initial_buffer_fullness: %"PRIu32"\n", asf_stream_extension->initial_buffer_fullness);
+ lprintf(" alternate_data_bitrate: %"PRIu32"\n", asf_stream_extension->alternate_data_bitrate);
+ lprintf(" alternate_buffer_size: %"PRIu32"\n", asf_stream_extension->alternate_buffer_size);
+ lprintf(" alternate_initial_buffer_fullness: %"PRIu32"\n", asf_stream_extension->alternate_initial_buffer_fullness);
+ lprintf(" max_object_size: %"PRIu32"\n", asf_stream_extension->max_object_size);
+ lprintf(" language_id: %"PRIu16"\n", asf_stream_extension->language_id);
+ lprintf(" average_time_per_frame: %"PRIu64"\n", asf_stream_extension->average_time_per_frame);
+ lprintf(" stream_name_count: %"PRIu16"\n", asf_stream_extension->stream_name_count);
+ lprintf(" payload_extension_system_count: %"PRIu16"\n", asf_stream_extension->payload_extension_system_count);
+ lprintf(" reliable_flag: %d\n", asf_stream_extension->reliable_flag);
+ lprintf(" seekable_flag: %d\n", asf_stream_extension->seekable_flag);
+ lprintf(" no_cleanpoints_flag: %d\n", asf_stream_extension->no_cleanpoints_flag);
+ lprintf(" resend_live_cleanpoints_flag: %d\n", asf_stream_extension->resend_live_cleanpoints_flag);
+
+ return 1;
+}
+
+int asf_header_parse_stream_bitrate_properties(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 bitrate_count;
+ int i;
+ int stream_id;
+
+ if (buffer_len < 2)
+ return 0;
+
+ asf_reader_init(&reader, buffer, buffer_len);
+ asf_reader_get_16(&reader, &bitrate_count);
+
+ if (buffer_len < (2 + 6 * bitrate_count))
+ return 0;
+
+ lprintf (" bitrate count: %d\n", bitrate_count);
+
+ for(i = 0; i < bitrate_count; i++) {
+ uint16_t flags;
+ uint32_t bitrate;
+ int stream_number;
+ uint8_t *bitrate_pointer;
+
+ asf_reader_get_16(&reader, &flags);
+ stream_number = flags & 0x7f;
+
+ bitrate_pointer = asf_reader_get_buffer(&reader);
+ asf_reader_get_32(&reader, &bitrate);
+ lprintf (" stream num %d, bitrate %"PRIu32"\n", stream_number, bitrate);
+
+ stream_id = asf_header_get_stream_id(&header->pub, stream_number);
+ if (stream_id >= 0) {
+ header->pub.bitrates[stream_id] = bitrate;
+ header->bitrate_pointers[stream_id] = bitrate_pointer;
+ }
+ }
+ return 1;
+}
+
+int asf_header_parse_header_extension(asf_header_t *header, uint8_t *buffer, int buffer_len) {
+ asf_reader_t reader;
+
+ GUID junk1;
+ uint16_t junk2;
+ uint32_t data_length;
+
+ if (buffer_len < 22)
+ return 0;
+
+ asf_reader_init(&reader, buffer, buffer_len);
+
+ asf_reader_get_guid(&reader, &junk1);
+ asf_reader_get_16(&reader, &junk2);
+ asf_reader_get_32(&reader, &data_length);
+
+ lprintf("parse_asf_header_extension: length: %"PRIu32"\n", data_length);
+
+ while (!asf_reader_eos(&reader)) {
+
+ GUID guid;
+ int object_id;
+ uint64_t object_length, object_data_length;
+
+ if (asf_reader_get_size(&reader) < 24) {
+ printf("invalid buffer size\n");
+ return 0;
+ }
+
+ asf_reader_get_guid(&reader, &guid);
+ asf_reader_get_64(&reader, &object_length);
+
+ object_data_length = object_length - 24;
+ object_id = asf_find_object_id(&guid);
+ switch (object_id) {
+ case GUID_EXTENDED_STREAM_PROPERTIES:
+ asf_header_parse_stream_extended_properties(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:
+ case GUID_TIMECODE_INDEX_PARAMETERS:
+ case GUID_ADVANCED_CONTENT_ENCRYPTION:
+ case GUID_COMPATIBILITY:
+ case GUID_ASF_PADDING:
+ break;
+ default:
+ lprintf ("unexpected object\n");
+ break;
+ }
+ asf_reader_skip(&reader, object_data_length);
+ }
+ return 1;
+}
+
+int asf_header_parse_content_description(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;
+ asf_content_t *content;
+ uint16_t title_length, author_length, copyright_length, description_length, rating_length;
+
+ if (buffer_len < 10)
+ return 0;
+
+ content = malloc(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);
+ asf_reader_get_16(&reader, &author_length);
+ asf_reader_get_16(&reader, &copyright_length);
+ asf_reader_get_16(&reader, &description_length);
+ asf_reader_get_16(&reader, &rating_length);
+
+ content->title = asf_reader_get_string(&reader, title_length, header->iconv_cd);
+ content->author = asf_reader_get_string(&reader, author_length, header->iconv_cd);
+ content->copyright = asf_reader_get_string(&reader, copyright_length, header->iconv_cd);
+ content->description = asf_reader_get_string(&reader, description_length, header->iconv_cd);
+ content->rating = asf_reader_get_string(&reader, rating_length, header->iconv_cd);
+
+ header->pub.content = content;
+ return 1;
+}
+
+
+asf_header_t *asf_header_new (uint8_t *buffer, int buffer_len) {
+
+ asf_header_internal_t *asf_header;
+ asf_reader_t reader;
+ uint32_t object_count;
+ uint16_t junk;
+
+ asf_header = malloc(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) {
+ printf("invalid buffer size\n");
+ free(asf_header);
+ return NULL;
+ }
+
+ asf_header->iconv_cd = iconv_open ("UTF-8", "UCS-2LE");
+ if (asf_header->iconv_cd == (iconv_t)-1) {
+ printf("iconv open error\n");
+ free(asf_header);
+ return NULL;
+ }
+
+ asf_reader_init(&reader, buffer, buffer_len);
+ asf_reader_get_32(&reader, &object_count);
+ asf_reader_get_16(&reader, &junk);
+
+ while (!asf_reader_eos(&reader)) {
+
+ GUID guid;
+ int object_id;
+ uint64_t object_length, object_data_length;
+
+ if (asf_reader_get_size(&reader) < 24) {
+ printf("invalid buffer size\n");
+ goto exit_error;
+ }
+
+ asf_reader_get_guid(&reader, &guid);
+ asf_reader_get_64(&reader, &object_length);
+
+ object_data_length = object_length - 24;
+
+ object_id = asf_find_object_id(&guid);
+ switch (object_id) {
+
+ case GUID_ASF_FILE_PROPERTIES:
+ asf_header_parse_file_properties(&asf_header->pub, asf_reader_get_buffer(&reader), object_data_length);
+ break;
+
+ case GUID_ASF_STREAM_PROPERTIES:
+ asf_header_parse_stream_properties(&asf_header->pub, asf_reader_get_buffer(&reader), object_data_length);
+ break;
+
+ case GUID_ASF_STREAM_BITRATE_PROPERTIES:
+ asf_header_parse_stream_bitrate_properties(&asf_header->pub, asf_reader_get_buffer(&reader), object_data_length);
+ break;
+
+ case GUID_ASF_HEADER_EXTENSION:
+ asf_header_parse_header_extension(&asf_header->pub, asf_reader_get_buffer(&reader), object_data_length);
+ break;
+
+ case GUID_ASF_CONTENT_DESCRIPTION:
+ asf_header_parse_content_description(&asf_header->pub, asf_reader_get_buffer(&reader), object_data_length);
+ break;
+
+ case GUID_ASF_CODEC_LIST:
+ case GUID_ASF_SCRIPT_COMMAND:
+ case GUID_ASF_MARKER:
+ case GUID_ASF_BITRATE_MUTUAL_EXCLUSION:
+ case GUID_ASF_ERROR_CORRECTION:
+ case GUID_ASF_EXTENDED_CONTENT_DESCRIPTION:
+ case GUID_ASF_EXTENDED_CONTENT_ENCRYPTION:
+ case GUID_ASF_PADDING:
+ break;
+
+ default:
+ lprintf ("unexpected object\n");
+ break;
+ }
+ asf_reader_skip(&reader, object_data_length);
+ }
+
+ /* basic checks */
+ if (!asf_header->pub.file) {
+ lprintf("no file object present\n");
+ goto exit_error;
+ }
+ if (!asf_header->pub.content) {
+ lprintf("no content object present\n");
+ asf_header->pub.content = malloc(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;
+
+exit_error:
+ asf_header_delete(&asf_header->pub);
+ return NULL;
+}
+
+
+void asf_header_delete_file_properties(asf_file_t *asf_file) {
+ free(asf_file);
+}
+
+void asf_header_delete_content(asf_content_t *asf_content) {
+ if (asf_content->title)
+ free(asf_content->title);
+ if (asf_content->author)
+ free(asf_content->author);
+ if (asf_content->copyright)
+ free(asf_content->copyright);
+ if (asf_content->description)
+ free(asf_content->description);
+ if (asf_content->rating)
+ free(asf_content->rating);
+ free(asf_content);
+}
+
+void asf_header_delete_stream_properties(asf_stream_t *asf_stream) {
+ if (asf_stream->private_data)
+ free(asf_stream->private_data);
+ if (asf_stream->error_correction_data)
+ free(asf_stream->error_correction_data);
+ free(asf_stream);
+}
+
+void asf_header_delete_stream_extended_properties(asf_stream_extension_t *asf_stream_extension) {
+ int i;
+
+ if (asf_stream_extension->stream_name_count > 0) {
+ for (i = 0; i < asf_stream_extension->stream_name_count; i++) {
+ free(asf_stream_extension->stream_names[i]);
+ }
+ free(asf_stream_extension->stream_names);
+ }
+ free(asf_stream_extension);
+}
+
+void asf_header_delete (asf_header_t *header_pub) {
+ asf_header_internal_t *header = (asf_header_internal_t *)header_pub;
+ int i;
+
+ if (header->pub.file)
+ asf_header_delete_file_properties(header->pub.file);
+
+ if (header->pub.content)
+ asf_header_delete_content(header->pub.content);
+
+ for (i = 0; i < ASF_MAX_NUM_STREAMS; i++) {
+ if (header->pub.streams[i])
+ asf_header_delete_stream_properties(header->pub.streams[i]);
+ if (header->pub.stream_extensions[i])
+ asf_header_delete_stream_extended_properties(header->pub.stream_extensions[i]);
+ }
+
+ if (header->iconv_cd != (iconv_t)-1)
+ iconv_close (header->iconv_cd);
+
+ free(header);
+}
+
+/* Given a bandwidth, select the best stream */
+static int asf_header_choose_stream (asf_header_internal_t *header, int stream_type,
+ uint32_t bandwidth) {
+ int i;
+ int max_lt, min_gt;
+
+ max_lt = min_gt = -1;
+ for (i = 0; i < header->pub.stream_count; i++) {
+ if (header->pub.streams[i]->stream_type == stream_type) {
+ if (header->pub.bitrates[i] <= bandwidth) {
+ if ((max_lt == -1) || (header->pub.bitrates[i] > header->pub.bitrates[max_lt]))
+ max_lt = i;
+ } else {
+ if ((min_gt == -1) || (header->pub.bitrates[i] < header->pub.bitrates[min_gt]))
+ min_gt = i;
+ }
+ }
+ }
+
+ return (max_lt != -1) ? max_lt : min_gt;
+}
+
+void asf_header_choose_streams (asf_header_t *header_pub, uint32_t bandwidth,
+ int *video_id, int *audio_id) {
+ asf_header_internal_t *header = (asf_header_internal_t *)header_pub;
+ uint32_t bandwidth_left;
+
+ *video_id = *audio_id = -1;
+ bandwidth_left = bandwidth;
+
+ lprintf("%d streams, bandwidth %"PRIu32"\n", header->pub.stream_count, bandwidth_left);
+
+ /* choose a video stream adapted to the user bandwidth */
+ *video_id = asf_header_choose_stream (header, GUID_ASF_VIDEO_MEDIA, bandwidth_left);
+ if (*video_id != -1) {
+ if (header->pub.bitrates[*video_id] < bandwidth_left) {
+ bandwidth_left -= header->pub.bitrates[*video_id];
+ } else {
+ bandwidth_left = 0;
+ }
+ lprintf("selected video stream %d, bandwidth left: %"PRIu32"\n",
+ header->pub.streams[*video_id]->stream_number, bandwidth_left);
+ } else {
+ lprintf("no video stream\n");
+ }
+
+ /* choose a audio stream adapted to the user bandwidth */
+ *audio_id = asf_header_choose_stream (header, GUID_ASF_AUDIO_MEDIA, bandwidth_left);
+ if (*audio_id != -1) {
+ if (header->pub.bitrates[*audio_id] < bandwidth_left) {
+ bandwidth_left -= header->pub.bitrates[*audio_id];
+ } else {
+ bandwidth_left = 0;
+ }
+ lprintf("selected audio stream %d, bandwidth left: %"PRIu32"\n",
+ header->pub.streams[*audio_id]->stream_number, bandwidth_left);
+ } else {
+ lprintf("no audio stream\n");
+ }
+}
+
+void asf_header_disable_streams (asf_header_t *header_pub, int video_id, int audio_id) {
+ asf_header_internal_t *header = (asf_header_internal_t *)header_pub;
+ int i;
+
+ for (i = 0; i < header->pub.stream_count; i++) {
+ int stream_type = header->pub.streams[i]->stream_type;
+
+ if (((stream_type == GUID_ASF_VIDEO_MEDIA) && (i != video_id)) ||
+ ((stream_type == GUID_ASF_AUDIO_MEDIA) && (i != audio_id))) {
+ uint8_t *bitrate_pointer = header->bitrate_pointers[i];
+ /* disable the stream */
+ lprintf("stream %d disabled\n", header->pub.streams[i]->stream_number);
+ *bitrate_pointer++ = 0;
+ *bitrate_pointer++ = 0;
+ *bitrate_pointer++ = 0;
+ *bitrate_pointer = 0;
+ }
+ }
+}
diff --git a/src/demuxers/asfheader.h b/src/demuxers/asfheader.h
index 1b6bade91..31ac6c90b 100644
--- a/src/demuxers/asfheader.h
+++ b/src/demuxers/asfheader.h
@@ -1,262 +1,403 @@
-/*
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- *
- * $Id: asfheader.h,v 1.6 2006/06/20 01:46:41 dgp85 Exp $
- *
- * demultiplexer for asf streams
- *
- * based on ffmpeg's
- * ASF compatible encoder and decoder.
- * Copyright (c) 2000, 2001 Gerard Lantau.
- *
- * GUID list from avifile
- * some other ideas from MPlayer
- */
-
-#ifndef ASFHEADER_H
-#define ASFHEADER_H
-
-/*
- * define asf GUIDs (list from avifile)
- */
-#define GUID_ERROR 0
-
- /* base ASF objects */
-#define GUID_ASF_HEADER 1
-#define GUID_ASF_DATA 2
-#define GUID_ASF_SIMPLE_INDEX 3
-#define GUID_INDEX 4
-#define GUID_MEDIA_OBJECT_INDEX 5
-#define GUID_TIMECODE_INDEX 6
-
- /* header ASF objects */
-#define GUID_ASF_FILE_PROPERTIES 7
-#define GUID_ASF_STREAM_PROPERTIES 8
-#define GUID_ASF_HEADER_EXTENSION 9
-#define GUID_ASF_CODEC_LIST 10
-#define GUID_ASF_SCRIPT_COMMAND 11
-#define GUID_ASF_MARKER 12
-#define GUID_ASF_BITRATE_MUTUAL_EXCLUSION 13
-#define GUID_ASF_ERROR_CORRECTION 14
-#define GUID_ASF_CONTENT_DESCRIPTION 15
-#define GUID_ASF_EXTENDED_CONTENT_DESCRIPTION 16
-#define GUID_ASF_STREAM_BITRATE_PROPERTIES 17
-#define GUID_ASF_EXTENDED_CONTENT_ENCRYPTION 18
-#define GUID_ASF_PADDING 19
-
- /* stream properties object stream type */
-#define GUID_ASF_AUDIO_MEDIA 20
-#define GUID_ASF_VIDEO_MEDIA 21
-#define GUID_ASF_COMMAND_MEDIA 22
-#define GUID_ASF_JFIF_MEDIA 23
-#define GUID_ASF_DEGRADABLE_JPEG_MEDIA 24
-#define GUID_ASF_FILE_TRANSFER_MEDIA 25
-#define GUID_ASF_BINARY_MEDIA 26
-
- /* stream properties object error correction type */
-#define GUID_ASF_NO_ERROR_CORRECTION 27
-#define GUID_ASF_AUDIO_SPREAD 28
-
- /* mutual exclusion object exlusion type */
-#define GUID_ASF_MUTEX_BITRATE 29
-#define GUID_ASF_MUTEX_UKNOWN 30
-
- /* header extension */
-#define GUID_ASF_RESERVED_1 31
-
- /* script command */
-#define GUID_ASF_RESERVED_SCRIPT_COMMNAND 32
-
- /* marker object */
-#define GUID_ASF_RESERVED_MARKER 33
-
- /* various */
-/*
-#define GUID_ASF_HEAD2 27
-*/
-#define GUID_ASF_AUDIO_CONCEAL_NONE 34
-#define GUID_ASF_CODEC_COMMENT1_HEADER 35
-#define GUID_ASF_2_0_HEADER 36
-
-#define GUID_END 37
-
-
-/* asf stream types */
-#define ASF_STREAM_TYPE_UNKNOWN 0
-#define ASF_STREAM_TYPE_AUDIO 1
-#define ASF_STREAM_TYPE_VIDEO 2
-#define ASF_STREAM_TYPE_CONTROL 3
-#define ASF_STREAM_TYPE_JFIF 4
-#define ASF_STREAM_TYPE_DEGRADABLE_JPEG 5
-#define ASF_STREAM_TYPE_FILE_TRANSFER 6
-#define ASF_STREAM_TYPE_BINARY 7
-
-#define ASF_MAX_NUM_STREAMS 23
-
-#if !defined(GUID_DEFINED) && !defined(_GUID_DEFINED)
-#define GUID_DEFINED
-#define _GUID_DEFINED
-
-typedef struct _GUID { /* size is 16 */
- uint32_t Data1;
- uint16_t Data2;
- uint16_t Data3;
- uint8_t Data4[8];
-} GUID;
-
-#endif /* !GUID_DEFINED */
-
-static const struct
-{
- const char* name;
- const GUID guid;
-} guids[] =
-{
- { "error",
- { 0x0, 0x0, 0x0, { 0x0 } } },
-
-
- /* base ASF objects */
- { "header",
- { 0x75b22630, 0x668e, 0x11cf, { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c }} },
-
- { "data",
- { 0x75b22636, 0x668e, 0x11cf, { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c }} },
-
- { "simple index",
- { 0x33000890, 0xe5b1, 0x11cf, { 0x89, 0xf4, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xcb }} },
-
- { "index",
- { 0xd6e229d3, 0x35da, 0x11d1, { 0x90, 0x34, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xbe }} },
-
- { "media object index",
- { 0xfeb103f8, 0x12ad, 0x4c64, { 0x84, 0x0f, 0x2a, 0x1d, 0x2f, 0x7a, 0xd4, 0x8c }} },
-
- { "timecode index",
- { 0x3cb73fd0, 0x0c4a, 0x4803, { 0x95, 0x3d, 0xed, 0xf7, 0xb6, 0x22, 0x8f, 0x0c }} },
-
- /* header ASF objects */
- { "file properties",
- { 0x8cabdca1, 0xa947, 0x11cf, { 0x8e, 0xe4, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 }} },
-
- { "stream header",
- { 0xb7dc0791, 0xa9b7, 0x11cf, { 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 }} },
-
- { "header extension",
- { 0x5fbf03b5, 0xa92e, 0x11cf, { 0x8e, 0xe3, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 }} },
-
- { "codec list",
- { 0x86d15240, 0x311d, 0x11d0, { 0xa3, 0xa4, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6 }} },
-
- { "script command",
- { 0x1efb1a30, 0x0b62, 0x11d0, { 0xa3, 0x9b, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6 }} },
-
- { "marker",
- { 0xf487cd01, 0xa951, 0x11cf, { 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 }} },
-
- { "bitrate mutual exclusion",
- { 0xd6e229dc, 0x35da, 0x11d1, { 0x90, 0x34, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xbe }} },
-
- { "error correction",
- { 0x75b22635, 0x668e, 0x11cf, { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c }} },
-
- { "content description",
- { 0x75b22633, 0x668e, 0x11cf, { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c }} },
-
- { "extended content description",
- { 0xd2d0a440, 0xe307, 0x11d2, { 0x97, 0xf0, 0x00, 0xa0, 0xc9, 0x5e, 0xa8, 0x50 }} },
-
- { "stream bitrate properties", /* (http://get.to/sdp) */
- { 0x7bf875ce, 0x468d, 0x11d1, { 0x8d, 0x82, 0x00, 0x60, 0x97, 0xc9, 0xa2, 0xb2 }} },
-
- { "extended content encryption",
- { 0x298ae614, 0x2622, 0x4c17, { 0xb9, 0x35, 0xda, 0xe0, 0x7e, 0xe9, 0x28, 0x9c }} },
-
- { "padding",
- { 0x1806d474, 0xcadf, 0x4509, { 0xa4, 0xba, 0x9a, 0xab, 0xcb, 0x96, 0xaa, 0xe8 }} },
-
-
- /* stream properties object stream type */
- { "audio media",
- { 0xf8699e40, 0x5b4d, 0x11cf, { 0xa8, 0xfd, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b }} },
-
- { "video media",
- { 0xbc19efc0, 0x5b4d, 0x11cf, { 0xa8, 0xfd, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b }} },
-
- { "command media",
- { 0x59dacfc0, 0x59e6, 0x11d0, { 0xa3, 0xac, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6 }} },
-
- { "JFIF media (JPEG)",
- { 0xb61be100, 0x5b4e, 0x11cf, { 0xa8, 0xfd, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b }} },
-
- { "Degradable JPEG media",
- { 0x35907de0, 0xe415, 0x11cf, { 0xa9, 0x17, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b }} },
-
- { "File Transfer media",
- { 0x91bd222c, 0xf21c, 0x497a, { 0x8b, 0x6d, 0x5a, 0xa8, 0x6b, 0xfc, 0x01, 0x85 }} },
-
- { "Binary media",
- { 0x3afb65e2, 0x47ef, 0x40f2, { 0xac, 0x2c, 0x70, 0xa9, 0x0d, 0x71, 0xd3, 0x43 }} },
-
- /* stream properties object error correction */
- { "no error correction",
- { 0x20fb5700, 0x5b55, 0x11cf, { 0xa8, 0xfd, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b }} },
-
- { "audio spread",
- { 0xbfc3cd50, 0x618f, 0x11cf, { 0x8b, 0xb2, 0x00, 0xaa, 0x00, 0xb4, 0xe2, 0x20 }} },
-
-
- /* mutual exclusion object exlusion type */
- { "mutex bitrate",
- { 0xd6e22a01, 0x35da, 0x11d1, { 0x90, 0x34, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xbe }} },
-
- { "mutex unknown",
- { 0xd6e22a02, 0x35da, 0x11d1, { 0x90, 0x34, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xbe }} },
-
-
- /* header extension */
- { "reserved_1",
- { 0xabd3d211, 0xa9ba, 0x11cf, { 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 }} },
-
-
- /* script command */
- { "reserved script command",
- { 0x4B1ACBE3, 0x100B, 0x11D0, { 0xA3, 0x9B, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6 }} },
-
- /* marker object */
- { "reserved marker",
- { 0x4CFEDB20, 0x75F6, 0x11CF, { 0x9C, 0x0F, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xCB }} },
-
- /* various */
- /* Already defined (reserved_1)
- { "head2",
- { 0xabd3d211, 0xa9ba, 0x11cf, { 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 }} },
- */
- { "audio conceal none",
- { 0x49f1a440, 0x4ece, 0x11d0, { 0xa3, 0xac, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6 }} },
-
- { "codec comment1 header",
- { 0x86d15241, 0x311d, 0x11d0, { 0xa3, 0xa4, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6 }} },
-
- { "asf 2.0 header",
- { 0xd6e229d1, 0x35da, 0x11d1, { 0x90, 0x34, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xbe }} },
-
-};
-
+/*
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * $Id: asfheader.h,v 1.7 2006/09/07 07:21:09 tmattern Exp $
+ *
+ * demultiplexer for asf streams
+ *
+ * based on ffmpeg's
+ * ASF compatible encoder and decoder.
+ * Copyright (c) 2000, 2001 Gerard Lantau.
+ *
+ * GUID list from avifile
+ * some other ideas from MPlayer
+ */
+
+#ifndef ASFHEADER_H
+#define ASFHEADER_H
+
+#include <inttypes.h>
+#include <iconv.h>
+
+/*
+ * define asf GUIDs (list from avifile)
+ */
+#define GUID_ERROR 0
+
+ /* base ASF objects */
+#define GUID_ASF_HEADER 1
+#define GUID_ASF_DATA 2
+#define GUID_ASF_SIMPLE_INDEX 3
+#define GUID_INDEX 4
+#define GUID_MEDIA_OBJECT_INDEX 5
+#define GUID_TIMECODE_INDEX 6
+
+ /* header ASF objects */
+#define GUID_ASF_FILE_PROPERTIES 7
+#define GUID_ASF_STREAM_PROPERTIES 8
+#define GUID_ASF_HEADER_EXTENSION 9
+#define GUID_ASF_CODEC_LIST 10
+#define GUID_ASF_SCRIPT_COMMAND 11
+#define GUID_ASF_MARKER 12
+#define GUID_ASF_BITRATE_MUTUAL_EXCLUSION 13
+#define GUID_ASF_ERROR_CORRECTION 14
+#define GUID_ASF_CONTENT_DESCRIPTION 15
+#define GUID_ASF_EXTENDED_CONTENT_DESCRIPTION 16
+#define GUID_ASF_STREAM_BITRATE_PROPERTIES 17
+#define GUID_ASF_EXTENDED_CONTENT_ENCRYPTION 18
+#define GUID_ASF_PADDING 19
+
+ /* stream properties object stream type */
+#define GUID_ASF_AUDIO_MEDIA 20
+#define GUID_ASF_VIDEO_MEDIA 21
+#define GUID_ASF_COMMAND_MEDIA 22
+#define GUID_ASF_JFIF_MEDIA 23
+#define GUID_ASF_DEGRADABLE_JPEG_MEDIA 24
+#define GUID_ASF_FILE_TRANSFER_MEDIA 25
+#define GUID_ASF_BINARY_MEDIA 26
+
+ /* stream properties object error correction type */
+#define GUID_ASF_NO_ERROR_CORRECTION 27
+#define GUID_ASF_AUDIO_SPREAD 28
+
+ /* mutual exclusion object exlusion type */
+#define GUID_ASF_MUTEX_BITRATE 29
+#define GUID_ASF_MUTEX_UKNOWN 30
+
+ /* header extension */
+#define GUID_ASF_RESERVED_1 31
+
+ /* script command */
+#define GUID_ASF_RESERVED_SCRIPT_COMMNAND 32
+
+ /* marker object */
+#define GUID_ASF_RESERVED_MARKER 33
+
+ /* various */
+#define GUID_ASF_AUDIO_CONCEAL_NONE 34
+#define GUID_ASF_CODEC_COMMENT1_HEADER 35
+#define GUID_ASF_2_0_HEADER 36
+
+#define GUID_EXTENDED_STREAM_PROPERTIES 37
+#define GUID_ADVANCED_MUTUAL_EXCLUSION 38
+#define GUID_GROUP_MUTUAL_EXCLUSION 39
+#define GUID_STREAM_PRIORITIZATION 40
+#define GUID_BANDWIDTH_SHARING 41
+#define GUID_LANGUAGE_LIST 42
+#define GUID_METADATA 43
+#define GUID_METADATA_LIBRARY 44
+#define GUID_INDEX_PARAMETERS 45
+#define GUID_MEDIA_OBJECT_INDEX_PARAMETERS 46
+#define GUID_TIMECODE_INDEX_PARAMETERS 47
+#define GUID_ADVANCED_CONTENT_ENCRYPTION 48
+#define GUID_COMPATIBILITY 49
+#define GUID_END 50
+
+
+/* asf stream types */
+#define ASF_STREAM_TYPE_UNKNOWN 0
+#define ASF_STREAM_TYPE_AUDIO 1
+#define ASF_STREAM_TYPE_VIDEO 2
+#define ASF_STREAM_TYPE_CONTROL 3
+#define ASF_STREAM_TYPE_JFIF 4
+#define ASF_STREAM_TYPE_DEGRADABLE_JPEG 5
+#define ASF_STREAM_TYPE_FILE_TRANSFER 6
+#define ASF_STREAM_TYPE_BINARY 7
+
+#define ASF_MAX_NUM_STREAMS 23
+
+#if !defined(GUID_DEFINED) && !defined(_GUID_DEFINED)
+#define GUID_DEFINED
+#define _GUID_DEFINED
+
+typedef struct _GUID { /* size is 16 */
+ uint32_t Data1;
+ uint16_t Data2;
+ uint16_t Data3;
+ uint8_t Data4[8];
+} GUID;
+
+#endif /* !GUID_DEFINED */
+
+static const struct
+{
+ const char* name;
+ const GUID guid;
+} guids[] =
+{
+ { "error",
+ { 0x0,} },
+
+
+ /* base ASF objects */
+ { "header",
+ { 0x75b22630, 0x668e, 0x11cf, { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c }} },
+
+ { "data",
+ { 0x75b22636, 0x668e, 0x11cf, { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c }} },
+
+ { "simple index",
+ { 0x33000890, 0xe5b1, 0x11cf, { 0x89, 0xf4, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xcb }} },
+
+ { "index",
+ { 0xd6e229d3, 0x35da, 0x11d1, { 0x90, 0x34, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xbe }} },
+
+ { "media object index",
+ { 0xfeb103f8, 0x12ad, 0x4c64, { 0x84, 0x0f, 0x2a, 0x1d, 0x2f, 0x7a, 0xd4, 0x8c }} },
+
+ { "timecode index",
+ { 0x3cb73fd0, 0x0c4a, 0x4803, { 0x95, 0x3d, 0xed, 0xf7, 0xb6, 0x22, 0x8f, 0x0c }} },
+
+ /* header ASF objects */
+ { "file properties",
+ { 0x8cabdca1, 0xa947, 0x11cf, { 0x8e, 0xe4, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 }} },
+
+ { "stream header",
+ { 0xb7dc0791, 0xa9b7, 0x11cf, { 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 }} },
+
+ { "header extension",
+ { 0x5fbf03b5, 0xa92e, 0x11cf, { 0x8e, 0xe3, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 }} },
+
+ { "codec list",
+ { 0x86d15240, 0x311d, 0x11d0, { 0xa3, 0xa4, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6 }} },
+
+ { "script command",
+ { 0x1efb1a30, 0x0b62, 0x11d0, { 0xa3, 0x9b, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6 }} },
+
+ { "marker",
+ { 0xf487cd01, 0xa951, 0x11cf, { 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 }} },
+
+ { "bitrate mutual exclusion",
+ { 0xd6e229dc, 0x35da, 0x11d1, { 0x90, 0x34, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xbe }} },
+
+ { "error correction",
+ { 0x75b22635, 0x668e, 0x11cf, { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c }} },
+
+ { "content description",
+ { 0x75b22633, 0x668e, 0x11cf, { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c }} },
+
+ { "extended content description",
+ { 0xd2d0a440, 0xe307, 0x11d2, { 0x97, 0xf0, 0x00, 0xa0, 0xc9, 0x5e, 0xa8, 0x50 }} },
+
+ { "stream bitrate properties", /* (http://get.to/sdp) */
+ { 0x7bf875ce, 0x468d, 0x11d1, { 0x8d, 0x82, 0x00, 0x60, 0x97, 0xc9, 0xa2, 0xb2 }} },
+
+ { "extended content encryption",
+ { 0x298ae614, 0x2622, 0x4c17, { 0xb9, 0x35, 0xda, 0xe0, 0x7e, 0xe9, 0x28, 0x9c }} },
+
+ { "padding",
+ { 0x1806d474, 0xcadf, 0x4509, { 0xa4, 0xba, 0x9a, 0xab, 0xcb, 0x96, 0xaa, 0xe8 }} },
+
+
+ /* stream properties object stream type */
+ { "audio media",
+ { 0xf8699e40, 0x5b4d, 0x11cf, { 0xa8, 0xfd, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b }} },
+
+ { "video media",
+ { 0xbc19efc0, 0x5b4d, 0x11cf, { 0xa8, 0xfd, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b }} },
+
+ { "command media",
+ { 0x59dacfc0, 0x59e6, 0x11d0, { 0xa3, 0xac, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6 }} },
+
+ { "JFIF media (JPEG)",
+ { 0xb61be100, 0x5b4e, 0x11cf, { 0xa8, 0xfd, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b }} },
+
+ { "Degradable JPEG media",
+ { 0x35907de0, 0xe415, 0x11cf, { 0xa9, 0x17, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b }} },
+
+ { "File Transfer media",
+ { 0x91bd222c, 0xf21c, 0x497a, { 0x8b, 0x6d, 0x5a, 0xa8, 0x6b, 0xfc, 0x01, 0x85 }} },
+
+ { "Binary media",
+ { 0x3afb65e2, 0x47ef, 0x40f2, { 0xac, 0x2c, 0x70, 0xa9, 0x0d, 0x71, 0xd3, 0x43 }} },
+
+ /* stream properties object error correction */
+ { "no error correction",
+ { 0x20fb5700, 0x5b55, 0x11cf, { 0xa8, 0xfd, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b }} },
+
+ { "audio spread",
+ { 0xbfc3cd50, 0x618f, 0x11cf, { 0x8b, 0xb2, 0x00, 0xaa, 0x00, 0xb4, 0xe2, 0x20 }} },
+
+
+ /* mutual exclusion object exlusion type */
+ { "mutex bitrate",
+ { 0xd6e22a01, 0x35da, 0x11d1, { 0x90, 0x34, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xbe }} },
+
+ { "mutex unknown",
+ { 0xd6e22a02, 0x35da, 0x11d1, { 0x90, 0x34, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xbe }} },
+
+
+ /* header extension */
+ { "reserved_1",
+ { 0xabd3d211, 0xa9ba, 0x11cf, { 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 }} },
+
+
+ /* script command */
+ { "reserved script command",
+ { 0x4B1ACBE3, 0x100B, 0x11D0, { 0xA3, 0x9B, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6 }} },
+
+ /* marker object */
+ { "reserved marker",
+ { 0x4CFEDB20, 0x75F6, 0x11CF, { 0x9C, 0x0F, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xCB }} },
+
+ /* various */
+ { "audio conceal none",
+ { 0x49f1a440, 0x4ece, 0x11d0, { 0xa3, 0xac, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6 }} },
+
+ { "codec comment1 header",
+ { 0x86d15241, 0x311d, 0x11d0, { 0xa3, 0xa4, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6 }} },
+
+ { "asf 2.0 header",
+ { 0xd6e229d1, 0x35da, 0x11d1, { 0x90, 0x34, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xbe }} },
+
+
+ /* header extension GUIDs */
+ { "extended stream properties",
+ { 0x14E6A5CB, 0xC672, 0x4332, { 0x83, 0x99, 0xA9, 0x69, 0x52, 0x6, 0x5B, 0x5A }} },
+
+ { "advanced mutual exclusion",
+ { 0xA08649CF, 0x4775, 0x4670, { 0x8a, 0x16, 0x6e, 0x35, 0x35, 0x75, 0x66, 0xcd }} },
+
+ { "group mutual exclusion",
+ { 0xD1465A40, 0x5A79, 0x4338, { 0xb7, 0x1b, 0xe3, 0x6b, 0x8f, 0xd6, 0xc2, 0x49 }} },
+
+ { "stream prioritization",
+ { 0xD4FED15B, 0x88D3, 0x454F, { 0x81, 0xf0, 0xed, 0x5c, 0x45, 0x99, 0x9e, 0x24 }} },
+
+ { "bandwidth sharing",
+ { 0xA69609E6, 0x517B, 0x11D2, { 0xb6, 0xaf, 0x00, 0xc0, 0x4f, 0xd9, 0x08, 0xe9 }} },
+
+ { "language list",
+ { 0x7C4346A9, 0xEFE0, 0x4BFC, {0xB2, 0x29, 0x39, 0x3E, 0xDE, 0x41, 0x5C, 0x85}} },
+
+ { "metadata",
+ { 0xC5F8CBEA, 0x5BAF, 0x4877, {0x84, 0x67, 0xAA, 0x8C, 0x44, 0xFA, 0x4C, 0xCA}} },
+
+ { "metadata library",
+ { 0x44231C94, 0x9498, 0x49D1, {0xA1, 0x41, 0x1D, 0x13, 0x4E, 0x45, 0x70, 0x54}} },
+
+ { "index parameters",
+ { 0xD6E229DF, 0x35DA, 0x11D1, {0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE}} },
+
+ { "media object index parameters",
+ { 0x6B203BAD, 0x3F11, 0x48E4, {0xAC, 0xA8, 0xD7, 0x61, 0x3D, 0xE2, 0xCF, 0xA7}} },
+
+ { "timecode index parameters",
+ { 0xF55E496D, 0x9797, 0x4B5D, {0x8C, 0x8B, 0x60, 0x4D, 0xF9, 0x9B, 0xFB, 0x24}} },
+
+ { "advanced content encryption",
+ { 0x43058533, 0x6981, 0x49E6, {0x9B, 0x74, 0xAD, 0x12, 0xCB, 0x86, 0xD5, 0x8C}} },
+
+ /* exotic stuff */
+ { "compatibility",
+ { 0x26F18B5D, 0x4584, 0x47EC, {0x9F, 0x5F, 0xE,0x65, 0x1F, 0x4, 0x52, 0xC9}} }
+};
+
+typedef struct asf_header_s asf_header_t;
+typedef struct asf_file_s asf_file_t;
+typedef struct asf_content_s asf_content_t;
+typedef struct asf_stream_s asf_stream_t;
+typedef struct asf_stream_extension_s asf_stream_extension_t;
+
+struct asf_header_s {
+ asf_file_t *file;
+ asf_content_t *content;
+ int stream_count;
+
+ 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 asf_file_s {
+ GUID file_id;
+ uint64_t file_size; /* in bytes */
+ uint64_t data_packet_count;
+ uint64_t play_duration; /* in 100 nanoseconds unit */
+ uint64_t send_duration; /* in 100 nanoseconds unit */
+ uint64_t preroll; /* in 100 nanoseconds unit */
+
+ uint32_t packet_size;
+ uint32_t max_bitrate;
+
+ uint8_t broadcast_flag;
+ uint8_t seekable_flag;
+};
+
+/* ms unicode strings */
+struct asf_content_s {
+ char *title;
+ char *author;
+ char *copyright;
+ char *description;
+ char *rating;
+};
+
+struct asf_stream_s {
+ uint16_t stream_number;
+ int stream_type;
+ int error_correction_type;
+ uint64_t time_offset;
+
+ uint32_t private_data_length;
+ uint8_t *private_data;
+
+ uint32_t error_correction_data_length;
+ uint8_t *error_correction_data;
+
+ uint8_t encrypted_flag;
+};
+
+struct asf_stream_extension_s {
+ uint64_t start_time;
+ uint64_t end_time;
+ uint32_t data_bitrate;
+ uint32_t buffer_size;
+ uint32_t initial_buffer_fullness;
+ uint32_t alternate_data_bitrate;
+ uint32_t alternate_buffer_size;
+ uint32_t alternate_initial_buffer_fullness;
+ uint32_t max_object_size;
+
+ uint8_t reliable_flag;
+ uint8_t seekable_flag;
+ uint8_t no_cleanpoints_flag;
+ uint8_t resend_live_cleanpoints_flag;
+
+ uint16_t language_id;
+ uint64_t average_time_per_frame;
+
+ uint16_t stream_name_count;
+ uint16_t payload_extension_system_count;
+
+ char **stream_names;
+};
+
+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);
+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,
+ int video_id, int audio_id);
+void asf_header_delete (asf_header_t *header);
+
+
#endif
diff --git a/src/demuxers/demux_asf.c b/src/demuxers/demux_asf.c
index ea44508e3..c95bf5460 100644
--- a/src/demuxers/demux_asf.c
+++ b/src/demuxers/demux_asf.c
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: demux_asf.c,v 1.180 2006/08/08 03:34:15 miguelfreitas Exp $
+ * $Id: demux_asf.c,v 1.181 2006/09/07 07:21:09 tmattern Exp $
*
* demultiplexer for asf streams
*
@@ -70,9 +70,9 @@
#define ASF_MODE_ASF_REF 3
#define ASF_MODE_ENCRYPTED_CONTENT 4
+#define ASF_HEADER_SIZE 8192 /* max header size */
typedef struct {
- int num;
int seq;
int frag_offset;
@@ -89,89 +89,75 @@ typedef struct {
int resync;
int first_seq;
- xine_waveformatex *wavex;
- int wavex_size;
-
- xine_bmiheader *bih;
- int bih_size;
-
int payload_size;
/* palette handling */
- int palette_count;
- palette_entry_t palette[256];
+ int palette_count;
+ palette_entry_t palette[256];
-} asf_stream_t;
+} asf_demux_stream_t;
typedef struct demux_asf_s {
- demux_plugin_t demux_plugin;
+ demux_plugin_t demux_plugin;
- xine_stream_t *stream;
+ xine_stream_t *stream;
- fifo_buffer_t *audio_fifo;
- fifo_buffer_t *video_fifo;
+ fifo_buffer_t *audio_fifo;
+ fifo_buffer_t *video_fifo;
- input_plugin_t *input;
+ input_plugin_t *input;
- int64_t keyframe_ts;
- int keyframe_found;
+ 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;
+ int seqno;
+ uint32_t packet_size;
+ uint8_t packet_len_flags;
+ uint32_t data_size;
+ uint64_t packet_count;
- asf_stream_t streams[MAX_NUM_STREAMS];
- uint32_t bitrates[MAX_NUM_STREAMS];
- int num_streams;
- int num_audio_streams;
- int num_video_streams;
- int audio_stream;
- int video_stream;
- int audio_stream_id;
- int video_stream_id;
- int control_stream_id;
-
- char title[512];
- char author[512];
- char copyright[512];
- char comment[512];
-
- uint64_t length;
- uint32_t rate;
- uint64_t preroll;
+ asf_demux_stream_t streams[MAX_NUM_STREAMS];
+ int video_stream;
+ int audio_stream;
+
+ uint64_t length;
+ uint32_t rate;
/* packet filling */
- int packet_size_left;
+ int packet_size_left;
/* discontinuity detection */
- int64_t last_pts[2];
- int send_newpts;
+ int64_t last_pts[2];
+ int send_newpts;
/* only for reading */
- uint32_t packet_padsize;
- int nb_frames;
- uint8_t frame_flag;
- uint8_t packet_prop_flags;
- int frame;
+ uint32_t packet_padsize;
+ int nb_frames;
+ uint8_t frame_flag;
+ uint8_t packet_prop_flags;
+ int frame;
- int status;
+ int status;
/* byte reordering from audio streams */
- int reorder_h;
- int reorder_w;
- int reorder_b;
+ int reorder_h;
+ int reorder_w;
+ int reorder_b;
- int buf_flag_seek;
+ int buf_flag_seek;
/* first packet position */
- int64_t first_packet_pos;
+ int64_t first_packet_pos;
- int mode;
+ int mode;
/* for fewer error messages */
- GUID last_unknown_guid;
+ GUID last_unknown_guid;
+
+ uint8_t asf_header_buffer[ASF_HEADER_SIZE];
+ uint32_t asf_header_len;
+ asf_header_t *asf_header;
+
} demux_asf_t ;
typedef struct {
@@ -306,29 +292,30 @@ static void get_str16_nolen(demux_asf_t *this, int len,
static void asf_send_audio_header (demux_asf_t *this, int stream) {
buf_element_t *buf;
- asf_stream_t *asf_stream = &this->streams[stream];
- xine_waveformatex *wavex = asf_stream->wavex;
+ asf_demux_stream_t *demux_stream = &this->streams[stream];
+ asf_stream_t *asf_stream = this->asf_header->streams[stream];
+ xine_waveformatex *wavex = (xine_waveformatex *)asf_stream->private_data;
if (!this->audio_fifo)
return;
buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo);
- if (asf_stream->wavex_size > buf->max_size) {
+ if (asf_stream->private_data_length > buf->max_size) {
xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
"demux_asf: private decoder data length (%d) is greater than fifo buffer length (%d)\n",
- asf_stream->wavex_size, buf->max_size);
+ asf_stream->private_data_length, buf->max_size);
buf->free_buffer(buf);
this->status = DEMUX_FINISHED;
return;
}
- memcpy (buf->content, wavex, asf_stream->wavex_size);
+ memcpy (buf->content, wavex, asf_stream->private_data_length);
_x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_FOURCC, wavex->wFormatTag);
- lprintf ("wavex header is %d bytes long\n", asf_stream->wavex_size);
+ lprintf ("wavex header is %d bytes long\n", asf_stream->private_data_length);
- buf->size = asf_stream->wavex_size;
+ buf->size = asf_stream->private_data_length;
buf->type = this->streams[stream].buf_type;
buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAME_END;
buf->decoder_info[1] = wavex->nSamplesPerSec;
@@ -346,17 +333,18 @@ static unsigned long str2ulong(unsigned char *str) {
static void asf_send_video_header (demux_asf_t *this, int stream) {
- buf_element_t *buf;
- asf_stream_t *asf_stream = &this->streams[stream];
- xine_bmiheader *bih = asf_stream->bih;
+ buf_element_t *buf;
+ asf_demux_stream_t *demux_stream = &this->streams[stream];
+ asf_stream_t *asf_stream = this->asf_header->streams[stream];
+ xine_bmiheader *bih = (xine_bmiheader *)(asf_stream->private_data + 11);
_x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_FOURCC, bih->biCompression);
buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
- if (asf_stream->bih_size > buf->max_size) {
+ if ((asf_stream->private_data_length-11) > buf->max_size) {
xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
"demux_asf: private decoder data length (%d) is greater than fifo buffer length (%d)\n",
- asf_stream->bih_size, buf->max_size);
+ asf_stream->private_data_length-10, buf->max_size);
buf->free_buffer(buf);
this->status = DEMUX_FINISHED;
return;
@@ -366,7 +354,7 @@ static void asf_send_video_header (demux_asf_t *this, int stream) {
BUF_FLAG_FRAME_END;
buf->decoder_info[0] = 0;
- buf->size = asf_stream->bih_size;
+ buf->size = asf_stream->private_data_length - 11;
memcpy (buf->content, bih, buf->size);
buf->type = this->streams[stream].buf_type;
@@ -374,14 +362,14 @@ static void asf_send_video_header (demux_asf_t *this, int stream) {
/* send off the palette, if there is one */
- if (asf_stream->palette_count) {
+ if (demux_stream->palette_count) {
xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
- "demux_asf: stream %d, palette : %d entries\n", stream, asf_stream->palette_count);
+ "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;
buf->decoder_info[1] = BUF_SPECIAL_PALETTE;
- buf->decoder_info[2] = asf_stream->palette_count;
- buf->decoder_info_ptr[2] = &asf_stream->palette;
+ buf->decoder_info[2] = demux_stream->palette_count;
+ buf->decoder_info_ptr[2] = &demux_stream->palette;
buf->size = 0;
buf->type = this->streams[stream].buf_type;
this->video_fifo->put (this->video_fifo, buf);
@@ -389,320 +377,174 @@ static void asf_send_video_header (demux_asf_t *this, int stream) {
}
static int asf_read_header (demux_asf_t *this) {
+ int i;
- int guid;
- uint64_t gsize;
-
- this->num_streams = 0;
- this->num_video_streams = 0;
- this->num_audio_streams = 0;
-
- get_le64(this);
- get_le32(this);
- get_byte(this);
- get_byte(this);
-
- while (this->status != DEMUX_FINISHED) {
- guid = get_guid(this);
- gsize = get_le64(this);
-
- if (gsize < 24)
- goto fail;
-
- switch (guid) {
- case GUID_ASF_FILE_PROPERTIES:
- {
- uint64_t file_size, send_time;
- uint32_t flags;
-
- guid = get_guid(this);
- file_size = get_le64(this); /* file size */
-
- get_le64(this); /* creation time */
- this->packet_count = get_le64(this); /* nb packets */
-
- this->length = get_le64(this) / 10000; /* duration */
- send_time = get_le64(this); /* send time */
-
- this->preroll = get_le64(this); /* preroll in 1/1000 s */
- this->length -= this->preroll;
-
- flags = get_le32(this); /* flags */
- get_le32(this); /* min packet size */
- this->packet_size = get_le32(this); /* max packet size */
- get_le32(this); /* max bitrate */
-
- if (this->length) {
- /* FIXME: the rate is not constant ! */
- this->rate = (file_size * 1000) / this->length;
- } else {
- this->rate = 0;
- }
-
- _x_stream_info_set(this->stream, XINE_STREAM_INFO_BITRATE, this->rate * 8);
-
-
- }
- break;
-
- case (GUID_ASF_STREAM_PROPERTIES):
- {
- int type;
- uint32_t total_size, stream_data_size;
- uint16_t flags;
- uint16_t stream_id;
- uint64_t pos1, pos2;
- asf_stream_t *asf_stream = &this->streams[this->num_streams];
-
- pos1 = this->input->get_current_pos (this->input);
-
- guid = get_guid(this);
- switch (guid) {
- case GUID_ASF_AUDIO_MEDIA:
- type = CODEC_TYPE_AUDIO;
- break;
-
- case GUID_ASF_VIDEO_MEDIA:
- type = CODEC_TYPE_VIDEO;
- break;
-
- case GUID_ASF_COMMAND_MEDIA:
- type = CODEC_TYPE_CONTROL;
- break;
-
- default:
- lprintf("unexpected GUID\n");
- pos2 = this->input->get_current_pos (this->input);
- this->input->seek (this->input, gsize - (pos2 - pos1 + 24), SEEK_CUR);
- continue;
- }
-
- guid = get_guid(this);
- get_le64(this);
- total_size = get_le32(this);
- stream_data_size = get_le32(this);
- flags = get_le16(this);
- stream_id = flags & 0x7F; /* stream id */
- if (flags & 0x8000) {
- /* Encrypted stream
- * Parse the end of the header but do not demux the stream.
- */
- if (this->mode != ASF_MODE_ENCRYPTED_CONTENT) {
- xine_log(this->stream->xine, XINE_LOG_MSG,
- _("demux_asf: warning: The stream id=%d is encrypted.\n"), stream_id);
- _x_message(this->stream, XINE_MSG_ENCRYPTED_SOURCE,
- _("Media stream scrambled/encrypted"), NULL);
- this->mode = ASF_MODE_ENCRYPTED_CONTENT;
- }
- }
-
- get_le32(this);
-
- if (type == CODEC_TYPE_AUDIO) {
- uint8_t buffer[6];
-
- asf_stream->wavex = (xine_waveformatex *)realloc(asf_stream->wavex, total_size);
- this->input->read (this->input, (uint8_t *) asf_stream->wavex, total_size);
- _x_waveformatex_le2me( (xine_waveformatex *) asf_stream->wavex );
-
- /*
- printf ("total size: %d bytes\n", total_size);
- */
-
- /*
- this->input->read (this->input, (uint8_t *) &this->wavex[9], this->wavex[8]);
- */
- if (guid == GUID_ASF_AUDIO_SPREAD) {
- this->input->read (this->input, buffer, 6);
- this->reorder_h = buffer[0];
- this->reorder_w = (buffer[2]<<8)|buffer[1];
- this->reorder_b = (buffer[4]<<8)|buffer[3];
- this->reorder_w /= this->reorder_b;
- 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;
- }
-
- asf_stream->wavex_size = total_size; /* 18 + this->wavex[8]; */
-
- asf_stream->buf_type = _x_formattag_to_buf_audio ( asf_stream->wavex->wFormatTag );
- if ( !asf_stream->buf_type ) {
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
- "demux_asf: unknown audio type 0x%x\n", asf_stream->wavex->wFormatTag);
- asf_stream->buf_type = BUF_AUDIO_UNKNOWN;
- }
-
- _x_meta_info_set(this->stream, XINE_META_INFO_AUDIOCODEC, _x_buf_audio_name(asf_stream->buf_type));
-
- this->streams[this->num_streams].fifo = this->audio_fifo;
- this->streams[this->num_streams].stream_id = stream_id;
- this->streams[this->num_streams].frag_offset = 0;
- this->streams[this->num_streams].seq = 0;
- if (this->reorder_h > 1 && this->reorder_w > 1 ) {
- if( !this->streams[this->num_streams].buffer )
- this->streams[this->num_streams].buffer = malloc( DEFRAG_BUFSIZE );
- this->streams[this->num_streams].defrag = 1;
- } else
- this->streams[this->num_streams].defrag = 0;
-
- lprintf ("found an audio stream id=%d \n", stream_id);
-
- this->num_audio_streams++;
- }
- else if (type == CODEC_TYPE_VIDEO) {
-
- uint16_t i;
- uint32_t width;
- uint32_t height;
- int j;
-
- width = get_le32(this); /* width */
- height = get_le32(this); /* height */
- get_byte(this);
-
- i = get_le16(this); /* size */
- asf_stream->bih = (xine_bmiheader *)realloc(asf_stream->bih, i);
-
- if (i > 0) {
- asf_stream->bih_size = i;
- this->input->read (this->input, (uint8_t *) asf_stream->bih, asf_stream->bih_size);
- _x_bmiheader_le2me( (xine_bmiheader *) asf_stream->bih );
-
- asf_stream->buf_type =
- _x_fourcc_to_buf_video(asf_stream->bih->biCompression);
- if( !asf_stream->buf_type ) {
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
- "demux_asf: unknown video format %.4s\n", (char*)&asf_stream->bih->biCompression);
-
- asf_stream->buf_type = BUF_VIDEO_UNKNOWN;
- }
-
- _x_meta_info_set(this->stream, XINE_META_INFO_VIDEOCODEC, _x_buf_video_name(asf_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[this->num_streams].fifo = this->video_fifo;
- this->streams[this->num_streams].stream_id = stream_id;
- this->streams[this->num_streams].frag_offset = 0;
- this->streams[this->num_streams].defrag = 0;
-
- /* load the palette, if there is one */
- asf_stream->palette_count = asf_stream->bih->biClrUsed;
-
- lprintf ("palette_count: %d\n", asf_stream->palette_count);
- if (asf_stream->palette_count > 256) {
- lprintf ("number of colors exceeded 256 (%d)", asf_stream->palette_count);
- asf_stream->palette_count = 256;
- }
- if ((asf_stream->bih_size - sizeof(xine_bmiheader)) >= (asf_stream->palette_count * 4)) {
- /* load the palette from the end of the strf chunk */
- for (j = 0; j < asf_stream->palette_count; j++) {
- asf_stream->palette[j].b = *((uint8_t *)asf_stream->bih + sizeof(xine_bmiheader) + j * 4 + 0);
- asf_stream->palette[j].g = *((uint8_t *)asf_stream->bih + sizeof(xine_bmiheader) + j * 4 + 1);
- asf_stream->palette[j].r = *((uint8_t *)asf_stream->bih + sizeof(xine_bmiheader) + j * 4 + 2);
- }
- } else {
- /* generate a greyscale palette */
- asf_stream->palette_count = 256;
- for (j = 0; j < asf_stream->palette_count; j++) {
- asf_stream->palette[j].r = j;
- asf_stream->palette[j].g = j;
- asf_stream->palette[j].b = j;
- }
- }
-
- } else
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
- "demux_asf: invalid bih_size received (%d), v_stream ignored.\n", i );
-
- lprintf ("found a video stream id=%d, buf_type=%08x \n",
- stream_id, this->streams[this->num_streams].buf_type);
-
- this->num_video_streams++;
- }
- else if (type == CODEC_TYPE_CONTROL) {
- this->streams[this->num_streams].stream_id = stream_id;
- this->control_stream_id = stream_id;
-
- /* This code does'nt work
- while (get_byte(this) != 0) {while (get_byte(this) != 0) {}}
- while (get_byte(this) != 0) {while (get_byte(this) != 0) {}}
- */
- lprintf ("found a control stream id=%d \n", stream_id);
+ this->asf_header_len = get_le64(this);
- }
+ if (this->input->read (this->input, this->asf_header_buffer, this->asf_header_len) != this->asf_header_len)
+ return 0;
- this->num_streams++;
- pos2 = this->input->get_current_pos (this->input);
- this->input->seek (this->input, gsize - (pos2 - pos1 + 24), SEEK_CUR);
- }
- break;
+ /* delete previous header */
+ if (this->asf_header) {
+ asf_header_delete(this->asf_header);
+ }
- case GUID_ASF_DATA:
- lprintf ("found data\n");
+ /* the header starts with :
+ * byte 0-15: header guid
+ * byte 16-23: header length
+ */
+ this->asf_header = asf_header_new(this->asf_header_buffer, this->asf_header_len);
+ if (!this->asf_header)
+ return 0;
- goto headers_ok;
- break;
- case GUID_ASF_CONTENT_DESCRIPTION:
- {
- uint16_t len1, len2, len3, len4, len5;
-
- len1 = get_le16(this);
- len2 = get_le16(this);
- len3 = get_le16(this);
- len4 = get_le16(this);
- len5 = get_le16(this);
- get_str16_nolen(this, len1, this->title, sizeof(this->title));
- get_str16_nolen(this, len2, this->author, sizeof(this->author));
- get_str16_nolen(this, len3, this->copyright, sizeof(this->copyright));
- get_str16_nolen(this, len4, this->comment, sizeof(this->comment));
- this->input->seek (this->input, len5, SEEK_CUR);
- /*
- } else if (url_feof(this)) {
- goto fail;
- */
- }
- break;
+ lprintf("asf header parsing ok\n");
- case GUID_ASF_STREAM_BITRATE_PROPERTIES:
- {
- uint16_t streams, stream_id;
- uint16_t i;
+ this->packet_size = this->asf_header->file->packet_size;
+ this->packet_count = this->asf_header->file->data_packet_count;
- lprintf("GUID stream group\n");
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_BITRATE, this->asf_header->file->max_bitrate);
- streams = get_le16(this);
- for(i = 0; i < streams; i++) {
- stream_id = get_le16(this);
- this->bitrates[stream_id] = get_le32(this);
- }
- }
- break;
+ for (i = 0; i < this->asf_header->stream_count; i++) {
+ asf_stream_t *asf_stream = this->asf_header->streams[i];
+ asf_demux_stream_t *demux_stream = &this->streams[i];
- default:
- this->input->seek (this->input, gsize - 24, SEEK_CUR);
+ if (asf_stream->encrypted_flag) {
+ if (this->mode != ASF_MODE_ENCRYPTED_CONTENT) {
+ xine_log(this->stream->xine, XINE_LOG_MSG,
+ _("demux_asf: warning: The stream id=%d is encrypted.\n"), asf_stream->stream_number);
+ _x_message(this->stream, XINE_MSG_ENCRYPTED_SOURCE,
+ _("Media stream scrambled/encrypted"), NULL);
+ this->mode = ASF_MODE_ENCRYPTED_CONTENT;
+ }
+ }
+ switch (asf_stream->stream_type) {
+ case GUID_ASF_AUDIO_MEDIA:
+
+ _x_waveformatex_le2me( (xine_waveformatex *) asf_stream->private_data );
+ if (asf_stream->error_correction_type == GUID_ASF_AUDIO_SPREAD) {
+ this->reorder_h = asf_stream->error_correction_data[0];
+ 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,
+ "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 ) {
+ 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_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;
+ if (this->reorder_h > 1 && this->reorder_w > 1 ) {
+ if( !this->streams[i].buffer )
+ this->streams[i].buffer = malloc( DEFRAG_BUFSIZE );
+ 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
+ * XX bytes : optional palette
+ */
+ uint32_t width, height;
+ uint16_t bmiheader_size;
+ xine_bmiheader *bmiheader;
+
+ width = LE_32(asf_stream->private_data);
+ height = LE_32(asf_stream->private_data + 4);
+ /* there is one unknown byte between height and the bmiheader size */
+ bmiheader_size = 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 colors exceeded 256 (%d)", demux_stream->palette_count);
+ demux_stream->palette_count = 256;
+ }
+ 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);
+ demux_stream->palette[j].g = *(palette + j * 4 + 1);
+ demux_stream->palette[j].r = *(palette + j * 4 + 2);
+ }
+ } else {
+ int j;
+
+ /* generate a greyscale palette */
+ demux_stream->palette_count = 256;
+ for (j = 0; j < demux_stream->palette_count; j++) {
+ demux_stream->palette[j].r = j;
+ demux_stream->palette[j].g = j;
+ 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);
+ }
+ break;
}
}
- headers_ok:
this->input->seek (this->input, sizeof(GUID) + 10, SEEK_CUR);
this->packet_size_left = 0;
this->first_packet_pos = this->input->get_current_pos (this->input);
return 1;
-
- fail:
- return 0;
}
static int demux_asf_send_headers_common (demux_asf_t *this) {
- int i;
- int stream_id;
- uint32_t buf_type, max_vrate, max_arate;
- uint32_t bitrate = 0;
-
/* will get overridden later */
_x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, 0);
_x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, 0);
@@ -710,11 +552,8 @@ static int demux_asf_send_headers_common (demux_asf_t *this) {
/*
* initialize asf engine
*/
- this->audio_stream = 0;
- this->video_stream = 0;
- this->audio_stream_id = -1;
- this->video_stream_id = -1;
- this->control_stream_id = 0;
+ this->audio_stream = -1;
+ this->video_stream = -1;
this->packet_size = 0;
this->seqno = 0;
@@ -731,56 +570,31 @@ static int demux_asf_send_headers_common (demux_asf_t *this) {
*/
_x_demux_control_start(this->stream);
- _x_meta_info_set(this->stream, XINE_META_INFO_TITLE, this->title);
- _x_meta_info_set(this->stream, XINE_META_INFO_ARTIST, this->author);
- _x_meta_info_set(this->stream, XINE_META_INFO_COMMENT, this->comment);
-
+ if (this->asf_header->content) {
+ _x_meta_info_set(this->stream, XINE_META_INFO_TITLE, this->asf_header->content->title);
+ _x_meta_info_set(this->stream, XINE_META_INFO_ARTIST, this->asf_header->content->author);
+ _x_meta_info_set(this->stream, XINE_META_INFO_COMMENT, this->asf_header->content->description);
+ }
/* Choose the best audio and the best video stream.
* Use the bitrate to do the choice.
*/
- max_vrate = 0;
- max_arate = 0;
- for (i = 0; i < this->num_streams; i++) {
- buf_type = (this->streams[i].buf_type & BUF_MAJOR_MASK);
- stream_id = this->streams[i].stream_id;
- bitrate = this->bitrates[stream_id];
+ asf_header_choose_streams(this->asf_header, -1, &this->video_stream, &this->audio_stream);
- xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
- "demux_asf: stream: %d, bitrate %d bps\n", stream_id, bitrate);
-
- if ((buf_type == BUF_VIDEO_BASE) &&
- (bitrate > max_vrate || this->video_stream_id == -1)) {
-
- _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, 1);
- _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_BITRATE,
- bitrate);
-
- max_vrate = bitrate;
- this->video_stream = i;
- this->video_stream_id = stream_id;
- } else if ((buf_type == BUF_AUDIO_BASE) &&
- (bitrate > max_arate || this->audio_stream_id == -1)) {
-
- _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, 1);
- _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE,
- bitrate);
-
- max_arate = bitrate;
- this->audio_stream = i;
- this->audio_stream_id = stream_id;
- }
- }
-
- _x_stream_info_set(this->stream, XINE_STREAM_INFO_BITRATE, bitrate);
xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
- "demux_asf: video stream_id: %d, audio stream_id: %d\n", this->video_stream_id, this->audio_stream_id);
+ "demux_asf: video stream_id: %d, audio stream_id: %d\n",
+ this->asf_header->streams[this->video_stream]->stream_number,
+ this->asf_header->streams[this->audio_stream]->stream_number);
- if(_x_stream_info_get(this->stream, XINE_STREAM_INFO_HAS_AUDIO))
+ if (this->audio_stream != -1) {
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, 1);
asf_send_audio_header(this, this->audio_stream);
- if(_x_stream_info_get(this->stream, XINE_STREAM_INFO_HAS_VIDEO))
+ }
+ if (this->video_stream != -1) {
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, 1);
asf_send_video_header(this, this->video_stream);
+ }
}
return 0;
}
@@ -843,7 +657,7 @@ static void check_newpts (demux_asf_t *this, int64_t pts, int video, int frame_e
}
-static void asf_send_buffer_nodefrag (demux_asf_t *this, asf_stream_t *stream,
+static void asf_send_buffer_nodefrag (demux_asf_t *this, asf_demux_stream_t *stream,
int frag_offset, int64_t timestamp,
int frag_len) {
@@ -892,6 +706,7 @@ static void asf_send_buffer_nodefrag (demux_asf_t *this, asf_stream_t *stream,
this->rate);
buf->pts = timestamp * 90;
+
buf->type = stream->buf_type;
buf->size = bufsize;
timestamp = 0;
@@ -923,7 +738,7 @@ static void asf_send_buffer_nodefrag (demux_asf_t *this, asf_stream_t *stream,
}
}
-static void asf_send_buffer_defrag (demux_asf_t *this, asf_stream_t *stream,
+static void asf_send_buffer_defrag (demux_asf_t *this, asf_demux_stream_t *stream,
int frag_offset, int64_t timestamp,
int frag_len) {
@@ -1216,7 +1031,7 @@ static int asf_parse_packet_payload_header(demux_asf_t *this, uint32_t p_hdr_siz
/* return 0 if ok */
static int asf_parse_packet_payload_common(demux_asf_t *this,
uint8_t raw_id,
- asf_stream_t **stream,
+ asf_demux_stream_t **stream,
uint32_t *frag_offset,
uint32_t *rlen) {
uint8_t stream_id;
@@ -1231,25 +1046,15 @@ static int asf_parse_packet_payload_common(demux_asf_t *this,
lprintf ("got raw_id=%d, stream_id=%d\n", raw_id, stream_id);
- for (i = 0; i < this->num_streams; i++) {
- lprintf ("this->streams[i].stream_id=%d\n", this->streams[i].stream_id);
- if ((this->streams[i].stream_id == stream_id) &&
- ((stream_id == this->audio_stream_id) || (stream_id == this->video_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) &&
+ ((stream_id == this->asf_header->streams[this->audio_stream]->stream_number) ||
+ (stream_id == this->asf_header->streams[this->video_stream]->stream_number))) {
*stream = &this->streams[i];
break;
}
}
-#ifdef LOG
- /* display "control stream" content */
- if (stream_id && (stream_id == this->control_stream_id)) {
- printf("demux_asf: Control Stream : begin\n");
- for (i = 0; i < (this->packet_size_left - s_hdr_size); i++){
- printf("%c", get_byte(this));
- }
- printf("\ndemux_asf: Control Stream : end\n");
- return 1;
- }
-#endif
switch ((this->packet_prop_flags >> 4) & 3){
case 1:
@@ -1278,7 +1083,7 @@ static int asf_parse_packet_payload_common(demux_asf_t *this,
/* check seq number */
if (*stream) {
- lprintf ("stream_id = %d, seq = %d\n", (*stream)->stream_id, seq);
+ lprintf ("stream_id = %d, seq = %d\n", stream_id, seq);
if ((*stream)->first_seq || (*stream)->skip) {
next_seq = seq;
(*stream)->first_seq = 0;
@@ -1293,7 +1098,7 @@ static int asf_parse_packet_payload_common(demux_asf_t *this,
buf->type = BUF_CONTROL_RESET_DECODER;
(*stream)->fifo->put((*stream)->fifo, buf);
}
- if ((*stream)->stream_id == this->video_stream_id) {
+ if (stream_id == this->asf_header->streams[this->video_stream]->stream_number) {
lprintf ("bad seq: waiting for keyframe\n");
(*stream)->resync = 1;
@@ -1342,7 +1147,7 @@ static int asf_parse_packet_payload_common(demux_asf_t *this,
/* return 0 if ok */
static int asf_parse_packet_compressed_payload(demux_asf_t *this,
- asf_stream_t *stream,
+ asf_demux_stream_t *stream,
uint8_t raw_id,
uint32_t frag_offset,
int64_t *timestamp) {
@@ -1352,7 +1157,7 @@ static int asf_parse_packet_compressed_payload(demux_asf_t *this,
*timestamp = frag_offset;
if (*timestamp)
- *timestamp -= this->preroll;
+ *timestamp -= this->asf_header->file->preroll;
frag_offset = 0;
get_byte (this); s_hdr_size += 1;
@@ -1436,7 +1241,7 @@ static int asf_parse_packet_compressed_payload(demux_asf_t *this,
/* return 0 if ok */
static int asf_parse_packet_payload(demux_asf_t *this,
- asf_stream_t *stream,
+ asf_demux_stream_t *stream,
uint8_t raw_id,
uint32_t frag_offset,
uint32_t rlen,
@@ -1449,7 +1254,7 @@ static int asf_parse_packet_payload(demux_asf_t *this,
payload_size = get_le32(this); s_hdr_size += 4;
*timestamp = get_le32(this); s_hdr_size += 4;
if (*timestamp)
- *timestamp -= this->preroll;
+ *timestamp -= this->asf_header->file->preroll;
if (stream)
stream->payload_size = payload_size;
if ((rlen - 8) > 0)
@@ -1842,7 +1647,7 @@ failure:
static int demux_asf_send_chunk (demux_plugin_t *this_gen) {
demux_asf_t *this = (demux_asf_t *) this_gen;
- asf_stream_t *stream = NULL;
+ asf_demux_stream_t *stream = NULL;
uint32_t frag_offset = 0;
uint32_t rlen = 0;
uint8_t raw_id = 0;
@@ -1905,26 +1710,19 @@ static void demux_asf_dispose (demux_plugin_t *this_gen) {
demux_asf_t *this = (demux_asf_t *) this_gen;
int i;
- for (i=0; i<this->num_streams; i++) {
- asf_stream_t *asf_stream;
+ for (i=0; i<this->asf_header->stream_count; i++) {
+ asf_demux_stream_t *asf_stream;
asf_stream = &this->streams[i];
if( asf_stream->buffer ) {
free( asf_stream->buffer );
asf_stream->buffer = NULL;
}
-
- if (asf_stream->wavex) {
- free (asf_stream->wavex);
- asf_stream->wavex = NULL;
- }
-
- if (asf_stream->bih) {
- free (asf_stream->bih);
- asf_stream->bih = NULL;
- }
}
+ if (this->asf_header)
+ asf_header_delete(this->asf_header);
+
free (this);
}
@@ -1973,7 +1771,7 @@ static int demux_asf_seek (demux_plugin_t *this_gen,
off_t start_pos, int start_time, int playing) {
demux_asf_t *this = (demux_asf_t *) this_gen;
- asf_stream_t *stream = NULL;
+ asf_demux_stream_t *stream = NULL;
uint32_t frag_offset = 0;
uint32_t rlen = 0;
uint8_t raw_id, stream_id;
@@ -1996,7 +1794,7 @@ static int demux_asf_seek (demux_plugin_t *this_gen,
/*
* seek to start position
*/
- for(i = 0; i < this->num_streams; i++) {
+ for(i = 0; i < this->asf_header->stream_count; i++) {
this->streams[i].frag_offset = 0;
this->streams[i].first_seq = 1;
this->streams[i].seq = 0;
@@ -2032,7 +1830,7 @@ static int demux_asf_seek (demux_plugin_t *this_gen,
state = 0;
/* no video stream */
- if (this->video_stream_id == -1) {
+ if (this->video_stream == -1) {
lprintf ("demux_asf_seek: no video stream\n");
state = 2;
}
@@ -2085,7 +1883,7 @@ static int demux_asf_seek (demux_plugin_t *this_gen,
if (state == 0) {
if (this->keyframe_found) {
- if (this->audio_stream_id == -1) {
+ if (this->audio_stream == -1) {
lprintf ("demux_asf_seek: no audio stream\n");
state = 5;
}
@@ -2095,7 +1893,7 @@ static int demux_asf_seek (demux_plugin_t *this_gen,
check_newpts (this, ts * 90, 1, 0);
}
} else if (state == 1) {
- if ((stream_id == this->audio_stream_id) && ts &&
+ if ((stream_id == this->asf_header->streams[this->audio_stream]->stream_number) && ts &&
(ts <= this->keyframe_ts)) {
lprintf ("demux_asf_seek: audio packet found at %lld, ts = %lld\n", start_pos, ts);
@@ -2103,7 +1901,7 @@ static int demux_asf_seek (demux_plugin_t *this_gen,
break;
}
} else if (state == 2) {
- if ((stream_id == this->audio_stream_id) && !frag_offset) {
+ if ((stream_id == this->asf_header->streams[this->audio_stream]->stream_number) && !frag_offset) {
this->keyframe_found = 1;
this->keyframe_ts = ts;
state = 5; /* end */
@@ -2165,7 +1963,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen,
input_plugin_t *input) {
demux_asf_t *this;
- char buf[MAX_PREVIEW_SIZE+1];
+ uint8_t buf[MAX_PREVIEW_SIZE+1];
int len;
switch (stream->content_detection_method) {
@@ -2255,11 +2053,11 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen,
}
if(len > 0) {
buf[len] = '\0';
- if( strstr(buf,"asx") || strstr(buf,"ASX") )
+ if( strstr((char*)buf,"asx") || strstr((char*)buf,"ASX") )
this->mode = ASF_MODE_ASX_REF;
- if( strstr(buf,"[Reference]") )
+ if( strstr((char*)buf,"[Reference]") )
this->mode = ASF_MODE_HTTP_REF;
- if( strstr(buf,"ASF ") )
+ if( strstr((char*)buf,"ASF ") )
this->mode = ASF_MODE_ASF_REF;
}
diff --git a/src/input/Makefile.am b/src/input/Makefile.am
index 1b651f1f5..c0924f829 100644
--- a/src/input/Makefile.am
+++ b/src/input/Makefile.am
@@ -86,7 +86,7 @@ xineplug_inp_net_la_LIBADD = $(XINE_LIB) $(THREAD_LIBS)
xineplug_inp_net_la_CFLAGS = $(VISIBILITY_FLAG) $(AM_CFLAGS)
xineplug_inp_net_la_LDFLAGS = -avoid-version -module
-xineplug_inp_mms_la_SOURCES = input_mms.c net_buf_ctrl.c mms.c mmsh.c http_helper.c
+xineplug_inp_mms_la_SOURCES = input_mms.c net_buf_ctrl.c mms.c mmsh.c http_helper.c ../demuxers/asfheader.c
xineplug_inp_mms_la_LIBADD = $(XINE_LIB) @LIBICONV@ $(THREAD_LIBS)
xineplug_inp_mms_la_CFLAGS = $(VISIBILITY_FLAG) $(AM_CFLAGS)
xineplug_inp_mms_la_LDFLAGS = -avoid-version -module
diff --git a/src/input/mms.c b/src/input/mms.c
index 8843970f6..6c735295e 100644
--- a/src/input/mms.c
+++ b/src/input/mms.c
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: mms.c,v 1.60 2006/07/11 09:37:31 mshopf Exp $
+ * $Id: mms.c,v 1.61 2006/09/07 07:21:06 tmattern Exp $
*
* MMS over TCP protocol
* based on work from major mms
@@ -131,25 +131,19 @@ struct mms_s {
int buf_size;
int buf_read;
- uint8_t asf_header[ASF_HEADER_LEN];
+ asf_header_t *asf_header;
+ uint8_t asf_header_buffer[ASF_HEADER_LEN];
uint32_t asf_header_len;
uint32_t asf_header_read;
+
int seq_num;
- int num_stream_ids;
- int stream_ids[ASF_MAX_NUM_STREAMS];
- int stream_types[ASF_MAX_NUM_STREAMS];
- uint32_t asf_packet_len;
- uint64_t file_len;
char guid[37];
- uint32_t bitrates[ASF_MAX_NUM_STREAMS];
- uint32_t bitrates_pos[ASF_MAX_NUM_STREAMS];
int bandwidth;
- int has_audio;
- int has_video;
- int live_flag;
off_t current_pos;
int eos;
+
+ uint8_t live_flag;
};
@@ -185,33 +179,6 @@ static void mms_buffer_put_32 (mms_buffer_t *mms_buffer, uint32_t value) {
mms_buffer->pos += 4;
}
-static int get_guid (unsigned char *buffer, int offset) {
- int i;
- GUID g;
-
- g.Data1 = LE_32(buffer + offset);
- g.Data2 = LE_16(buffer + offset + 4);
- g.Data3 = LE_16(buffer + offset + 6);
- for(i = 0; i < 8; i++) {
- g.Data4[i] = buffer[offset + 8 + i];
- }
-
- for (i = 1; i < GUID_END; i++) {
- if (!memcmp(&g, &guids[i].guid, sizeof(GUID))) {
- lprintf ("GUID: %s\n", guids[i].name);
- return i;
- }
- }
-
- lprintf ("unknown GUID: 0x%x, 0x%x, 0x%x, "
- "{ 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx }\n",
- g.Data1, g.Data2, g.Data3,
- g.Data4[0], g.Data4[1], g.Data4[2], g.Data4[3],
- g.Data4[4], g.Data4[5], g.Data4[6], g.Data4[7]);
-
- return GUID_ERROR;
-}
-
static void print_command (char *data, int len) {
@@ -524,122 +491,22 @@ static int get_asf_header (mms_t *this) {
return 1;
}
-static void interp_asf_header (mms_t *this) {
-
- unsigned int i;
-
- this->asf_packet_len = 0;
- this->num_stream_ids = 0;
- /*
- * parse header
- */
-
- i = 30;
- while (i < this->asf_header_len) {
-
- uint64_t length;
- int guid;
-
- guid = get_guid(this->asf_header, i);
- i += 16;
-
- length = LE_64(this->asf_header + i);
- i += 8;
-
- switch (guid) {
-
- case GUID_ASF_FILE_PROPERTIES:
-
- this->asf_packet_len = LE_32(this->asf_header + i + 92 - 24);
- if (this->asf_packet_len > BUF_SIZE) {
- this->asf_packet_len = 0;
- xprintf (this->stream->xine, XINE_VERBOSITY_LOG,
- "libmms: asf packet len too large\n");
- break;
- }
- this->file_len = LE_64(this->asf_header + i + 40 - 24);
- lprintf ("file object, file_length = %lld, packet length = %d",
- this->file_len, this->asf_packet_len);
- break;
-
- case GUID_ASF_STREAM_PROPERTIES:
- {
- uint16_t flags;
- uint16_t stream_id;
- int type;
- int encrypted;
-
- guid = get_guid(this->asf_header, i);
- switch (guid) {
- case GUID_ASF_AUDIO_MEDIA:
- type = ASF_STREAM_TYPE_AUDIO;
- this->has_audio = 1;
- break;
-
- case GUID_ASF_VIDEO_MEDIA:
- case GUID_ASF_JFIF_MEDIA:
- case GUID_ASF_DEGRADABLE_JPEG_MEDIA:
- type = ASF_STREAM_TYPE_VIDEO;
- this->has_video = 1;
- break;
-
- case GUID_ASF_COMMAND_MEDIA:
- type = ASF_STREAM_TYPE_CONTROL;
- break;
-
- default:
- type = ASF_STREAM_TYPE_UNKNOWN;
- }
-
- flags = LE_16(this->asf_header + i + 48);
- stream_id = flags & 0x7F;
- encrypted = flags >> 15;
-
- lprintf ("stream object, stream id: %d, type: %d, encrypted: %d\n",
- stream_id, type, encrypted);
-
- if (this->num_stream_ids < ASF_MAX_NUM_STREAMS && stream_id < ASF_MAX_NUM_STREAMS) {
- this->stream_types[stream_id] = type;
- this->stream_ids[this->num_stream_ids] = stream_id;
- this->num_stream_ids++;
- } else {
- lprintf ("too many streams, skipping\n");
- }
-
- }
- break;
+static int interp_asf_header (mms_t *this) {
- case GUID_ASF_STREAM_BITRATE_PROPERTIES:
- {
- uint16_t streams = LE_16(this->asf_header + i);
- uint16_t stream_id;
- int j;
-
- lprintf ("stream bitrate properties\n");
- lprintf ("streams %d\n", streams);
-
- for(j = 0; j < streams; j++) {
- stream_id = LE_16(this->asf_header + i + 2 + j * 6);
- lprintf ("stream id %d\n", stream_id);
- this->bitrates[stream_id] = LE_32(this->asf_header + i + 4 + j * 6);
- this->bitrates_pos[stream_id] = i + 4 + j * 6;
- lprintf ("stream id %d, bitrate %d\n", stream_id,
- this->bitrates[stream_id]);
- }
- }
- break;
-
- default:
- lprintf ("unknown object\n");
- break;
- }
+ /* delete previous header */
+ if (this->asf_header) {
+ asf_header_delete(this->asf_header);
+ }
- lprintf ("length : %lld\n", length);
+ /* the header starts with :
+ * byte 0-15: header guid
+ * byte 16-23: header length
+ */
+ this->asf_header = asf_header_new(this->asf_header_buffer + 24, this->asf_header_len - 24);
+ if (!this->asf_header)
+ return 0;
- if (length > 24) {
- i += length - 24;
- }
- }
+ return 1;
}
static const char *const mmst_proto_s[] = { "mms", "mmst", NULL };
@@ -729,99 +596,35 @@ static int mms_choose_best_streams(mms_t *this) {
int i;
int video_stream = 0;
int audio_stream = 0;
- unsigned int max_arate = 0;
- unsigned int min_vrate = 0;
- unsigned int min_bw_left = 0;
- int stream_id;
- unsigned int bandwitdh_left;
int res;
- /* command 0x33 */
/* choose the best quality for the audio stream */
- /* i've never seen more than one audio stream */
- lprintf("num_stream_ids=%d\n", this->num_stream_ids);
- for (i = 0; i < this->num_stream_ids; i++) {
- stream_id = this->stream_ids[i];
- switch (this->stream_types[stream_id]) {
- case ASF_STREAM_TYPE_AUDIO:
- if (this->bitrates[stream_id] > max_arate) {
- audio_stream = stream_id;
- max_arate = this->bitrates[stream_id];
- }
- break;
- default:
- break;
- }
- }
-
- /* choose a video stream adapted to the user bandwidth */
- bandwitdh_left = (int)( this->bandwidth - max_arate ) < 0 ? 0 : this->bandwidth - max_arate;
- lprintf("bandwitdh %d, left %d\n", this->bandwidth, bandwitdh_left);
-
- min_bw_left = bandwitdh_left;
- for (i = 0; i < this->num_stream_ids; i++) {
- stream_id = this->stream_ids[i];
- switch (this->stream_types[stream_id]) {
- case ASF_STREAM_TYPE_VIDEO:
- if (((bandwitdh_left - this->bitrates[stream_id]) < min_bw_left) &&
- (bandwitdh_left >= this->bitrates[stream_id])) {
- video_stream = stream_id;
- min_bw_left = bandwitdh_left - this->bitrates[stream_id];
- }
- break;
- default:
- break;
- }
- }
-
- /* choose the lower bitrate of */
- if (!video_stream && this->has_video) {
- for (i = 0; i < this->num_stream_ids; i++) {
- stream_id = this->stream_ids[i];
- switch (this->stream_types[stream_id]) {
- case ASF_STREAM_TYPE_VIDEO:
- if ((this->bitrates[stream_id] < min_vrate) ||
- (!min_vrate)) {
- video_stream = stream_id;
- min_vrate = this->bitrates[stream_id];
- }
- break;
- default:
- break;
- }
- }
- }
+
+ asf_header_choose_streams (this->asf_header, this->bandwidth, &video_stream, &audio_stream);
lprintf("selected streams: audio %d, video %d\n", audio_stream, video_stream);
lprintf("disabling other streams\n");
memset (this->scmd_body, 0, 40);
- for (i = 1; i < this->num_stream_ids; i++) {
+ for (i = 1; i < this->asf_header->stream_count; i++) {
this->scmd_body [ (i - 1) * 6 + 2 ] = 0xFF;
this->scmd_body [ (i - 1) * 6 + 3 ] = 0xFF;
- this->scmd_body [ (i - 1) * 6 + 4 ] = this->stream_ids[i] ;
- this->scmd_body [ (i - 1) * 6 + 5 ] = this->stream_ids[i] >> 8;
- if ((this->stream_ids[i] == audio_stream) ||
- (this->stream_ids[i] == video_stream)) {
+ this->scmd_body [ (i - 1) * 6 + 4 ] = this->asf_header->streams[i]->stream_number;
+ this->scmd_body [ (i - 1) * 6 + 5 ] = this->asf_header->streams[i]->stream_number >> 8;
+ if ((i == audio_stream) ||
+ (i == video_stream)) {
this->scmd_body [ (i - 1) * 6 + 6 ] = 0x00;
this->scmd_body [ (i - 1) * 6 + 7 ] = 0x00;
} else {
- lprintf("disabling stream %d\n", this->stream_ids[i]);
+ lprintf("disabling stream %d\n", this->asf_header->streams[i]->stream_number);
this->scmd_body [ (i - 1) * 6 + 6 ] = 0x02;
this->scmd_body [ (i - 1) * 6 + 7 ] = 0x00;
-
- /* forces the asf demuxer to not choose this stream */
- if (this->bitrates_pos[this->stream_ids[i]]) {
- this->asf_header[this->bitrates_pos[this->stream_ids[i]]] = 0;
- this->asf_header[this->bitrates_pos[this->stream_ids[i]] + 1] = 0;
- this->asf_header[this->bitrates_pos[this->stream_ids[i]] + 2] = 0;
- this->asf_header[this->bitrates_pos[this->stream_ids[i]] + 3] = 0;
- }
}
}
- if (!send_command (this, 0x33, this->num_stream_ids,
- 0xFFFF | this->stream_ids[0] << 16,
- this->num_stream_ids * 6 + 2)) {
+ /* command 0x33 */
+ if (!send_command (this, 0x33, this->asf_header->stream_count,
+ 0xFFFF | this->asf_header->streams[0]->stream_number << 16,
+ this->asf_header->stream_count * 6 + 2)) {
xprintf (this->stream->xine, XINE_VERBOSITY_LOG,
"libmms: mms_choose_best_streams failed\n");
return 0;
@@ -861,12 +664,8 @@ mms_t *mms_connect (xine_stream_t *stream, const char *url, int bandwidth) {
this->scmd_body = this->scmd + CMD_HEADER_LEN + CMD_PREFIX_LEN;
this->asf_header_len = 0;
this->asf_header_read = 0;
- this->num_stream_ids = 0;
- this->asf_packet_len = 0;
this->buf_size = 0;
this->buf_read = 0;
- this->has_audio = 0;
- this->has_video = 0;
this->bandwidth = bandwidth;
this->current_pos = 0;
this->eos = 0;
@@ -1022,7 +821,6 @@ mms_t *mms_connect (xine_stream_t *stream, const char *url, int bandwidth) {
goto fail;
}
- this->num_stream_ids = 0;
if (!get_asf_header (this))
goto fail;
@@ -1195,7 +993,7 @@ static int get_media_packet (mms_t *this) {
lprintf ("asf media packet detected, packet_len=%d, packet_seq=%d\n",
header.packet_len, header.packet_seq);
- if (header.packet_len > this->asf_packet_len) {
+ if (header.packet_len > this->asf_header->file->packet_size) {
xprintf (this->stream->xine, XINE_VERBOSITY_LOG,
"libmms: invalid asf packet len: %d bytes\n", header.packet_len);
return 0;
@@ -1209,9 +1007,9 @@ static int get_media_packet (mms_t *this) {
}
/* explicit padding with 0 */
- lprintf("padding: %d bytes\n", this->asf_packet_len - header.packet_len);
- memset(this->buf + header.packet_len, 0, this->asf_packet_len - header.packet_len);
- this->buf_size = this->asf_packet_len;
+ lprintf("padding: %d bytes\n", this->asf_header->file->packet_size - header.packet_len);
+ memset(this->buf + header.packet_len, 0, this->asf_header->file->packet_size - header.packet_len);
+ this->buf_size = this->asf_header->file->packet_size;
}
break;
}
@@ -1228,7 +1026,7 @@ size_t mms_peek_header (mms_t *this, char *data, size_t maxsize) {
len = (this->asf_header_len < maxsize) ? this->asf_header_len : maxsize;
- memcpy(data, this->asf_header, len);
+ memcpy(data, this->asf_header_buffer, len);
return len;
}
@@ -1248,7 +1046,7 @@ int mms_read (mms_t *this, char *data, int len) {
else
n = bytes_left;
- xine_fast_memcpy (&data[total], &this->asf_header[this->asf_header_read], n);
+ xine_fast_memcpy (&data[total], &this->asf_header_buffer[this->asf_header_read], n);
this->asf_header_read += n;
total += n;
@@ -1300,12 +1098,13 @@ void mms_close (mms_t *this) {
free(this->password);
if (this->uri)
free(this->uri);
-
+ if (this->asf_header)
+ asf_header_delete(this->asf_header);
free (this);
}
uint32_t mms_get_length (mms_t *this) {
- return this->file_len;
+ return this->asf_header->file->file_size;
}
off_t mms_get_current_pos (mms_t *this) {
diff --git a/src/input/mmsh.c b/src/input/mmsh.c
index 0b63c8db3..76854b409 100644
--- a/src/input/mmsh.c
+++ b/src/input/mmsh.c
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: mmsh.c,v 1.38 2006/07/11 09:37:31 mshopf Exp $
+ * $Id: mmsh.c,v 1.39 2006/09/07 07:21:06 tmattern Exp $
*
* MMS over HTTP protocol
* written by Thibaut Mattern
@@ -162,8 +162,9 @@ struct mmsh_s {
char str[SCRATCH_SIZE]; /* scratch buffer to built strings */
- int stream_type; /* seekable or broadcast */
-
+ asf_header_t *asf_header;
+ int stream_type;
+
/* receive buffer */
/* chunk */
@@ -175,53 +176,15 @@ struct mmsh_s {
int buf_size;
int buf_read;
- uint8_t asf_header[ASF_HEADER_SIZE];
+ uint8_t asf_header_buffer[ASF_HEADER_SIZE];
uint32_t asf_header_len;
uint32_t asf_header_read;
int seq_num;
- int num_stream_ids;
- int stream_ids[ASF_MAX_NUM_STREAMS];
- int stream_types[ASF_MAX_NUM_STREAMS];
- uint32_t packet_length;
- int64_t file_length;
- char guid[37];
- uint32_t bitrates[ASF_MAX_NUM_STREAMS];
- uint32_t bitrates_pos[ASF_MAX_NUM_STREAMS];
-
- int has_audio;
- int has_video;
-
+
off_t current_pos;
int user_bandwitdh;
};
-static int get_guid (unsigned char *buffer, int offset) {
- int i;
- GUID g;
-
- g.Data1 = LE_32(buffer + offset);
- g.Data2 = LE_16(buffer + offset + 4);
- g.Data3 = LE_16(buffer + offset + 6);
- for(i = 0; i < 8; i++) {
- g.Data4[i] = buffer[offset + 8 + i];
- }
-
- for (i = 1; i < GUID_END; i++) {
- if (!memcmp(&g, &guids[i].guid, sizeof(GUID))) {
- lprintf ("GUID: %s\n", guids[i].name);
-
- return i;
- }
- }
-
- lprintf ("libmmsh: unknown GUID: 0x%x, 0x%x, 0x%x, "
- "{ 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx }\n",
- g.Data1, g.Data2, g.Data3,
- g.Data4[0], g.Data4[1], g.Data4[2], g.Data4[3],
- g.Data4[4], g.Data4[5], g.Data4[6], g.Data4[7]);
- return GUID_ERROR;
-}
-
static int send_command (mmsh_t *this, char *cmd) {
int length;
@@ -274,28 +237,28 @@ static int get_answer (mmsh_t *this) {
if (sscanf((char*)this->buf, "HTTP/%d.%d %d %50[^\015\012]", &httpver, &httpsub,
&httpcode, httpstatus) != 4) {
xine_log (this->stream->xine, XINE_LOG_MSG,
- _("libmmsh: bad response format\n"));
+ _("libmmsh: bad response format\n"));
return 0;
}
if (httpcode >= 300 && httpcode < 400) {
xine_log (this->stream->xine, XINE_LOG_MSG,
- _("libmmsh: 3xx redirection not implemented: >%d %s<\n"),
- httpcode, httpstatus);
+ _("libmmsh: 3xx redirection not implemented: >%d %s<\n"),
+ httpcode, httpstatus);
return 0;
}
if (httpcode < 200 || httpcode >= 300) {
xine_log (this->stream->xine, XINE_LOG_MSG,
- _("libmmsh: http status not 2xx: >%d %s<\n"),
- httpcode, httpstatus);
+ _("libmmsh: http status not 2xx: >%d %s<\n"),
+ httpcode, httpstatus);
return 0;
}
} else {
if (!strncasecmp((char*)this->buf, "Location: ", 10)) {
xine_log (this->stream->xine, XINE_LOG_MSG,
- _("libmmsh: Location redirection not implemented\n"));
+ _("libmmsh: Location redirection not implemented\n"));
return 0;
}
@@ -460,123 +423,25 @@ static int get_header (mmsh_t *this) {
}
}
-static void interp_header (mmsh_t *this) {
-
- unsigned int i;
+static int interp_header (mmsh_t *this) {
lprintf ("interp_header, header_len=%d\n", this->asf_header_len);
- this->packet_length = 0;
+ /* delete previous header */
+ if (this->asf_header) {
+ asf_header_delete(this->asf_header);
+ }
- /*
- * parse asf header
+ /* the header starts with :
+ * byte 0-15: header guid
+ * byte 16-23: header length
*/
+ this->asf_header = asf_header_new(this->asf_header_buffer + 24, this->asf_header_len - 24);
+ if (!this->asf_header)
+ return 0;
- i = 30;
- while ((i + 24) < this->asf_header_len) {
-
- int guid;
- uint64_t length;
-
- guid = get_guid(this->asf_header, i);
- i += 16;
-
- length = LE_64(this->asf_header + i);
- i += 8;
-
- if ((i + length) >= this->asf_header_len) return;
-
- switch (guid) {
-
- case GUID_ASF_FILE_PROPERTIES:
-
- this->packet_length = LE_32(this->asf_header + i + 92 - 24);
- if (this->packet_length > CHUNK_SIZE) {
- this->packet_length = 0;
- break;
- }
- this->file_length = LE_64(this->asf_header + i + 40 - 24);
- /*lprintf ("file object, file_length = %lld, packet length = %d",
- this->file_length, this->packet_count);*/
- break;
-
- case GUID_ASF_STREAM_PROPERTIES:
- {
- uint16_t flags;
- uint16_t stream_id;
- int type;
- int encrypted;
-
- guid = get_guid(this->asf_header, i);
- switch (guid) {
- case GUID_ASF_AUDIO_MEDIA:
- type = ASF_STREAM_TYPE_AUDIO;
- this->has_audio = 1;
- break;
-
- case GUID_ASF_VIDEO_MEDIA:
- case GUID_ASF_JFIF_MEDIA:
- case GUID_ASF_DEGRADABLE_JPEG_MEDIA:
- type = ASF_STREAM_TYPE_VIDEO;
- this->has_video = 1;
- break;
-
- case GUID_ASF_COMMAND_MEDIA:
- type = ASF_STREAM_TYPE_CONTROL;
- break;
-
- default:
- type = ASF_STREAM_TYPE_UNKNOWN;
- }
-
- flags = LE_16(this->asf_header + i + 48);
- stream_id = flags & 0x7F;
- encrypted = flags >> 15;
-
- lprintf ("stream object, stream id: %d, type: %d, encrypted: %d\n",
- stream_id, type, encrypted);
-
- this->stream_types[stream_id] = type;
- this->stream_ids[this->num_stream_ids] = stream_id;
- this->num_stream_ids++;
-
- }
- break;
-
- case GUID_ASF_STREAM_BITRATE_PROPERTIES:
- {
- uint16_t streams = LE_16(this->asf_header + i);
- uint16_t stream_id;
- int j;
-
- lprintf ("stream bitrate properties\n");
- lprintf ("streams %d\n", streams);
-
- for(j = 0; j < streams; j++) {
- stream_id = LE_16(this->asf_header + i + 2 + j * 6);
-
- lprintf ("stream id %d\n", stream_id);
-
- this->bitrates[stream_id] = LE_32(this->asf_header + i + 4 + j * 6);
- this->bitrates_pos[stream_id] = i + 4 + j * 6;
- xprintf (this->stream->xine, XINE_VERBOSITY_LOG,
- "libmmsh: stream id %d, bitrate %d\n",
- stream_id, this->bitrates[stream_id]);
- }
- }
- break;
-
- default:
- lprintf ("unknown object\n");
- break;
- }
-
- lprintf ("length : %lld\n", length);
-
- if (length > 24) {
- i += length - 24;
- }
- }
+ this->buf_size = this->asf_header->file->packet_size;
+ return 1;
}
static const char *const mmsh_proto_s[] = { "mms", "mmsh", NULL };
@@ -652,19 +517,13 @@ static int mmsh_tcp_connect(mmsh_t *this) {
static int mmsh_connect_int(mmsh_t *this, int bandwidth) {
int i;
- int video_stream = -1;
- int audio_stream = -1;
- int max_arate = -1;
- int min_vrate = -1;
- int min_bw_left = 0;
- int stream_id;
- int bandwitdh_left;
char stream_selection[10 * ASF_MAX_NUM_STREAMS]; /* 10 chars per stream */
int offset;
+ int audio_stream, video_stream;
+
/*
* let the negotiations begin...
*/
- this->num_stream_ids = 0;
/* first request */
lprintf("first http request\n");
@@ -678,71 +537,15 @@ static int mmsh_connect_int(mmsh_t *this, int bandwidth) {
if (!get_answer (this))
goto fail;
-
- get_header(this);
- interp_header(this);
+ get_header(this); /* FIXME: it returns 0 */
+
+ if (!interp_header(this))
+ goto fail;
close(this->s);
report_progress (this->stream, 20);
-
- /* choose the best quality for the audio stream */
- /* i've never seen more than one audio stream */
- for (i = 0; i < this->num_stream_ids; i++) {
- stream_id = this->stream_ids[i];
- switch (this->stream_types[stream_id]) {
- case ASF_STREAM_TYPE_AUDIO:
- if ((audio_stream == -1) || (this->bitrates[stream_id] > max_arate)) {
- audio_stream = stream_id;
- max_arate = this->bitrates[stream_id];
- }
- break;
- default:
- break;
- }
- }
-
- /* choose a video stream adapted to the user bandwidth */
- bandwitdh_left = bandwidth - max_arate;
- if (bandwitdh_left < 0) {
- bandwitdh_left = 0;
- }
- lprintf("bandwitdh %d, left %d\n", bandwidth, bandwitdh_left);
-
- min_bw_left = bandwitdh_left;
- for (i = 0; i < this->num_stream_ids; i++) {
- stream_id = this->stream_ids[i];
- switch (this->stream_types[stream_id]) {
- case ASF_STREAM_TYPE_VIDEO:
- if (((bandwitdh_left - this->bitrates[stream_id]) < min_bw_left) &&
- (bandwitdh_left >= this->bitrates[stream_id])) {
- video_stream = stream_id;
- min_bw_left = bandwitdh_left - this->bitrates[stream_id];
- }
- break;
- default:
- break;
- }
- }
-
- /* choose the stream with the lower bitrate */
- if ((video_stream == -1) && this->has_video) {
- for (i = 0; i < this->num_stream_ids; i++) {
- stream_id = this->stream_ids[i];
- switch (this->stream_types[stream_id]) {
- case ASF_STREAM_TYPE_VIDEO:
- if ((video_stream == -1) ||
- (this->bitrates[stream_id] < min_vrate) ||
- (!min_vrate)) {
- video_stream = stream_id;
- min_vrate = this->bitrates[stream_id];
- }
- break;
- default:
- break;
- }
- }
- }
+ asf_header_choose_streams (this->asf_header, bandwidth, &video_stream, &audio_stream);
lprintf("audio stream %d, video stream %d\n", audio_stream, video_stream);
@@ -758,17 +561,17 @@ static int mmsh_connect_int(mmsh_t *this, int bandwidth) {
/* 0 means selected */
/* 2 means disabled */
offset = 0;
- for (i = 0; i < this->num_stream_ids; i++) {
+ for (i = 0; i < this->asf_header->stream_count; i++) {
int size;
- if ((this->stream_ids[i] == audio_stream) ||
- (this->stream_ids[i] == video_stream)) {
+ if ((i == audio_stream) ||
+ (i == video_stream)) {
size = snprintf(stream_selection + offset, sizeof(stream_selection) - offset,
- "ffff:%d:0 ", this->stream_ids[i]);
+ "ffff:%d:0 ", this->asf_header->streams[i]->stream_number);
} else {
xprintf (this->stream->xine, XINE_VERBOSITY_LOG,
- "disabling stream %d\n", this->stream_ids[i]);
+ "disabling stream %d\n", this->asf_header->streams[i]->stream_number);
size = snprintf(stream_selection + offset, sizeof(stream_selection) - offset,
- "ffff:%d:2 ", this->stream_ids[i]);
+ "ffff:%d:2 ", this->asf_header->streams[i]->stream_number);
}
if (size < 0) goto fail;
offset += size;
@@ -778,12 +581,12 @@ static int mmsh_connect_int(mmsh_t *this, int bandwidth) {
case MMSH_SEEKABLE:
snprintf (this->str, SCRATCH_SIZE, mmsh_SeekableRequest, this->uri,
this->host, this->port, 0, 0, 0, 2, 0,
- this->num_stream_ids, stream_selection);
+ this->asf_header->stream_count, stream_selection);
break;
case MMSH_LIVE:
snprintf (this->str, SCRATCH_SIZE, mmsh_LiveRequest, this->uri,
this->host, this->port, 2,
- this->num_stream_ids, stream_selection);
+ this->asf_header->stream_count, stream_selection);
break;
}
@@ -797,23 +600,12 @@ static int mmsh_connect_int(mmsh_t *this, int bandwidth) {
if (!get_header(this))
goto fail;
- interp_header(this);
- this->buf_size = this->packet_length;
-
- for (i = 0; i < this->num_stream_ids; i++) {
- if ((this->stream_ids[i] != audio_stream) &&
- (this->stream_ids[i] != video_stream)) {
- lprintf("disabling stream %d\n", this->stream_ids[i]);
-
- /* forces the asf demuxer to not choose this stream */
- if (this->bitrates_pos[this->stream_ids[i]]) {
- this->asf_header[this->bitrates_pos[this->stream_ids[i]]] = 0;
- this->asf_header[this->bitrates_pos[this->stream_ids[i]] + 1] = 0;
- this->asf_header[this->bitrates_pos[this->stream_ids[i]] + 2] = 0;
- this->asf_header[this->bitrates_pos[this->stream_ids[i]] + 3] = 0;
- }
- }
- }
+
+ if (!interp_header(this))
+ goto fail;
+
+ asf_header_disable_streams (this->asf_header, video_stream, audio_stream);
+
return 1;
fail:
@@ -835,12 +627,8 @@ mmsh_t *mmsh_connect (xine_stream_t *stream, const char *url, int bandwidth) {
this->s = -1;
this->asf_header_len = 0;
this->asf_header_read = 0;
- this->num_stream_ids = 0;
- this->packet_length = 0;
this->buf_size = 0;
this->buf_read = 0;
- this->has_audio = 0;
- this->has_video = 0;
this->current_pos = 0;
this->user_bandwitdh = bandwidth;
@@ -904,7 +692,7 @@ fail:
static int get_media_packet (mmsh_t *this) {
int len = 0;
- lprintf("get_media_packet: this->packet_length: %d\n", this->packet_length);
+ lprintf("get_media_packet: this->packet_length: %d\n", this->asf_header->file->packet_size);
if (get_chunk_header(this)) {
switch (this->chunk_type) {
@@ -942,7 +730,6 @@ static int get_media_packet (mmsh_t *this) {
if (!get_header(this))
return 0;
interp_header(this);
- this->buf_size = this->packet_length;
return 2;
default:
@@ -955,15 +742,14 @@ static int get_media_packet (mmsh_t *this) {
if (len == this->chunk_length) {
/* explicit padding with 0 */
- if (this->chunk_length > this->packet_length) {
+ if (this->chunk_length > this->asf_header->file->packet_size) {
xprintf (this->stream->xine, XINE_VERBOSITY_LOG,
"libmmsh: chunk_length(%d) > packet_length(%d)\n",
- this->chunk_length, this->packet_length);
+ this->chunk_length, this->asf_header->file->packet_size);
return 0;
}
memset(this->buf + this->chunk_length, 0,
- this->packet_length - this->chunk_length);
- this->buf_size = this->packet_length;
+ this->asf_header->file->packet_size - this->chunk_length);
return 1;
} else {
xprintf (this->stream->xine, XINE_VERBOSITY_LOG,
@@ -982,7 +768,7 @@ size_t mmsh_peek_header (mmsh_t *this, char *data, size_t maxsize) {
len = (this->asf_header_len < maxsize) ? this->asf_header_len : maxsize;
- memcpy(data, this->asf_header, len);
+ memcpy(data, this->asf_header_buffer, len);
return len;
}
@@ -1001,11 +787,11 @@ int mmsh_read (mmsh_t *this, char *data, int len) {
bytes_left = this->asf_header_len - this->asf_header_read ;
if ((len-total) < bytes_left)
- n = len-total;
+ n = len-total;
else
- n = bytes_left;
+ n = bytes_left;
- xine_fast_memcpy (&data[total], &this->asf_header[this->asf_header_read], n);
+ xine_fast_memcpy (&data[total], &this->asf_header_buffer[this->asf_header_read], n);
this->asf_header_read += n;
total += n;
@@ -1022,13 +808,13 @@ int mmsh_read (mmsh_t *this, char *data, int len) {
this->buf_read = 0;
packet_type = get_media_packet (this);
- if (packet_type == 0) {
- xprintf (this->stream->xine, XINE_VERBOSITY_LOG,
+ if (packet_type == 0) {
+ xprintf (this->stream->xine, XINE_VERBOSITY_LOG,
"libmmsh: get_media_packet failed\n");
return total;
- } else if (packet_type == 2) {
- continue;
- }
+ } else if (packet_type == 2) {
+ continue;
+ }
bytes_left = this->buf_size;
}
@@ -1067,13 +853,15 @@ void mmsh_close (mmsh_t *this) {
free(this->password);
if (this->uri)
free(this->uri);
+ if (this->asf_header)
+ asf_header_delete(this->asf_header);
if (this)
free (this);
}
uint32_t mmsh_get_length (mmsh_t *this) {
- return this->file_length;
+ return this->asf_header->file->file_size;
}
off_t mmsh_get_current_pos (mmsh_t *this) {