Mercurial > audlegacy-plugins
changeset 502:d9fe80b35381 trunk
[svn] - remove broken mms code, libmms-based transport in progress
author | nenolod |
---|---|
date | Sun, 21 Jan 2007 21:15:15 -0800 |
parents | 1b06f6690022 |
children | fe2c60ca8c98 |
files | ChangeLog src/wma/libffwma/Makefile src/wma/libffwma/mms.c src/wma/libffwma/mms.h src/wma/libffwma/mmsh.c src/wma/libffwma/mmsh.h src/wma/libffwma/mmsio.h |
diffstat | 7 files changed, 9 insertions(+), 2969 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Sun Jan 21 21:01:41 2007 -0800 +++ b/ChangeLog Sun Jan 21 21:15:15 2007 -0800 @@ -1,3 +1,11 @@ +2007-01-22 05:01:41 +0000 William Pitcock <nenolod@sacredspiral.co.uk> + revision [1088] + - ssl support (no idea why, but hey, we can!) + + trunk/src/curl/curl.c | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + + 2007-01-22 04:51:22 +0000 William Pitcock <nenolod@sacredspiral.co.uk> revision [1086] - URIs are now passed naked instead of mangled by the VFS subsystem.
--- a/src/wma/libffwma/Makefile Sun Jan 21 21:01:41 2007 -0800 +++ b/src/wma/libffwma/Makefile Sun Jan 21 21:15:15 2007 -0800 @@ -8,7 +8,7 @@ avi.h avio.c avio.h aviobuf.c \ bswap.h common.c common.h \ cutils.c cutils.h dsputil.c dsputil.h \ - fft.c file.c futils.c mdct.c mms.c \ + fft.c file.c futils.c mdct.c \ os_support.c os_support.h \ parser.c simple_idct.c simple_idct.h \ utils.h utils.c wmadata.h wmadec.c mem.c uri.c
--- a/src/wma/libffwma/mms.c Sun Jan 21 21:01:41 2007 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1496 +0,0 @@ -/* - * Copyright (C) 2002-2004 the xine project - * - * This file is part of LibMMS, an MMS protocol handling library. - * - * 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 ree 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - * - * $Id: mms.c,v 1.21 2006/07/13 12:32:20 shawarma Exp $ - * - * MMS over TCP protocol - * based on work from major mms - * utility functions to handle communication with an mms server - * - * TODO: - * error messages - * enable seeking ! - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <unistd.h> -#include <stdio.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <netdb.h> -#include <string.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <errno.h> -#include <stdlib.h> -#include <time.h> - -/********** logging **********/ -#define LOG_MODULE "mms" -#define LOG_VERBOSE -#ifdef DEBUG -# define lprintf printf -#else -# define lprintf(x...) -#endif - - -#include "bswap.h" -#include "mms.h" -#include "asfheader.h" -#include "uri.h" - - -/* - * mms specific types - */ - -#define MMST_PORT 1755 - -#define BUF_SIZE 102400 - -#define CMD_HEADER_LEN 40 -#define CMD_PREFIX_LEN 8 -#define CMD_BODY_LEN 1024 - -#define ASF_HEADER_LEN 8192 - - -#define MMS_PACKET_ERR 0 -#define MMS_PACKET_COMMAND 1 -#define MMS_PACKET_ASF_HEADER 2 -#define MMS_PACKET_ASF_PACKET 3 - -#define ASF_HEADER_PACKET_ID_TYPE 2 -#define ASF_MEDIA_PACKET_ID_TYPE 4 - - -typedef struct mms_buffer_s mms_buffer_t; -struct mms_buffer_s { - uint8_t *buffer; - int pos; -}; - -typedef struct mms_packet_header_s mms_packet_header_t; -struct mms_packet_header_s { - uint32_t packet_len; - uint8_t flags; - uint8_t packet_id_type; - uint32_t packet_seq; -}; - - -struct mms_s { - - /* FIXME: de-xine-ification */ - void *custom_data; - - int s; - - /* url parsing */ - char *url; - char *proto; - char *host; - int port; - char *user; - char *password; - char *uri; - - /* command to send */ - char scmd[CMD_HEADER_LEN + CMD_BODY_LEN]; - char *scmd_body; /* pointer to &scmd[CMD_HEADER_LEN] */ - int scmd_len; /* num bytes written in header */ - - char str[1024]; /* scratch buffer to built strings */ - - /* receive buffer */ - uint8_t buf[BUF_SIZE]; - int buf_size; - int buf_read; - - uint8_t asf_header[ASF_HEADER_LEN]; - uint32_t asf_header_len; - uint32_t asf_header_read; - int seq_num; - int num_stream_ids; - int stream_ids[ASF_MAX_NUM_STREAMS]; - int stream_types[ASF_MAX_NUM_STREAMS]; - off_t start_packet_seq; /* for live streams != 0, need to keep it around */ - int need_discont; /* whether we need to set start_packet_seq */ - uint32_t asf_packet_len; - uint64_t file_len; - char guid[37]; - uint32_t bitrates[ASF_MAX_NUM_STREAMS]; - uint32_t bitrates_pos[ASF_MAX_NUM_STREAMS]; - int bandwidth; - - int has_audio; - int has_video; - int live_flag; - off_t current_pos; - int eos; -}; - -static int fallback_io_select(void *data, int socket, int state, int timeout_msec) -{ - fd_set set; - struct timeval tv = { timeout_msec / 1000, (timeout_msec % 1000) * 1000}; - FD_ZERO(&set); - FD_SET(socket, &set); - return select(1, (state == MMS_IO_READ_READY) ? &set : NULL, - (state == MMS_IO_WRITE_READY) ? &set : NULL, NULL, &tv); -} - -static off_t fallback_io_read(void *data, int socket, char *buf, off_t num) -{ - off_t len = 0, ret; -/* lprintf("%d\n", fallback_io_select(data, socket, MMS_IO_READ_READY, 1000)); */ - errno = 0; - while (len < num) - { - ret = (off_t)read(socket, buf + len, num - len); - if(ret == 0) - break; /* EOF */ - if(ret < 0) - switch(errno) - { - case EAGAIN: - lprintf("len == %lld\n", (long long int) len); - break; - default: - lprintf("len == %lld\n", (long long int) len); - perror(NULL); - /* if already read something, return it, we will fail next time */ - return len ? len : ret; - } - len += ret; - } - lprintf("ret len == %lld\nnum == %lld\n", (long long int) len, (long long int) num); - return len; -} - -static off_t fallback_io_write(void *data, int socket, char *buf, off_t num) -{ - return (off_t)write(socket, buf, num); -} - -static int fallback_io_tcp_connect(void *data, const char *host, int port) -{ - - struct hostent *h; - int i, s; - - h = gethostbyname(host); - if (h == NULL) { -/* fprintf(stderr, "unable to resolve host: %s\n", host); */ - return -1; - } - - s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); - if (s == -1) { -/* fprintf(stderr, "failed to create socket: %s", strerror(errno)); */ - return -1; - } - - if (fcntl (s, F_SETFL, fcntl (s, F_GETFL) & ~O_NONBLOCK) == -1) { -/* _x_message(stream, XINE_MSG_CONNECTION_REFUSED, "can't put socket in non-blocking mode", strerror(errno), NULL); */ - return -1; - } - - for (i = 0; h->h_addr_list[i]; i++) { - struct in_addr ia; - struct sockaddr_in sin; - - memcpy (&ia, h->h_addr_list[i], 4); - sin.sin_family = AF_INET; - sin.sin_addr = ia; - sin.sin_port = htons(port); - - if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) ==-1 && errno != EINPROGRESS) { - - /* FIXME: de-xine-ification */ -/* _x_message(stream, XINE_MSG_CONNECTION_REFUSED, strerror(errno), NULL); */ - close(s); - continue; - } - - return s; - } - return -1; -} - - -static mms_io_t fallback_io = - { - &fallback_io_select, - NULL, - &fallback_io_read, - NULL, - &fallback_io_write, - NULL, - &fallback_io_tcp_connect, - NULL, - }; - -static mms_io_t default_io = { - &fallback_io_select, - NULL, - &fallback_io_read, - NULL, - &fallback_io_write, - NULL, - &fallback_io_tcp_connect, - NULL, - }; - - -#define io_read(io, args...) ((io) ? (io)->read(io->read_data , ## args) : default_io.read(NULL , ## args)) -#define io_write(io, args...) ((io) ? (io)->write(io->write_data , ## args) : default_io.write(NULL , ## args)) -#define io_select(io, args...) ((io) ? (io)->select(io->select_data , ## args) : default_io.select(NULL , ## args)) -#define io_connect(io, args...) ((io) ? (io)->connect(io->connect_data , ## args) : default_io.connect(NULL , ## args)) - -const mms_io_t* mms_get_default_io_impl() -{ - return &default_io; -} - -void mms_set_default_io_impl(const mms_io_t *io) -{ - if(io->select) - { - default_io.select = io->select; - default_io.select_data = io->select_data; - } else - { - default_io.select = fallback_io.select; - default_io.select_data = fallback_io.select_data; - } - if(io->read) - { - default_io.read = io->read; - default_io.read_data = io->read_data; - } else - { - default_io.read = fallback_io.read; - default_io.read_data = fallback_io.read_data; - } - if(io->write) - { - default_io.write = io->write; - default_io.write_data = io->write_data; - } else - { - default_io.write = fallback_io.write; - default_io.write_data = fallback_io.write_data; - } - if(io->connect) - { - default_io.connect = io->connect; - default_io.connect_data = io->connect_data; - } else - { - default_io.connect = fallback_io.connect; - default_io.connect_data = fallback_io.connect_data; - } -} - -static void mms_buffer_init (mms_buffer_t *mms_buffer, uint8_t *buffer) { - mms_buffer->buffer = buffer; - mms_buffer->pos = 0; -} - -static void mms_buffer_put_8 (mms_buffer_t *mms_buffer, uint8_t value) { - - mms_buffer->buffer[mms_buffer->pos] = value & 0xff; - - mms_buffer->pos += 1; -} - -#if 0 -static void mms_buffer_put_16 (mms_buffer_t *mms_buffer, uint16_t value) { - - mms_buffer->buffer[mms_buffer->pos] = value & 0xff; - mms_buffer->buffer[mms_buffer->pos + 1] = (value >> 8) & 0xff; - - mms_buffer->pos += 2; -} -#endif - -static void mms_buffer_put_32 (mms_buffer_t *mms_buffer, uint32_t value) { - - mms_buffer->buffer[mms_buffer->pos] = value & 0xff; - mms_buffer->buffer[mms_buffer->pos + 1] = (value >> 8) & 0xff; - mms_buffer->buffer[mms_buffer->pos + 2] = (value >> 16) & 0xff; - mms_buffer->buffer[mms_buffer->pos + 3] = (value >> 24) & 0xff; - - mms_buffer->pos += 4; -} - -static int get_guid (unsigned char *buffer, int offset) { - int i; - GUID g; - - g.Data1 = LE_32(buffer + offset); - g.Data2 = LE_16(buffer + offset + 4); - g.Data3 = LE_16(buffer + offset + 6); - for(i = 0; i < 8; i++) { - g.Data4[i] = buffer[offset + 8 + i]; - } - - for (i = 1; i < GUID_END; i++) { - if (!memcmp(&g, &guids[i].guid, sizeof(GUID))) { - lprintf("GUID: %s\n", guids[i].name); - return i; - } - } - - lprintf("unknown GUID: 0x%x, 0x%x, 0x%x, " - "{ 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx }\n", - g.Data1, g.Data2, g.Data3, - g.Data4[0], g.Data4[1], g.Data4[2], g.Data4[3], - g.Data4[4], g.Data4[5], g.Data4[6], g.Data4[7]); - - return GUID_ERROR; -} - - -static void print_command (char *data, int len) { - -#ifdef DEBUG - int i; - int dir = LE_32 (data + 36) >> 16; - int comm = LE_32 (data + 36) & 0xFFFF; - - lprintf ("----------------------------------------------\n"); - if (dir == 3) { - lprintf ("send command 0x%02x, %d bytes\n", comm, len); - } else { - lprintf ("receive command 0x%02x, %d bytes\n", comm, len); - } - lprintf (" start sequence %08x\n", LE_32 (data + 0)); - lprintf (" command id %08x\n", LE_32 (data + 4)); - lprintf (" length %8x \n", LE_32 (data + 8)); - lprintf (" protocol %08x\n", LE_32 (data + 12)); - lprintf (" len8 %8x \n", LE_32 (data + 16)); - lprintf (" sequence # %08x\n", LE_32 (data + 20)); - lprintf (" len8 (II) %8x \n", LE_32 (data + 32)); - lprintf (" dir | comm %08x\n", LE_32 (data + 36)); - if (len >= 4) - lprintf (" prefix1 %08x\n", LE_32 (data + 40)); - if (len >= 8) - lprintf (" prefix2 %08x\n", LE_32 (data + 44)); - - for (i = (CMD_HEADER_LEN + CMD_PREFIX_LEN); i < (CMD_HEADER_LEN + CMD_PREFIX_LEN + len); i += 1) { - unsigned char c = data[i]; - - if ((c >= 32) && (c < 128)) - lprintf ("%c", c); - else - lprintf (" %02x ", c); - - } - if (len > CMD_HEADER_LEN) - lprintf ("\n"); - lprintf ("----------------------------------------------\n"); -#endif -} - - - -static int send_command (mms_io_t *io, mms_t *this, int command, - uint32_t prefix1, uint32_t prefix2, - int length) { - int len8; - off_t n; - mms_buffer_t command_buffer; - - len8 = (length + 7) / 8; - - this->scmd_len = 0; - - mms_buffer_init(&command_buffer, this->scmd); - mms_buffer_put_32 (&command_buffer, 0x00000001); /* start sequence */ - mms_buffer_put_32 (&command_buffer, 0xB00BFACE); /* #-)) */ - mms_buffer_put_32 (&command_buffer, len8 * 8 + 32); - mms_buffer_put_32 (&command_buffer, 0x20534d4d); /* protocol type "MMS " */ - mms_buffer_put_32 (&command_buffer, len8 + 4); - mms_buffer_put_32 (&command_buffer, this->seq_num); - this->seq_num++; - mms_buffer_put_32 (&command_buffer, 0x0); /* timestamp */ - mms_buffer_put_32 (&command_buffer, 0x0); - mms_buffer_put_32 (&command_buffer, len8 + 2); - mms_buffer_put_32 (&command_buffer, 0x00030000 | command); /* dir | command */ - /* end of the 40 byte command header */ - - mms_buffer_put_32 (&command_buffer, prefix1); - mms_buffer_put_32 (&command_buffer, prefix2); - - if (length & 7) - memset(this->scmd + length + CMD_HEADER_LEN + CMD_PREFIX_LEN, 0, 8 - (length & 7)); - - n = io_write(io, this->s, this->scmd, len8 * 8 + CMD_HEADER_LEN + CMD_PREFIX_LEN); - if (n != (len8 * 8 + CMD_HEADER_LEN + CMD_PREFIX_LEN)) { - return 0; - } - - print_command (this->scmd, length); - - return 1; -} - -static void string_utf16(int unused, char *dest, char *src, int len) { - int i; - - memset (dest, 0, 2 * len); - - for (i = 0; i < len; i++) { - dest[i * 2] = src[i]; - dest[i * 2 + 1] = 0; - } - - dest[i * 2] = 0; - dest[i * 2 + 1] = 0; -} - -/* - * return packet type - */ -static int get_packet_header (mms_io_t *io, mms_t *this, mms_packet_header_t *header) { - size_t len; - int packet_type; - - header->packet_len = 0; - header->packet_seq = 0; - header->flags = 0; - header->packet_id_type = 0; - len = io_read(io, this->s, this->buf, 8); - if (len != 8) - goto error; - - if (LE_32(this->buf + 4) == 0xb00bface) { - /* command packet */ - header->flags = this->buf[3]; - len = io_read(io, this->s, this->buf + 8, 4); - if (len != 4) - goto error; - - header->packet_len = LE_32(this->buf + 8) + 4; - if (header->packet_len > BUF_SIZE - 12) { - header->packet_len = 0; - goto error; - } - lprintf("mms command\n"); - packet_type = MMS_PACKET_COMMAND; - } else { - header->packet_seq = LE_32(this->buf); - header->packet_id_type = this->buf[4]; - header->flags = this->buf[5]; - header->packet_len = (LE_16(this->buf + 6) - 8) & 0xffff; - if (header->packet_id_type == ASF_HEADER_PACKET_ID_TYPE) { - lprintf("asf header\n"); - packet_type = MMS_PACKET_ASF_HEADER; - } else { - lprintf("asf packet\n"); - packet_type = MMS_PACKET_ASF_PACKET; - } - } - - return packet_type; - -error: - lprintf("read error, len=%d\n", len); - perror("Could not read packet header"); - return MMS_PACKET_ERR; -} - - -static int get_packet_command (mms_io_t *io, mms_t *this, uint32_t packet_len) { - - - int command = 0; - size_t len; - - /* always enter this loop */ - lprintf("packet_len: %d bytes\n", packet_len); - - len = io_read(io, this->s, this->buf + 12, packet_len) ; - if (len != packet_len) { - return 0; - } - - print_command (this->buf, len); - - /* check protocol type ("MMS ") */ - if (LE_32(this->buf + 12) != 0x20534D4D) { - lprintf("unknown protocol type: %c%c%c%c (0x%08X)\n", - this->buf[12], this->buf[13], this->buf[14], this->buf[15], - LE_32(this->buf + 12)); - return 0; - } - - command = LE_32 (this->buf + 36) & 0xFFFF; - lprintf("command = 0x%2x\n", command); - - return command; -} - -static int get_answer (mms_io_t *io, mms_t *this) { - int command = 0; - mms_packet_header_t header; - - switch (get_packet_header (io, this, &header)) { - case MMS_PACKET_ERR: - /* FIXME: de-xine-ification */ - lprintf( "***LOG:*** -- " - "libmms: failed to read mms packet header\n"); - break; - case MMS_PACKET_COMMAND: - command = get_packet_command (io, this, header.packet_len); - - if (command == 0x1b) { - - if (!send_command (io, this, 0x1b, 0, 0, 0)) { - /* FIXME: de-xine-ification */ - lprintf( "***LOG:*** -- " - "libmms: failed to send command\n"); - return 0; - } - /* FIXME: limit recursion */ - command = get_answer (io, this); - } - break; - case MMS_PACKET_ASF_HEADER: - /* FIXME: de-xine-ification */ - lprintf( "***LOG:*** -- " - "libmms: unexpected asf header packet\n"); - break; - case MMS_PACKET_ASF_PACKET: - /* FIXME: de-xine-ification */ - lprintf( "***LOG:*** -- " -"libmms: unexpected asf packet\n"); - break; - } - - return command; -} - - -static int get_asf_header (mms_io_t *io, mms_t *this) { - - off_t len; - int stop = 0; - - this->asf_header_read = 0; - this->asf_header_len = 0; - - while (!stop) { - mms_packet_header_t header; - int command; - - switch (get_packet_header (io, this, &header)) { - case MMS_PACKET_ERR: - /* FIXME: de-xine-ification */ - lprintf( "***LOG:*** -- " - "libmms: failed to read mms packet header\n"); - return 0; - break; - case MMS_PACKET_COMMAND: - command = get_packet_command (io, this, header.packet_len); - - if (command == 0x1b) { - - if (!send_command (io, this, 0x1b, 0, 0, 0)) { - /* FIXME: de-xine-ification */ - lprintf( "***LOG:*** -- " - "libmms: failed to send command\n"); - return 0; - } - command = get_answer (io, this); - } else { - /* FIXME: de-xine-ification */ - lprintf( "***LOG:*** -- " - "libmms: unexpected command packet\n"); - } - break; - case MMS_PACKET_ASF_HEADER: - case MMS_PACKET_ASF_PACKET: - if (header.packet_len + this->asf_header_len > ASF_HEADER_LEN) { - lprintf( "***LOG:*** -- " - "libmms: asf packet too large\n"); - return 0; - } - len = io_read(io, this->s, - this->asf_header + this->asf_header_len, header.packet_len); - if (len != header.packet_len) { - /* FIXME: de-xine-ification */ - lprintf( "***LOG:*** -- " - "libmms: get_asf_header failed\n"); - return 0; - } - this->asf_header_len += header.packet_len; - lprintf("header flags: %d\n", header.flags); - if ((header.flags == 0X08) || (header.flags == 0X0C)) - stop = 1; - break; - } - } - lprintf ("get header packet succ\n"); - return 1; -} - -static void interp_asf_header (mms_t *this) { - - int i; - - this->asf_packet_len = 0; - this->num_stream_ids = 0; - /* - * parse header - */ - - i = 30; - while (i < this->asf_header_len) { - - int guid; - uint64_t length; - - guid = get_guid(this->asf_header, i); - i += 16; - - length = LE_64(this->asf_header + i); - i += 8; - - switch (guid) { - - case GUID_ASF_FILE_PROPERTIES: - - this->asf_packet_len = LE_32(this->asf_header + i + 92 - 24); - if (this->asf_packet_len > BUF_SIZE) { - this->asf_packet_len = 0; - lprintf( "***LOG:*** -- " - "libmms: asf packet len too large\n"); - break; - } - this->file_len = LE_64(this->asf_header + i + 40 - 24); - lprintf ("file object, packet length = %d (%d)\n", - this->asf_packet_len, LE_32(this->asf_header + i + 96 - 24)); - break; - - case GUID_ASF_STREAM_PROPERTIES: - { - uint16_t flags; - uint16_t stream_id; - int type; - int encrypted; - - guid = get_guid(this->asf_header, i); - switch (guid) { - case GUID_ASF_AUDIO_MEDIA: - type = ASF_STREAM_TYPE_AUDIO; - this->has_audio = 1; - break; - - case GUID_ASF_VIDEO_MEDIA: - case GUID_ASF_JFIF_MEDIA: - case GUID_ASF_DEGRADABLE_JPEG_MEDIA: - type = ASF_STREAM_TYPE_VIDEO; - this->has_video = 1; - break; - - case GUID_ASF_COMMAND_MEDIA: - type = ASF_STREAM_TYPE_CONTROL; - break; - - default: - type = ASF_STREAM_TYPE_UNKNOWN; - } - - flags = LE_16(this->asf_header + i + 48); - stream_id = flags & 0x7F; - encrypted = flags >> 15; - - lprintf ("stream object, stream id: %d, type: %d, encrypted: %d\n", - stream_id, type, encrypted); - - if (this->num_stream_ids < ASF_MAX_NUM_STREAMS && stream_id < ASF_MAX_NUM_STREAMS) { - this->stream_types[stream_id] = type; - this->stream_ids[this->num_stream_ids] = stream_id; - this->num_stream_ids++; - } else { - lprintf ("too many streams, skipping\n"); - } - } - break; - - case GUID_ASF_STREAM_BITRATE_PROPERTIES: - { - uint16_t streams = LE_16(this->asf_header + i); - uint16_t stream_id; - int j; - - lprintf ("stream bitrate properties\n"); - lprintf ("streams %d\n", streams); - - for(j = 0; j < streams; j++) { - stream_id = LE_16(this->asf_header + i + 2 + j * 6); - lprintf ("stream id %d\n", stream_id); - this->bitrates[stream_id] = LE_32(this->asf_header + i + 4 + j * 6); - this->bitrates_pos[stream_id] = i + 4 + j * 6; - lprintf ("stream id %d, bitrate %d\n", stream_id, - this->bitrates[stream_id]); - } - } - break; - - default: - lprintf ("unknown object\n"); - break; - } - - lprintf ("length : %lld\n", length); - - if (length > 24) { - i += length - 24; - } - } -} - -const static char *const mmst_proto_s[] = { "mms", "mmst", NULL }; - -static int mmst_valid_proto (char *proto) { - int i = 0; - - lprintf("mmst_valid_proto\n"); - - if (!proto) - return 0; - - while(mmst_proto_s[i]) { - if (!strcasecmp(proto, mmst_proto_s[i])) { - return 1; - } - i++; - } - return 0; -} - -/* FIXME: de-xine-ification */ - -/* static void report_progress (void *data, int p) { - - xine_event_t event; - xine_progress_data_t prg; - - prg.description = _("Connecting MMS server (over tcp)..."); - prg.percent = p; - - event.type = XINE_EVENT_PROGRESS; - event.data = &prg; - event.data_length = sizeof (xine_progress_data_t); - - xine_event_send (stream, &event); -} */ - - -/* - * returns 1 on error - */ -static int mms_tcp_connect(mms_io_t *io, mms_t *this) { - int progress, res; - - if (!this->port) this->port = MMST_PORT; - - /* - * try to connect - */ - lprintf("try to connect to %s on port %d \n", this->host, this->port); - this->s = io_connect(io, this->host, this->port); - if (this->s == -1) { - /* FIXME: de-xine-ification */ - lprintf ( "***LOG:*** -- " - "failed to connect '%s'\n", this->host); - return 1; - } - - /* connection timeout 15s */ - progress = 0; - do { - /*FIXME: de-xine-ification */ -/* report_progress(this->stream, progress); */ - res = io_select(io, this->s, MMS_IO_WRITE_READY, 500); - progress += 1; - } while ((res == MMS_IO_STATUS_TIMEOUT) && (progress < 30)); - if (res != MMS_IO_STATUS_READY) { - return 1; - } - lprintf ("connected\n"); - return 0; -} - -static void mms_gen_guid(char guid[]) { - static char digit[16] = "0123456789ABCDEF"; - int i = 0; - - srand(time(NULL)); - for (i = 0; i < 36; i++) { - guid[i] = digit[(int) ((16.0*rand())/(RAND_MAX+1.0))]; - } - guid[8] = '-'; guid[13] = '-'; guid[18] = '-'; guid[23] = '-'; - guid[36] = '\0'; -} - -/* - * return 0 on error - */ -int static mms_choose_best_streams(mms_io_t *io, mms_t *this) { - int i; - int video_stream = 0; - int audio_stream = 0; - int max_arate = 0; - int min_vrate = 0; - int min_bw_left = 0; - int stream_id; - int bandwitdh_left; - int res; - - /* command 0x33 */ - /* choose the best quality for the audio stream */ - /* i've never seen more than one audio stream */ - lprintf("num_stream_ids=%d\n", this->num_stream_ids); - for (i = 0; i < this->num_stream_ids; i++) { - stream_id = this->stream_ids[i]; - switch (this->stream_types[stream_id]) { - case ASF_STREAM_TYPE_AUDIO: - if (this->bitrates[stream_id] > max_arate) { - audio_stream = stream_id; - max_arate = this->bitrates[stream_id]; - } - break; - default: - break; - } - } - - /* choose a video stream adapted to the user bandwidth */ - bandwitdh_left = this->bandwidth - max_arate; - if (bandwitdh_left < 0) { - bandwitdh_left = 0; - } - lprintf("bandwitdh %d, left %d\n", this->bandwidth, bandwitdh_left); - - min_bw_left = bandwitdh_left; - for (i = 0; i < this->num_stream_ids; i++) { - stream_id = this->stream_ids[i]; - switch (this->stream_types[stream_id]) { - case ASF_STREAM_TYPE_VIDEO: - if (((bandwitdh_left - this->bitrates[stream_id]) < min_bw_left) && - (bandwitdh_left >= this->bitrates[stream_id])) { - video_stream = stream_id; - min_bw_left = bandwitdh_left - this->bitrates[stream_id]; - } - break; - default: - break; - } - } - - /* choose the lower bitrate of */ - if (!video_stream && this->has_video) { - for (i = 0; i < this->num_stream_ids; i++) { - stream_id = this->stream_ids[i]; - switch (this->stream_types[stream_id]) { - case ASF_STREAM_TYPE_VIDEO: - if ((this->bitrates[stream_id] < min_vrate) || - (!min_vrate)) { - video_stream = stream_id; - min_vrate = this->bitrates[stream_id]; - } - break; - default: - break; - } - } - } - - lprintf("selected streams: audio %d, video %d\n", audio_stream, video_stream); - lprintf("disabling other streams\n"); - memset (this->scmd_body, 0, 40); - for (i = 1; i < this->num_stream_ids; i++) { - this->scmd_body [ (i - 1) * 6 + 2 ] = 0xFF; - this->scmd_body [ (i - 1) * 6 + 3 ] = 0xFF; - this->scmd_body [ (i - 1) * 6 + 4 ] = this->stream_ids[i] ; - this->scmd_body [ (i - 1) * 6 + 5 ] = this->stream_ids[i] >> 8; - if ((this->stream_ids[i] == audio_stream) || - (this->stream_ids[i] == video_stream)) { - this->scmd_body [ (i - 1) * 6 + 6 ] = 0x00; - this->scmd_body [ (i - 1) * 6 + 7 ] = 0x00; - } else { - lprintf("disabling stream %d\n", this->stream_ids[i]); - this->scmd_body [ (i - 1) * 6 + 6 ] = 0x02; - this->scmd_body [ (i - 1) * 6 + 7 ] = 0x00; - - /* forces the asf demuxer to not choose this stream */ - if (this->bitrates_pos[this->stream_ids[i]]) { - this->asf_header[this->bitrates_pos[this->stream_ids[i]]] = 0; - this->asf_header[this->bitrates_pos[this->stream_ids[i]] + 1] = 0; - this->asf_header[this->bitrates_pos[this->stream_ids[i]] + 2] = 0; - this->asf_header[this->bitrates_pos[this->stream_ids[i]] + 3] = 0; - } - } - } - - if (!send_command (io, this, 0x33, this->num_stream_ids, - 0xFFFF | this->stream_ids[0] << 16, - this->num_stream_ids * 6 + 2)) { - /* FIXME: de-xine-ification */ - lprintf ( "***LOG:*** -- " - "libmms: mms_choose_best_streams failed\n"); - return 0; - } - - if ((res = get_answer (io, this)) != 0x21) { - /* FIXME: de-xine-ification */ - lprintf ( "***LOG:*** -- " - "libmms: unexpected response: %02x (0x21)\n", res); - } - - return 1; -} - -/* - * TODO: error messages - * network timing request - */ -/* FIXME: got somewhat broken during xine_stream_t->(void*) conversion */ -mms_t *mms_connect (mms_io_t *io, void *data, const char *url, int bandwidth) { - int url_conv = 0; - mms_t *this; - int res; - GURI *uri; - - if (!url) - return NULL; - - /* FIXME: needs proper error-signalling work */ - this = (mms_t*) malloc (sizeof (mms_t)); - - this->custom_data = data; - this->url = strdup (url); - this->s = -1; - this->seq_num = 0; - this->scmd_body = this->scmd + CMD_HEADER_LEN + CMD_PREFIX_LEN; - this->asf_header_len = 0; - this->asf_header_read = 0; - this->num_stream_ids = 0; - this->asf_packet_len = 0; - this->start_packet_seq= 0; - this->need_discont = 1; - this->buf_size = 0; - this->buf_read = 0; - this->has_audio = 0; - this->has_video = 0; - this->bandwidth = bandwidth; - this->current_pos = 0; - this->eos = 0; - - /* FIXME de-xine-ification */ -/* report_progress (stream, 0); */ - - uri = gnet_uri_new(this->url); - if(!uri) { - lprintf ("invalid url\n"); - goto fail; - } - this->proto = uri->scheme; - this->user = uri->user; - this->host = uri->hostname; - this->port = uri->port; - this->password = uri->passwd; - this->uri = uri->path; - - if (!mmst_valid_proto(this->proto)) { - lprintf ("unsupported protocol\n"); - goto fail; - } - - if (mms_tcp_connect(io, this)) { - goto fail; - } - /* FIXME de-xine-ification */ -/* report_progress (stream, 30); */ - - /* - * let the negotiations begin... - */ - - /* command 0x1 */ - lprintf("send command 0x01\n"); - mms_gen_guid(this->guid); - sprintf (this->str, "\x1c\x03NSPlayer/7.0.0.1956; {%s}; Host: %s", - this->guid, this->host); - string_utf16 (url_conv, this->scmd_body, this->str, strlen(this->str) + 2); - - if (!send_command (io, this, 1, 0, 0x0004000b, strlen(this->str) * 2 + 8)) { - /* FIXME: de-xine-ification */ - lprintf( "***LOG:*** -- " - "libmms: failed to send command 0x01\n"); - goto fail; - } - - if ((res = get_answer (io, this)) != 0x01) { - /* FIXME: de-xine-ification */ - lprintf ( "***LOG:*** -- " - "libmms: unexpected response: %02x (0x01)\n", res); - lprintf("answer: %d\n", res); - goto fail; - } - - /* FIXME de-xine-ification */ -/* report_progress (stream, 40); */ - - /* TODO: insert network timing request here */ - /* command 0x2 */ - lprintf("send command 0x02\n"); - string_utf16 (url_conv, &this->scmd_body[8], "\002\000\\\\192.168.0.129\\TCP\\1037\0000", 28); - memset (this->scmd_body, 0, 8); - if (!send_command (io, this, 2, 0, 0, 28 * 2 + 8)) { - /* FIXME: de-xine-ification */ - lprintf( "***LOG:*** -- " - "libmms: failed to send command 0x02\n"); - - goto fail; - } - - switch (res = get_answer (io, this)) { - case 0x02: - /* protocol accepted */ - break; - case 0x03: - /* FIXME: de-xine-ification */ - lprintf( "***LOG:*** -- " - "libmms: protocol failed\n"); - goto fail; - break; - default: - lprintf("unexpected response: %02x (0x02 or 0x03)\n", res); - goto fail; - } - - /* FIXME de-xine-ification */ -/* report_progress (stream, 50); */ - - /* command 0x5 */ - { - mms_buffer_t command_buffer; - - lprintf("send command 0x05\n"); - mms_buffer_init(&command_buffer, this->scmd_body); - mms_buffer_put_32 (&command_buffer, 0x00000000); /* ?? */ - mms_buffer_put_32 (&command_buffer, 0x00000000); /* ?? */ - string_utf16 (url_conv, this->scmd_body + command_buffer.pos, this->uri, strlen(this->uri)); - if (!send_command (io, this, 5, 1, 0xffffffff, strlen(this->uri) * 2 + 12)) - goto fail; - } - - switch (res = get_answer (io, this)) { - case 0x06: - { - int xx, yy; - /* no authentication required */ - - /* Warning: sdp is not right here */ - xx = this->buf[62]; - yy = this->buf[63]; - this->live_flag = ((xx == 0) && ((yy & 0xf) == 2)); - lprintf("live: live_flag=%d, xx=%d, yy=%d\n", this->live_flag, xx, yy); - } - break; - case 0x1A: - /* authentication request, not yet supported */ - /* FIXME: de-xine-ification */ - lprintf ( "***LOG:*** -- " - "libmms: authentication request, not yet supported\n"); - goto fail; - break; - default: - /* FIXME: de-xine-ification */ - lprintf ( "***LOG:*** -- " - "libmms: unexpected response: %02x (0x06 or 0x1A)\n", res); - goto fail; - } - - /* FIXME de-xine-ification */ -/* report_progress (stream, 60); */ - - /* command 0x15 */ - lprintf("send command 0x15\n"); - { - mms_buffer_t command_buffer; - mms_buffer_init(&command_buffer, this->scmd_body); - mms_buffer_put_32 (&command_buffer, 0x00000000); /* ?? */ - mms_buffer_put_32 (&command_buffer, 0x00800000); /* ?? */ - mms_buffer_put_32 (&command_buffer, 0xFFFFFFFF); /* ?? */ - mms_buffer_put_32 (&command_buffer, 0x00000000); /* ?? */ - mms_buffer_put_32 (&command_buffer, 0x00000000); /* ?? */ - mms_buffer_put_32 (&command_buffer, 0x00000000); /* ?? */ - mms_buffer_put_32 (&command_buffer, 0x00000000); /* ?? */ - mms_buffer_put_32 (&command_buffer, 0x40AC2000); /* ?? */ - mms_buffer_put_32 (&command_buffer, ASF_HEADER_PACKET_ID_TYPE); /* Header Packet ID type */ - mms_buffer_put_32 (&command_buffer, 0x00000000); /* ?? */ - if (!send_command (io, this, 0x15, 1, 0, command_buffer.pos)) { - /* FIXME: de-xine-ification */ - lprintf ( "***LOG:*** -- " - "libmms: failed to send command 0x15\n"); - goto fail; - } - } - - if ((res = get_answer (io, this)) != 0x11) { - /* FIXME: de-xine-ification */ - lprintf ( "***LOG:*** -- " - "libmms: unexpected response: %02x (0x11)\n", res); - goto fail; - } - - this->num_stream_ids = 0; - - if (!get_asf_header (io, this)) - goto fail; - - interp_asf_header (this); - - /* FIXME de-xine-ification */ -/* report_progress (stream, 70); */ - - if (!mms_choose_best_streams(io, this)) { - /* FIXME: de-xine-ification */ - lprintf ( "***LOG:*** -- " - "libmms: mms_choose_best_streams failed"); - goto fail; - } - - /* FIXME de-xine-ification */ -/* report_progress (stream, 80); */ - - /* command 0x07 */ - { - mms_buffer_t command_buffer; - mms_buffer_init(&command_buffer, this->scmd_body); - mms_buffer_put_32 (&command_buffer, 0x00000000); /* 64 byte float timestamp */ - mms_buffer_put_32 (&command_buffer, 0x00000000); - mms_buffer_put_32 (&command_buffer, 0xFFFFFFFF); /* ?? */ - mms_buffer_put_32 (&command_buffer, 0xFFFFFFFF); /* first packet sequence */ - mms_buffer_put_8 (&command_buffer, 0xFF); /* max stream time limit (3 bytes) */ - mms_buffer_put_8 (&command_buffer, 0xFF); - mms_buffer_put_8 (&command_buffer, 0xFF); - mms_buffer_put_8 (&command_buffer, 0x00); /* stream time limit flag */ - mms_buffer_put_32 (&command_buffer, ASF_MEDIA_PACKET_ID_TYPE); /* asf media packet id type */ - if (!send_command (io, this, 0x07, 1, 0x0001FFFF, command_buffer.pos)) { - /* FIXME: de-xine-ification */ - lprintf ( "***LOG:*** -- " - "libmms: failed to send command 0x07\n"); - goto fail; - } - } - -/* report_progress (stream, 100); */ - - lprintf("mms_connect: passed\n" ); - - return this; - -fail: - if (this->s != -1) - close (this->s); - if (this->url) - free(this->url); - if (this->proto) - free(this->proto); - if (this->host) - free(this->host); - if (this->user) - free(this->user); - if (this->password) - free(this->password); - if (this->uri) - free(this->uri); - - free (this); - return NULL; -} - -static int get_media_packet (mms_io_t *io, mms_t *this) { - mms_packet_header_t header; - off_t len; - - switch (get_packet_header (io, this, &header)) { - case MMS_PACKET_ERR: - /* FIXME: de-xine-ification */ - lprintf( "***LOG:*** -- " - "libmms: failed to read mms packet header\n"); - return 0; - break; - - case MMS_PACKET_COMMAND: - { - int command; - command = get_packet_command (io, this, header.packet_len); - - switch (command) { - case 0x1e: - { - uint32_t error_code; - - /* Warning: sdp is incomplete. Do not stop if error_code==1 */ - error_code = LE_32(this->buf + CMD_HEADER_LEN); - lprintf ("End of the current stream. Continue=%d\n", error_code); - - if (error_code == 0) { - this->eos = 1; - return 0; - } - - } - break; - - case 0x20: - { - lprintf ("new stream.\n"); - /* asf header */ - if (!get_asf_header (io, this)) { - /* FIXME: de-xine-ification */ - lprintf ( "***LOG:*** -- " - "failed to read new ASF header\n"); - return 0; - } - - interp_asf_header (this); - - if (!mms_choose_best_streams(io, this)) - return 0; - - /* send command 0x07 */ - /* TODO: ugly */ - /* command 0x07 */ - { - mms_buffer_t command_buffer; - mms_buffer_init(&command_buffer, this->scmd_body); - mms_buffer_put_32 (&command_buffer, 0x00000000); /* 64 byte float timestamp */ - mms_buffer_put_32 (&command_buffer, 0x00000000); - mms_buffer_put_32 (&command_buffer, 0xFFFFFFFF); /* ?? */ - mms_buffer_put_32 (&command_buffer, 0xFFFFFFFF); /* first packet sequence */ - mms_buffer_put_8 (&command_buffer, 0xFF); /* max stream time limit (3 bytes) */ - mms_buffer_put_8 (&command_buffer, 0xFF); - mms_buffer_put_8 (&command_buffer, 0xFF); - mms_buffer_put_8 (&command_buffer, 0x00); /* stream time limit flag */ - mms_buffer_put_32 (&command_buffer, ASF_MEDIA_PACKET_ID_TYPE); /* asf media packet id type */ - if (!send_command (io, this, 0x07, 1, 0x0001FFFF, command_buffer.pos)) { - /* FIXME: de-xine-ification */ - lprintf ( "***LOG:*** -- " - "libmms: failed to send command 0x07\n"); - return 0; - } - } - this->current_pos = 0; - } - break; - - case 0x1b: - { - if (!send_command (io, this, 0x1b, 0, 0, 0)) { - /* FIXME: de-xine-ification */ - lprintf( "***LOG:*** -- " - "libmms: failed to send command\n"); - return 0; - } - } - break; - - case 0x05: - break; - - default: - /* FIXME: de-xine-ification */ - lprintf ( "***LOG:*** -- " - "unexpected mms command %02x\n", command); - } - this->buf_size = 0; - } - break; - - case MMS_PACKET_ASF_HEADER: - /* FIXME: de-xine-ification */ - lprintf( "***LOG:*** -- " - "libmms: unexpected asf header packet\n"); - this->buf_size = 0; - break; - - case MMS_PACKET_ASF_PACKET: - { - /* media packet */ - - /* FIXME: probably needs some more sophisticated logic, but - until we do seeking, this should work */ - if(this->need_discont) - { - this->need_discont = 0; - this->start_packet_seq = header.packet_seq; - } - - lprintf ("asf media packet detected, packet_len=%d, packet_seq=%d\n", - header.packet_len, header.packet_seq); - if (header.packet_len > this->asf_packet_len) { - /* FIXME: de-xine-ification */ - lprintf ( "***LOG:*** -- " - "libmms: invalid asf packet len: %d bytes\n", header.packet_len); - return 0; - } - - /* simulate a seek */ - this->current_pos = (off_t)this->asf_header_len + - ((off_t)header.packet_seq - this->start_packet_seq) * (off_t)this->asf_packet_len; - - len = io_read(io, this->s, this->buf, header.packet_len); - if (len != header.packet_len) { - /* FIXME: de-xine-ification */ - lprintf ( "***LOG:*** -- " - "libmms: read failed\n"); - return 0; - } - - /* explicit padding with 0 */ - lprintf("padding: %d bytes\n", this->asf_packet_len - header.packet_len); - { - char *base = (char *)(this->buf); - char *start = base + header.packet_len; - char *end = start + this->asf_packet_len - header.packet_len; - if ((start > base) && (start < (base+BUF_SIZE-1)) && - (start < end) && (end < (base+BUF_SIZE-1))) { - memset(this->buf + header.packet_len, 0, this->asf_packet_len - header.packet_len); - } - if (this->asf_packet_len > BUF_SIZE) { - this->buf_size = BUF_SIZE; - } else { - this->buf_size = this->asf_packet_len; - } - } - } - break; - } - - lprintf ("get media packet succ\n"); - - return 1; -} - - -int mms_peek_header (mms_t *this, char *data, int maxsize) { - - int len; - - len = (this->asf_header_len < maxsize) ? this->asf_header_len : maxsize; - - memcpy(data, this->asf_header, len); - return len; -} - -int mms_read (mms_io_t *io, mms_t *this, char *data, int len) { - int total; - - total = 0; - while (total < len && !this->eos) { - - if (this->asf_header_read < this->asf_header_len) { - int n, bytes_left; - - bytes_left = this->asf_header_len - this->asf_header_read ; - - if ((len - total) < bytes_left) - n = len-total; - else - n = bytes_left; - - memcpy (&data[total], &this->asf_header[this->asf_header_read], n); - - this->asf_header_read += n; - total += n; - this->current_pos += n; - } else { - - int n, bytes_left; - - bytes_left = this->buf_size - this->buf_read; - if (bytes_left == 0) { - this->buf_size = this->buf_read = 0; - if (!get_media_packet (io, this)) { - /* FIXME: de-xine-ification */ - lprintf ( "***LOG:*** -- " - "libmms: get_media_packet failed\n"); - return total; - } - bytes_left = this->buf_size; - } - - if ((len - total) < bytes_left) - n = len - total; - else - n = bytes_left; - - memcpy (&data[total], &this->buf[this->buf_read], n); - - this->buf_read += n; - total += n; - this->current_pos += n; - } - } - return total; -} - - -void mms_close (mms_t *this) { - - if (this->s != -1) - close (this->s); - if (this->url) - free(this->url); - if (this->proto) - free(this->proto); - if (this->host) - free(this->host); - if (this->user) - free(this->user); - if (this->password) - free(this->password); - if (this->uri) - free(this->uri); - - free (this); -} - -uint32_t mms_get_length (mms_t *this) { - return this->file_len; -} - -off_t mms_get_current_pos (mms_t *this) { - return this->current_pos; -}
--- a/src/wma/libffwma/mms.h Sun Jan 21 21:01:41 2007 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2002-2003 the xine project - * - * This file is part of xine, a free video player. - * - * xine is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * xine is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - * - * $Id: mms.h,v 1.11 2006/06/06 09:49:15 shawarma Exp $ - * - * libmms public header - */ - -/* TODO/dexineification: - * + functions needed: - * - _x_io_*() - * - xine_malloc() [?] - * - xine_fast_memcpy() [?] - */ - -#ifndef HAVE_MMS_H -#define HAVE_MMS_H - -#include <inttypes.h> -#include <stdio.h> -#include <sys/types.h> - -/* #include "xine_internal.h" */ - -#include "bswap.h" -#include "mmsio.h" - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -typedef struct mms_s mms_t; - -mms_t* mms_connect (mms_io_t *io, void *data, const char *url, int bandwidth); - -int mms_read (mms_io_t *io, mms_t *instance, char *data, int len); -uint32_t mms_get_length (mms_t *instance); -void mms_close (mms_t *instance); - -int mms_peek_header (mms_t *instance, char *data, int maxsize); - -off_t mms_get_current_pos (mms_t *instance); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif -
--- a/src/wma/libffwma/mmsh.c Sun Jan 21 21:01:41 2007 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1274 +0,0 @@ -/* - * Copyright (C) 2002-2003 the xine project - * - * This file is part of xine, a free video player. - * - * xine is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * xine is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - * - * $Id: mmsh.c,v 1.5 2006/07/13 12:32:20 shawarma Exp $ - * - * MMS over HTTP protocol - * written by Thibaut Mattern - * based on mms.c and specs from avifile - * (http://avifile.sourceforge.net/asf-1.0.htm) - * - * TODO: - * error messages - * http support cleanup, find a way to share code with input_http.c (http.h|c) - * http proxy support - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <netdb.h> -#include <string.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <errno.h> -#include <stdlib.h> -#include <time.h> -#include <assert.h> - -#define LOG_MODULE "mmsh" -#define LOG_VERBOSE -#ifdef DEBUG -# define lprintf printf -#else -# define lprintf(x...) -#endif - -#include "bswap.h" -#include "mmsh.h" -#include "asfheader.h" -#include "uri.h" - -/* #define USERAGENT "User-Agent: NSPlayer/7.1.0.3055\r\n" */ -#define USERAGENT "User-Agent: NSPlayer/4.1.0.3856\r\n" -#define CLIENTGUID "Pragma: xClientGUID={c77e7400-738a-11d2-9add-0020af0a3278}\r\n" - - -#define MMSH_PORT 80 -#define MMSH_UNKNOWN 0 -#define MMSH_SEEKABLE 1 -#define MMSH_LIVE 2 - -#define CHUNK_HEADER_LENGTH 4 -#define EXT_HEADER_LENGTH 8 -#define CHUNK_TYPE_RESET 0x4324 -#define CHUNK_TYPE_DATA 0x4424 -#define CHUNK_TYPE_END 0x4524 -#define CHUNK_TYPE_ASF_HEADER 0x4824 -#define CHUNK_SIZE 65536 /* max chunk size */ -#define ASF_HEADER_SIZE 8192 /* max header size */ - -#define SCRATCH_SIZE 1024 - -static const char* mmsh_FirstRequest = - "GET %s HTTP/1.0\r\n" - "Accept: */*\r\n" - USERAGENT - "Host: %s:%d\r\n" - "Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=0:0,request-context=%u,max-duration=0\r\n" - CLIENTGUID - "Connection: Close\r\n\r\n"; - -static const char* mmsh_SeekableRequest = - "GET %s HTTP/1.0\r\n" - "Accept: */*\r\n" - USERAGENT - "Host: %s:%d\r\n" - "Pragma: no-cache,rate=1.000000,stream-time=%u,stream-offset=%u:%u,request-context=%u,max-duration=%u\r\n" - CLIENTGUID - "Pragma: xPlayStrm=1\r\n" - "Pragma: stream-switch-count=%d\r\n" - "Pragma: stream-switch-entry=%s\r\n" /* ffff:1:0 ffff:2:0 */ - "Connection: Close\r\n\r\n"; - -static const char* mmsh_LiveRequest = - "GET %s HTTP/1.0\r\n" - "Accept: */*\r\n" - USERAGENT - "Host: %s:%d\r\n" - "Pragma: no-cache,rate=1.000000,request-context=%u\r\n" - "Pragma: xPlayStrm=1\r\n" - CLIENTGUID - "Pragma: stream-switch-count=%d\r\n" - "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" - "Accept: */*\r\n" - 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: Content-Length: 0\r\n" - CLIENTGUID - "\r\n"; - -static const char* mmsh_RangeRequest = - "GET %s HTTP/1.0\r\n" - "Accept: */*\r\n" - USERAGENT - "Host: %s:%d\r\n" - "Range: bytes=%Lu-\r\n" - CLIENTGUID - "Connection: Close\r\n\r\n"; -#endif - - - -/* - * mmsh specific types - */ - - -struct mmsh_s { - - /* FIXME: de-xine-ification */ - void *custom_data; - - int s; - - /* url parsing */ - char *url; - char *proxy_url; - char *proto; - char *connect_host; - int connect_port; - char *http_host; - int http_port; - char *proxy_user; - char *proxy_password; - char *host_user; - char *host_password; - char *uri; - - char str[SCRATCH_SIZE]; /* scratch buffer to built strings */ - - int stream_type; /* seekable or broadcast */ - - /* receive buffer */ - - /* chunk */ - uint16_t chunk_type; - uint16_t chunk_length; - uint16_t chunk_seq_number; - uint8_t buf[CHUNK_SIZE]; - - int buf_size; - int buf_read; - - uint8_t asf_header[ASF_HEADER_SIZE]; - uint32_t asf_header_len; - uint32_t asf_header_read; - int seq_num; - int num_stream_ids; - int stream_ids[ASF_MAX_NUM_STREAMS]; - int stream_types[ASF_MAX_NUM_STREAMS]; - uint32_t packet_length; - int64_t file_length; - char guid[37]; - uint32_t bitrates[ASF_MAX_NUM_STREAMS]; - uint32_t bitrates_pos[ASF_MAX_NUM_STREAMS]; - - int has_audio; - int has_video; - - off_t current_pos; - int user_bandwidth; -}; - -static int fallback_io_select(void *data, int socket, int state, int timeout_msec) -{ - fd_set set; - struct timeval tv = { timeout_msec / 1000, (timeout_msec % 1000) * 1000}; - FD_ZERO(&set); - FD_SET(socket, &set); - return select(1, (state == MMS_IO_READ_READY) ? &set : NULL, - (state == MMS_IO_WRITE_READY) ? &set : NULL, NULL, &tv); -} - -static off_t fallback_io_read(void *data, int socket, char *buf, off_t num) -{ - off_t len = 0, ret; -/* lprintf("%d\n", fallback_io_select(data, socket, MMS_IO_READ_READY, 1000)); */ - errno = 0; - while (len < num) - { - ret = (off_t)read(socket, buf + len, num - len); - if(ret == 0) - break; /* EOF */ - if(ret < 0) - switch(errno) - { - case EAGAIN: - lprintf("len == %lld\n", (long long int) len); - break; - default: - lprintf("len == %lld\n", (long long int) len); - perror(NULL); - /* if already read something, return it, we will fail next time */ - return len ? len : ret; - } - len += ret; - } - lprintf("ret len == %lld\nnum == %lld\n", (long long int) len, (long long int) num); - lprintf("read\n"); - return len; -} - -static off_t fallback_io_write(void *data, int socket, char *buf, off_t num) -{ - return (off_t)write(socket, buf, num); -} - -static int fallback_io_tcp_connect(void *data, const char *host, int port) -{ - - struct hostent *h; - int i, s; - - h = gethostbyname(host); - if (h == NULL) { -/* fprintf(stderr, "unable to resolve host: %s\n", host); */ - return -1; - } - - s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); - if (s == -1) { -/* fprintf(stderr, "failed to create socket: %s", strerror(errno)); */ - return -1; - } - - if (fcntl (s, F_SETFL, fcntl (s, F_GETFL) & ~O_NONBLOCK) == -1) { -/* _x_message(stream, XINE_MSG_CONNECTION_REFUSED, "can't put socket in non-blocking mode", strerror(errno), NULL); */ - return -1; - } - - for (i = 0; h->h_addr_list[i]; i++) { - struct in_addr ia; - struct sockaddr_in sin; - - memcpy (&ia, h->h_addr_list[i], 4); - sin.sin_family = AF_INET; - sin.sin_addr = ia; - sin.sin_port = htons(port); - - if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) ==-1 && errno != EINPROGRESS) { - - /* FIXME: de-xine-ification */ -/* _x_message(stream, XINE_MSG_CONNECTION_REFUSED, strerror(errno), NULL); */ - close(s); - continue; - } - - return s; - } - return -1; -} - - -static mms_io_t fallback_io = - { - &fallback_io_select, - NULL, - &fallback_io_read, - NULL, - &fallback_io_write, - NULL, - &fallback_io_tcp_connect, - NULL, - }; - -static mms_io_t default_io = { - &fallback_io_select, - NULL, - &fallback_io_read, - NULL, - &fallback_io_write, - NULL, - &fallback_io_tcp_connect, - NULL, - }; - - -#define io_read(io, args...) ((io) ? (io)->read(io->read_data , ## args) : default_io.read(NULL , ## args)) -#define io_write(io, args...) ((io) ? (io)->write(io->write_data , ## args) : default_io.write(NULL , ## args)) -#define io_select(io, args...) ((io) ? (io)->select(io->select_data , ## args) : default_io.select(NULL , ## args)) -#define io_connect(io, args...) ((io) ? (io)->connect(io->connect_data , ## args) : default_io.connect(NULL , ## args)) - -static int get_guid (unsigned char *buffer, int offset) { - int i; - GUID g; - - g.Data1 = LE_32(buffer + offset); - g.Data2 = LE_16(buffer + offset + 4); - g.Data3 = LE_16(buffer + offset + 6); - for(i = 0; i < 8; i++) { - g.Data4[i] = buffer[offset + 8 + i]; - } - - for (i = 1; i < GUID_END; i++) { - if (!memcmp(&g, &guids[i].guid, sizeof(GUID))) { - lprintf ("GUID: %s\n", guids[i].name); - - return i; - } - } - - lprintf ("libmmsh: unknown GUID: 0x%x, 0x%x, 0x%x, " - "{ 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx }\n", - g.Data1, g.Data2, g.Data3, - g.Data4[0], g.Data4[1], g.Data4[2], g.Data4[3], - g.Data4[4], g.Data4[5], g.Data4[6], g.Data4[7]); - return GUID_ERROR; -} - -static int send_command (mms_io_t *io, mmsh_t *this, char *cmd) { - int length; - - lprintf ("send_command:\n%s\n", cmd); - - length = strlen(cmd); - if (io_write(io, this->s, cmd, length) != length) { - lprintf ("mmsh: send error.\n"); - return 0; - } - return 1; -} - -static int get_answer (mms_io_t *io, mmsh_t *this) { - - int done, len, linenum; - char *features; - - lprintf ("get_answer\n"); - - done = 0; len = 0; linenum = 0; - this->stream_type = MMSH_UNKNOWN; - - while (!done) { - - if (io_read(io, this->s, &(this->buf[len]), 1) != 1) { - lprintf ("mmsh: alart: end of stream\n"); - return 0; - } - - if (this->buf[len] == '\012') { - - this->buf[len] = '\0'; - len--; - - if ((len >= 0) && (this->buf[len] == '\015')) { - this->buf[len] = '\0'; - len--; - } - - linenum++; - - lprintf ("answer: >%s<\n", this->buf); - - if (linenum == 1) { - int httpver, httpsub, httpcode; - char httpstatus[51]; - - if (sscanf(this->buf, "HTTP/%d.%d %d %50[^\015\012]", &httpver, &httpsub, - &httpcode, httpstatus) != 4) { - lprintf ("mmsh: bad response format\n"); - return 0; - } - - if (httpcode >= 300 && httpcode < 400) { - lprintf ("mmsh: 3xx redirection not implemented: >%d %s<\n", httpcode, httpstatus); - return 0; - } - - if (httpcode < 200 || httpcode >= 300) { - lprintf ("mmsh: http status not 2xx: >%d %s<\n", httpcode, httpstatus); - return 0; - } - } else { - - if (!strncasecmp(this->buf, "Location: ", 10)) { - lprintf ("mmsh: Location redirection not implemented.\n"); - return 0; - } - - if (!strncasecmp(this->buf, "Pragma:", 7)) { - features = strstr(this->buf + 7, "features="); - if (features) { - if (strstr(features, "seekable")) { - lprintf("seekable stream\n"); - this->stream_type = MMSH_SEEKABLE; - } else { - if (strstr(features, "broadcast")) { - lprintf("live stream\n"); - this->stream_type = MMSH_LIVE; - } - } - } - } - } - - if (len == -1) { - done = 1; - } else { - len = 0; - } - } else { - len ++; - } - } - if (this->stream_type == MMSH_UNKNOWN) { - lprintf ("mmsh: unknown stream type\n"); - this->stream_type = MMSH_SEEKABLE; /* FIXME ? */ - } - return 1; -} - -static int get_chunk_header (mms_io_t *io, mmsh_t *this) { - uint8_t chunk_header[CHUNK_HEADER_LENGTH]; - uint8_t ext_header[EXT_HEADER_LENGTH]; - int read_len; - int ext_header_len; - - lprintf ("get_chunk_header\n"); - - /* read chunk header */ - read_len = io_read(io, this->s, chunk_header, CHUNK_HEADER_LENGTH); - if (read_len != CHUNK_HEADER_LENGTH) { - lprintf ("chunk header read failed, %d != %d\n", len, CHUNK_HEADER_LENGTH); - return 0; - } - this->chunk_type = LE_16 (&chunk_header[0]); - this->chunk_length = LE_16 (&chunk_header[2]); - - switch (this->chunk_type) { - case CHUNK_TYPE_DATA: - ext_header_len = 8; - break; - case CHUNK_TYPE_END: - ext_header_len = 4; - break; - case CHUNK_TYPE_ASF_HEADER: - ext_header_len = 8; - break; - case CHUNK_TYPE_RESET: - ext_header_len = 4; - break; - default: - ext_header_len = 0; - } - /* read extended header */ - if (ext_header_len > 0) { - read_len = io_read (io, this->s, ext_header, ext_header_len); - if (read_len != ext_header_len) { - lprintf ("extended header read failed. %d != %d\n", read_len, ext_header_len); - return 0; - } - } - /* display debug infos */ -#ifdef DEBUG - switch (this->chunk_type) { - case CHUNK_TYPE_DATA: - this->chunk_seq_number = LE_32 (&ext_header[0]); - lprintf ("chunk type: CHUNK_TYPE_DATA\n"); - lprintf ("chunk length: %d\n", this->chunk_length); - lprintf ("chunk seq: %d\n", this->chunk_seq_number); - lprintf ("unknown: %d\n", ext_header[4]); - lprintf ("mmsh seq: %d\n", ext_header[5]); - lprintf ("len2: %d\n", LE_16(&ext_header[6])); - break; - case CHUNK_TYPE_END: - this->chunk_seq_number = LE_32 (&ext_header[0]); - lprintf ("chunk type: CHUNK_TYPE_END\n"); - lprintf ("continue: %d\n", this->chunk_seq_number); - break; - case CHUNK_TYPE_ASF_HEADER: - lprintf ("chunk type: CHUNK_TYPE_ASF_HEADER\n"); - lprintf ("chunk length: %d\n", this->chunk_length); - lprintf ("unknown: %2X %2X %2X %2X %2X %2X\n", - ext_header[0], ext_header[1], ext_header[2], ext_header[3], - ext_header[4], ext_header[5]); - lprintf ("len2: %d\n", LE_16(&ext_header[6])); - break; - case CHUNK_TYPE_RESET: - lprintf ("chunk type: CHUNK_TYPE_RESET\n"); - lprintf ("chunk seq: %d\n", this->chunk_seq_number); - lprintf ("unknown: %2X %2X %2X %2X\n", - ext_header[0], ext_header[1], ext_header[2], ext_header[3]); - break; - default: - lprintf ("unknown chunk: %4X\n", this->chunk_type); - } -#endif - - this->chunk_length -= ext_header_len; - return 1; -} - -static int get_header (mms_io_t *io, mmsh_t *this) { - int len = 0; - - lprintf("get_header\n"); - - this->asf_header_len = 0; - this->asf_header_read = 0; - - /* read chunk */ - while (1) { - if (get_chunk_header(io, this)) { - if (this->chunk_type == CHUNK_TYPE_ASF_HEADER) { - if ((this->asf_header_len + this->chunk_length) > ASF_HEADER_SIZE) { - lprintf ("mmsh: the asf header exceed %d bytes\n", ASF_HEADER_SIZE); - return 0; - } else { - len = io_read(io, this->s, this->asf_header + this->asf_header_len, - this->chunk_length); - this->asf_header_len += len; - if (len != this->chunk_length) { - return 0; - } - } - } else { - break; - } - } else { - lprintf("get_chunk_header failed\n"); - return 0; - } - } - - if (this->chunk_type == CHUNK_TYPE_DATA) { - /* read the first data chunk */ - len = io_read (io, this->s, this->buf, this->chunk_length); - - if (len != this->chunk_length) { - return 0; - } else { - return 1; - } - } else { - /* unexpected packet type */ - return 0; - } -} - -static void interp_header (mms_io_t *io, mmsh_t *this) { - - int i; - - lprintf ("interp_header, header_len=%d\n", this->asf_header_len); - - this->packet_length = 0; - - /* - * parse asf header - */ - - i = 30; - while ((i + 24) < this->asf_header_len) { - - int guid; - uint64_t length; - - guid = get_guid(this->asf_header, i); - i += 16; - - length = LE_64(this->asf_header + i); - i += 8; - - if ((i + length) >= this->asf_header_len) return; - - switch (guid) { - - case GUID_ASF_FILE_PROPERTIES: - - this->packet_length = LE_32(this->asf_header + i + 92 - 24); - if (this->packet_length > CHUNK_SIZE) { - this->packet_length = 0; - break; - } - this->file_length = LE_64(this->asf_header + i + 40 - 24); - lprintf ("file object, packet length = %d (%d)\n", - this->packet_length, LE_32(this->asf_header + i + 96 - 24)); - break; - - case GUID_ASF_STREAM_PROPERTIES: - { - uint16_t flags; - uint16_t stream_id; - int type; - int encrypted; - - guid = get_guid(this->asf_header, i); - switch (guid) { - case GUID_ASF_AUDIO_MEDIA: - type = ASF_STREAM_TYPE_AUDIO; - this->has_audio = 1; - break; - - case GUID_ASF_VIDEO_MEDIA: - case GUID_ASF_JFIF_MEDIA: - case GUID_ASF_DEGRADABLE_JPEG_MEDIA: - type = ASF_STREAM_TYPE_VIDEO; - this->has_video = 1; - break; - - case GUID_ASF_COMMAND_MEDIA: - type = ASF_STREAM_TYPE_CONTROL; - break; - - default: - type = ASF_STREAM_TYPE_UNKNOWN; - } - - flags = LE_16(this->asf_header + i + 48); - stream_id = flags & 0x7F; - encrypted = flags >> 15; - - lprintf ("stream object, stream id: %d, type: %d, encrypted: %d\n", - stream_id, type, encrypted); - - this->stream_types[stream_id] = type; - this->stream_ids[this->num_stream_ids] = stream_id; - this->num_stream_ids++; - - } - break; - - case GUID_ASF_STREAM_BITRATE_PROPERTIES: - { - uint16_t streams = LE_16(this->asf_header + i); - uint16_t stream_id; - int j; - - lprintf ("stream bitrate properties\n"); - lprintf ("streams %d\n", streams); - - for(j = 0; j < streams; j++) { - stream_id = LE_16(this->asf_header + i + 2 + j * 6); - - lprintf ("stream id %d\n", stream_id); - - this->bitrates[stream_id] = LE_32(this->asf_header + i + 4 + j * 6); - this->bitrates_pos[stream_id] = i + 4 + j * 6; - lprintf ("mmsh: stream id %d, bitrate %d\n", stream_id, this->bitrates[stream_id]); - } - } - break; - - default: - lprintf ("unknown object\n"); - break; - } - - lprintf ("length : %lld\n", length); - - if (length > 24) { - i += length - 24; - } - } -} - -const static char *const mmsh_proto_s[] = { "mms", "mmsh", NULL }; - -static int mmsh_valid_proto (char *proto) { - int i = 0; - - lprintf("mmsh_valid_proto\n"); - - if (!proto) - return 0; - - while(mmsh_proto_s[i]) { - if (!strcasecmp(proto, mmsh_proto_s[i])) { - return 1; - } - i++; - } - return 0; -} - -/* - * returns 1 on error - */ -static int mmsh_tcp_connect(mms_io_t *io, mmsh_t *this) { - int progress, res; - - if (!this->connect_port) this->connect_port = MMSH_PORT; - - /* - * try to connect - */ - lprintf("try to connect to %s on port %d \n", this->connect_host, this->connect_port); - - this->s = io_connect (io, this->connect_host, this->connect_port); - - if (this->s == -1) { - lprintf ("mmsh: failed to connect '%s'\n", this->connect_host); - return 1; - } - - /* connection timeout 15s */ - progress = 0; - do { -// report_progress(this->stream, progress); - res = io_select (io, this->s, MMS_IO_WRITE_READY, 500); - progress += 1; - } while ((res == MMS_IO_STATUS_TIMEOUT) && (progress < 30)); - if (res != MMS_IO_STATUS_READY) { - return 1; - } - lprintf ("connected\n"); - - return 0; -} - -static int mmsh_connect_int (mms_io_t *io, mmsh_t *this, int bandwidth) { - int i; - int video_stream = -1; - int audio_stream = -1; - int max_arate = -1; - int min_vrate = -1; - int min_bw_left = 0; - int stream_id; - int bandwitdh_left; - char stream_selection[10 * ASF_MAX_NUM_STREAMS]; /* 10 chars per stream */ - int offset; - - /* - * let the negotiations begin... - */ - this->num_stream_ids = 0; - - /* first request */ - lprintf("first http request\n"); - - snprintf (this->str, SCRATCH_SIZE, mmsh_FirstRequest, this->uri, - this->http_host, this->http_port, 1); - - if (!send_command (io, this, this->str)) - goto fail; - - if (!get_answer (io, this)) - goto fail; - - - get_header(io, this); - interp_header(io, this); - - close(this->s); -// report_progress (stream, 20); - - - /* choose the best quality for the audio stream */ - /* i've never seen more than one audio stream */ - for (i = 0; i < this->num_stream_ids; i++) { - stream_id = this->stream_ids[i]; - switch (this->stream_types[stream_id]) { - case ASF_STREAM_TYPE_AUDIO: - if ((audio_stream == -1) || (this->bitrates[stream_id] > max_arate)) { - audio_stream = stream_id; - max_arate = this->bitrates[stream_id]; - } - break; - default: - break; - } - } - - /* choose a video stream adapted to the user bandwidth */ - bandwitdh_left = bandwidth - max_arate; - if (bandwitdh_left < 0) { - bandwitdh_left = 0; - } - lprintf("bandwitdh %d, left %d\n", bandwidth, bandwitdh_left); - - min_bw_left = bandwitdh_left; - for (i = 0; i < this->num_stream_ids; i++) { - stream_id = this->stream_ids[i]; - switch (this->stream_types[stream_id]) { - case ASF_STREAM_TYPE_VIDEO: - if (((bandwitdh_left - this->bitrates[stream_id]) < min_bw_left) && - (bandwitdh_left >= this->bitrates[stream_id])) { - video_stream = stream_id; - min_bw_left = bandwitdh_left - this->bitrates[stream_id]; - } - break; - default: - break; - } - } - - /* choose the stream with the lower bitrate */ - if ((video_stream == -1) && this->has_video) { - for (i = 0; i < this->num_stream_ids; i++) { - stream_id = this->stream_ids[i]; - switch (this->stream_types[stream_id]) { - case ASF_STREAM_TYPE_VIDEO: - if ((video_stream == -1) || - (this->bitrates[stream_id] < min_vrate) || - (!min_vrate)) { - video_stream = stream_id; - min_vrate = this->bitrates[stream_id]; - } - break; - default: - break; - } - } - } - - lprintf("audio stream %d, video stream %d\n", audio_stream, video_stream); - - /* second request */ - lprintf("second http request\n"); - - if (mmsh_tcp_connect(io, this)) { - goto fail; - } - - /* stream selection string */ - /* The same selection is done with mmst */ - /* 0 means selected */ - /* 2 means disabled */ - offset = 0; - for (i = 0; i < this->num_stream_ids; i++) { - int size; - if ((this->stream_ids[i] == audio_stream) || - (this->stream_ids[i] == video_stream)) { - size = snprintf(stream_selection + offset, sizeof(stream_selection) - offset, - "ffff:%d:0 ", this->stream_ids[i]); - } else { - lprintf ("disabling stream %d\n", this->stream_ids[i]); - size = snprintf(stream_selection + offset, sizeof(stream_selection) - offset, - "ffff:%d:2 ", this->stream_ids[i]); - } - if (size < 0) goto fail; - offset += size; - } - - switch (this->stream_type) { - case MMSH_SEEKABLE: - snprintf (this->str, SCRATCH_SIZE, mmsh_SeekableRequest, this->uri, - this->http_host, this->http_port, 0, 0, 0, 2, 0, - this->num_stream_ids, stream_selection); - break; - case MMSH_LIVE: - snprintf (this->str, SCRATCH_SIZE, mmsh_LiveRequest, this->uri, - this->http_host, this->http_port, 2, - this->num_stream_ids, stream_selection); - break; - } - - if (!send_command (io, this, this->str)) - goto fail; - - lprintf("before read \n"); - - if (!get_answer (io, this)) - goto fail; - - if (!get_header(io, this)) - goto fail; - interp_header(io, this); - - for (i = 0; i < this->num_stream_ids; i++) { - if ((this->stream_ids[i] != audio_stream) && - (this->stream_ids[i] != video_stream)) { - lprintf("disabling stream %d\n", this->stream_ids[i]); - - /* forces the asf demuxer to not choose this stream */ - if (this->bitrates_pos[this->stream_ids[i]]) { - this->asf_header[this->bitrates_pos[this->stream_ids[i]]] = 0; - this->asf_header[this->bitrates_pos[this->stream_ids[i]] + 1] = 0; - this->asf_header[this->bitrates_pos[this->stream_ids[i]] + 2] = 0; - this->asf_header[this->bitrates_pos[this->stream_ids[i]] + 3] = 0; - } - } - } - return 1; -fail: - return 0; -} - -mmsh_t *mmsh_connect (mms_io_t *io, void *data, const char *url, int bandwidth) { - mmsh_t *this; - GURI *uri = NULL; - GURI *proxy_uri = NULL; - char *proxy_env; - if (!url) - return NULL; - -// report_progress (stream, 0); - /* - * initializatoin is essential here. the fail: label depends - * on the various char * in our this structure to be - * NULL if they haven't been assigned yet. - */ - this = (mmsh_t*) malloc (sizeof (mmsh_t)); - this->url=NULL; - this->proxy_url = NULL; - this->proto = NULL; - this->connect_host = NULL; - this->http_host = NULL; - this->proxy_user = NULL; - this->proxy_password = NULL; - this->host_user = NULL; - this->host_password = NULL; - this->uri = NULL; - - this->custom_data = data; - this->url = strdup(url); - if ((proxy_env = getenv("http_proxy")) != NULL) - this->proxy_url = strdup(proxy_env); - else - this->proxy_url = NULL; - 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_bandwidth = bandwidth; - -// report_progress (stream, 0); - - if (this->proxy_url) { - proxy_uri = gnet_uri_new(this->proxy_url); - if (!proxy_uri) { - lprintf("invalid proxy url\n"); - goto fail; - } - if (! proxy_uri->port ) { - proxy_uri->port = 3128; //default squid port - } - } - uri = gnet_uri_new(this->url); - if (!uri) { - lprintf ("invalid url\n"); - goto fail; - } - if (! uri->port ) { - //checked in tcp_connect, but it's better to initialize it here - uri->port = MMSH_PORT; - } - if (this->proxy_url) { - this->proto = (uri->scheme) ? strdup(uri->scheme) : NULL; - this->connect_host = (proxy_uri->hostname) ? strdup(proxy_uri->hostname) : NULL; - this->connect_port = proxy_uri->port; - this->http_host = (uri->scheme) ? strdup(uri->hostname) : NULL; - this->http_port = uri->port; - this->proxy_user = (proxy_uri->user) ? strdup(proxy_uri->user) : NULL; - this->proxy_password = (proxy_uri->passwd) ? strdup(proxy_uri->passwd) : NULL; - this->host_user = (uri->user) ? strdup(uri->user) : NULL; - this->host_password = (uri->passwd) ? strdup(uri->passwd) : NULL; - gnet_uri_set_scheme(uri,"http"); - char * uri_string = gnet_uri_get_string(uri); - this->uri = strdup(uri_string); - g_free(uri_string); - } else { - this->proto = (uri->scheme) ? strdup(uri->scheme) : NULL; - this->connect_host = (uri->hostname) ? strdup(uri->hostname) : NULL; - this->connect_port = uri->port; - this->http_host = (uri->hostname) ? strdup(uri->hostname) : NULL; - this->http_port = uri->port; - this->proxy_user = NULL; - this->proxy_password = NULL; - this->host_user =(uri->user) ? strdup(uri->user) : NULL; - this->host_password = (uri->passwd) ? strdup(uri->passwd) : NULL; - this->uri = (uri->path) ? strdup(uri->path) : NULL; - } - if (proxy_uri) { - gnet_uri_delete(proxy_uri); - proxy_uri = NULL; - } - if (uri) { - gnet_uri_delete(uri); - uri = NULL; - } - if (!mmsh_valid_proto(this->proto)) { - lprintf ("unsupported protocol\n"); - goto fail; - } - - if (mmsh_tcp_connect(io, this)) { - goto fail; - } -// report_progress (stream, 30); - - if (!mmsh_connect_int(io, this, this->user_bandwidth)) - goto fail; - -// report_progress (stream, 100); - - lprintf("mmsh_connect: passed\n" ); - - return this; - -fail: - lprintf("mmsh_connect: failed\n" ); - if (proxy_uri) - gnet_uri_delete(proxy_uri); - if (uri) - gnet_uri_delete(uri); - if (this->s != -1) - close(this->s); - if (this->url) - free(this->url); - if (this->proxy_url) - free(this->proxy_url); - if (this->proto) - free(this->proto); - if (this->connect_host) - free(this->connect_host); - if (this->http_host) - free(this->http_host); - if (this->proxy_user) - free(this->proxy_user); - if (this->proxy_password) - free(this->proxy_password); - if (this->host_user) - free(this->host_user); - if (this->host_password) - free(this->host_password); - if (this->uri) - free(this->uri); - - free(this); - - lprintf("mmsh_connect: failed return\n" ); - return NULL; -} - - -/* - * returned value: - * 0: error - * 1: data packet read - * 2: new header read - */ -static int get_media_packet (mms_io_t *io, mmsh_t *this) { - int len = 0; - - lprintf("get_media_packet: this->packet_length: %d\n", this->packet_length); - - if (get_chunk_header(io, this)) { - switch (this->chunk_type) { - case CHUNK_TYPE_END: - /* this->chunk_seq_number: - * 0: stop - * 1: a new stream follows - */ - if (this->chunk_seq_number == 0) - return 0; - - close (this->s); - - if (mmsh_tcp_connect (io, this)) - return 0; - - if (!mmsh_connect_int (io, this, this->user_bandwidth)) - return 0; - - /* mmsh_connect_int reads the first data packet */ - /* this->buf_size is set by mmsh_connect_int */ - return 2; - - case CHUNK_TYPE_DATA: - /* nothing to do */ - break; - - case CHUNK_TYPE_RESET: - /* next chunk is an ASF header */ - - if (this->chunk_length != 0) { - /* that's strange, don't know what to do */ - return 0; - } - if (!get_header (io, this)) - return 0; - interp_header(io, this); - this->buf_size = this->packet_length; - return 2; - - default: - lprintf ("mmsh: unexpected chunk type\n"); - return 0; - } - - len = io_read (io, this->s, this->buf, this->chunk_length); - - if (len == this->chunk_length) { - /* explicit padding with 0 */ - if (this->chunk_length > this->packet_length) { - lprintf ("mmsh: chunk_length(%d) > packet_length(%d)\n", - this->chunk_length, this->packet_length); - return 0; - } - - { - char *base = (char *)(this->buf); - char *start = base + this->chunk_length; - char *end = start + this->packet_length - this->chunk_length; - if ((start > base) && (start < (base+CHUNK_SIZE-1)) && - (start < end) && (end < (base+CHUNK_SIZE-1))) { - memset(start, 0, - this->packet_length - this->chunk_length); - } - if (this->packet_length > CHUNK_SIZE) { - this->buf_size = CHUNK_SIZE; - } else { - this->buf_size = this->packet_length; - } - } - return 1; - } else { - lprintf ("mmsh: read error, %d != %d\n", len, this->chunk_length); - return 0; - } - } else { - return 0; - } -} - -int mmsh_peek_header (mmsh_t *this, char *data, int maxsize) { - int len; - - lprintf("mmsh_peek_header\n"); - - len = (this->asf_header_len < maxsize) ? this->asf_header_len : maxsize; - - memcpy(data, this->asf_header, len); - return len; -} - -int mmsh_read (mms_io_t *io, mmsh_t *this, char *data, int len) { - int total; - - total = 0; - - lprintf ("mmsh_read: len: %d\n", len); - - while (total < len) { - - if (this->asf_header_read < this->asf_header_len) { - int n, bytes_left ; - - bytes_left = this->asf_header_len - this->asf_header_read ; - - if ((len-total) < bytes_left) - n = len-total; - else - n = bytes_left; - - memcpy (&data[total], &this->asf_header[this->asf_header_read], n); - - this->asf_header_read += n; - total += n; - this->current_pos += n; - } else { - - int n, bytes_left ; - - bytes_left = this->buf_size - this->buf_read; - - if (bytes_left == 0) { - int packet_type; - - this->buf_size=this ->buf_read = 0; - packet_type = get_media_packet (io, this); - - if (packet_type == 0) { - lprintf ("mmsh: get_media_packet failed\n"); - return total; - } else if (packet_type == 2) { - continue; - } - bytes_left = this->buf_size; - } - - if ((len-total) < bytes_left) - n = len-total; - else - n = bytes_left; - - memcpy (&data[total], &this->buf[this->buf_read], n); - - this->buf_read += n; - total += n; - this->current_pos += n; - } - } - return total; -} - - -void mmsh_close (mmsh_t *this) { - - lprintf("mmsh_close\n"); - - if (this->s != -1) - close(this->s); - if (this->url) - free(this->url); - if (this->proxy_url) - free(this->proxy_url); - if (this->proto) - free(this->proto); - if (this->connect_host) - free(this->connect_host); - if (this->http_host) - free(this->http_host); - if (this->proxy_user) - free(this->proxy_user); - if (this->proxy_password) - free(this->proxy_password); - if (this->host_user) - free(this->host_user); - if (this->host_password) - free(this->host_password); - if (this->uri) - free(this->uri); - if (this) - free (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; -}
--- a/src/wma/libffwma/mmsh.h Sun Jan 21 21:01:41 2007 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2002-2003 the xine project - * - * This file is part of xine, a free video player. - * - * xine is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * xine is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - * - * $Id: mmsh.h,v 1.4 2006/06/06 09:52:28 shawarma Exp $ - * - * libmmsh public header - */ - -#ifndef HAVE_MMSH_H -#define HAVE_MMSH_H - -#include <inttypes.h> -#include <stdio.h> -#include <sys/types.h> -#include "mmsio.h" - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -typedef struct mmsh_s mmsh_t; - -char* mmsh_connect_common(int *s ,int *port, char *url, char **host, char **path, char **file); -mmsh_t* mmsh_connect (mms_io_t *io, void *data, const char *url_, int bandwidth); - -int mmsh_read (mms_io_t *io, mmsh_t *instance, char *data, int len); -uint32_t mmsh_get_length (mmsh_t *instance); -off_t mmsh_get_current_pos (mmsh_t *instance); -void mmsh_close (mmsh_t *instance); - -int mmsh_peek_header (mmsh_t *instance, char *data, int maxsize); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif
--- a/src/wma/libffwma/mmsio.h Sun Jan 21 21:01:41 2007 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -#ifndef __MMS_IO_H__ -#define __MMS_IO_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -typedef off_t (*mms_io_write_func)(void *data, int socket, char *buf, off_t num); -typedef off_t (*mms_io_read_func)(void *data, int socket, char *buf, off_t num); - -/* select states */ -#define MMS_IO_READ_READY 1 -#define MMS_IO_WRITE_READY 2 - -enum - { - MMS_IO_STATUS_READY, /* IO can be safely performed */ - MMS_IO_STATUS_ERROR, /* There was IO error */ - MMS_IO_STATUS_ABORTED, /* IO command was (somehow) - aborted. This is not error, but invalidates IO for further operations*/ - MMS_IO_STATUS_TIMEOUT /* Timeout was exceeded */ - }; - -/* - * Waits for a file descriptor/socket to change status. - * - * users can use this handler to provide their own implementations, - * for example abortable ones - * - * params : - * data whatever parameter may be needed by implementation - * fd file/socket descriptor - * state MMS_IO_READ_READY, MMS_IO_WRITE_READY - * timeout_sec timeout in seconds - * - * - * return value : - * MMS_IO_READY the file descriptor is ready for cmd - * MMS_IO_ERROR an i/o error occured - * MMS_IO_ABORTED command aborted - * MMS_IO_TIMEOUT the file descriptor is not ready after timeout_msec milliseconds - * every other return value is interpreted same as MMS_IO_ABORTED - */ -typedef int (*mms_io_select_func)(void *data, int fd, int state, int timeout_msec); - -/* - * open a tcp connection - * - * params : - * stream needed for reporting errors but may be NULL - * host address of target - * port port on target - * - * returns a socket descriptor or -1 if an error occured - */ -typedef int (*mms_io_tcp_connect_func)(void *data, const char *host, int port); - -typedef struct -{ - mms_io_select_func select; - void *select_data; - mms_io_read_func read; - void *read_data; - mms_io_write_func write; - void *write_data; - mms_io_tcp_connect_func connect; - void *connect_data; -} mms_io_t; - -/* set default IO implementation, it will be used in absence of specific IO - parameter. Structure is referenced, not copied, must remain valid for entire - usage period. Passing NULL reverts to default, POSIX based implementation */ -void mms_set_default_io_impl(const mms_io_t *io); -const mms_io_t* mms_get_default_io_impl(); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __MMS_IO_H__ */