summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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) {