[MPlayer-dev-eng] MMS support in mplayer begun

Derek J Witt djw at flinthills.com
Thu Dec 6 10:21:02 CET 2001


Hi, all. I have started on MMS support in mplayer.  I have it at least
connecting to TCP MMS streams.  I have included the patch. For some
reason, if I try using "cvs rdiff 120601 main", I keep getting a whole
messful of parsed_root_directory errors. So,  I  was only able to run
"cvs diff -NR" to get a file. I had to edit the file to get a proper
patch file. But, it didn't include the new file I put in. 

So, I have included both the patch and the new file.  I do have my test
mms stream being connected.  I do send it the correct header. I have yet
to get it to start the actual data packets. But, it should not affect
anything else in mplayer. Let me know what you think.

Thanks.

-- 
**  Derek J Witt                                              **
*   Email: mailto:djw at flinthills.com                           *
*   Home Page: http://www.flinthills.com/~djw/                 *
*** "...and on the eighth day, God met Bill Gates." - Unknown **
-------------- next part --------------
--- libmpdemux/Makefile	24 Nov 2001 23:58:12 -0000	1.11
+++ libmpdemux/Makefile	6 Dec 2001 09:24:13 -0000
@@ -5,7 +5,7 @@
 
 SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c aviwrite.c demux_asf.c demux_avi.c demux_mov.c demux_mpg.c demux_viv.c demuxer.c dvdauth.c open.c parse_es.c stream.c tv.c tvi_dummy.c tvi_v4l.c frequencies.c demux_fli.c
 ifeq ($(STREAMING),yes)
-SRCS += asf_streaming.c url.c http.c network.c
+SRCS += asf_streaming.c url.c http.c network.c asf_helper.c
 endif
 
 OBJS	= $(SRCS:.c=.o)
--- libmpdemux/asf_streaming.c	20 Nov 2001 22:20:20 -0000	1.9
+++ libmpdemux/asf_streaming.c	6 Dec 2001 09:24:14 -0000
@@ -9,7 +9,7 @@
 #include "http.h"
 #include "asf.h"
 #include "network.h"
-
+#include "mmst.h"
 #include "stream.h"
 
 static ASF_StreamType_e streaming_type = ASF_Unknown_e;
@@ -20,6 +20,8 @@
 // So for now, we use the HTTP protocol.
 int
 asf_streaming_start( stream_t *stream ) {
+	printf("This ASF network stream uses %s protocol\n", stream->streaming_ctrl->url->protocol);
+
 	return asf_http_streaming_start( stream );	
 }
 
@@ -269,23 +271,73 @@
 	int i;
 	int fd = stream->fd;
 	int done=1;
+	unsigned int MMSCSeq = 0;
+
+	streaming_type = ASF_Live_e;
 
-streaming_type = ASF_Live_e;
 	do {
 		if( fd>0 ) close( fd );
 
 		fd = connect2Server( url->hostname, url->port );
 		if( fd<0 ) return -1;
 
+		/* START - MMS (TCP/IP) support based on ASFRecorder+ by an anonymous author.
+		 * Adapted to MPlayer by Derek J Witt <djw at flinthills.com>.
+		 * -- Started on 6 December 2001 at 1:06 am CST.
+		 */
+
+		if (strcasecmp(url->protocol, "mms") == 0) {
+			// First, we have to send out the header when we
+			// connect to the MMS server.
+			char GUID[] = "{c77e7400-738a-11d2-9add-0020af0a3278}";
+			char *BufPtr;
+			unsigned int MMSCSize;
+
+                        BufPtr = buffer; /* Send Initial Request */
+                        BufPtr += my_sprintf(BufPtr, MMSC_HEADER, sizeof(MMSC_HEADER));
+                        BufPtr += my_sprintf(BufPtr, MMSC_REQUEST_INIT, sizeof(MMSC_REQUEST_INIT));
+                        BufPtr += my_swprintf(BufPtr, "NSPlayer/6.4.0.3845; ", 0);
+                        BufPtr += my_swprintf(BufPtr, GUID, 0);
+                        BufPtr += my_swprintf(BufPtr, "\0", 1);
+
+			MMSCSize=(int)BufPtr-(int)buffer; 
+
+			if(MMSCSize%8) 
+				MMSCSize+=8-MMSCSize%8; 
+
+			put_long(buffer+MMSC_POS_SIZE, MMSCSize-0x10);
+                        put_long(buffer+MMSC_POS_SEQ, MMSCSeq++);
+	
+
+			write( fd, buffer, MMSCSize);
+			i = read( fd, buffer, BUFFER_SIZE );
+			my_hex_printf(buffer, i);
+		} else 
+			/* END - MMS (TCP/IP) support. */
+
+			{
 		http_hdr = asf_http_request( url );
-printf("Request [%s]\n", http_hdr->buffer );
+			printf("Request [%s]\n", http_hdr->buffer );
 		write( fd, http_hdr->buffer, http_hdr->buffer_size );
 		http_free( http_hdr );
 
+			i = read( fd, buffer, BUFFER_SIZE );
+
+			//printf("read: %d bytes:\t", i);
+
+			//my_hex_printf(buffer, i);
+		}
+
 		http_hdr = http_new_header();
 		do {
 			i = read( fd, buffer, BUFFER_SIZE );
-printf("read: %d\n", i );
+
+			//printf("read: %d bytes\n", i);
+			
+			//my_hex_printf(buffer, i);
+		       
+			//if (i == 0) break;
+
 			if( i<0 ) {
 				perror("read");
 				http_free( http_hdr );
--- libmpdemux/network.c	22 Nov 2001 17:14:26 -0000	1.11
+++ libmpdemux/network.c	6 Dec 2001 09:24:14 -0000
@@ -32,6 +32,7 @@
 #include "network.h"
 #include "http.h"
 #include "url.h"
+//#include "mmst.h"
 #include "asf.h"
 
 static struct {
@@ -245,7 +246,11 @@
 
 		// Checking for ASF
 		if( !strcasecmp(url->protocol, "mms") ) {
-			if( url->port==0 ) url->port = 80;
+
+			// START - Derek J Witt, djw at flinthills.com
+			if( url->port==0 ) url->port = 1755;
+			// END - Derek J Witt, djw at flinthills.com
+			//			printf("[%s]\n", MMSC_REQUEST_INIT);
 			return DEMUXER_TYPE_ASF;
 		}
 
--- libmpdemux/open.c	1 Dec 2001 23:40:24 -0000	1.26
+++ libmpdemux/open.c	6 Dec 2001 09:24:14 -0000
@@ -381,7 +381,7 @@
         //if(f<0){ mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_UnableOpenURL, url->url); return NULL; }
         mp_msg(MSGT_OPEN,MSGL_INFO,MSGTR_ConnToServer, url->hostname );
         stream=new_stream(f,STREAMTYPE_STREAM);
-	if( streaming_start( stream , url, *file_format )<0){
+	if( streaming_start( &stream , url, *file_format )<0){
           mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_UnableOpenURL, filename);
           url_free(url);
 	  return NULL;
-------------- next part --------------
/*
 * Some helper functions needed for the MMS protocol.
 * Adapted from ASFRecorder+ (originally written by an anonymous author (http://yaan2.linux.net.cn)
 * Adapted by Derek J Witt <djw at flinthills.com> on 6 December 2001.
 */
#include <stdio.h>
#include <stdlib.h>


/* get 64bit integer (Little endian) */
void get_quad(unsigned char *pos, unsigned int *hi, unsigned int *lo)
{
	unsigned char c1 = *pos++, c2 = *pos++, c3 = *pos++, c4 = *pos++;
	unsigned char c5 = *pos++, c6 = *pos++, c7 = *pos++, c8 = *pos++;
	(*hi) = (c8<<24) + (c7<<16) + (c6<<8) + c5;
	(*lo) = (c4<<24) + (c3<<16) + (c2<<8) + c1;
}

/* write 64bit integer to stream (Little endian) */
void write_quad(FILE *outfile, unsigned int hi, unsigned int lo)
{
	unsigned char c1 = (lo & 0xff), c2 = ((lo>>8) & 0xff), c3 = ((lo>>16) & 0xff), c4 = ((lo>>24) & 0xff);
	unsigned char c5 = (hi & 0xff), c6 = ((hi>>8) & 0xff), c7 = ((hi>>16) & 0xff), c8 = ((hi>>24) & 0xff);
	fputc(c1, outfile);
	fputc(c2, outfile);
	fputc(c3, outfile);
	fputc(c4, outfile);
	fputc(c5, outfile);
	fputc(c6, outfile);
	fputc(c7, outfile);
	fputc(c8, outfile);
}

/* get 32bit integer (Little endian) */
void get_long(unsigned char *pos, unsigned int *val)
{
	unsigned char c1 = *pos++, c2 = *pos++, c3 = *pos++, c4 = *pos++;
	(*val) = (c4<<24) + (c3<<16) + (c2<<8) + c1;
}

/* put 32 bit integer (Little endian) */
void put_long(unsigned char *pos, unsigned int val)
{
	*pos++ = (val & 0xff);
	*pos++ = ((val>>8) & 0xff), *pos++ = ((val>>16) & 0xff), *pos++ = ((val>>24) & 0xff);
}

/* write a 32 bit integer to stream (Little endian) */
void write_long(FILE *outfile, unsigned int val)
{
	unsigned char c1 = (val & 0xff), c2 = ((val>>8) & 0xff), c3 = ((val>>16) & 0xff), c4 = ((val>>24) & 0xff);
	fputc(c1, outfile);
	fputc(c2, outfile);
	fputc(c3, outfile);
	fputc(c4, outfile);
}

/* get short integer (Little endian) */
void get_short(unsigned char *pos, unsigned short *val)
{
	unsigned char c1 = *pos++, c2 = *pos++;
	(*val) = (c2<<8) + c1;
}

/* write a 32 bit integer to stream (Little endian) */
void write_short(FILE *outfile, unsigned short val)
{
	unsigned char c1 = (val & 0xff), c2 = ((val>>8) & 0xff);
	fputc(c1, outfile);
	fputc(c2, outfile);
}

/* 64 bit subtraction with unsigned integers */
void quad_subtraction(unsigned int *dst_hi, unsigned int *dst_lo, unsigned int hi, unsigned int lo)
{
	unsigned int tmp;

	*dst_hi -= hi;

	tmp = *dst_lo;
	*dst_lo -= lo;

	/* handle "carry bit" */
	if (*dst_lo > tmp) (*dst_hi)--;
}

/* timecode helper functions */
/* get position of timecode in chunk (-1 if unknown) */
int whereis_timecode(unsigned char *Buffer)
{
	int tc_start = -1;
	/* timecode position varies with type of chunk */
	switch(Buffer[3])
	{
		case 0x00:	tc_start =  5;	break;
		case 0x01:	tc_start =  5;	break;
		case 0x08:	tc_start =  6;	break;
		case 0x09:	tc_start =  6;	break;
		case 0x10:	tc_start =  7;	break;
		case 0x11:	tc_start =  7;	break;
		case 0x48:	tc_start =  8;	break;
		case 0x49:	tc_start =  8;	break;
		case 0x50:	tc_start =  9;	break;
		case 0x51:	tc_start =  9;	break;
	default:	tc_start = -1;	//gui_showstatus(STATUS_ERROR, "unknown format type: $%02x\n", (int)Buffer[3]);
	}
	return tc_start;
}

/* Create a randomized GUID string to avoid filtering ASFRecorder's */
/* stream requests by means of detecting any hardcoded GUIDs */
void randomize_guid(unsigned char *buf)
{
	int digit, dig;
	time_t curtime;

	*buf++='{';
	time(&curtime);
	srand(curtime);
	for (digit=0; digit <32; digit++)
	{
		if (digit==8 || digit == 12 || digit == 16 || digit == 20) *buf++='-';
		dig = rand()%0xf;
		if (dig<10)
			*buf++='0'+dig;
		else
			*buf++='A'+(dig-10);
	}
	*buf++='}';
	*buf++='\0';
}

/* create a timecode string from a timecode in milliseconds */
char *createtimestring(unsigned int timecode)
{
	static char timecodestring[64];

	if (timecode/1000 >= 24*3600)
		sprintf(timecodestring, "%d:%02d:%02d:%02d.%03d", (timecode/1000)/(24*3600), ((timecode/1000)/3600)%24, ((timecode/1000)/60)%60, (timecode/1000)%60, timecode%1000);
	else
		if (timecode/1000 >= 3600)
			sprintf(timecodestring, "%d:%02d:%02d.%03d", (timecode/1000)/3600, ((timecode/1000)/60)%60, (timecode/1000)%60, timecode%1000);
		else
			if (timecode/1000 >= 60)
				sprintf(timecodestring, "%d:%02d.%03d", (timecode/1000)/60, (timecode/1000)%60, timecode%1000);
			else
				sprintf(timecodestring, "%d.%03d", (timecode/1000)%60, timecode%1000);
	return timecodestring;
}

/* subroutine for base64 encoding (used in HTTP Basic authentification) */
int base64enc(char *data,char *out)
{
	char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
	int len = strlen(data);
	int i,index;
	int val;

	for (i=0, index=0; i<len; i+=3, index+=4)
	{
		int quad = 0;
		int trip = 0;

		val = (0xff & data[i]);
		val <<= 8;
		if ((i+1) < len) {
			val |= (0xff & data[i+1]);
			trip = 1;
		}
		val <<= 8;
		if ((i+2) < len) {
			val |= (0xff & data[i+2]);
			quad = 1;
		}
		out[index+3] = alphabet[(quad? (val & 0x3f): 64)];
		val >>= 6;
		out[index+2] = alphabet[(trip? (val & 0x3f): 64)];
		val >>= 6;
		out[index+1] = alphabet[val & 0x3f];
		val >>= 6;
		out[index+0] = alphabet[val & 0x3f];
	}

	out[++index] = 0;
	return index;
}

/* helper routine for ASF header parsing */
int find_id(unsigned char *id, unsigned char *Buffer, int bufsize)
{
	int offs, i, found;
	for (offs = 0; offs < bufsize-16; offs++) {
		found=1;
		for (i=0; i<16; i++) if (Buffer[offs+i] != id[i]) {
			found = 0;
			break;
		}
		if (found) return(offs);
	}
	return -1;
}

/* These routines are used to parse the packet and find */
/* and modify timecodes for live streams */
unsigned int get_data(unsigned char **bp, unsigned int type)
{
	unsigned int res = 0;
	switch (type) {
	case 0:
		break;
	case 1:
		res = *(*bp+0);
		*bp+=1;
		break;
	case 2:
		res = *(*bp+0) + (*(*bp+1) << 8);
		*bp+=2;
		break;
	case 3:
		res = *(*bp+0) + (*(*bp+1) << 8) + (*(*bp+2) << 16) + (*(*bp+3) << 24);
		*bp+=4;
		break;
	default:
		//gui_showstatus(STATUS_CRITICALERROR, "unknown format type %d\n", type);
		break;
	}
	return res;
}

/* Replace specific characters in the URL string by an escape sequence */
/* works like strcpy(), but without return argument */
void escape_url_string(char *outbuf, char *inbuf)
{
	unsigned char c;
	do
	    {
		c = *inbuf++;

		if ((c >= 'A' && c <= 'Z') ||
		    (c >= 'a' && c <= 'z') ||
	   		(c >= '0' && c <= '9') ||
			(c >= 0x7f) ||										/* fareast languages(Chinese, Korean, Japanese) */
			c=='-' || c=='_'  || c=='.' || c=='!' || c=='~'  || /* mark characters */
			c=='*' || c=='\'' || c=='(' || c==')' || c=='%'  || /* do not touch escape character */
			c==';' || c=='/'  || c=='?' || c==':' || c=='@'  || /* reserved characters */
			c=='&' || c=='='  || c=='+' || c=='$' || c==','  || /* see RFC 2396 */
			c=='\0' )
		{
			*outbuf++ = c;
		}
		else
		    {
			/* all others will be escaped */
			unsigned char c1 = ((c & 0xf0) >> 4);
			unsigned char c2 =  (c & 0x0f);
			if (c1 < 10) c1+='0';
			else c1+='A';
			if (c2 < 10) c2+='0';
			else c2+='A';
			*outbuf++ = '%';
			*outbuf++ = c1;
			*outbuf++ = c2;
		}
	}
	while (c != '\0');
}


int my_sprintf(unsigned char *pos, unsigned char *CWord, int number)
{
	if(number==0) number = strlen(CWord);
	memcpy(pos, CWord, number);
	return number;
}

int my_swprintf(unsigned char *pos, unsigned char *CWord, int number)
{
	int i, count;
	unsigned short *SWord;
	if(number==0) number = strlen(CWord);
	SWord = malloc(number*2);
	for(i=0, count=0 ; i<number ; i++)
	{
		if((CWord[i] > 0x7f) && (CWord[i+1] > 0x7f))
		{
			SWord[count++] = CWord[i+1]*256 + CWord[i];
			i++;
		}
		else
		{
			SWord[count++] = CWord[i];
		}
	}
	memcpy(pos, SWord, count*2);
	free(SWord);
	//count = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, CWord, number, pos, number);
	return count*2;
}

void my_hex_printf(unsigned char *buffer, unsigned int length) {
	int i;

	printf("Hex:\n");
	for (i = 0; i < length; i++)
		printf("%2x ", buffer[i]);
	printf("\n");

	printf("ASCII:\n");

	for (i = 0; i < length; i++)
		printf("%c", buffer[i]);

	printf("\n");
}

	


More information about the MPlayer-dev-eng mailing list