From 77ab2d6c6a0e8ac45f7936d71ef5f8e923275cbe Mon Sep 17 00:00:00 2001 From: Thibaut Mattern Date: Tue, 6 Apr 2004 00:25:29 +0000 Subject: Asf demuxer: - fix error correction handling. - detect properly the end of the stream using packet_count (now that mms plugin handles correctly current_pos). - rename some properties mmst/mmsh: - handle current stream pos correctly, based on packet sequence_id (needed for seeking). mmsh: - some reverse ingeneering to support for grouped ASF streams like mmst (mmsh://wms03.nordicwebradio.com/chelsea) - fix a potential crash at the end of stream CVS patchset: 6334 CVS date: 2004/04/06 00:25:29 --- src/demuxers/demux_asf.c | 138 +++++++++++++++++++++--------------- src/input/input_mms.c | 61 +++++++++------- src/input/mms.c | 25 +++++-- src/input/mms.h | 4 +- src/input/mmsh.c | 178 +++++++++++++++++++++++++++++------------------ src/input/mmsh.h | 4 +- 6 files changed, 252 insertions(+), 158 deletions(-) diff --git a/src/demuxers/demux_asf.c b/src/demuxers/demux_asf.c index 0f86a15b2..aeae83101 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.154 2004/04/02 06:52:39 tmattern Exp $ + * $Id: demux_asf.c,v 1.155 2004/04/06 00:25:29 tmattern Exp $ * * demultiplexer for asf streams * @@ -106,8 +106,9 @@ typedef struct demux_asf_s { int seqno; uint32_t packet_size; - uint8_t packet_flags; + 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]; @@ -131,8 +132,8 @@ typedef struct demux_asf_s { char copyright[512]; char comment[512]; - uint32_t length; - uint32_t rate; + uint64_t length; + uint32_t rate; uint64_t preroll; /* packet filling */ @@ -149,7 +150,7 @@ typedef struct demux_asf_s { uint32_t packet_padsize; int nb_frames; uint8_t frame_flag; - uint8_t segtype; + uint8_t packet_prop_flags; int frame; int status; @@ -376,14 +377,14 @@ static int asf_read_header (demux_asf_t *this) { file_size = get_le64(this); /* file size */ get_le64(this); /* creation time */ - get_le64(this); /* nb packets */ - + 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 */ @@ -981,21 +982,54 @@ static int asf_parse_packet_align(demux_asf_t *this) { uint64_t current_pos, packet_pos; uint32_t mod; + uint64_t packet_num; + + /* skip padding */ + current_pos = this->input->seek (this->input, this->packet_size_left, SEEK_CUR); + /* seek to the beginning of the next packet */ - 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; packet_pos = current_pos + this->packet_size_left; if (this->packet_size_left) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_asf: last packet is not finished\n"); current_pos = this->input->seek (this->input, packet_pos, SEEK_SET); if (current_pos != packet_pos) { - this->status = DEMUX_FINISHED; return 1; } } this->packet_size_left = 0; + /* check packet_count */ + packet_num = (current_pos - this->first_packet_pos) / this->packet_size; + if (packet_num == this->packet_count) { + /* end of payload data */ + current_pos = this->input->get_current_pos (this->input); + lprintf("demux_asf: end of payload data, current_pos=%lld\n", current_pos); + { + /* check new asf header */ + GUID g; + int i; + + g.Data1 = (get_byte(this)) + (get_byte(this) << 8) + + (get_byte(this) << 16) + (get_byte(this) << 24); + g.Data2 = get_le16(this); + g.Data3 = get_le16(this); + for(i = 0; i < 8; i++) { + g.Data4[i] = get_byte(this); + } + if (get_guid_id(this, g) == GUID_ASF_HEADER) { + lprintf("demux_asf: new asf header detected\n"); + if (demux_asf_send_headers_common(this, 0)) + return 1; + } else { + /* not an ASF stream */ + return 1; + } + } + } + return 0; } @@ -1005,48 +1039,38 @@ static int asf_parse_packet_ecd(demux_asf_t *this, uint32_t *p_hdr_size) { uint8_t ecd_flags; uint8_t buf[16]; int invalid_packet; - uint32_t rsize; do { ecd_flags = get_byte(this); *p_hdr_size = 1; if (this->status == DEMUX_FINISHED) return 1; invalid_packet = 0; - - /* check new asf header */ - if (ecd_flags == 0x30) { - GUID g; - int i; + { + int ecd_len; + int ecd_opaque; + int ecd_len_type; + int ecd_present; + + ecd_len = ecd_flags & 0xF; + ecd_opaque = (ecd_flags >> 4) & 0x1; + ecd_len_type = (ecd_flags >> 5) & 0x3; + ecd_present = (ecd_flags >> 7) & 0x1; - g.Data1 = (ecd_flags) + (get_byte(this) << 8) + - (get_byte(this) << 16) + (get_byte(this) << 24); - g.Data2 = get_le16(this); - g.Data3 = get_le16(this); - for(i = 0; i < 8; i++) { - g.Data4[i] = get_byte(this); - } - if (get_guid_id(this, g) == GUID_ASF_HEADER) { - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_asf: new asf header detected\n"); - if (demux_asf_send_headers_common(this, 0)) - return 1; - invalid_packet = 1; - } - } else { - /* skip ecd */ - if (ecd_flags & 0x80) { - rsize = this->input->read (this->input, buf, ecd_flags & 0x0F); - if (rsize != (ecd_flags & 0x0F)) { + if (ecd_present && !ecd_opaque && !ecd_len_type) { + int read_size; + + read_size = this->input->read (this->input, buf, ecd_len); + if (read_size != ecd_len) { this->status = DEMUX_FINISHED; return 1; } - *p_hdr_size += rsize; - } + *p_hdr_size += read_size; - if (ecd_flags & 0x70) { - /* skip invalid packet */ - lprintf("skip invalid packet: %d\n", ecd_flags); + } else { + /* skip invalid packet */ + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_asf: skip invalid packet: %2X\n", ecd_flags); this->input->seek (this->input, this->packet_size - *p_hdr_size, SEEK_CUR); invalid_packet = 1; } @@ -1062,11 +1086,11 @@ static int asf_parse_packet_payload_header(demux_asf_t *this, uint32_t p_hdr_siz int64_t timestamp; int64_t duration; - this->packet_flags = get_byte(this); p_hdr_size += 1; - this->segtype = get_byte(this); p_hdr_size += 1; + this->packet_len_flags = get_byte(this); p_hdr_size += 1; + this->packet_prop_flags = get_byte(this); p_hdr_size += 1; /* packet size */ - switch((this->packet_flags >> 5) & 3) { + switch((this->packet_len_flags >> 5) & 3) { case 1: this->data_size = get_byte(this); p_hdr_size += 1; break; case 2: @@ -1078,7 +1102,7 @@ static int asf_parse_packet_payload_header(demux_asf_t *this, uint32_t p_hdr_siz } /* sequence */ - switch ((this->packet_flags >> 1) & 3) { + switch ((this->packet_len_flags >> 1) & 3) { case 1: get_byte(this); p_hdr_size += 1; break; case 2: @@ -1088,7 +1112,7 @@ static int asf_parse_packet_payload_header(demux_asf_t *this, uint32_t p_hdr_siz } /* padding size */ - switch ((this->packet_flags >> 3) & 3){ + switch ((this->packet_len_flags >> 3) & 3){ case 1: this->packet_padsize = get_byte(this); p_hdr_size += 1; break; case 2: @@ -1104,7 +1128,7 @@ static int asf_parse_packet_payload_header(demux_asf_t *this, uint32_t p_hdr_siz lprintf ("timestamp=%lld, duration=%lld\n", timestamp, duration); - if ((this->packet_flags >> 5) & 3) { + if ((this->packet_len_flags >> 5) & 3) { /* absolute data size */ lprintf ("absolute data size\n"); @@ -1123,7 +1147,7 @@ static int asf_parse_packet_payload_header(demux_asf_t *this, uint32_t p_hdr_siz } /* Multiple frames */ - if (this->packet_flags & 0x01) { + if (this->packet_len_flags & 0x01) { this->frame_flag = get_byte(this); p_hdr_size += 1; this->nb_frames = (this->frame_flag & 0x3F); @@ -1136,7 +1160,7 @@ static int asf_parse_packet_payload_header(demux_asf_t *this, uint32_t p_hdr_siz /* this->packet_size_left = this->packet_size - p_hdr_size; */ this->packet_size_left = this->data_size - p_hdr_size; lprintf ("new packet, size = %d, size_left = %d, flags = 0x%02x, padsize = %d, this->packet_size = %d\n", - this->data_size, this->packet_size_left, this->packet_flags, this->packet_padsize, this->packet_size); + this->data_size, this->packet_size_left, this->packet_len_flags, this->packet_padsize, this->packet_size); return 0; } @@ -1157,11 +1181,12 @@ static int asf_parse_packet_payload_common(demux_asf_t *this, stream_id = raw_id & 0x7f; *stream = NULL; - lprintf ("got raw_id=%d\n", raw_id); + lprintf ("got raw_id=%d, stream_id=%d\n", raw_id, stream_id); for (i = 0; i < this->num_streams; i++) { - if (this->streams[i].stream_id == stream_id && - (stream_id == this->audio_stream_id || stream_id == this->video_stream_id)) { + 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))) { *stream = &this->streams[i]; break; } @@ -1177,10 +1202,8 @@ static int asf_parse_packet_payload_common(demux_asf_t *this, return 1; } #endif - if (*stream == NULL) - return 1; - switch ((this->segtype >> 4) & 3){ + switch ((this->packet_prop_flags >> 4) & 3){ case 1: *seq = get_byte(this); s_hdr_size += 1; if (*stream) @@ -1202,7 +1225,6 @@ 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); if ((*stream)->first_seq || (*stream)->skip) { @@ -1233,7 +1255,7 @@ static int asf_parse_packet_payload_common(demux_asf_t *this, } } - switch ((this->segtype >> 2) & 3) { + switch ((this->packet_prop_flags >> 2) & 3) { case 1: *frag_offset = get_byte(this); s_hdr_size += 1; break; case 2: @@ -1245,7 +1267,7 @@ static int asf_parse_packet_payload_common(demux_asf_t *this, *frag_offset = 0; } - switch (this->segtype & 3) { + switch (this->packet_prop_flags & 3) { case 1: *rlen = get_byte(this); s_hdr_size += 1; break; case 2: @@ -1287,7 +1309,7 @@ static int asf_parse_packet_compressed_payload(demux_asf_t *this, frag_offset = 0; get_byte (this); s_hdr_size += 1; - if (this->packet_flags & 0x01) { + if (this->packet_len_flags & 0x01) { /* multiple frames */ switch ((this->frame_flag >> 6) & 3) { case 1: @@ -1390,7 +1412,7 @@ static int asf_parse_packet_payload(demux_asf_t *this, s_hdr_size += rlen; } - if (this->packet_flags & 0x01) { + if (this->packet_len_flags & 0x01) { switch ((this->frame_flag >> 6) & 3) { case 1: frag_len = get_byte(this); s_hdr_size += 1; break; diff --git a/src/input/input_mms.c b/src/input/input_mms.c index 8c4718ac3..d353895b6 100644 --- a/src/input/input_mms.c +++ b/src/input/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: input_mms.c,v 1.46 2004/02/17 13:40:57 valtri Exp $ + * $Id: input_mms.c,v 1.47 2004/04/06 00:25:29 tmattern Exp $ * * mms input plugin based on work from major mms */ @@ -82,8 +82,6 @@ typedef struct { char *mrl; - off_t curpos; - nbc_t *nbc; char scratch[1025]; @@ -110,8 +108,6 @@ static off_t mms_plugin_read (input_plugin_t *this_gen, lprintf ("mms_plugin_read: %lld bytes ...\n", len); - nbc_check_buffers (this->nbc); - switch (this->protocol) { case PROTOCOL_MMST: n = mms_read (this->mms, buf, len); @@ -120,8 +116,6 @@ static off_t mms_plugin_read (input_plugin_t *this_gen, n = mmsh_read (this->mmsh, buf, len); break; } - - this->curpos += n; return n; } @@ -151,37 +145,45 @@ static buf_element_t *mms_plugin_read_block (input_plugin_t *this_gen, static off_t mms_plugin_seek (input_plugin_t *this_gen, off_t offset, int origin) { mms_input_plugin_t *this = (mms_input_plugin_t *) this_gen; - off_t dest = this->curpos; + off_t dest = 0; + off_t curpos = 0; lprintf ("mms_plugin_seek: %lld offset, %d origin...\n", offset, origin); + + switch (this->protocol) { + case PROTOCOL_MMST: + curpos = mms_get_current_pos (this->mms); + break; + case PROTOCOL_MMSH: + curpos = mmsh_get_current_pos (this->mmsh); + break; + } + switch (origin) { case SEEK_SET: dest = offset; break; case SEEK_CUR: - dest = this->curpos + offset; + dest = curpos + offset; break; - case SEEK_END: - printf ("input_mms: SEEK_END not implemented!\n"); - return this->curpos; default: printf ("input_mms: unknown origin in seek!\n"); - return this->curpos; + return curpos; } - if (this->curpos > dest) { + if (curpos > dest) { printf ("input_mms: cannot seek back!\n"); - return this->curpos; + return curpos; } - - while (this->curposcurpos; + diff = dest - curpos; - if (diff>1024) + if (diff > 1024) diff = 1024; switch (this->protocol) { @@ -193,14 +195,14 @@ static off_t mms_plugin_seek (input_plugin_t *this_gen, off_t offset, int origin break; } - this->curpos += n; + curpos += n; if (n < diff) - return this->curpos; + return curpos; } - return this->curpos; + return curpos; } static off_t mms_plugin_get_length (input_plugin_t *this_gen) { @@ -235,12 +237,21 @@ static uint32_t mms_plugin_get_blocksize (input_plugin_t *this_gen) { static off_t mms_plugin_get_current_pos (input_plugin_t *this_gen){ mms_input_plugin_t *this = (mms_input_plugin_t *) this_gen; - + off_t curpos; + /* printf ("current pos is %lld\n", this->curpos); */ + switch (this->protocol) { + case PROTOCOL_MMST: + curpos = mms_get_current_pos(this->mms); + break; + case PROTOCOL_MMSH: + curpos = mmsh_get_current_pos(this->mmsh); + break; + } - return this->curpos; + return curpos; } static void mms_plugin_dispose (input_plugin_t *this_gen) { @@ -351,7 +362,6 @@ static int mms_plugin_open (input_plugin_t *this_gen) { this->mms = mms; this->mmsh = mmsh; - this->curpos = 0; return 1; } @@ -385,7 +395,6 @@ static input_plugin_t *mms_class_get_instance (input_class_t *cls_gen, xine_stre this->mmsh = NULL; this->protocol = protocol; this->mrl = mrl; - this->curpos = 0; this->nbc = nbc_init (this->stream); if (xine_config_lookup_entry (stream->xine, "input.mms_network_bandwidth", diff --git a/src/input/mms.c b/src/input/mms.c index a101e1324..e5e4ce027 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.43 2004/04/04 12:19:06 tmattern Exp $ + * $Id: mms.c,v 1.44 2004/04/06 00:25:29 tmattern Exp $ * * MMS over TCP protocol * based on work from major mms @@ -25,7 +25,7 @@ * * TODO: * general cleanup, error messages - * allways check packet size + * always check packet size * enable seeking ! */ @@ -126,6 +126,7 @@ struct mms_s { int has_audio; int has_video; int live_flag; + off_t current_pos; }; @@ -487,6 +488,7 @@ static void interp_header (mms_t *this) { /* * parse header */ + i = 30; while (i < this->asf_header_len) { @@ -804,6 +806,7 @@ mms_t *mms_connect (xine_stream_t *stream, const char *url, int bandwidth) { this->has_audio = 0; this->has_video = 0; this->bandwidth = bandwidth; + this->current_pos = 0; report_progress (stream, 0); @@ -963,6 +966,7 @@ mms_t *mms_connect (xine_stream_t *stream, const char *url, int bandwidth) { #endif lprintf("mms_connect: passed\n" ); + return this; fail: @@ -1007,10 +1011,16 @@ static int get_media_packet (mms_t *this) { if (pre_header[4] == 0x04) { - uint32_t packet_len; + uint32_t packet_len, sequence; - packet_len = (pre_header[7] << 8 | pre_header[6]) - 8; + packet_len = LE_16(&pre_header[6]) - 8; + sequence = LE_32(&pre_header[0]); + lprintf ("sequence=%d\n", sequence); + + /* simulate a seek */ + this->current_pos = this->asf_header_len + sequence * this->packet_length; + lprintf ("asf media packet detected, len=%d\n", packet_len); if (packet_len > (BUF_SIZE)) { xprintf (this->stream->xine, XINE_VERBOSITY_LOG, @@ -1109,6 +1119,7 @@ static int get_media_packet (mms_t *this) { "failed to send command 0x07\n"); return 0; } + this->current_pos = 0; } else if (command != 0x05) { xprintf (this->stream->xine, XINE_VERBOSITY_LOG, @@ -1157,6 +1168,7 @@ int mms_read (mms_t *this, char *data, int len) { this->asf_header_read += n; total += n; + this->current_pos += n; } else { int n, bytes_left ; @@ -1181,6 +1193,7 @@ int mms_read (mms_t *this, char *data, int len) { this->buf_read += n; total += n; + this->current_pos += n; } } return total; @@ -1210,3 +1223,7 @@ void mms_close (mms_t *this) { uint32_t mms_get_length (mms_t *this) { return this->file_length; } + +off_t mms_get_current_pos (mms_t *this) { + return this->current_pos; +} diff --git a/src/input/mms.h b/src/input/mms.h index b18a90f45..3c1b4af81 100644 --- a/src/input/mms.h +++ b/src/input/mms.h @@ -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.h,v 1.10 2003/12/09 00:02:30 f1rmb Exp $ + * $Id: mms.h,v 1.11 2004/04/06 00:25:29 tmattern Exp $ * * libmms public header */ @@ -39,5 +39,7 @@ void mms_close (mms_t *this); int mms_peek_header (mms_t *this, char *data, int maxsize); +off_t mms_get_current_pos (mms_t *this); + #endif diff --git a/src/input/mmsh.c b/src/input/mmsh.c index 425b957f8..67c2dc7fa 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.27 2004/01/23 00:01:15 valtri Exp $ + * $Id: mmsh.c,v 1.28 2004/04/06 00:25:29 tmattern Exp $ * * MMS over HTTP protocol * written by Thibaut Mattern @@ -53,7 +53,6 @@ /* #define LOG */ - #include "xine_internal.h" #include "xineutils.h" @@ -113,8 +112,6 @@ static const char* mmsh_LiveRequest = "Pragma: stream-switch-entry=%s\r\n" "Connection: Close\r\n\r\n"; - -#if 0 /* Unused requests */ static const char* mmsh_PostRequest = "POST %s HTTP/1.0\r\n" @@ -122,7 +119,8 @@ static const char* mmsh_PostRequest = USERAGENT "Host: %s\r\n" "Pragma: client-id=%u\r\n" -/* "Pragma: log-line=no-cache,rate=1.000000,stream-time=%u,stream-offset=%u:%u,request-context=2,max-duration=%u\r\n" */ +/* "Pragma: log-line=no-cache,rate=1.000000,stream-time=%u,stream-offset=%u:%u,request-context=2,max-duration=%u\r\n" + */ "Pragma: Content-Length: 0\r\n" CLIENTGUID "\r\n"; @@ -135,7 +133,6 @@ static const char* mmsh_RangeRequest = "Range: bytes=%Lu-\r\n" CLIENTGUID "Connection: Close\r\n\r\n"; -#endif @@ -169,7 +166,6 @@ struct mmsh_s { uint16_t chunk_type; uint16_t chunk_length; uint16_t chunk_seq_number; - int chunk_eos; uint8_t buf[CHUNK_SIZE]; int buf_size; @@ -190,6 +186,9 @@ struct mmsh_s { int has_audio; int has_video; + + off_t current_pos; + int user_bandwitdh; }; static int get_guid (unsigned char *buffer, int offset) { @@ -345,22 +344,25 @@ static int get_chunk_header (mmsh_t *this) { this->chunk_type = LE_16 (chunk_header); this->chunk_length = LE_16 (chunk_header + 2) - 8; this->chunk_seq_number = LE_32 (chunk_header + 4); - + + /* display debug infos */ #ifdef LOG switch (this->chunk_type) { case CHUNK_TYPE_DATA: printf ("libmmsh: chunk type: CHUNK_TYPE_DATA\n"); + printf ("libmmsh: chunk length: %d\n", this->chunk_length); + printf ("libmmsh: chunk seq: %d\n", this->chunk_seq_number); break; case CHUNK_TYPE_END: printf ("libmmsh: chunk type: CHUNK_TYPE_END\n"); + printf ("libmmsh: continue: %d\n", this->chunk_seq_number); break; case CHUNK_TYPE_ASF_HEADER: printf ("libmmsh: chunk type: CHUNK_TYPE_ASF_HEADER\n"); + printf ("libmmsh: chunk length: %d\n", this->chunk_length); break; } - printf ("libmmsh: chunk length: %d\n", this->chunk_length); - printf ("libmmsh: chunk seq_number: %d\n", this->chunk_seq_number); #endif return 1; @@ -372,7 +374,8 @@ static int get_header (mmsh_t *this) { lprintf("get_header\n"); this->asf_header_len = 0; - + this->asf_header_read = 0; + /* read chunk */ while (1) { if (get_chunk_header(this)) { @@ -411,7 +414,7 @@ static void interp_header (mmsh_t *this) { int i; - lprintf ("interp_header\n"); + lprintf ("interp_header, header_len=%d\n", this->asf_header_len); this->packet_length = 0; @@ -585,8 +588,8 @@ static int mmsh_tcp_connect(mmsh_t *this) { return 0; } -mmsh_t *mmsh_connect (xine_stream_t *stream, const char *url, int bandwidth) { - mmsh_t *this; + +static int mmsh_connect_int(mmsh_t *this, int bandwidth) { int i; int video_stream = -1; int audio_stream = -1; @@ -597,49 +600,11 @@ mmsh_t *mmsh_connect (xine_stream_t *stream, const char *url, int bandwidth) { int bandwitdh_left; char stream_selection[10 * ASF_MAX_NUM_STREAMS]; /* 10 chars per stream */ int offset; - - if (!url) - return NULL; - - report_progress (stream, 0); - - this = (mmsh_t*) xine_xmalloc (sizeof (mmsh_t)); - - this->stream = stream; - this->url = strdup(url); - 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->chunk_eos = 0; - - report_progress (stream, 0); - - if (!_x_parse_url (this->url, &this->proto, &this->host, &this->port, - &this->user, &this->password, &this->uri)) { - xine_log (this->stream->xine, XINE_LOG_MSG, _("invalid url\n")); - goto fail; - } - - if (!mmsh_valid_proto(this->proto)) { - xine_log (this->stream->xine, XINE_LOG_MSG, _("unsupported protocol\n")); - goto fail; - } - - if (mmsh_tcp_connect(this)) { - goto fail; - } - report_progress (stream, 30); - /* * let the negotiations begin... */ - + this->num_stream_ids = 0; + /* first request */ lprintf("first http request\n"); @@ -657,7 +622,7 @@ mmsh_t *mmsh_connect (xine_stream_t *stream, const char *url, int bandwidth) { interp_header(this); close(this->s); - report_progress (stream, 20); + report_progress (this->stream, 20); /* choose the best quality for the audio stream */ @@ -769,7 +734,8 @@ mmsh_t *mmsh_connect (xine_stream_t *stream, const char *url, int bandwidth) { if (!get_answer (this)) goto fail; - get_header(this); + if (!get_header(this)) + goto fail; interp_header(this); for (i = 0; i < this->num_stream_ids; i++) { @@ -784,9 +750,59 @@ mmsh_t *mmsh_connect (xine_stream_t *stream, const char *url, int bandwidth) { this->asf_header[this->bitrates_pos[this->stream_ids[i]] + 3] = 0; } } + return 1; + +fail: + return 0; +} - report_progress (stream, 100); +mmsh_t *mmsh_connect (xine_stream_t *stream, const char *url, int bandwidth) { + mmsh_t *this; + + if (!url) + return NULL; + + report_progress (stream, 0); + + this = (mmsh_t*) xine_xmalloc (sizeof (mmsh_t)); + + this->stream = stream; + this->url = strdup(url); + 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; + + report_progress (stream, 0); + + if (!_x_parse_url (this->url, &this->proto, &this->host, &this->port, + &this->user, &this->password, &this->uri)) { + xine_log (this->stream->xine, XINE_LOG_MSG, _("invalid url\n")); + goto fail; + } + + if (!mmsh_valid_proto(this->proto)) { + xine_log (this->stream->xine, XINE_LOG_MSG, _("unsupported protocol\n")); + goto fail; + } + + if (mmsh_tcp_connect(this)) + goto fail; + + report_progress (stream, 30); + + if (!mmsh_connect_int(this, this->user_bandwitdh)) + goto fail; + report_progress (stream, 100); + lprintf("mmsh_connect: passed\n" ); return this; @@ -820,11 +836,31 @@ static int get_media_packet (mmsh_t *this) { lprintf("get_media_packet: this->packet_length: %d\n", this->packet_length); - if (!this->chunk_eos && get_chunk_header(this)) { + if (get_chunk_header(this)) { switch (this->chunk_type) { case CHUNK_TYPE_END: - this->chunk_eos = 1; + /* this->chunk_seq_number: + * 0: stop + * 1: a new stream follows + */ + if (this->chunk_seq_number == 0) { + return 0; + } else { + close(this->s); + + if (mmsh_tcp_connect(this)) + return 0; + + if (!mmsh_connect_int(this, this->user_bandwitdh)) + return 0; + + this->current_pos = 0; + this->buf_size = 0; + return 1; + } + break; case CHUNK_TYPE_DATA: + this->current_pos = this->asf_header_len + this->chunk_seq_number * this->packet_length; break; default: xprintf (this->stream->xine, XINE_VERBOSITY_LOG, @@ -884,6 +920,7 @@ int mmsh_read (mmsh_t *this, char *data, int len) { this->asf_header_read += n; total += n; + this->current_pos += n; } else { int n, bytes_left ; @@ -891,24 +928,25 @@ int mmsh_read (mmsh_t *this, char *data, int len) { bytes_left = this->buf_size - this->buf_read; if (bytes_left == 0) { - this->buf_read = 0; - if (!get_media_packet (this)) { + this->buf_read = 0; + if (!get_media_packet (this)) { xprintf (this->stream->xine, XINE_VERBOSITY_LOG, - "libmmsh: get_media_packet failed\n"); - return total; - } - bytes_left = this->buf_size; + "libmmsh: get_media_packet failed\n"); + return total; + } + bytes_left = this->buf_size; } - if ((len-total) < bytes_left) - n = len-total; + if ((len - total) < bytes_left) + n = len - total; else - n = bytes_left; + n = bytes_left; xine_fast_memcpy (&data[total], &this->buf[this->buf_read], n); this->buf_read += n; total += n; + this->current_pos += n; } } return total; @@ -941,3 +979,7 @@ void mmsh_close (mmsh_t *this) { uint32_t mmsh_get_length (mmsh_t *this) { return this->file_length; } + +off_t mmsh_get_current_pos (mmsh_t *this) { + return this->current_pos; +} diff --git a/src/input/mmsh.h b/src/input/mmsh.h index 756629ee1..4ae838526 100644 --- a/src/input/mmsh.h +++ b/src/input/mmsh.h @@ -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.h,v 1.3 2003/12/09 00:02:30 f1rmb Exp $ + * $Id: mmsh.h,v 1.4 2004/04/06 00:25:29 tmattern Exp $ * * libmmsh public header */ @@ -39,4 +39,6 @@ void mmsh_close (mmsh_t *this); int mmsh_peek_header (mmsh_t *this, char *data, int maxsize); +off_t mmsh_get_current_pos (mmsh_t *this); + #endif -- cgit v1.2.3