diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/demuxers/demux_asf.c | 1066 |
1 files changed, 656 insertions, 410 deletions
diff --git a/src/demuxers/demux_asf.c b/src/demuxers/demux_asf.c index 2bd3f1f05..dac20428a 100644 --- a/src/demuxers/demux_asf.c +++ b/src/demuxers/demux_asf.c @@ -17,13 +17,16 @@ * 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.83 2002/11/28 10:21:05 petli Exp $ + * $Id: demux_asf.c,v 1.84 2002/12/01 17:07:17 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 */ #ifdef HAVE_CONFIG_H @@ -43,17 +46,71 @@ /* #define LOG */ - -#define PACKET_SIZE 3200 -#define PACKET_HEADER_SIZE 12 -#define FRAME_HEADER_SIZE 17 -#define CODEC_TYPE_AUDIO 0 -#define CODEC_TYPE_VIDEO 1 -#define CODEC_TYPE_CONTROL 2 -#define MAX_NUM_STREAMS 23 +#define CODEC_TYPE_AUDIO 0 +#define CODEC_TYPE_VIDEO 1 +#define CODEC_TYPE_CONTROL 2 +#define MAX_NUM_STREAMS 23 #define DEFRAG_BUFSIZE 65536 +/* + * 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 + + /* header ASF objects */ +#define GUID_ASF_FILE_PROPERTIES 4 +#define GUID_ASF_STREAM_PROPERTIES 5 +#define GUID_ASF_STREAM_BITRATE_PROPERTIES 6 +#define GUID_ASF_CONTENT_DESCRIPTION 7 +#define GUID_ASF_EXTENDED_CONTENT_ENCRYPTION 8 +#define GUID_ASF_SCRIPT_COMMAND 9 +#define GUID_ASF_MARKER 10 +#define GUID_ASF_HEADER_EXTENSION 11 +#define GUID_ASF_BITRATE_MUTUAL_EXCLUSION 12 +#define GUID_ASF_CODEC_LIST 13 +#define GUID_ASF_EXTENDED_CONTENT_DESCRIPTION 14 +#define GUID_ASF_ERROR_CORRECTION 15 +#define GUID_ASF_PADDING 16 + + /* stream properties object stream type */ +#define GUID_ASF_AUDIO_MEDIA 17 +#define GUID_ASF_VIDEO_MEDIA 18 +#define GUID_ASF_COMMAND_MEDIA 19 + + /* stream properties object error correction type */ +#define GUID_ASF_NO_ERROR_CORRECTION 20 +#define GUID_ASF_AUDIO_SPREAD 21 + + /* mutual exclusion object exlusion type */ +#define GUID_ASF_MUTEX_BITRATE 22 +#define GUID_ASF_MUTEX_UKNOWN 23 + + /* header extension */ +#define GUID_ASF_RESERVED_1 24 + + /* script command */ +#define GUID_ASF_RESERVED_SCRIPT_COMMNAND 25 + + /* marker object */ +#define GUID_ASF_RESERVED_MARKER 26 + + /* various */ +/* +#define GUID_ASF_HEAD2 27 +*/ +#define GUID_ASF_AUDIO_CONCEAL_NONE 27 +#define GUID_ASF_CODEC_COMMENT1_HEADER 28 +#define GUID_ASF_2_0_HEADER 29 + +#define GUID_END 30 + + typedef struct { int num; int seq; @@ -134,6 +191,10 @@ typedef struct demux_asf_s { off_t header_size; int buf_flag_seek; + + /* first packet position */ + int64_t first_packet_pos; + } demux_asf_t ; typedef struct { @@ -146,6 +207,7 @@ typedef struct { config_values_t *config; } demux_asf_class_t; + typedef struct { uint32_t v1; uint16_t v2; @@ -153,84 +215,125 @@ typedef struct { uint8_t v4[8]; } GUID; -static const GUID asf_header = { - 0x75B22630, 0x668E, 0x11CF, { 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C }, -}; +static const struct +{ + const char* name; + const GUID guid; +} guids[] = +{ + { "error", + { 0x0,} }, -static const GUID file_header = { - 0x8CABDCA1, 0xA947, 0x11CF, { 0x8E, 0xE4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }, -}; -static const GUID stream_header = { - 0xB7DC0791, 0xA9B7, 0x11CF, { 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }, -}; + /* 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 }} }, -static const GUID audio_stream = { - 0xF8699E40, 0x5B4D, 0x11CF, { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B }, -}; + { "simple index", + { 0x33000890, 0xe5b1, 0x11cf, { 0x89, 0xf4, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xcb }} }, -static const GUID audio_conceal_none = { - 0x49f1a440, 0x4ece, 0x11d0, { 0xa3, 0xac, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6 }, -}; -static const GUID audio_conceal_interleave = { - 0xbfc3cd50, 0x618f, 0x11cf, {0x8b, 0xb2, 0x00, 0xaa, 0x00, 0xb4, 0xe2, 0x20} }; + /* 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 }} }, -static const GUID video_stream = { - 0xBC19EFC0, 0x5B4D, 0x11CF, { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B }, -}; + { "stream bitrate properties", /* (http://get.to/sdp) */ + { 0x7bf875ce, 0x468d, 0x11d1, { 0x8d, 0x82, 0x00, 0x60, 0x97, 0xc9, 0xa2, 0xb2 }} }, -static const GUID video_conceal_none = { - 0x20FB5700, 0x5B55, 0x11CF, { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B }, -}; + { "content description", + { 0x75b22633, 0x668e, 0x11cf, { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c }} }, + { "extended content encryption", + { 0x298ae614, 0x2622, 0x4c17, { 0xb9, 0x35, 0xda, 0xe0, 0x7e, 0xe9, 0x28, 0x9c }} }, -static const GUID control_stream = { - 0x59dacfc0, 0x59e6, 0x11d0, { 0xa3, 0xac, 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 }} }, -static const GUID comment_header = { - 0x75b22633, 0x668e, 0x11cf, { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c }, -}; + { "header extension", + { 0x5fbf03b5, 0xa92e, 0x11cf, { 0x8e, 0xe3, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 }} }, -static const GUID codec_comment_header = { - 0x86D15240, 0x311D, 0x11D0, { 0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6 }, -}; -static const GUID codec_comment1_header = { - 0x86d15241, 0x311d, 0x11d0, { 0xa3, 0xa4, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6 }, -}; + { "bitrate mutual exclusion", + { 0xd6e229dc, 0x35da, 0x11d1, { 0x90, 0x34, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xbe }} }, + { "codec list", + { 0x86d15240, 0x311d, 0x11d0, { 0xa3, 0xa4, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6 }} }, -static const GUID data_header = { - 0x75b22636, 0x668e, 0x11cf, { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c }, -}; + { "extended content description", + { 0xd2d0a440, 0xe307, 0x11d2, { 0x97, 0xf0, 0x00, 0xa0, 0xc9, 0x5e, 0xa8, 0x50 }} }, -static const GUID index_guid = { - 0x33000890, 0xe5b1, 0x11cf, { 0x89, 0xf4, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xcb }, -}; + { "error correction", + { 0x75b22635, 0x668e, 0x11cf, { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c }} }, -static const GUID head1_guid = { - 0x5fbf03b5, 0xa92e, 0x11cf, { 0x8e, 0xe3, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 }, -}; + { "padding", + { 0x1806d474, 0xcadf, 0x4509, { 0xa4, 0xba, 0x9a, 0xab, 0xcb, 0x96, 0xaa, 0xe8 }} }, -static const GUID head2_guid = { - 0xabd3d211, 0xa9ba, 0x11cf, { 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 }, -}; -static const GUID stream_group_guid = { - 0x7bf875ce, 0x468d, 0x11d1, { 0x8d, 0x82, 0x00, 0x60, 0x97, 0xc9, 0xa2, 0xb2 }, -}; + /* 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 }} }, + + + /* 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 }} }, -/* I am not a number !!! This GUID is the one found on the PC used to - generate the stream */ -static const GUID my_guid = { - 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 }, }; + static uint8_t get_byte (demux_asf_t *this) { uint8_t buf; @@ -304,21 +407,31 @@ static uint64_t get_le64 (demux_asf_t *this) { | ((uint64_t) buf[7] << 54) ; } -static void get_guid (demux_asf_t *this, GUID *g) { +static int get_guid (demux_asf_t *this) { int i; - - g->v1 = get_le32(this); - g->v2 = get_le16(this); - g->v3 = get_le16(this); - for(i=0;i<8;i++) { - g->v4[i] = get_byte(this); + GUID g; + + g.v1 = get_le32(this); + g.v2 = get_le16(this); + g.v3 = get_le16(this); + for(i = 0; i < 8; i++) { + g.v4[i] = get_byte(this); } + + for (i = 1; i < GUID_END; i++) { + if (!memcmp(&g, &guids[i].guid, sizeof(GUID))) { #ifdef LOG - printf ("demux_asf: 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->v1, g->v2, g->v3, - g->v4[0], g->v4[1], g->v4[2], g->v4[3], g->v4[4], g->v4[5], g->v4[6], g->v4[7]); + printf ("demux_asf: GUID: %s\n", guids[i].name); #endif + return i; + } + } + + printf ("demux_asf: 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.v1, g.v2, g.v3, + g.v4[0], g.v4[1], g.v4[2], g.v4[3], g.v4[4], g.v4[5], g.v4[6], g.v4[7]); + return GUID_ERROR; } static void get_str16_nolen(demux_asf_t *this, int len, @@ -400,18 +513,12 @@ static void asf_send_video_header (demux_asf_t *this, int stream) { static int asf_read_header (demux_asf_t *this) { - GUID g; + int guid; uint64_t gsize; - get_guid(this, &g); - if (memcmp(&g, &asf_header, sizeof(GUID))) { + guid = get_guid(this); + if (guid != GUID_ASF_HEADER) { printf ("demux_asf: file doesn't start with an asf header\n"); -#ifdef LOG - printf ("demux_asf: 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.v1, g.v2, g.v3, - g.v4[0], g.v4[1], g.v4[2], g.v4[3], g.v4[4], g.v4[5], g.v4[6], g.v4[7]); -#endif return 0; } get_le64(this); @@ -419,198 +526,223 @@ static int asf_read_header (demux_asf_t *this) { get_byte(this); get_byte(this); - for(;;) { - get_guid(this, &g); - + while (this->status != DEMUX_FINISHED) { + guid = get_guid(this); gsize = get_le64(this); if (gsize < 24) goto fail; - if (!memcmp(&g, &file_header, sizeof(GUID))) { - - uint64_t start_time, end_time; + switch (guid) { + case GUID_ASF_FILE_PROPERTIES: + { + uint64_t start_time, end_time; - get_guid(this, &g); - get_le64(this); /* file size */ - get_le64(this); /* file time */ - get_le64(this); /* nb_packets */ + guid = get_guid(this); + get_le64(this); /* file size */ + get_le64(this); /* file time */ + get_le64(this); /* nb_packets */ - end_time = get_le64 (this); + end_time = get_le64 (this); - this->length = get_le64(this) / 10000000; - if (this->length) - this->rate = this->input->get_length (this->input) / this->length; - else - this->rate = 0; - - this->stream->stream_info[XINE_STREAM_INFO_BITRATE] = this->rate*8; + this->length = get_le64(this) / 10000000; + if (this->length) + this->rate = this->input->get_length (this->input) / this->length; + else + this->rate = 0; - start_time = get_le32(this); /* start timestamp in 1/1000 s*/ + this->stream->stream_info[XINE_STREAM_INFO_BITRATE] = this->rate*8; - get_le32(this); - get_le32(this); - this->packet_size = get_le32(this); - get_le32(this); - get_le32(this); + start_time = get_le32(this); /* start timestamp in 1/1000 s*/ - } else if (!memcmp(&g, &stream_header, sizeof(GUID))) { - - int type, total_size, stream_data_size, stream_id; - uint64_t pos1, pos2; - xine_bmiheader *bih = (xine_bmiheader *) this->bih; - xine_waveformatex *wavex = (xine_waveformatex *) this->wavex ; - - pos1 = this->input->get_current_pos (this->input); - - get_guid(this, &g); - if (!memcmp(&g, &audio_stream, sizeof(GUID))) { - type = CODEC_TYPE_AUDIO; - } else if (!memcmp(&g, &video_stream, sizeof(GUID))) { - type = CODEC_TYPE_VIDEO; - } else if (!memcmp(&g, &control_stream, sizeof(GUID))) { - type = CODEC_TYPE_CONTROL; - } else { - goto fail; - } - get_guid(this, &g); - get_le64(this); - total_size = get_le32(this); - stream_data_size = get_le32(this); - stream_id = get_le16(this); /* stream id */ - get_le32(this); - - if (type == CODEC_TYPE_AUDIO) { - uint8_t buffer[6]; - - this->input->read (this->input, (uint8_t *) this->wavex, total_size); - xine_waveformatex_le2me( (xine_waveformatex *) this->wavex ); - - /* - printf ("total size: %d bytes\n", total_size); - */ - - /* - this->input->read (this->input, (uint8_t *) &this->wavex[9], this->wavex[8]); - */ - if (!memcmp(&g, &audio_conceal_interleave, sizeof(GUID))) { - 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; - printf ("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; + get_le32(this); /* unknown */ + get_le32(this); /* min size */ + this->packet_size = get_le32(this); /* max size */ + get_le32(this); /* max bitrate */ + get_le32(this); } + break; + + case (GUID_ASF_STREAM_PROPERTIES): + { + int type; + uint32_t total_size, stream_data_size; + uint16_t stream_id; + uint64_t pos1, pos2; + xine_bmiheader *bih = (xine_bmiheader *) this->bih; + xine_waveformatex *wavex = (xine_waveformatex *) this->wavex ; + + pos1 = this->input->get_current_pos (this->input); - this->wavex_size = total_size; /* 18 + this->wavex[8]; */ - - this->streams[this->num_streams].buf_type = - formattag_to_buf_audio ( wavex->wFormatTag ); - - 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; + 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: + goto fail; + } + + guid = get_guid(this); + get_le64(this); + total_size = get_le32(this); + stream_data_size = get_le32(this); + stream_id = get_le16(this); /* stream id */ + get_le32(this); + + if (type == CODEC_TYPE_AUDIO) { + uint8_t buffer[6]; + + this->input->read (this->input, (uint8_t *) this->wavex, total_size); + xine_waveformatex_le2me( (xine_waveformatex *) this->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; + printf ("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; + } + + this->wavex_size = total_size; /* 18 + this->wavex[8]; */ + + this->streams[this->num_streams].buf_type = + formattag_to_buf_audio ( wavex->wFormatTag ); + + 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; #ifdef LOG - printf ("demux_asf: found a_stream id=%d \n", stream_id); + printf ("demux_asf: found a_stream id=%d \n", stream_id); #endif - this->num_audio_streams++; - } - else if (type == CODEC_TYPE_VIDEO) { + this->num_audio_streams++; + } + else if (type == CODEC_TYPE_VIDEO) { - int i; + uint16_t i; - get_le32(this); /* width */ - get_le32(this); /* height */ - get_byte(this); + get_le32(this); /* width */ + get_le32(this); /* height */ + get_byte(this); - i = get_le16(this); /* size */ - if( i > 0 && i < sizeof(this->bih) ) { - this->bih_size = i; - this->input->read (this->input, (uint8_t *) this->bih, this->bih_size); - xine_bmiheader_le2me( (xine_bmiheader *) this->bih ); + i = get_le16(this); /* size */ + if( i > 0 && i < sizeof(this->bih) ) { + this->bih_size = i; + this->input->read (this->input, (uint8_t *) this->bih, this->bih_size); + xine_bmiheader_le2me( (xine_bmiheader *) this->bih ); - this->streams[this->num_streams].buf_type = - fourcc_to_buf_video(bih->biCompression); + this->streams[this->num_streams].buf_type = + fourcc_to_buf_video(bih->biCompression); - 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; + 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; - } else - printf ("demux_asf: invalid bih_size received (%d), v_stream ignored.\n", i ); + } else + printf ("demux_asf: invalid bih_size received (%d), v_stream ignored.\n", i ); #ifdef LOG - printf ("demux_asf: found v_stream id=%d \n", stream_id); + printf ("demux_asf: found v_stream id=%d \n", stream_id); #endif - this->num_video_streams++; - } - else if (type == CODEC_TYPE_CONTROL) { - while (get_byte(this) != 0) {while (get_byte(this) != 0) {}} - while (get_byte(this) != 0) {while (get_byte(this) != 0) {}} - } - - this->num_streams++; - pos2 = this->input->get_current_pos (this->input); - this->input->seek (this->input, gsize - (pos2 - pos1 + 24), SEEK_CUR); + this->num_video_streams++; + } + else if (type == CODEC_TYPE_CONTROL) { + printf ("demux_asf: CODEC_TYPE_CONTROL\n"); + + /* 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) {}} + */ + } + + this->num_streams++; + pos2 = this->input->get_current_pos (this->input); + this->input->seek (this->input, gsize - (pos2 - pos1 + 24), SEEK_CUR); + } + break; - } else if (!memcmp(&g, &data_header, sizeof(GUID))) { - break; + case GUID_ASF_DATA: +#ifdef LOG + printf ("demux_asf: found data\n"); +#endif + 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; - } else if (!memcmp(&g, &comment_header, sizeof(GUID))) { - int 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; - */ - } else if (!memcmp(&g, &stream_group_guid, sizeof(GUID))) { - int streams; - int stream_id; - int i; + case GUID_ASF_STREAM_BITRATE_PROPERTIES: + { + uint16_t streams, stream_id; + uint16_t i; #ifdef LOG - printf("demux_asf: GUID stream group\n"); + printf("demux_asf: GUID stream group\n"); #endif - streams = get_le16(this); - for(i = 0; i < streams; i++) { - stream_id = get_le16(this); - this->bitrates[stream_id] = get_le32(this); - } + streams = get_le16(this); + for(i = 0; i < streams; i++) { + stream_id = get_le16(this); + this->bitrates[stream_id] = get_le32(this); + } + } + break; - } else { - this->input->seek (this->input, gsize - 24, SEEK_CUR); + default: + this->input->seek (this->input, gsize - 24, SEEK_CUR); } } - get_guid(this, &g); - get_le64(this); - get_byte(this); - get_byte(this); - + + 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: @@ -618,89 +750,123 @@ static int asf_read_header (demux_asf_t *this) { } static void asf_reorder(demux_asf_t *this, uint8_t *src, int len){ - uint8_t *dst=malloc(len); - uint8_t *s2=src; - int i=0,x,y; + uint8_t *dst = malloc(len); + uint8_t *s2 = src; + int i = 0, x, y; - while(len-i >= this->reorder_h*this->reorder_w*this->reorder_b){ - for(x=0;x<this->reorder_w;x++) - for(y=0;y<this->reorder_h;y++){ - memcpy(dst+i,s2+(y*this->reorder_w+x)*this->reorder_b,this->reorder_b); - i+=this->reorder_b; - } - s2+=this->reorder_h*this->reorder_w*this->reorder_b; + while(len-i >= this->reorder_h * this->reorder_w*this->reorder_b){ + for(x = 0; x < this->reorder_w; x++) + for(y = 0; y < this->reorder_h; y++){ + memcpy(dst + i, s2 + (y * this->reorder_w+x) * this->reorder_b, + this->reorder_b); + i += this->reorder_b; + } + s2 += this->reorder_h * this->reorder_w * this->reorder_b; } xine_fast_memcpy(src,dst,i); free(dst); } -static int asf_get_packet(demux_asf_t *this) { +static uint32_t asf_get_packet(demux_asf_t *this) { - int64_t timestamp; - int hdr_size; - uint32_t sig = 0; - int duration; - int packet_size; - - hdr_size = 11; + int64_t timestamp; + int duration; + uint32_t data_size; + uint8_t ecc_flags = 0; + uint8_t buf[16]; + uint32_t p_hdr_size = 0; +#ifdef LOG + int i; +#endif + + ecc_flags = get_byte(this); p_hdr_size += 1; + p_hdr_size += this->input->read (this->input, buf, ecc_flags & 15); +#ifdef LOG + printf("ecc_flags: %d ", ecc_flags); + for (i = 0; i < (ecc_flags & 15); i++) + printf(", %d", buf[i]); + printf("\n"); +#endif - while ( (this->status == DEMUX_OK) && (sig != 0x820000) ) { - sig = ((sig << 8) | get_byte(this)) & 0xFFFFFF; - } if( this->status != DEMUX_OK ) return 0; - this->packet_flags = get_byte(this); - this->segtype = get_byte(this); - this->packet_padsize = 0; - - if (this->packet_flags & 0x40) { + this->packet_flags = get_byte(this); p_hdr_size += 1; + this->segtype = get_byte(this); p_hdr_size += 1; - /* packet size given */ + /* Read packet size (plen): */ + switch((this->packet_flags >> 5) & 3) { + case 1: + data_size = get_byte(this); p_hdr_size += 1; + break; + case 2: + data_size = get_le16(this); p_hdr_size += 2; + break; + case 3: + data_size = get_le32(this); p_hdr_size += 4; + break; + default: + data_size = 0; + } - packet_size = get_le16(this); -#ifdef LOG - printf ("demux_asf: absolute packet size is %d\n", packet_size); -#endif - hdr_size += 2; - - if (this->packet_flags & 0x10) { - /* FIXME: ignore ? this->packet_padsize =*/ get_le16(this); - hdr_size += 2; - } else if (this->packet_flags & 0x08) { - /* FIXME: ignore ? this->packet_padsize =*/ get_byte(this); - hdr_size++; - } - } else { - packet_size = this->packet_size; - - if (this->packet_flags & 0x10) { - this->packet_padsize = get_le16(this); - hdr_size += 2; - } else if (this->packet_flags & 0x08) { - this->packet_padsize = get_byte(this); - hdr_size++; - } + /* Read sequence: */ + switch ((this->packet_flags >> 1) & 3) { + case 1: + get_byte(this); p_hdr_size += 1; + break; + case 2: + get_le16(this); p_hdr_size += 2; + break; + case 3: + get_le32(this); p_hdr_size += 4; + break; } - timestamp = get_le32(this); - duration = get_le16(this) ; /* duration */ - if (this->packet_flags & 0x01) { - this->nb_frames = get_byte(this); /* nb_frames */ - hdr_size++; + /* Read padding size */ + switch ((this->packet_flags >> 3) & 3){ + case 1: + this->packet_padsize = get_byte(this); p_hdr_size += 1; + break; + case 2: + this->packet_padsize = get_le16(this); p_hdr_size += 2; + break; + case 3: + this->packet_padsize = get_le32(this); p_hdr_size += 4; + break; + default: + this->packet_padsize = 0; } - else + + timestamp = get_le32(this); p_hdr_size += 4; + duration = get_le16(this); p_hdr_size += 2; + + if (this->packet_flags & 0x01) { + this->nb_frames = get_byte(this) & 0x3F; p_hdr_size += 1; + } else { this->nb_frames = 1; - + } + this->frame = 0; - this->packet_size_left = packet_size - hdr_size; - - /* - printf ("demux_asf: new packet, size = %d, flags = 0x%02x, padsize = %d\n", - this->packet_size_left, this->packet_flags, this->packet_padsize); - */ + if ((this->packet_flags >> 5) & 3) { + /* absolute packet size */ +#ifdef LOG + printf ("demux_asf: absolute packet size\n"); +#endif + this->packet_padsize = this->packet_size - data_size; + } else { + /* relative packet size */ +#ifdef LOG + printf ("demux_asf: relative packet size\n"); +#endif + } + this->packet_size_left = this->packet_size - p_hdr_size; + +#ifdef LOG + printf ("demux_asf: new packet, size = %d, size_left = %d, flags = 0x%02x, padsize = %d, this->packet_size = %d\n", + data_size, this->packet_size_left, this->packet_flags, this->packet_padsize, this->packet_size); +#endif return 1; } @@ -708,9 +874,9 @@ static int asf_get_packet(demux_asf_t *this) { static void hexdump (unsigned char *data, int len, xine_t *xine) { int i; - for (i=0; i<len; i++) - printf ( "%02x ", data[i]); - printf ("\n"); + for (i = 0; i < len; i++) + printf("%02x ", data[i]); + printf("\n"); } @@ -722,7 +888,6 @@ static void asf_send_discontinuity (demux_asf_t *this, int64_t pts) { if (this->buf_flag_seek) { xine_demux_control_newpts(this->stream, pts, BUF_FLAG_SEEK); - xine_demux_flush_engine(this->stream); this->buf_flag_seek = 0; } else { xine_demux_control_newpts(this->stream, pts, 0); @@ -788,9 +953,13 @@ static void asf_send_buffer_nodefrag (demux_asf_t *this, asf_stream_t *stream, buf->pts = timestamp * 90; - if (buf->pts && this->send_discontinuity && this->keyframe_found) { - this->send_discontinuity=0; - asf_send_discontinuity (this, buf->pts); + if (buf->pts && this->send_discontinuity) { + if (this->keyframe_found) { + this->send_discontinuity = 0; + asf_send_discontinuity (this, buf->pts); + } else { + buf->pts = 0; + } } buf->type = stream->buf_type; @@ -804,13 +973,12 @@ static void asf_send_buffer_nodefrag (demux_asf_t *this, asf_stream_t *stream, if (stream->frag_offset == payload_size) { if ( (buf->type & BUF_MAJOR_MASK) == BUF_VIDEO_BASE) { - if (buf->pts && this->last_video_pts) + if (buf->pts && this->last_video_pts) { this->frame_duration = (3*this->frame_duration + (buf->pts - this->last_video_pts)) / 4; - - /* + } +#ifdef LOG printf ("demux_asf: frame_duration is %d\n", this->frame_duration); - */ - +#endif this->last_video_pts = buf->pts; buf->decoder_flags = BUF_FLAG_FRAME_END | BUF_FLAG_FRAMERATE; @@ -881,13 +1049,13 @@ static void asf_send_buffer_defrag (demux_asf_t *this, asf_stream_t *stream, buf->input_time = 0 ; } - buf->pts = stream->timestamp * 90 + stream->ts_per_kbyte * + buf->pts = stream->timestamp * 90 + stream->ts_per_kbyte * (p-stream->buffer) / 1024; if (buf->pts && this->send_discontinuity) { buf->pts = 0; } - + buf->type = stream->buf_type; buf->size = bufsize; @@ -935,21 +1103,28 @@ static void asf_send_buffer_defrag (demux_asf_t *this, asf_stream_t *stream, } } - static void asf_read_packet(demux_asf_t *this) { - int raw_id, stream_id, seq, frag_offset, payload_size, frag_len; - int flags, i; + uint8_t raw_id, stream_id; + uint32_t seq, frag_offset, payload_size, frag_len, rlen; + int i; int64_t timestamp; asf_stream_t *stream; - - if ((this->packet_size_left < FRAME_HEADER_SIZE) || - (this->packet_size_left <= this->packet_padsize) || - (++this->frame == (this->nb_frames & 0x3f)) ) { - /* fail safe */ - + + uint32_t s_hdr_size = 0; + + uint64_t current_pos; + uint32_t mod; + uint32_t psl; + + if ((++this->frame == (this->nb_frames & 0x3f)) ) { + psl = this->packet_size_left; + current_pos = this->input->get_current_pos (this->input); + mod = (current_pos - this->first_packet_pos) % this->packet_size; + this->packet_size_left = mod ? this->packet_size - mod : 0; + #ifdef LOG - printf ("demux_asf: reading new packet, packet size left %d\n", this->packet_size_left); + printf ("demux_asf: reading new packet, packet size left %d, %d\n", psl, this->packet_size_left); #endif if (this->packet_size_left) @@ -960,17 +1135,25 @@ static void asf_read_packet(demux_asf_t *this) { this->status = DEMUX_FINISHED; return ; } + + if ((this->packet_padsize < 0) || (this->packet_padsize > this->packet_size)) { + /* skip packet */ + printf ("demux_asf: invalid padsize\n"); + this->frame = this->nb_frames - 1; + return; + } } - + /* read segment header, find stream */ - raw_id = get_byte(this); + raw_id = get_byte(this); s_hdr_size += 1; stream_id = raw_id & 0x7f; stream = NULL; #ifdef LOG - printf ("asf_demuxer: got raw_id =%d keyframe_found=%d\n", raw_id, this->keyframe_found); + printf ("demux_asf: got raw_id =%d keyframe_found=%d\n", raw_id, this->keyframe_found); #endif + if ( (raw_id & 0x80) || this->keyframe_found || (this->num_video_streams==0)) { for (i = 0; i < this->num_streams; i++){ if (this->streams[i].stream_id == stream_id && @@ -979,134 +1162,191 @@ static void asf_read_packet(demux_asf_t *this) { } } } - - seq = get_byte(this); - switch (this->segtype){ - case 0x55: - frag_offset = get_byte(this); - this->packet_size_left -= 1; + + switch ((this->segtype >> 4) & 3){ + case 1: + seq = get_byte(this); s_hdr_size += 1; break; - case 0x59: - frag_offset = get_le16(this); - this->packet_size_left -= 2; + case 2: + seq = get_le16(this); s_hdr_size += 2; break; - case 0x5D: - frag_offset = get_le32(this); - this->packet_size_left -= 4; + case 3: + seq = get_le32(this); s_hdr_size += 4; break; default: - printf ("demux_asf: unknown segtype %x\n", this->segtype); - frag_offset = 0; + seq = 0; break; } + switch ((this->segtype >> 2) & 3) { + case 1: + frag_offset = get_byte(this); s_hdr_size += 1; + break; + case 2: + frag_offset = get_le16(this); s_hdr_size += 2; + break; + case 3: + frag_offset = get_le32(this); s_hdr_size += 4; + break; + default: + printf ("demux_asf: unknown segtype %x\n", this->segtype); + /* skip packet */ + this->frame = this->nb_frames - 1; + return; + break; + } + /* only set keyframe_found if we have it's beginning */ if( (raw_id & 0x80) && stream && !frag_offset ) this->keyframe_found = 1; - - flags = get_byte(this); + + switch (this->segtype & 3) { + case 1: + rlen = get_byte(this); s_hdr_size += 1; + break; + case 2: + rlen = get_le16(this); s_hdr_size += 2; + break; + case 3: + rlen = get_le32(this); s_hdr_size += 4; + break; + default: + rlen = 0; + break; + } + + if (rlen > this->packet_size_left) { + /* skip packet */ + printf ("demux_asf: invalid rlen %d\n", rlen); + this->frame = this->nb_frames - 1; + return; + } #ifdef LOG printf ("demux_asf: segment header, stream id %02x, frag_offset %d, flags : %02x\n", - stream_id, frag_offset, flags); + stream_id, frag_offset, rlen); #endif - if (flags == 1) { + if (rlen == 1) { int data_length, data_sent=0; timestamp = frag_offset; - get_byte (this); - + get_byte (this); s_hdr_size += 1; if (this->packet_flags & 0x01) { - if( (this->nb_frames & 0xc0) == 0x40 ) { - data_length = get_byte (this); - this->packet_size_left --; - } else { - data_length = get_le16 (this); - this->packet_size_left -= 2; + switch ((this->nb_frames >> 6) & 3) { + case 1: + data_length = get_byte(this); s_hdr_size += 1; + break; + case 2: + data_length = get_le16(this); s_hdr_size += 2; + break; + case 3: + data_length = get_le32(this); s_hdr_size += 4; + break; + default: +#ifdef LOG + printf ("demux_asf: this->nb_frames is null\n"); +#endif + data_length = get_le16(this); s_hdr_size += 2; } - this->packet_size_left -= data_length + 4; - /* - printf ("demux_asf: reading grouping part segment, size = %d\n", - data_length); - */ +#ifdef LOG + printf ("demux_asf: reading grouping part segment, size = %d\n", data_length); +#endif } else { - data_length = this->packet_size_left - 4 - this->packet_padsize; - this->packet_size_left = this->packet_padsize; - - /* - printf ("demux_asf: reading grouping single segment, size = %d\n", data_length); - */ + data_length = this->packet_size_left - s_hdr_size - this->packet_padsize; +#ifdef LOG + printf ("demux_asf: reading grouping single segment, size = %d\n", data_length); +#endif } + if (data_length > this->packet_size_left) { + /* skip packet */ + printf ("demux_asf: invalid data_length\n"); + this->frame = this->nb_frames - 1; + return; + } + + this->packet_size_left -= s_hdr_size; + while (data_sent < data_length) { int object_length = get_byte(this); - - /* - printf ("demux_asf: sending grouped object, len = %d\n", object_length); - */ + +#ifdef LOG + printf ("demux_asf: sending grouped object, len = %d\n", object_length); +#endif + if (stream) { #ifdef LOG - printf ("demux_asf: sending buffer of type %08x\n", stream->buf_type); + printf ("demux_asf: sending buffer of type %08x\n", stream->buf_type); #endif - if (stream->defrag) + if (stream->defrag) asf_send_buffer_defrag (this, stream, 0, seq, timestamp, - object_length, object_length); + object_length, object_length); else asf_send_buffer_nodefrag (this, stream, 0, seq, timestamp, - object_length, object_length); - } - else { -#ifdef LOG - printf ("demux_asf: unhandled stream type, id %d\n", stream_id); -#endif - this->input->seek (this->input, object_length, SEEK_CUR); + object_length, object_length); + } else { + printf ("demux_asf: unhandled stream type, id %d\n", stream_id); + this->input->seek (this->input, object_length, SEEK_CUR); } - seq++; - data_sent += object_length+1; + data_sent += object_length + 1; + this->packet_size_left -= object_length + 1; timestamp = 0; - } } else { - payload_size = get_le32(this); - timestamp = get_le32(this); + if (rlen >= 8) { + payload_size = get_le32(this); s_hdr_size += 4; + timestamp = get_le32(this); s_hdr_size += 4; + this->input->seek (this->input, rlen - 8, SEEK_CUR); + s_hdr_size += rlen - 8; + } else { + printf ("demux_asf: strange rlen %d\n", rlen); + timestamp = 0; + payload_size = 0; + this->input->seek (this->input, rlen, SEEK_CUR); + s_hdr_size += rlen; + } + if (this->packet_flags & 0x01) { if( (this->nb_frames & 0xc0) == 0x40 ) { - frag_len = get_byte(this); - this->packet_size_left--; + frag_len = get_byte(this); s_hdr_size += 1; } else { - frag_len = get_le16(this); - this->packet_size_left -= 2; + frag_len = get_le16(this); s_hdr_size += 2; } - this->packet_size_left -= FRAME_HEADER_SIZE + frag_len - 6; - - /* - printf ("demux_asf: reading part segment, size = %d\n", - frag_len); - */ - +#ifdef LOG + printf ("demux_asf: reading part segment, size = %d\n", frag_len); +#endif } else { - frag_len = this->packet_size_left - 11 - this->packet_padsize; - this->packet_size_left = this->packet_padsize; - - /* - printf ("demux_asf: reading single segment, size = %d\n", frag_len); - */ - + frag_len = this->packet_size_left - s_hdr_size - this->packet_padsize; +#ifdef LOG + printf ("demux_asf: reading single segment, size = %d\n", frag_len); +#endif } + if (frag_len > this->packet_size_left) { + /* skip packet */ + printf ("demux_asf: invalid rlen %d\n", rlen); + this->frame = this->nb_frames - 1; + return; + } - if (stream) { + if (!payload_size) { + payload_size = frag_len; + } + + this->packet_size_left -= s_hdr_size; + if (stream) { + #ifdef LOG printf ("demux_asf: sending buffer of type %08x\n", stream->buf_type); #endif @@ -1118,12 +1358,10 @@ static void asf_read_packet(demux_asf_t *this) { asf_send_buffer_nodefrag (this, stream, frag_offset, seq, timestamp, frag_len, payload_size); } else { - -#ifdef LOG printf ("demux_asf: unhandled stream type, id %d\n", stream_id); -#endif this->input->seek (this->input, frag_len, SEEK_CUR); - } + } + this->packet_size_left -= frag_len; } } @@ -1264,6 +1502,8 @@ static void demux_asf_send_headers (demux_plugin_t *this_gen) { asf_send_video_header(this, this->video_stream); } + this->frame = 0; + this->nb_frames = 1; xine_demux_control_headers_done (this->stream); } @@ -1272,6 +1512,9 @@ static int demux_asf_seek (demux_plugin_t *this_gen, demux_asf_t *this = (demux_asf_t *) this_gen; + printf("demux_asf: demux_asf_seek begin\n"); + + this->status = DEMUX_OK; xine_demux_flush_engine(this->stream); @@ -1282,6 +1525,7 @@ static int demux_asf_seek (demux_plugin_t *this_gen, this->send_discontinuity = 1; this->last_video_pts = 0; this->frame = 0; + this->nb_frames = 1; this->packet_size_left = 0; this->keyframe_found = (this->num_video_streams==0); @@ -1294,6 +1538,7 @@ static int demux_asf_seek (demux_plugin_t *this_gen, start_pos = this->header_size; this->input->seek (this->input, start_pos, SEEK_SET); + } /* @@ -1306,6 +1551,7 @@ static int demux_asf_seek (demux_plugin_t *this_gen, this->buf_flag_seek = 1; } + printf("demux_asf: demux_asf_seek end\n"); return this->status; } @@ -1355,7 +1601,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, } else return NULL; } - if (memcmp(buf, &asf_header, sizeof(GUID))) + if (memcmp(buf, &guids[GUID_ASF_HEADER].guid, sizeof(GUID))) return NULL; #ifdef LOG |