changeset 1124:a63e0fdb3d1e trunk

[svn] - initial mms stream support
author nenolod
date Fri, 02 Jun 2006 09:58:51 -0700
parents 170f9b68dd03
children 790c3a23eea2
files Plugins/Input/wma/libffwma/Makefile.in Plugins/Input/wma/libffwma/allformats.c Plugins/Input/wma/libffwma/avio.h Plugins/Input/wma/libffwma/file.c Plugins/Input/wma/libffwma/mms.c Plugins/Input/wma/libffwma/mms.h
diffstat 6 files changed, 890 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/Plugins/Input/wma/libffwma/Makefile.in	Fri Jun 02 09:08:57 2006 -0700
+++ b/Plugins/Input/wma/libffwma/Makefile.in	Fri Jun 02 09:58:51 2006 -0700
@@ -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 \
+		fft.c file.c futils.c mdct.c mms.c \
 		os_support.c os_support.h \
 		parser.c simple_idct.c simple_idct.h \
 		utils.h utils.c wmadata.h wmadec.c
--- a/Plugins/Input/wma/libffwma/allformats.c	Fri Jun 02 09:08:57 2006 -0700
+++ b/Plugins/Input/wma/libffwma/allformats.c	Fri Jun 02 09:58:51 2006 -0700
@@ -28,4 +28,5 @@
     /* file protocols */
     register_protocol(&file_protocol);
     register_protocol(&pipe_protocol);
+    register_protocol(&mms_protocol);
 }
--- a/Plugins/Input/wma/libffwma/avio.h	Fri Jun 02 09:08:57 2006 -0700
+++ b/Plugins/Input/wma/libffwma/avio.h	Fri Jun 02 09:58:51 2006 -0700
@@ -165,5 +165,7 @@
 /* http.c */
 extern URLProtocol http_protocol;
 
+extern URLProtocol mms_protocol;
+
 #endif
 
--- a/Plugins/Input/wma/libffwma/file.c	Fri Jun 02 09:08:57 2006 -0700
+++ b/Plugins/Input/wma/libffwma/file.c	Fri Jun 02 09:58:51 2006 -0700
@@ -23,6 +23,7 @@
 #include <sys/ioctl.h>
 #include <sys/time.h>
 #include "libaudacious/vfs.h"
+#include "mms.h"
 
 /* standard file protocol */
 
@@ -130,3 +131,39 @@
     pipe_close,
     NULL
 };
+
+/* new mms protocol stuff --nenolod */
+
+static int _mms_open(URLContext *h, const char *filename, int flags)
+{
+    mms_t *mms = mms_connect(filename);
+
+    if (mms == NULL)
+	return -ENOENT;
+
+    h->priv_data = (void *)mms;
+    return 0;
+}
+
+static int _mms_read(URLContext *h, unsigned char *buf, int size)
+{
+    mms_t *mms = (mms_t *) h->priv_data;
+    return mms_read(mms, buf, size);
+}
+
+static int _mms_close(URLContext *h)
+{
+    mms_t *mms = (mms_t *) h->priv_data;
+    mms_close(mms);
+    return 0;
+}
+
+URLProtocol mms_protocol = {
+    "mms",
+    _mms_open,
+    _mms_read,
+    NULL,
+    NULL,
+    _mms_close,
+    NULL
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/wma/libffwma/mms.c	Fri Jun 02 09:58:51 2006 -0700
@@ -0,0 +1,815 @@
+/* 
+ * Copyright (C) 2000-2001 major mms
+ * 
+ * This file is part of libmms
+ * 
+ * libmms 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.
+ * 
+ * libmms is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
+ *
+ * utility functions to handle communication with an mms server
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.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 "avcodec.h"
+#include "bswap.h"
+#include "mms.h"
+
+#define LOG
+
+/* 
+ * mms specific types 
+ */
+
+#define MMS_PORT 1755
+
+#define BUF_SIZE 102400
+
+#define CMD_HEADER_LEN   48
+#define CMD_BODY_LEN   1024
+
+struct mms_s {
+
+  int           s;
+
+  char         *host;
+  char         *path;
+  char         *file;
+  char         *url;
+
+  /* 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 */
+  char          buf[BUF_SIZE];
+  int           buf_size;
+  int           buf_read;
+
+  uint8_t       asf_header[8192];
+  int           asf_header_len;
+  int           asf_header_read;
+  int           seq_num;
+  int           num_stream_ids;
+  int           stream_ids[20];
+  int           packet_length;
+
+};
+
+/* network/socket utility functions */
+
+static int host_connect_attempt(struct in_addr ia, int port) {
+
+  int                s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+  struct sockaddr_in sin;
+  
+  if (s==-1) {
+    printf ("libmms: socket(): %s\n", strerror(errno));
+    return -1;
+  }
+
+  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) {
+    printf ("libmms: connect(): %s\n", strerror(errno));
+    close(s);
+    return -1;
+  }	
+	
+  return s;
+}
+
+static int host_connect(const char *host, int port) {
+
+  struct hostent *h;
+  int i, s;
+  
+  h=gethostbyname(host);
+  if (h==NULL) {
+    printf ("libmms: unable to resolve '%s'.\n", host);
+    return -1;
+  }
+	
+  for (i=0; h->h_addr_list[i]; i++) {
+    struct in_addr ia;
+    memcpy (&ia, h->h_addr_list[i],4);
+    s = host_connect_attempt(ia, port);
+    if(s != -1)
+      return s;
+  }
+  printf ("libmms: unable to connect to '%s'.\n", host);
+  return -1;
+}
+
+static void put_32 (mms_t *this, uint32_t value) {
+
+  this->scmd[this->scmd_len  ] = value % 256;
+  value = value >> 8;
+  this->scmd[this->scmd_len+1] = value % 256 ;
+  value = value >> 8;
+  this->scmd[this->scmd_len+2] = value % 256 ;
+  value = value >> 8;
+  this->scmd[this->scmd_len+3] = value % 256 ;
+
+  this->scmd_len += 4;
+}
+
+static int send_data (int s, char *buf, int len) {
+  int total;
+
+  total=0;
+  while (total<len){ 
+    int n;
+
+    n = write (s, &buf[total], len-total);
+    if (n > 0)
+      total += n;
+    else if (n<0 && errno!=EAGAIN) 
+      return total;
+  }
+  return total;
+}
+
+static uint32_t get_32 (unsigned char *cmd, int offset) {
+
+  uint32_t ret;
+
+  ret = cmd[offset] ;
+  ret |= cmd[offset+1]<<8 ;
+  ret |= cmd[offset+2]<<16 ;
+  ret |= cmd[offset+3]<<24 ;
+
+  return ret;
+}
+
+static void send_command (mms_t *this, int command, uint32_t switches, 
+			  uint32_t extra, int length) {
+  
+  int        len8;
+  int        i;
+
+  len8 = (length + (length%8)) / 8;
+
+  this->scmd_len = 0;
+
+  put_32 (this, 0x00000001); /* start sequence */
+  put_32 (this, 0xB00BFACE); /* #-)) */
+  put_32 (this, length + 32);
+  put_32 (this, 0x20534d4d); /* protocol type "MMS " */
+  put_32 (this, len8 + 4);
+  put_32 (this, this->seq_num); this->seq_num++;
+  put_32 (this, 0x0);        /* unknown */
+  put_32 (this, 0x0);
+  put_32 (this, len8+2);
+  put_32 (this, 0x00030000 | command); /* dir | command */
+  put_32 (this, switches);
+  put_32 (this, extra);
+
+  /* memcpy (&cmd->buf[48], data, length); */
+
+  if (send_data (this->s, this->scmd, length+48) != (length+48)) {
+    printf ("libmms: send error\n");
+  }
+
+#ifdef LOG
+  printf ("\nlibmms: ***************************************************\ncommand sent, %d bytes\n", length+48);
+
+  printf ("start sequence %08x\n", get_32 (this->scmd,  0));
+  printf ("command id     %08x\n", get_32 (this->scmd,  4));
+  printf ("length         %8x \n", get_32 (this->scmd,  8));
+  printf ("len8           %8x \n", get_32 (this->scmd, 16));
+  printf ("sequence #     %08x\n", get_32 (this->scmd, 20));
+  printf ("len8  (II)     %8x \n", get_32 (this->scmd, 32));
+  printf ("dir | comm     %08x\n", get_32 (this->scmd, 36));
+  printf ("switches       %08x\n", get_32 (this->scmd, 40));
+
+  printf ("ascii contents>");
+  for (i=48; i<(length+48); i+=2) {
+    unsigned char c = this->scmd[i];
+
+    if ((c>=32) && (c<=128))
+      printf ("%c", c);
+    else
+      printf (".");
+  }
+  printf ("\n");
+
+  printf ("libmms: complete hexdump of package follows:\n");
+  for (i=0; i<(length+48); i++) {
+    unsigned char c = this->scmd[i];
+
+    printf ("%02x", c);
+
+    if ((i % 16) == 15)
+      printf ("\nlibmms: ");
+
+    if ((i % 2) == 1)
+      printf (" ");
+
+  }
+  printf ("\n");
+#endif
+}
+
+static void string_utf16(char *dest, char *src, int len) {
+  int i;
+
+  memset (dest, 0, 1000);
+
+  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;
+}
+
+static void print_answer (char *data, int len) {
+
+#ifdef LOG
+  int i;
+
+  printf ("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\nanswer received, %d bytes\n", len);
+
+  printf ("start sequence %08x\n", get_32 (data, 0));
+  printf ("command id     %08x\n", get_32 (data, 4));
+  printf ("length         %8x \n", get_32 (data, 8));
+  printf ("len8           %8x \n", get_32 (data, 16));
+  printf ("sequence #     %08x\n", get_32 (data, 20));
+  printf ("len8  (II)     %8x \n", get_32 (data, 32));
+  printf ("dir | comm     %08x\n", get_32 (data, 36));
+  printf ("switches       %08x\n", get_32 (data, 40));
+
+  for (i=48; i<len; i+=2) {
+    unsigned char c = data[i];
+    
+    if ((c>=32) && (c<128))
+      printf ("%c", c);
+    else
+      printf (" %02x ", c);
+    
+  }
+  printf ("\n");
+#endif
+
+}  
+
+static void get_answer (mms_t *this) {
+
+  int   command = 0x1b;
+
+  while (command == 0x1b) {
+    int len;
+
+    len = read (this->s, this->buf, BUF_SIZE) ;
+    if (!len) {
+      printf ("\nalert! eof\n");
+      return;
+    }
+
+    print_answer (this->buf, len);
+
+    command = get_32 (this->buf, 36) & 0xFFFF;
+
+    if (command == 0x1b) 
+      send_command (this, 0x1b, 0, 0, 0);
+  }
+}
+
+static int receive (int s, char *buf, size_t count) {
+
+  ssize_t  len, total;
+
+  total = 0;
+
+  while (total < count) {
+
+    len = read (s, &buf[total], count-total);
+
+    if (len<0) {
+      perror ("read error:");
+      return 0;
+    }
+
+    total += len;
+
+#ifdef LOG
+    if (len != 0) {
+      printf ("[%d/%d]", total, count);
+      fflush (stdout);
+    }
+#endif
+
+  }
+
+  return 1;
+
+}
+
+static void get_header (mms_t *this) {
+
+  unsigned char  pre_header[8];
+  int            i;
+
+  this->asf_header_len = 0;
+
+  while (1) {
+
+    if (!receive (this->s, pre_header, 8)) {
+      printf ("libmms: pre-header read failed\n");
+      return ;
+    }
+
+#ifdef LOG    
+    for (i=0; i<8; i++)
+      printf ("libmms: pre_header[%d] = %02x (%d)\n",
+	      i, pre_header[i], pre_header[i]);
+#endif    
+
+    if (pre_header[4] == 0x02) {
+      
+      int packet_len;
+      
+      packet_len = (pre_header[7] << 8 | pre_header[6]) - 8;
+
+#ifdef LOG    
+      printf ("libmms: asf header packet detected, len=%d\n",
+	      packet_len);
+#endif
+
+      if (!receive (this->s, &this->asf_header[this->asf_header_len], packet_len)) {
+	printf ("libmms: header data read failed\n");
+	return;
+      }
+
+      this->asf_header_len += packet_len;
+
+      if ( (this->asf_header[this->asf_header_len-1] == 1) 
+	   && (this->asf_header[this->asf_header_len-2]==1)) {
+
+	printf ("libmms: get header packet finished\n");
+
+	return;
+
+      } 
+
+    } else {
+
+      int packet_len, command;
+
+      if (!receive (this->s, (char *) &packet_len, 4)) {
+	printf ("packet_len read failed\n");
+	return;
+      }
+      
+      packet_len = get_32 ((char *)&packet_len, 0) + 4;
+      
+#ifdef LOG    
+      printf ("command packet detected, len=%d\n",
+	      packet_len);
+#endif
+      
+      if (!receive (this->s, this->buf, packet_len)) {
+	printf ("command data read failed\n");
+	return ;
+      }
+      
+      command = get_32 (this->buf, 24) & 0xFFFF;
+      
+#ifdef LOG    
+      printf ("command: %02x\n", command);
+#endif
+      
+      if (command == 0x1b) 
+	send_command (this, 0x1b, 0, 0, 0);
+      
+    }
+
+    printf ("mms: get header packet succ\n");
+  }
+}
+
+static void interp_header (mms_t *this) {
+
+  int i;
+
+  this->packet_length = 0;
+
+  /*
+   * parse header
+   */
+
+  i = 30;
+  while (i<this->asf_header_len) {
+    
+    uint64_t  guid_1, guid_2, length;
+
+    guid_2 = (uint64_t)this->asf_header[i] | ((uint64_t)this->asf_header[i+1]<<8) 
+      | ((uint64_t)this->asf_header[i+2]<<16) | ((uint64_t)this->asf_header[i+3]<<24)
+      | ((uint64_t)this->asf_header[i+4]<<32) | ((uint64_t)this->asf_header[i+5]<<40)
+      | ((uint64_t)this->asf_header[i+6]<<48) | ((uint64_t)this->asf_header[i+7]<<56);
+    i += 8;
+
+    guid_1 = (uint64_t)this->asf_header[i] | ((uint64_t)this->asf_header[i+1]<<8) 
+      | ((uint64_t)this->asf_header[i+2]<<16) | ((uint64_t)this->asf_header[i+3]<<24)
+      | ((uint64_t)this->asf_header[i+4]<<32) | ((uint64_t)this->asf_header[i+5]<<40)
+      | ((uint64_t)this->asf_header[i+6]<<48) | ((uint64_t)this->asf_header[i+7]<<56);
+    i += 8;
+    
+#ifdef LOG    
+    printf ("guid found: %016llx%016llx\n", guid_1, guid_2);
+#endif
+
+    length = (uint64_t)this->asf_header[i] | ((uint64_t)this->asf_header[i+1]<<8) 
+      | ((uint64_t)this->asf_header[i+2]<<16) | ((uint64_t)this->asf_header[i+3]<<24)
+      | ((uint64_t)this->asf_header[i+4]<<32) | ((uint64_t)this->asf_header[i+5]<<40)
+      | ((uint64_t)this->asf_header[i+6]<<48) | ((uint64_t)this->asf_header[i+7]<<56);
+
+    i += 8;
+
+    if ( (guid_1 == 0x6cce6200aa00d9a6) && (guid_2 == 0x11cf668e75b22630) ) {
+      printf ("header object\n");
+    } else if ((guid_1 == 0x6cce6200aa00d9a6) && (guid_2 == 0x11cf668e75b22636)) {
+      printf ("data object\n");
+    } else if ((guid_1 == 0x6553200cc000e48e) && (guid_2 == 0x11cfa9478cabdca1)) {
+
+      this->packet_length = get_32(this->asf_header, i+92-24);
+
+#ifdef LOG    
+      printf ("file object, packet length = %d (%d)\n",
+	      this->packet_length, get_32(this->asf_header, i+96-24));
+#endif
+
+
+    } else if ((guid_1 == 0x6553200cc000e68e) && (guid_2 == 0x11cfa9b7b7dc0791)) {
+
+      int stream_id = this->asf_header[i+48] | this->asf_header[i+49] << 8;
+
+#ifdef LOG    
+      printf ("stream object, stream id: %d\n", stream_id);
+#endif
+
+      this->stream_ids[this->num_stream_ids] = stream_id;
+      this->num_stream_ids++;
+      
+
+      /*
+	} else if ((guid_1 == 0x) && (guid_2 == 0x)) {
+	printf ("??? object\n");
+      */
+    } else {
+      printf ("unknown object\n");
+    }
+
+#ifdef LOG    
+    printf ("length    : %lld\n", length);
+#endif
+
+    i += length-24;
+
+  }
+}
+
+
+mms_t *mms_connect (const char *url_) {
+
+  mms_t *this;
+  char  *url, *host, *hostend;
+  char  *path, *file;
+  int    hostlen, s, len, i;
+
+  /* parse url*/
+
+  if (strncasecmp (url_, "mms://",6)) {
+    printf ("libmms: invalid url >%s< (should be mms:// - style)\n", url_);
+    return NULL;
+  }
+
+  url = strdup (url_);
+
+  /* extract hostname */
+
+  hostend = strchr(&url[6],'/');
+  if (!hostend) {
+    printf ("libmms: invalid url >%s<, failed to find hostend\n", url);
+    return NULL;
+  }
+  hostlen = hostend - url - 6;
+  host = malloc (hostlen+1);
+  strncpy (host, &url[6], hostlen);
+  host[hostlen]=0;
+
+  /* extract path and file */
+
+  path = url+hostlen+7;
+  file = strrchr (url, '/');
+
+  /* 
+   * try to connect 
+   */
+
+  s = host_connect (host, MMS_PORT);
+  if (s == -1) {
+    printf ("libmms: failed to connect\n");
+    free (host);
+    free (url);
+    return NULL;
+  }
+
+  this = (mms_t*) malloc (sizeof (mms_t));
+
+  this->url             = url;
+  this->host            = host;
+  this->path            = path;
+  this->file            = file;
+  this->s               = s;
+  this->seq_num         = 0;
+  this->scmd_body       = &this->scmd[CMD_HEADER_LEN];
+  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;
+
+  /*
+   * let the negotiations begin...
+   */
+
+  /* cmd1 */
+  
+  sprintf (this->str, "\034\003NSPlayer/7.0.0.1956; {33715801-BAB3-9D85-24E9-03B90328270A}; Host: %s",
+	   this->host);
+  string_utf16 (this->scmd_body, this->str, strlen(this->str)+2);
+
+  send_command (this, 1, 0, 0x0004000b, strlen(this->str) * 2+8);
+
+  len = read (this->s, this->buf, BUF_SIZE) ;
+  if (len>0)
+    print_answer (this->buf, len);
+  else {
+    printf ("libmms: read failed: %s\n", strerror(errno));
+
+  }
+
+  /* cmd2 */
+
+  string_utf16 (&this->scmd_body[8], "\002\000\\\\192.168.0.129\\TCP\\1037\0000", 
+		28);
+  memset (this->scmd_body, 0, 8);
+  send_command (this, 2, 0, 0, 28*2+8);
+
+  len = read (this->s, this->buf, BUF_SIZE) ;
+  if (len)
+    print_answer (this->buf, len);
+
+  /* 0x5 */
+
+  string_utf16 (&this->scmd_body[8], path, strlen(path));
+  memset (this->scmd_body, 0, 8);
+  send_command (this, 5, 0, 0, strlen(path)*2+12);
+
+  get_answer (this);
+
+  /* 0x15 */
+
+  memset (this->scmd_body, 0, 40);
+  this->scmd_body[32] = 2;
+
+  send_command (this, 0x15, 1, 0, 40);
+
+  this->num_stream_ids = 0;
+
+  get_header (this);
+  interp_header (this);
+
+  /* 0x33 */
+
+  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 ] = 0x00;
+  }
+
+  send_command (this, 0x33, this->num_stream_ids, 
+		0xFFFF | this->stream_ids[0] << 16, 
+		(this->num_stream_ids-1)*6+2);
+
+  get_answer (this);
+
+  /* 0x07 */
+
+  memset (this->scmd_body, 0, 40);
+
+  for (i=8; i<16; i++)
+    this->scmd_body[i] = 0xFF;
+
+  this->scmd_body[20] = 0x04;
+
+  send_command (this, 0x07, 1, 
+		0xFFFF | this->stream_ids[0] << 16, 
+		24);
+
+  return this;
+}
+
+static int get_media_packet (mms_t *this) {
+
+  unsigned char  pre_header[8];
+  int            i;
+
+  if (!receive (this->s, pre_header, 8)) {
+    printf ("pre-header read failed\n");
+    return 0;
+  }
+
+#ifdef LOG
+  for (i=0; i<8; i++)
+    printf ("pre_header[%d] = %02x (%d)\n",
+	    i, pre_header[i], pre_header[i]);
+#endif
+
+  if (pre_header[4] == 0x04) {
+
+    int packet_len;
+
+    packet_len = (pre_header[7] << 8 | pre_header[6]) - 8;
+
+#ifdef LOG
+    printf ("asf media packet detected, len=%d\n",
+	    packet_len);
+#endif
+
+    if (!receive (this->s, this->buf, packet_len)) {
+      printf ("media data read failed\n");
+      return 0;
+    }
+
+    /* implicit padding (with "random" data)*/
+    this->buf_size = this->packet_length;
+
+  } else {
+
+    int packet_len, command;
+
+    if (!receive (this->s, (char *)&packet_len, 4)) {
+      printf ("packet_len read failed\n");
+      return 0;
+    }
+
+    packet_len = get_32 ((char *)&packet_len, 0) + 4;
+
+#ifdef LOG
+    printf ("command packet detected, len=%d\n",
+	    packet_len);
+#endif
+
+    if (!receive (this->s, this->buf, packet_len)) {
+      printf ("command data read failed\n");
+      return 0;
+    }
+
+    if ( (pre_header[7] != 0xb0) || (pre_header[6] != 0x0b)
+	 || (pre_header[5] != 0xfa) || (pre_header[4] != 0xce) ) {
+
+      printf ("missing signature\n");
+      exit (1);
+
+    }
+
+    command = get_32 (this->buf, 24) & 0xFFFF;
+
+#ifdef LOG
+    printf ("command: %02x\n", command);
+#endif
+
+    if (command == 0x1b) 
+      send_command (this, 0x1b, 0, 0, 0);
+    else if (command == 0x1e) {
+
+      printf ("libmms: everything done. Thank you for downloading a media file containing proprietary and patentend technology.\n");
+
+      return 0;
+    } else if (command != 0x05) {
+      printf ("unknown command %02x\n", command);
+      exit (1);
+    }
+  }
+
+#ifdef LOG
+  printf ("get media packet succ\n");
+#endif
+
+  return 1;
+}
+
+int mms_read (mms_t *this, char *data, int len) {
+
+  int total;
+
+  total = 0;
+
+  while (total < len) {
+
+#ifdef LOG
+    printf ("libmms: read, got %d / %d bytes\n", total, len);
+#endif
+
+    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<bytes_left)
+	n = len;
+      else
+	n = bytes_left;
+
+      memcpy (&data[total], &this->asf_header[this->asf_header_read], n);
+
+      this->asf_header_read += n;
+      total += n;
+    } else {
+
+      int n, bytes_left ;
+
+      bytes_left = this->buf_size - this->buf_read;
+
+      while (!bytes_left) {
+	
+	this->buf_read = 0;
+
+	if (!get_media_packet (this)) {
+	  printf ("libmms: get_media_packet failed\n");
+	  return total;
+	}
+	bytes_left = this->buf_size - this->buf_read;
+      }
+      
+
+      if (len<bytes_left)
+	n = len;
+      else
+	n = bytes_left;
+
+      memcpy (&data[total], &this->buf[this->buf_read], n);
+
+      this->buf_read += n;
+      total += n;
+    }
+  }
+
+  return total;
+}
+
+void mms_close (mms_t *this) {
+
+  if (this->s >= 0) {
+    close(this->s);
+  }
+
+  free (this->host);
+  free (this->url);
+  free (this);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/wma/libffwma/mms.h	Fri Jun 02 09:58:51 2006 -0700
@@ -0,0 +1,34 @@
+/* 
+ * Copyright (C) 2000-2001 major mms
+ * 
+ * This file is part of libmms
+ * 
+ * xine-mms 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-mms is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
+ *
+ * libmms public header
+ */
+#ifndef HAVE_MMS_H
+#define HAVE_MMS_H
+
+typedef struct mms_s mms_t;
+
+mms_t *mms_connect (const char *url);
+
+int mms_read (mms_t *this, char *data, int len);
+
+void mms_close (mms_t *this);
+
+#endif
+