changeset 6092:1529f01e8108

Added support for asf mmst protocol. Implementation taken from the xine-mms plugin made by majormms Modified to work with mplayer by Abhijeet Phatak <abhijeetphatak@yahoo.com>
author bertrand
date Tue, 14 May 2002 22:31:21 +0000
parents 8a7bcb49686f
children 839bc172ea4a
files libmpdemux/asf_mmst_streaming.c
diffstat 1 files changed, 628 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmpdemux/asf_mmst_streaming.c	Tue May 14 22:31:21 2002 +0000
@@ -0,0 +1,628 @@
+// mmst implementation taken from the xine-mms plugin made by majormms (http://geocities.com/majormms/)
+// 
+// ported to mplayer by Abhijeet Phatak <abhijeetphatak@yahoo.com>
+// date : 16 April 2002
+//
+// information about the mms protocol can be find at http://get.to/sdp
+//
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "config.h"
+
+#include "url.h"
+#include "asf.h"
+
+#include "stream.h"
+
+#include "network.h"
+
+int data_length = 0;
+int packet_length1;
+int media_padding;
+int to_skip = 0;
+
+#include <inttypes.h>
+
+#define BUF_SIZE 102400
+int checknum =1;
+
+typedef struct 
+{
+  uint8_t buf[BUF_SIZE];
+  int     num_bytes;
+
+} command_t;
+
+int seq_num;
+int num_stream_ids;
+int stream_ids[20];
+int output_fh;
+
+static int get_data (int s, char *buf, size_t count);
+int store_data(int s, int size, char *buffer)
+{
+//	printf("data_length %d, media_padding %d, size %d \n", data_length, media_padding, size );
+	if(data_length >= size)
+	{   
+		if (!get_data (s, buffer, size)) 
+		{
+			printf ("media data read failed\n");
+			return 0;
+		}
+		data_length -= size;
+		return size;
+	}
+	else 
+	{
+		int temp_size, media_temp_padding;
+		if(data_length)	
+		{
+			if (!get_data (s, buffer, data_length)) 
+			{
+				printf ("media data read failed\n");
+				return 0;
+			}
+		}
+		if(media_padding)
+		{
+			if(media_padding > size - data_length)
+			{
+				memset(buffer+data_length,0,(size - data_length));
+				media_padding -= (size - data_length);
+				data_length = 0;
+				return size;
+			}
+			else
+			{
+				memset(buffer+data_length,0,media_padding);
+				media_temp_padding = media_padding;
+				media_padding = 0;
+				temp_size =data_length;
+				data_length = 0;
+				return (temp_size + media_temp_padding);
+			}
+		}
+		temp_size = data_length;
+		data_length = 0;
+		return temp_size;
+	}
+}
+
+static void put_32 (command_t *cmd, uint32_t value) 
+{
+  cmd->buf[cmd->num_bytes  ] = value % 256;
+  value = value >> 8;
+  cmd->buf[cmd->num_bytes+1] = value % 256 ;
+  value = value >> 8;
+  cmd->buf[cmd->num_bytes+2] = value % 256 ;
+  value = value >> 8;
+  cmd->buf[cmd->num_bytes+3] = value % 256 ;
+
+  cmd->num_bytes += 4;
+}
+
+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 (int s, int command, uint32_t switches, 
+			  uint32_t extra, int length,
+			  char *data) 
+{
+  command_t  cmd;
+  int        len8;
+
+  len8 = (length + (length%8)) / 8;
+
+  cmd.num_bytes = 0;
+
+  put_32 (&cmd, 0x00000001); /* start sequence */
+  put_32 (&cmd, 0xB00BFACE); /* #-)) */
+  put_32 (&cmd, length + 32);
+  put_32 (&cmd, 0x20534d4d); /* protocol type "MMS " */
+  put_32 (&cmd, len8 + 4);
+  put_32 (&cmd, seq_num);
+  seq_num++;
+  put_32 (&cmd, 0x0);        /* unknown */
+  put_32 (&cmd, 0x0);
+  put_32 (&cmd, len8+2);
+  put_32 (&cmd, 0x00030000 | command); /* dir | command */
+  put_32 (&cmd, switches);
+  put_32 (&cmd, extra);
+
+  memcpy (&cmd.buf[48], data, length);
+
+  if (write (s, cmd.buf, length+48) != (length+48)) {
+    printf ("write error\n");
+  }
+}
+
+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 get_answer (int s) 
+{
+  char  data[BUF_SIZE];
+  int   command = 0x1b;
+
+  while (command == 0x1b) {
+    int len;
+
+    len = read (s, data, BUF_SIZE) ;
+    if (!len) {
+      printf ("\nalert! eof\n");
+      return;
+    }
+
+    command = get_32 (data, 36) & 0xFFFF;
+
+    if (command == 0x1b) 
+      send_command (s, 0x1b, 0, 0, 0, data);
+  }
+}
+
+static int get_data (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;
+
+    if (len != 0) {
+//      printf ("[%d/%d]", total, count);
+      fflush (stdout);
+    }
+
+  }
+
+  return 1;
+
+}
+
+static int get_header (int s, uint8_t *header, streaming_ctrl_t *streaming_ctrl) 
+{
+  unsigned char  pre_header[8];
+  int            header_len,i ;
+
+  header_len = 0;
+
+  while (1) {
+    if (!get_data (s, pre_header, 8)) {
+      printf ("pre-header read failed\n");
+      return 0;
+    }
+    if (pre_header[4] == 0x02) {
+      
+      int packet_len;
+      
+      packet_len = (pre_header[7] << 8 | pre_header[6]) - 8;
+
+//      printf ("asf header packet detected, len=%d\n", packet_len);
+
+      if (!get_data (s, &header[header_len], packet_len)) {
+	printf ("header data read failed\n");
+	return 0;
+      }
+
+      header_len += packet_len;
+
+      if ( (header[header_len-1] == 1) && (header[header_len-2]==1)) {
+	
+
+     if( streaming_bufferize( streaming_ctrl, header, header_len )<0 ) {
+				return -1;
+ 	 }
+
+     //	printf ("get header packet finished\n");
+
+	return (header_len);
+
+      } 
+
+    } else {
+
+      char packet_len;
+      int command;
+      char data[BUF_SIZE];
+
+      if (!get_data (s, &packet_len, 4)) {
+	printf ("packet_len read failed\n");
+	return 0;
+      }
+      
+      packet_len = get_32 (&packet_len, 0) + 4;
+      
+//      printf ("command packet detected, len=%d\n", packet_len);
+      
+      if (!get_data (s, data, packet_len)) {
+	printf ("command data read failed\n");
+	return 0;
+      }
+      
+      command = get_32 (data, 24) & 0xFFFF;
+      
+//      printf ("command: %02x\n", command);
+      
+      if (command == 0x1b) 
+	send_command (s, 0x1b, 0, 0, 0, data);
+      
+    }
+
+//    printf ("get header packet succ\n");
+  }
+}
+
+int interp_header (uint8_t *header, int header_len) 
+{
+  int i;
+  int packet_length;
+
+  /*
+   * parse header
+   */
+
+  i = 30;
+  while (i<header_len) {
+    
+    uint64_t  guid_1, guid_2, length;
+
+    guid_2 = (uint64_t)header[i] | ((uint64_t)header[i+1]<<8) 
+      | ((uint64_t)header[i+2]<<16) | ((uint64_t)header[i+3]<<24)
+      | ((uint64_t)header[i+4]<<32) | ((uint64_t)header[i+5]<<40)
+      | ((uint64_t)header[i+6]<<48) | ((uint64_t)header[i+7]<<56);
+    i += 8;
+
+    guid_1 = (uint64_t)header[i] | ((uint64_t)header[i+1]<<8) 
+      | ((uint64_t)header[i+2]<<16) | ((uint64_t)header[i+3]<<24)
+      | ((uint64_t)header[i+4]<<32) | ((uint64_t)header[i+5]<<40)
+      | ((uint64_t)header[i+6]<<48) | ((uint64_t)header[i+7]<<56);
+    i += 8;
+    
+//    printf ("guid found: %016llx%016llx\n", guid_1, guid_2);
+
+    length = (uint64_t)header[i] | ((uint64_t)header[i+1]<<8) 
+      | ((uint64_t)header[i+2]<<16) | ((uint64_t)header[i+3]<<24)
+      | ((uint64_t)header[i+4]<<32) | ((uint64_t)header[i+5]<<40)
+      | ((uint64_t)header[i+6]<<48) | ((uint64_t)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)) {
+
+      packet_length = get_32(header, i+92-24);
+
+      printf ("file object, packet length = %d (%d)\n",
+	      packet_length, get_32(header, i+96-24));
+
+
+    } else if ((guid_1 == 0x6553200cc000e68e) && (guid_2 == 0x11cfa9b7b7dc0791)) {
+
+      int stream_id = header[i+48] | header[i+49] << 8;
+
+      printf ("stream object, stream id: %d\n", stream_id);
+
+      stream_ids[num_stream_ids] = stream_id;
+      num_stream_ids++;
+      
+    } else {
+      printf ("unknown object\n");
+    }
+
+//    printf ("length    : %lld\n", length);
+
+    i += length-24;
+
+  }
+
+  return packet_length;
+
+}
+
+
+static int get_media_packet (int s, int padding, char *buffer, int size) 
+{
+  unsigned char  pre_header[8];
+  char           data[BUF_SIZE];
+  int 		 CheckInnerData = 1;
+  int 		 CheckOuterData = 1;
+
+
+while(CheckOuterData)
+{
+	int a;
+	if(media_padding ==0 && data_length == 0)
+	{
+		while(CheckInnerData)
+		{
+			if (!get_data (s, pre_header, 8)) {
+			    printf ("pre-header read failed\n");
+			    return 0;
+  			}
+
+	 		if (pre_header[4] == 0x04) 
+			{
+    				data_length = (pre_header[7] << 8 | pre_header[6]) - 8;
+				media_padding = packet_length1 - data_length;
+				if(to_skip)
+				{
+					a =  store_data(s, size - to_skip, buffer + to_skip);
+					to_skip = 0;
+				}
+				else
+				{
+					a = store_data(s, size, buffer);	
+				}
+//				printf("a inner  %d  \n", size);
+				return size;
+  			} 
+	  		else 
+			{
+    				int command;
+				char packet_len;
+    				if (!get_data (s, &packet_len, 4)) 
+				{
+      					printf ("packet_len read failed\n");
+      					return 0;
+    				}
+	    			packet_len = get_32 (&packet_len, 0) + 4;
+	
+    				if (!get_data (s, data, 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 (data, 24) & 0xFFFF;
+	
+				if (command == 0x1b)
+    				{ 
+      					send_command (s, 0x1b, 0, 0, 0, data);
+	    			}
+    				else if (command == 0x1e) 
+				{
+      					printf ("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);
+	    			}
+  			}
+		}
+	}
+	if(to_skip)
+	{
+		a =  store_data(s, size - to_skip,  buffer+to_skip );
+		to_skip = 0;
+	}
+	else
+	{
+		a =  store_data(s, size,  buffer);
+	}
+		
+	if(a == size)
+	{
+//		printf("a outer %d", a );	
+		return a;
+	}
+	else
+		to_skip = a;
+			
+}
+
+}
+
+int
+asf_mmst_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *stream_ctrl ) 
+{
+  int len = 0;
+  if( stream_ctrl->buffer_size!=0 ) {
+	  int buffer_len = stream_ctrl->buffer_size-stream_ctrl->buffer_pos;
+	  len = (size<buffer_len)?size:buffer_len;
+	  memcpy( buffer, (stream_ctrl->buffer)+(stream_ctrl->buffer_pos), len );
+	  stream_ctrl->buffer_pos += len;
+	  if( stream_ctrl->buffer_pos>=stream_ctrl->buffer_size ) {
+		  free( stream_ctrl->buffer );
+		  stream_ctrl->buffer = NULL;
+		  stream_ctrl->buffer_size = 0;
+		  stream_ctrl->buffer_pos = 0;
+	  }
+
+  }
+
+  if( len<size ) {
+
+	  int ret;
+
+	  ret = get_media_packet( fd, size - len, buffer+len, size-len );
+
+	  if( ret<0 ) {
+
+		  printf("nop_streaming_read error : %s\n",strerror(errno));
+
+	  }
+
+	  len += ret;
+
+	  //printf("read %d bytes from network\n", len );
+
+	 }			      
+
+  return len;
+}
+
+int
+asf_mmst_streaming_seek( int fd, off_t pos, streaming_ctrl_t *streaming_ctrl ) 
+{
+	return -1;
+}
+
+int asf_mmst_streaming_start(stream_t *stream)
+{
+  char                 str[1024];
+  char                 data[1024];
+  uint8_t              asf_header[8192];
+  int                  asf_header_len;
+  int                  len, i, packet_length;
+  char                 host[256];
+  char                *path;
+  URL_t *url1 = stream->streaming_ctrl->url;
+  int s = stream->fd;
+
+  /* parse url */
+  path = strchr(url1->file,'/') + 1;
+
+  url1->port=1755;
+  s = connect2Server( url1->hostname, url1->port );
+  printf ("connected\n");
+
+  /*
+  * Send the initial connect info including player version no. Client GUID (random) and the host address being connected to. 
+  * This command is sent at the very start of protocol initiation. It sends local information to the serve 
+  * cmd 1 0x01 
+  * */
+
+  sprintf (str, "\034\003NSPlayer/7.0.0.1956; {33715801-BAB3-9D85-24E9-03B90328270A}; Host: %s", host);
+  string_utf16 (data, str, strlen(str)+2);
+// send_command(s, commandno ....)
+  send_command (s, 1, 0, 0x0004000b, strlen(str) * 2+8, data);
+
+  len = read (s, data, BUF_SIZE) ;
+
+  /*This sends details of the local machine IP address to a Funnel system at the server. 
+  * Also, the TCP or UDP transport selection is sent.
+  *
+  * here 192.168.0.129 is local ip address TCP/UDP states the tronsport we r using
+  * and 1037 is the  local TCP or UDP socket number
+  * cmd 2 0x02
+  *  */
+
+  string_utf16 (&data[8], "\002\000\\\\192.168.0.1\\TCP\\1037\0000", 
+		28);
+  memset (data, 0, 8);
+  send_command (s, 2, 0, 0, 28*2+8, data);
+
+  len = read (s, data, BUF_SIZE) ;
+
+  /* This command sends file path (at server) and file name request to the server.
+  * 0x5 */
+
+  string_utf16 (&data[8], path, strlen(path));
+  memset (data, 0, 8);
+  send_command (s, 5, 0, 0, strlen(path)*2+12, data);
+
+  get_answer (s);
+
+  /* The ASF header chunk request. Includes ?session' variable for pre header value. 
+  * After this command is sent, 
+  * the server replies with 0x11 command and then the header chunk with header data follows.
+  * 0x15 */
+
+  memset (data, 0, 40);
+  data[32] = 2;
+
+  send_command (s, 0x15, 1, 0, 40, data);
+
+  num_stream_ids = 0;
+  /* get_headers(s, asf_header);  */
+
+  asf_header_len = get_header (s, asf_header, stream->streaming_ctrl);
+//  printf("---------------------------------- asf_header %d\n",asf_header);
+  packet_length = interp_header (asf_header, asf_header_len);
+
+
+  /* 
+  * This command is the media stream MBR selector. Switches are always 6 bytes in length.  
+  * After all switch elements, data ends with bytes [00 00] 00 20 ac 40 [02]. 
+  * Where:  
+  * [00 00] shows 0x61 0x00 (on the first 33 sent) or 0xff 0xff for ASF files, and with no ending data for WMV files. 
+  * It is not yet understood what all this means. 
+  * And the last [02] byte is probably the header ?session' value. 
+  *  
+  *  0x33 */
+
+  memset (data, 0, 40);
+
+  for (i=1; i<num_stream_ids; i++) {
+    data [ (i-1) * 6 + 2 ] = 0xFF;
+    data [ (i-1) * 6 + 3 ] = 0xFF;
+    data [ (i-1) * 6 + 4 ] = stream_ids[i];
+    data [ (i-1) * 6 + 5 ] = 0x00;
+  }
+
+  send_command (s, 0x33, num_stream_ids, 0xFFFF | stream_ids[0] << 16, (num_stream_ids-1)*6+2 , data);
+
+  get_answer (s);
+
+  /* Start sending file from packet xx. 
+  * This command is also used for resume downloads or requesting a lost packet. 
+  * Also used for seeking by sending a play point value which seeks to the media time point. 
+  * Includes ?session' value in pre header and the maximum media stream time. 
+  * 0x07 */
+
+  memset (data, 0, 40);
+
+  for (i=8; i<16; i++)
+    data[i] = 0xFF;
+
+  data[20] = 0x04;
+
+  send_command (s, 0x07, 1, 0xFFFF | stream_ids[0] << 16, 24, data);
+
+
+	stream->fd = s;
+		stream->streaming_ctrl->streaming_read = asf_mmst_streaming_read;
+		stream->streaming_ctrl->streaming_seek = asf_mmst_streaming_seek;
+		stream->streaming_ctrl->buffering = 1;
+
+	stream->streaming_ctrl->status = streaming_playing_e;
+	stream->streaming_ctrl->buffering = 1;
+
+      	packet_length1 = packet_length;
+
+  return 0;
+}