From 968596abb7b88b3fe6195b771ea57cefdfa45569 Mon Sep 17 00:00:00 2001 From: Guenter Bartsch Date: Sun, 14 Oct 2001 00:18:27 +0000 Subject: an asf demuxer CVS patchset: 792 CVS date: 2001/10/14 00:18:27 --- src/demuxers/Makefile.am | 5 +- src/demuxers/demux_asf.c | 1104 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1108 insertions(+), 1 deletion(-) create mode 100644 src/demuxers/demux_asf.c (limited to 'src') diff --git a/src/demuxers/Makefile.am b/src/demuxers/Makefile.am index 8ff778bde..57cfac345 100644 --- a/src/demuxers/Makefile.am +++ b/src/demuxers/Makefile.am @@ -18,7 +18,7 @@ lib_LTLIBRARIES = $(ogg_module) xineplug_dmx_avi.la \ xineplug_dmx_mpeg_block.la xineplug_dmx_mpeg.la \ xineplug_dmx_mpeg_elem.la xineplug_dmx_mpeg_audio.la \ xineplug_dmx_mpeg_pes.la xineplug_dmx_mpeg_ts.la \ - xineplug_dmx_qt.la + xineplug_dmx_qt.la xineplug_dmx_asf.la xineplug_dmx_ogg_la_SOURCES = demux_ogg.c xineplug_dmx_ogg_la_LIBADD = @OGG_LIBS@ @@ -50,6 +50,9 @@ xineplug_dmx_qt_la_SOURCES = demux_qt.c xineplug_dmx_qt_la_LDFLAGS = -avoid-version -module xineplug_dmx_qt_la_LIBADD = -lz +xineplug_dmx_asf_la_SOURCES = demux_asf.c +xineplug_dmx_asf_la_LDFLAGS = -avoid-version -module + include_HEADERS = demux.h ## diff --git a/src/demuxers/demux_asf.c b/src/demuxers/demux_asf.c new file mode 100644 index 000000000..548258850 --- /dev/null +++ b/src/demuxers/demux_asf.c @@ -0,0 +1,1104 @@ +/* + * Copyright (C) 2000, 2001 the xine project + * + * This file is part of xine, a unix 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: demux_asf.c,v 1.1 2001/10/14 00:18:27 guenter Exp $ + * + * demultiplexer for asf streams + * + * based on ffmpeg's + * ASF compatible encoder and decoder. + * Copyright (c) 2000, 2001 Gerard Lantau. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include "xine_internal.h" +#include "monitor.h" +#include "demux.h" +#include "utils.h" + +#define WINE_TYPEDEFS_ONLY +#include "libw32dll/wine/avifmt.h" +#include "libw32dll/wine/windef.h" +#include "libw32dll/wine/vfw.h" +#include "libw32dll/wine/mmreg.h" + +#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 MAX_NUM_STREAMS 23 + +typedef struct { + int num; + int seq; + + int frag_offset; + + uint32_t buf_type; + int stream_id; + fifo_buffer_t *fifo; +} asf_stream_t; + +static uint32_t xine_debug; + +typedef struct demux_asf_s { + demux_plugin_t demux_plugin; + + fifo_buffer_t *audio_fifo; + fifo_buffer_t *video_fifo; + + input_plugin_t *input; + + int keyframe_found; + + int seqno; + int packet_size; + int packet_flags; + + asf_stream_t streams[MAX_NUM_STREAMS]; + int num_streams; + int num_audio_streams; + int num_video_streams; + + uint16_t wavex[128]; + int wavex_size; + + uint16_t bih[128]; + int bih_size; + + char title[512]; + char author[512]; + char copyright[512]; + char comment[512]; + + uint32_t length, rate; + + /* packet filling */ + int packet_size_left; + + /* only for reading */ + int packet_padsize; + + pthread_t thread; + + int status; + + int send_end_buffers; + +} demux_asf_t ; + + +typedef struct { + uint32_t v1; + uint16_t v2; + uint16_t v3; + uint8_t v4[8]; +} GUID; + +static const GUID asf_header = { + 0x75B22630, 0x668E, 0x11CF, { 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C }, +}; + +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 }, +}; + +static const GUID audio_stream = { + 0xF8699E40, 0x5B4D, 0x11CF, { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B }, +}; + +static const GUID audio_conceal_none = { + 0x49f1a440, 0x4ece, 0x11d0, { 0xa3, 0xac, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6 }, +}; + +static const GUID video_stream = { + 0xBC19EFC0, 0x5B4D, 0x11CF, { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B }, +}; + +static const GUID video_conceal_none = { + 0x20FB5700, 0x5B55, 0x11CF, { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B }, +}; + + +static const GUID comment_header = { + 0x75b22633, 0x668e, 0x11cf, { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c }, +}; + +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 }, +}; + +static const GUID data_header = { + 0x75b22636, 0x668e, 0x11cf, { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c }, +}; + +static const GUID index_guid = { + 0x33000890, 0xe5b1, 0x11cf, { 0x89, 0xf4, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xcb }, +}; + +static const GUID head1_guid = { + 0x5fbf03b5, 0xa92e, 0x11cf, { 0x8e, 0xe3, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 }, +}; + +static const GUID head2_guid = { + 0xabd3d211, 0xa9ba, 0x11cf, { 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 }, +}; + +/* 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; + int i; + + i = this->input->read (this->input, &buf, 1); + + /* printf ("%02x ", buf); */ + + if (i != 1) { + printf ("demux_asf: end of data\n"); + this->status = DEMUX_FINISHED; + } + + return buf; +} + +static uint16_t get_le16 (demux_asf_t *this) { + + uint8_t buf[2]; + int i; + + i = this->input->read (this->input, buf, 2); + + /* printf (" [%02x %02x] ", buf[0], buf[1]); */ + + if (i != 2) { + printf ("demux_asf: end of data\n"); + this->status = DEMUX_FINISHED; + } + + return buf[0] | (buf[1] << 8); +} + +static uint32_t get_le32 (demux_asf_t *this) { + + uint8_t buf[4]; + int i; + + i = this->input->read (this->input, buf, 4); + + /* printf ("%02x %02x %02x %02x ", buf[0], buf[1], buf[2], buf[3]); */ + + if (i != 4) { + printf ("demux_asf: end of data\n"); + this->status = DEMUX_FINISHED; + } + + return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); +} + +static uint64_t get_le64 (demux_asf_t *this) { + + uint8_t buf[8]; + int i; + + i = this->input->read (this->input, buf, 8); + + if (i != 8) { + printf ("demux_asf: end of data\n"); + this->status = DEMUX_FINISHED; + } + + return (uint64_t) buf[0] + | ((uint64_t) buf[1] << 8) + | ((uint64_t) buf[2] << 16) + | ((uint64_t) buf[3] << 24) + | ((uint64_t) buf[4] << 32) + | ((uint64_t) buf[5] << 40) + | ((uint64_t) buf[6] << 48) + | ((uint64_t) buf[7] << 54) ; +} + +static void get_guid (demux_asf_t *this, GUID *g) { + 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); + +} + +static void get_str16_nolen(demux_asf_t *this, int len, + char *buf, int buf_size) { + + int c; + char *q; + + q = buf; + while (len > 0) { + c = get_le16(this); + if ((q - buf) < buf_size - 1) + *q++ = c; + len-=2; + } + *q = '\0'; +} + +static void asf_send_audio_header (demux_asf_t *this, int stream_id) { + + buf_element_t *buf; + WAVEFORMATEX *wavex = (WAVEFORMATEX *) this->wavex ; + + if (!this->audio_fifo) + return; + + switch (wavex->wFormatTag) { + case 0x01: + this->streams[this->num_streams].buf_type = BUF_AUDIO_LPCM_LE; + break; + case 0x2000: + this->streams[this->num_streams].buf_type = BUF_AUDIO_A52; + break; + case 0x50: + case 0x55: + this->streams[this->num_streams].buf_type = BUF_AUDIO_MPEG; + break; + case 0x160: + case 0x161: + this->streams[this->num_streams].buf_type = BUF_AUDIO_DIVXA; + break; + case 0x02: + this->streams[this->num_streams].buf_type = BUF_AUDIO_MSADPCM; + break; + case 0x11: + this->streams[this->num_streams].buf_type = BUF_AUDIO_IMAADPCM; + break; + case 0x31: + case 0x32: + this->streams[this->num_streams].buf_type = BUF_AUDIO_MSGSM; + break; + default: + printf ("demux_asf: unknown audio type 0x%x\n", wavex->wFormatTag); + this->streams[this->num_streams].buf_type = BUF_CONTROL_NOP; + break; + } + + printf ("demux_asf: audio format :0x%02x (buf_type %08x)\n", + wavex->wFormatTag, this->streams[this->num_streams].buf_type ); + + + this->streams[this->num_streams].buf_type |= this->num_audio_streams; + 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; + + buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); + buf->content = buf->mem; + memcpy (buf->content, this->wavex, this->wavex_size); + + printf ("demux_asf: wavex header is %d bytes long\n", this->wavex_size); + + buf->size = this->wavex_size; + buf->type = this->streams[this->num_streams].buf_type; + buf->decoder_info[0] = 0; /* first package, containing wavex */ + buf->decoder_info[1] = wavex->nSamplesPerSec; + buf->decoder_info[2] = wavex->wBitsPerSample; + buf->decoder_info[3] = wavex->nChannels; + this->audio_fifo->put (this->audio_fifo, buf); + + this->num_streams++; + this->num_audio_streams++; +} + +static unsigned long str2ulong(unsigned char *str) { + return ( str[0] | (str[1]<<8) | (str[2]<<16) | (str[3]<<24) ); +} + +static void asf_send_video_header (demux_asf_t *this, int stream_id) { + + buf_element_t *buf; + BITMAPINFOHEADER *bih = (BITMAPINFOHEADER *) this->bih; + + + switch (str2ulong((void*)&bih->biCompression)) { + + case mmioFOURCC('M', 'P', '4', '3'): + case mmioFOURCC('m', 'p', '4', '3'): + case mmioFOURCC('D', 'I', 'V', '3'): + case mmioFOURCC('d', 'i', 'v', '3'): + case mmioFOURCC('D', 'I', 'V', '4'): + case mmioFOURCC('d', 'i', 'v', '4'): + case mmioFOURCC('D', 'I', 'V', '5'): + case mmioFOURCC('d', 'i', 'v', '5'): + case mmioFOURCC('D', 'I', 'V', '6'): + case mmioFOURCC('d', 'i', 'v', '6'): + /* Video in Microsoft MPEG-4 format v3 */ + this->streams[this->num_streams].buf_type = BUF_VIDEO_MSMPEG4_V3; + break; + + case mmioFOURCC('M', 'P', 'G', '4'): + case mmioFOURCC('m', 'p', 'g', '4'): + case mmioFOURCC('M', 'P', '4', '1'): + case mmioFOURCC('m', 'p', '4', '1'): + case mmioFOURCC('M', 'P', '4', '2'): + case mmioFOURCC('m', 'p', '4', '2'): + case mmioFOURCC('D', 'I', 'V', '2'): + case mmioFOURCC('d', 'i', 'v', '2'): + /* Video in Microsoft MPEG-4 format v1/v2 */ + this->streams[this->num_streams].buf_type = BUF_VIDEO_MSMPEG4_V12; + break; + + case mmioFOURCC('D', 'I', 'V', 'X'): + case mmioFOURCC('d', 'i', 'v', 'x'): + case mmioFOURCC('D', 'i', 'v', 'x'): + case mmioFOURCC('D', 'i', 'v', 'X'): + /* Video in mpeg4 (opendivx) format */ + this->streams[this->num_streams].buf_type = BUF_VIDEO_MPEG4; + break; + + case mmioFOURCC('d', 'm', 'b', '1'): + case mmioFOURCC('M', 'J', 'P', 'G'): + /* Video in motion jpeg format */ + this->streams[this->num_streams].buf_type = BUF_VIDEO_MJPEG; + break; + + case mmioFOURCC('I', 'V', '5', '0'): + case mmioFOURCC('i', 'v', '5', '0'): + /* Video in Indeo Video 5.0 format */ + this->streams[this->num_streams].buf_type = BUF_VIDEO_IV50; + break; + + case mmioFOURCC('I', 'V', '4', '1'): + case mmioFOURCC('i', 'v', '4', '1'): + /* Video in Indeo Video 4.1 format */ + this->streams[this->num_streams].buf_type = BUF_VIDEO_IV41; + break; + case mmioFOURCC('I', 'V', '3', '2'): + case mmioFOURCC('i', 'v', '3', '2'): + /* Video in Indeo Video 3.2 format */ + this->streams[this->num_streams].buf_type = BUF_VIDEO_IV32; + break; + + case mmioFOURCC('I', 'V', '3', '1'): + case mmioFOURCC('i', 'v', '3', '1'): + /* Video in Indeo Video 3.1 format */ + this->streams[this->num_streams].buf_type = BUF_VIDEO_IV31; + break; + + case mmioFOURCC('c', 'v', 'i', 'd'): + /* Video in Cinepak format */ + this->streams[this->num_streams].buf_type = BUF_VIDEO_CINEPAK; + break; + case mmioFOURCC('V', 'C', 'R', '1'): + /* Video in ATI VCR1 format */ + this->streams[this->num_streams].buf_type = BUF_VIDEO_ATIVCR1; + break; + case mmioFOURCC('V', 'C', 'R', '2'): + /* Video in ATI VCR2 format */ + this->streams[this->num_streams].buf_type = BUF_VIDEO_ATIVCR2; + break; + case mmioFOURCC('I', '2', '6', '3'): + case mmioFOURCC('i', '2', '6', '3'): + /* Video in I263 format */ + this->streams[this->num_streams].buf_type = BUF_VIDEO_I263; + break; + default: + printf ("demux_asf: unknown video format %.4s\n", + (char*)&bih->biCompression); + + this->status = DEMUX_FINISHED; + return; + } + + this->streams[this->num_streams].buf_type |= this->num_video_streams; + 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; + + printf ("demux_asf: video format : %.4s\n", (char*)&bih->biCompression); + + buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); + buf->content = buf->mem; + buf->decoder_info[0] = 0; /* first package, containing bih */ + buf->decoder_info[1] = 3000; /* FIXME ? */ + memcpy (buf->content, &this->bih, this->bih_size); + buf->size = this->bih_size; + buf->type = this->streams[this->num_streams].buf_type ; + this->video_fifo->put (this->video_fifo, buf); + + this->num_streams++; + this->num_video_streams++; + +} + +static int asf_read_header (demux_asf_t *this) { + + GUID g; + uint64_t gsize; + + get_guid(this, &g); + if (memcmp(&g, &asf_header, sizeof(GUID))) { + printf ("demux_asf: file doesn't start with an asf header\n"); + return 0; + } + get_le64(this); + get_le32(this); + get_byte(this); + get_byte(this); + + for(;;) { + get_guid(this, &g); + + gsize = get_le64(this); + + if (gsize < 24) + goto fail; + + if (!memcmp(&g, &file_header, sizeof(GUID))) { + + 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 */ + + end_time = get_le64 (this); + + this->length = get_le64(this) / 10000000; + if (this->input->get_capabilities(this->input) & INPUT_CAP_SEEKABLE) { + this->rate = this->input->get_length (this->input) / this->length; + } else + this->rate = 0; + + printf ("demux_asf: stream length is %d sec, rate is %d bytes/sec\n", + this->length, this->rate); + + start_time = get_le32(this); /* start timestamp in 1/1000 s*/ + + get_le32(this); + get_le32(this); + this->packet_size = get_le32(this); + get_le32(this); + get_le32(this); + + } else if (!memcmp(&g, &stream_header, sizeof(GUID))) { + + int type, total_size, stream_id; + uint64_t pos1, pos2; + + 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 { + goto fail; + } + get_guid(this, &g); + get_le64(this); + total_size = get_le32(this); + get_le32(this); + stream_id = get_le16(this); /* stream id */ + get_le32(this); + + if (type == CODEC_TYPE_AUDIO) { + + this->input->read (this->input, (uint8_t *) this->wavex, total_size); + + printf ("total size: %d bytes\n", total_size); + + /* + this->input->read (this->input, (uint8_t *) &this->wavex[9], this->wavex[8]); + */ + + this->wavex_size = total_size; /* 18 + this->wavex[8]; */ + + asf_send_audio_header (this, stream_id); + + } else { + + get_le32(this); /* width */ + get_le32(this); /* height */ + get_byte(this); + this->bih_size = get_le16(this); /* size */ + + this->input->read (this->input, (uint8_t *) this->bih, this->bih_size); + + asf_send_video_header (this, stream_id); + } + pos2 = this->input->get_current_pos (this->input); + this->input->seek (this->input, gsize - (pos2 - pos1 + 24), SEEK_CUR); + + } else if (!memcmp(&g, &data_header, sizeof(GUID))) { + 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 { + this->input->seek (this->input, gsize - 24, SEEK_CUR); + } + } + get_guid(this, &g); + get_le64(this); + get_byte(this); + get_byte(this); + + this->packet_size_left = 0; + + return 1; + + fail: + return 0; +} + + +static int asf_get_packet(demux_asf_t *this) { + + int timestamp, hdr_size; + + uint32_t sig = 0; + + hdr_size = 11; + + while ( (this->status == DEMUX_OK) && (sig != 0x820000) ) { + sig = ((sig << 8) | get_byte(this)) & 0xFFFFFF; + } + + this->packet_flags = get_byte(this); + get_byte(this); + this->packet_padsize = 0; + 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++; + + } + timestamp = get_le32(this); + get_le16(this); /* duration */ + if (this->packet_flags & 0x01) { + get_byte(this); /* nb_frames */ + hdr_size++; + } + this->packet_size_left = this->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); + */ + + return 1; +} + +static void hexdump (unsigned char *data, int len) { + int i; + + for (i=0; ifrag_offset == 0) { + /* new packet */ + stream->seq = seq; + } else { + if (seq == stream->seq && + frag_offset == stream->frag_offset) { + /* continuing packet */ + } else { + /* cannot continue current packet: free it */ + stream->frag_offset = 0; + if (frag_offset != 0) { + /* cannot create new packet */ + this->input->seek (this->input, frag_len, SEEK_CUR); + return ; + } else { + /* create new packet */ + stream->seq = seq; + } + } + } + + buf = stream->fifo->buffer_pool_alloc (stream->fifo); + buf->content = buf->mem; + this->input->read (this->input, buf->content, frag_len); + + /* + printf ("demux_asf: read %d bytes :", frag_len); + hexdump (buf->content, frag_len); + */ + + stream->frag_offset += frag_len; + + if (stream->fifo == this->video_fifo) { + buf->input_pos = this->input->get_current_pos (this->input); + buf->input_time = buf->input_pos / this->rate; + } else { + buf->input_pos = 0 ; + buf->input_time = 0 ; + } + buf->PTS = timestamp * 90; + buf->type = stream->buf_type; + buf->size = frag_len; + + /* test if whole packet read */ + + if (stream->frag_offset == payload_size) { + buf->decoder_info[0] = 2; + stream->frag_offset = 0; + } else + buf->decoder_info[0] = 1; + + stream->fifo->put (stream->fifo, buf); +} + +static void asf_read_packet(demux_asf_t *this) { + + int raw_id, stream_id, seq, frag_offset, payload_size, frag_len; + int timestamp, flags, i; + asf_stream_t *stream; + + if ((this->packet_size_left < FRAME_HEADER_SIZE) || + (this->packet_size_left <= this->packet_padsize)) { + /* fail safe */ + + /* printf ("demux_asf: reading new packet, packet size left %d\n", this->packet_size_left); */ + + if (this->packet_size_left) + this->input->seek (this->input, this->packet_size_left, SEEK_CUR); + + if (!asf_get_packet(this)) { + printf ("demux_asf: get_packet failed\n"); + this->status = DEMUX_FINISHED; + return ; + } + } + + /* read segment header, find stream */ + + raw_id = get_byte(this); + stream_id = raw_id & 0x7f; + + stream = NULL; + if ( (raw_id & 0x80) || this->keyframe_found ) { + for (i=0; inum_streams; i++) + if (this->streams[i].stream_id == stream_id) + stream = &this->streams[i]; + this->keyframe_found = 1; + } + + seq = get_byte(this); + frag_offset = get_le32(this); + flags = get_byte(this); + + /* + printf ("\ndemux_asf: segment header, stream id %02x, frag_offset %d, flags : %02x\n", + stream_id, frag_offset, flags); + */ + + if (flags == 1) { + int data_length, data_sent=0; + + timestamp = frag_offset; + get_byte (this); + + + if (this->packet_flags & 0x01) { + + data_length = get_le16 (this); + this->packet_size_left -= data_length + 10; + /* + printf ("demux_asf: reading grouping part segment, size = %d\n", + data_length); + */ + + } else { + + data_length = this->packet_size_left - 8 - this->packet_padsize; + this->packet_size_left = this->packet_padsize; + + /* + printf ("demux_asf: reading grouping single segment, size = %d\n", data_length); + */ + } + + while (data_sent < data_length) { + int object_length = get_byte(this); + + /* + printf ("demux_asf: sending grouped object, len = %d\n", object_length); + */ + + if (stream) + asf_send_buffer (this, stream, 0, seq, timestamp, + 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; + timestamp = 0; + + } + + } else { + + payload_size = get_le32(this); + timestamp = get_le32(this); + if (this->packet_flags & 0x01) { + frag_len = get_le16(this); + this->packet_size_left -= FRAME_HEADER_SIZE + frag_len; + + /* + printf ("demux_asf: reading part segment, size = %d\n", + frag_len); + */ + + } else { + frag_len = this->packet_size_left-15 - this->packet_padsize; + this->packet_size_left = this->packet_padsize; + + /* + printf ("demux_asf: reading single segment, size = %d\n", frag_len); + */ + + } + + + if (stream) { + + asf_send_buffer (this, stream, frag_offset, seq, timestamp, frag_len, payload_size); + + } else { + printf ("demux_asf: unhandled stream type, id %d\n", stream_id); + this->input->seek (this->input, frag_len, SEEK_CUR); + } + } +} + +/* + * xine specific functions start here + */ + +static void *demux_asf_loop (void *this_gen) { + buf_element_t *buf; + + demux_asf_t *this = (demux_asf_t *) this_gen; + + /* printf ("demux_asf: demux loop starting...\n"); */ + + this->send_end_buffers = 1; + + while (this->status == DEMUX_OK) { + + asf_read_packet (this); + + } + + /* + printf ("demux_asf: demux loop finished (status: %d)\n", + this->status); + */ + + this->status = DEMUX_FINISHED; + + if (this->send_end_buffers) { + buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); + buf->type = BUF_CONTROL_END; + buf->decoder_info[0] = 0; /* stream finished */ + this->video_fifo->put (this->video_fifo, buf); + + if(this->audio_fifo) { + buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); + buf->type = BUF_CONTROL_END; + buf->decoder_info[0] = 0; /* stream finished */ + this->audio_fifo->put (this->audio_fifo, buf); + } + + } + + pthread_exit(NULL); + + return NULL; +} + +static void demux_asf_close (demux_plugin_t *this_gen) { + + demux_asf_t *this = (demux_asf_t *) this_gen; + free (this); + +} + +static void demux_asf_stop (demux_plugin_t *this_gen) { + + demux_asf_t *this = (demux_asf_t *) this_gen; + buf_element_t *buf; + void *p; + + if (this->status != DEMUX_OK) { + printf ("demux_asf: stop...ignored\n"); + return; + } + + this->send_end_buffers = 0; + this->status = DEMUX_FINISHED; + + pthread_cancel (this->thread); + pthread_join (this->thread, &p); + + this->video_fifo->clear(this->video_fifo); + if (this->audio_fifo) + this->audio_fifo->clear(this->audio_fifo); + + buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); + buf->type = BUF_CONTROL_END; + buf->decoder_info[0] = 1; /* forced */ + + this->video_fifo->put (this->video_fifo, buf); + + if(this->audio_fifo) { + buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); + buf->type = BUF_CONTROL_END; + buf->decoder_info[0] = 1; /* forced */ + this->audio_fifo->put (this->audio_fifo, buf); + } +} + +static int demux_asf_get_status (demux_plugin_t *this_gen) { + demux_asf_t *this = (demux_asf_t *) this_gen; + + return this->status; +} + +static void demux_asf_start (demux_plugin_t *this_gen, + fifo_buffer_t *video_fifo, + fifo_buffer_t *audio_fifo, + off_t start_pos, int start_time, + gui_get_next_mrl_cb_t next_mrl_cb, + gui_branched_cb_t branched_cb) { + + demux_asf_t *this = (demux_asf_t *) this_gen; + buf_element_t *buf; + int err; + + this->video_fifo = video_fifo; + this->audio_fifo = audio_fifo; + + /* + * send start buffer + */ + + buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); + buf->type = BUF_CONTROL_START; + this->video_fifo->put (this->video_fifo, buf); + + if(this->audio_fifo) { + buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); + buf->type = BUF_CONTROL_START; + this->audio_fifo->put (this->audio_fifo, buf); + } + + /* + * initialize asf engine + */ + + this->num_streams = 0; + this->num_audio_streams = 0; + this->num_video_streams = 0; + this->packet_size = 0; + this->seqno = 0; + + + if (this->input->get_capabilities (this->input) & INPUT_CAP_SEEKABLE) + this->input->seek (this->input, 0, SEEK_SET); + + if (!asf_read_header (this)) { + + this->status = DEMUX_FINISHED; + return; + } + + printf ("demux_asf: title : %s\n", this->title); + printf ("demux_asf: author : %s\n", this->author); + printf ("demux_asf: copyright : %s\n", this->copyright); + printf ("demux_asf: comment : %s\n", this->comment); + + /* + * seek to start position + */ + + if (this->input->get_capabilities(this->input) & INPUT_CAP_SEEKABLE) { + + off_t cur_pos = this->input->get_current_pos (this->input); + + if ( (!start_pos) && (start_time)) + start_pos = start_time * this->rate; + + if (start_posinput->seek (this->input, start_pos, SEEK_SET); + } + + /* + * now start demuxing + */ + + this->keyframe_found = 0; + this->status = DEMUX_OK; + + if ((err = pthread_create (&this->thread, + NULL, demux_asf_loop, this)) != 0) { + fprintf (stderr, "demux_asf: can't create new thread (%s)\n", + strerror(err)); + exit (1); + } +} + +static int demux_asf_open(demux_plugin_t *this_gen, + input_plugin_t *input, int stage) { + + demux_asf_t *this = (demux_asf_t *) this_gen; + + switch(stage) { + + case STAGE_BY_CONTENT: + return DEMUX_CANNOT_HANDLE; + break; + + case STAGE_BY_EXTENSION: { + char *ending; + char *MRL; + + MRL = input->get_mrl (input); + + /* + * check ending + */ + + ending = strrchr(MRL, '.'); + + if(!ending) + return DEMUX_CANNOT_HANDLE; + + if(!strcasecmp(ending, ".asf")) { + this->input = input; + return DEMUX_CAN_HANDLE; + } else if(!strcasecmp(ending, ".wmv")) { + this->input = input; + return DEMUX_CAN_HANDLE; + } + } + break; + } + + return DEMUX_CANNOT_HANDLE; +} + +static char *demux_asf_get_id(void) { + return "ASF"; +} + +static int demux_asf_get_stream_length (demux_plugin_t *this_gen) { + + demux_asf_t *this = (demux_asf_t *) this_gen; + + return this->length; +} + +demux_plugin_t *init_demuxer_plugin(int iface, config_values_t *config) { + + demux_asf_t *this; + + if (iface != 3) { + printf( "demux_asf: plugin doesn't support plugin API version %d.\n" + "demux_asf: this means there's a version mismatch between xine and this " + "demux_asf: demuxer plugin.\nInstalling current demux plugins should help.\n", + iface); + return NULL; + } + + this = xmalloc (sizeof (demux_asf_t)); + xine_debug = config->lookup_int (config, "xine_debug", 0); + + this->demux_plugin.interface_version = DEMUXER_PLUGIN_IFACE_VERSION; + this->demux_plugin.open = demux_asf_open; + this->demux_plugin.start = demux_asf_start; + this->demux_plugin.stop = demux_asf_stop; + this->demux_plugin.close = demux_asf_close; + this->demux_plugin.get_status = demux_asf_get_status; + this->demux_plugin.get_identifier = demux_asf_get_id; + this->demux_plugin.get_stream_length = demux_asf_get_stream_length; + + return (demux_plugin_t *) this; +} -- cgit v1.2.3