diff options
-rw-r--r-- | src/demuxers/Makefile.am | 2 | ||||
-rw-r--r-- | src/demuxers/asfheader.c | 806 | ||||
-rw-r--r-- | src/demuxers/asfheader.h | 663 | ||||
-rw-r--r-- | src/demuxers/demux_asf.c | 720 | ||||
-rw-r--r-- | src/input/Makefile.am | 2 | ||||
-rw-r--r-- | src/input/mms.c | 281 | ||||
-rw-r--r-- | src/input/mmsh.c | 336 |
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, ©right_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) { |