From 045444a964c3b8d84142697bbcc98db3d959a0db Mon Sep 17 00:00:00 2001 From: Thibaut Mattern Date: Thu, 7 Sep 2006 07:21:06 +0000 Subject: Added common asf header parser. Modified the mms input plugins and the asf demuxer to use the new parser. Added Asf Extended Header parsing, fixed best stream selection. CVS patchset: 8203 CVS date: 2006/09/07 07:21:06 --- src/demuxers/Makefile.am | 2 +- src/demuxers/asfheader.c | 806 +++++++++++++++++++++++++++++++++++++++++++++++ src/demuxers/asfheader.h | 663 +++++++++++++++++++++++--------------- src/demuxers/demux_asf.c | 720 +++++++++++++++--------------------------- src/input/Makefile.am | 2 +- src/input/mms.c | 281 +++-------------- src/input/mmsh.c | 336 ++++---------------- 7 files changed, 1571 insertions(+), 1239 deletions(-) create mode 100644 src/demuxers/asfheader.c 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 +#include +#include + + +#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 +#include + +/* + * 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; inum_streams; i++) { - asf_stream_t *asf_stream; + for (i=0; iasf_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) { -- cgit v1.2.3