Re: [PATCH] ported mms from main

Fabian Franz <[email protected]>
Newsgroups gmane.comp.video.mplayer.g2.devel
Message-ID <[email protected]>
Am Montag, 26. Mai 2003 01:54 schrieb Arpi:
> Hi,
>
> > here it is.
>
> cool!
>
> btw it doesn't compile, could you send complete diff to pre30?

of course :)

> it includes asf.h, but the one in g2 doesn't work (missing defines).

yeah... sorry forgot that. 

> also the stream_priv_s is nowhere defined, but is used.

huh ? it is defined in stream.h isn't it ?

cu

Fabian
>
>
> A'rpi / Astral & ESP-team
>
> --
> Developer of MPlayer G2, the Movie Framework for all -
> http://www.MPlayerHQ.hu
>
> _______________________________________________
> MPlayer-G2-dev mailing list
> [email protected]
> http://mplayerhq.hu/mailman/listinfo/mplayer-g2-dev

_______________________________________________
MPlayer-G2-dev mailing list
[email protected]
http://mplayerhq.hu/mailman/listinfo/mplayer-g2-dev
g2-mms-support.diff (text/x-diff, 30.6 KB)
diff -Nur g2.pre30/stream/asf.h g2/stream/asf.h
--- g2.pre30/stream/asf.h	1970-01-01 01:00:00.000000000 +0100
+++ g2/stream/asf.h	2003-05-26 00:41:58.000000000 +0200
@@ -0,0 +1,215 @@
+#ifndef __ASF_H
+#define __ASF_H
+
+//#include "config.h"	/* for WORDS_BIGENDIAN */
+#include <inttypes.h>
+#include "../bswap.h"
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+///////////////////////
+// MS GUID definition
+///////////////////////
+#ifndef GUID_DEFINED
+#define GUID_DEFINED
+// Size of GUID is 16 bytes!
+typedef struct __attribute__((packed)) {
+	uint32_t	Data1;		// 4 bytes
+	uint16_t	Data2;		// 2 bytes
+	uint16_t	Data3;		// 2 bytes
+	uint8_t		Data4[8];	// 8 bytes
+} GUID_t;
+#endif
+
+///////////////////////
+// ASF Object Header 
+///////////////////////
+typedef struct __attribute__((packed)) {
+  uint8_t guid[16];
+  uint64_t size;
+} ASF_obj_header_t;
+
+////////////////
+// ASF Header 
+////////////////
+typedef struct __attribute__((packed)) {
+  ASF_obj_header_t objh;
+  uint32_t cno; // number of subchunks
+  uint8_t v1; // unknown (0x01)
+  uint8_t v2; // unknown (0x02)
+} ASF_header_t;
+
+/////////////////////
+// ASF File Header 
+/////////////////////
+typedef struct __attribute__((packed)) {
+  uint8_t stream_id[16]; // stream GUID
+  uint64_t file_size;
+  uint64_t creation_time; //File creation time FILETIME 8
+  uint64_t num_packets;    //Number of packets UINT64 8
+  uint64_t play_duration; //Timestamp of the end position UINT64 8
+  uint64_t send_duration;  //Duration of the playback UINT64 8
+  uint64_t preroll; //Time to bufferize before playing UINT32 4
+  uint32_t flags; //Unknown, maybe flags ( usually contains 2 ) UINT32 4
+  uint32_t min_packet_size; //Min size of the packet, in bytes UINT32 4
+  uint32_t max_packet_size; //Max size of the packet  UINT32 4
+  uint32_t max_bitrate; //Maximum bitrate of the media (sum of all the stream)
+} ASF_file_header_t;
+
+///////////////////////
+// ASF Stream Header
+///////////////////////
+typedef struct __attribute__((packed)) {
+  uint8_t type[16]; // Stream type (audio/video) GUID 16
+  uint8_t concealment[16]; // Audio error concealment type GUID 16
+  uint64_t unk1; // Unknown, maybe reserved ( usually contains 0 ) UINT64 8
+  uint32_t type_size; //Total size of type-specific data UINT32 4
+  uint32_t stream_size; //Size of stream-specific data UINT32 4
+  uint16_t stream_no; //Stream number UINT16 2
+  uint32_t unk2; //Unknown UINT32 4
+} ASF_stream_header_t;
+
+///////////////////////////
+// ASF Content Description
+///////////////////////////
+typedef struct  __attribute__((packed)) {
+  uint16_t title_size;
+  uint16_t author_size;
+  uint16_t copyright_size;
+  uint16_t comment_size;
+  uint16_t rating_size;
+} ASF_content_description_t;
+
+////////////////////////
+// ASF Segment Header 
+////////////////////////
+typedef struct __attribute__((packed)) {
+  uint8_t streamno;
+  uint8_t seq;
+  uint32_t x;
+  uint8_t flag;
+} ASF_segmhdr_t;
+
+//////////////////////
+// ASF Stream Chunck
+//////////////////////
+typedef struct __attribute__((packed)) {
+	uint16_t	type;
+	uint16_t	size;
+	uint32_t	sequence_number;
+	uint16_t	unknown;
+	uint16_t	size_confirm;
+} ASF_stream_chunck_t;
+
+// Definition of the stream type
+#ifdef WORDS_BIGENDIAN
+	#define ASF_STREAMING_CLEAR	0x2443		// $C
+	#define ASF_STREAMING_DATA	0x2444		// $D
+	#define ASF_STREAMING_END_TRANS	0x2445		// $E
+	#define	ASF_STREAMING_HEADER	0x2448		// $H
+#else
+	#define ASF_STREAMING_CLEAR	0x4324		// $C
+	#define ASF_STREAMING_DATA	0x4424		// $D
+	#define ASF_STREAMING_END_TRANS	0x4524		// $E
+	#define	ASF_STREAMING_HEADER	0x4824		// $H
+#endif
+
+// Definition of the differents type of ASF streaming
+typedef enum {
+	ASF_Unknown_e,
+	ASF_Live_e,
+	ASF_Prerecorded_e,
+	ASF_Redirector_e,
+	ASF_PlainText_e,
+	ASF_Authenticate_e
+} ASF_StreamType_e;
+
+typedef struct stream_priv_s {
+	ASF_StreamType_e streaming_type;
+	int request;
+	int packet_size;
+	int *audio_streams,n_audio,*video_streams,n_video;
+	int audio_id, video_id;
+} asf_http_streaming_ctrl_t;
+
+
+/*
+ * Some macros to swap little endian structures read from an ASF file
+ * into machine endian format
+ */
+#ifdef WORDS_BIGENDIAN
+#define	le2me_ASF_obj_header_t(h) {					\
+    (h)->size = le2me_64((h)->size);					\
+}
+#define	le2me_ASF_header_t(h) {						\
+    le2me_ASF_obj_header_t(&(h)->objh);					\
+    (h)->cno = le2me_32((h)->cno);					\
+}
+#define le2me_ASF_stream_header_t(h) {					\
+    (h)->unk1 = le2me_64((h)->unk1);					\
+    (h)->type_size = le2me_32((h)->type_size);				\
+    (h)->stream_size = le2me_32((h)->stream_size);			\
+    (h)->stream_no = le2me_16((h)->stream_no);				\
+    (h)->unk2 = le2me_32((h)->unk2);					\
+}
+#define le2me_ASF_file_header_t(h) {					\
+    (h)->file_size = le2me_64((h)->file_size);				\
+    (h)->creation_time = le2me_64((h)->creation_time);			\
+    (h)->num_packets = le2me_64((h)->num_packets);			\
+    (h)->play_duration = le2me_64((h)->play_duration);			\
+    (h)->send_duration = le2me_64((h)->send_duration);			\
+    (h)->preroll = le2me_64((h)->preroll);				\
+    (h)->flags = le2me_32((h)->flags);					\
+    (h)->min_packet_size = le2me_32((h)->min_packet_size);		\
+    (h)->max_packet_size = le2me_32((h)->max_packet_size);		\
+    (h)->max_bitrate = le2me_32((h)->max_bitrate);			\
+}
+#define le2me_ASF_content_description_t(h) {				\
+    (h)->title_size = le2me_16((h)->title_size);			\
+    (h)->author_size = le2me_16((h)->author_size);			\
+    (h)->copyright_size = le2me_16((h)->copyright_size);		\
+    (h)->comment_size = le2me_16((h)->comment_size);			\
+    (h)->rating_size = le2me_16((h)->rating_size);			\
+}
+#define le2me_BITMAPINFOHEADER(h) {					\
+    (h)->biSize = le2me_32((h)->biSize);				\
+    (h)->biWidth = le2me_32((h)->biWidth);				\
+    (h)->biHeight = le2me_32((h)->biHeight);				\
+    (h)->biPlanes = le2me_16((h)->biPlanes);				\
+    (h)->biBitCount = le2me_16((h)->biBitCount);			\
+    (h)->biCompression = le2me_32((h)->biCompression);			\
+    (h)->biSizeImage = le2me_32((h)->biSizeImage);			\
+    (h)->biXPelsPerMeter = le2me_32((h)->biXPelsPerMeter);		\
+    (h)->biYPelsPerMeter = le2me_32((h)->biYPelsPerMeter);		\
+    (h)->biClrUsed = le2me_32((h)->biClrUsed);				\
+    (h)->biClrImportant = le2me_32((h)->biClrImportant);		\
+}
+#define le2me_WAVEFORMATEX(h) {						\
+    (h)->wFormatTag = le2me_16((h)->wFormatTag);			\
+    (h)->nChannels = le2me_16((h)->nChannels);				\
+    (h)->nSamplesPerSec = le2me_32((h)->nSamplesPerSec);		\
+    (h)->nAvgBytesPerSec = le2me_32((h)->nAvgBytesPerSec);		\
+    (h)->nBlockAlign = le2me_16((h)->nBlockAlign);			\
+    (h)->wBitsPerSample = le2me_16((h)->wBitsPerSample);		\
+    (h)->cbSize = le2me_16((h)->cbSize);				\
+}
+#define le2me_ASF_stream_chunck_t(h) {					\
+    (h)->size = le2me_16((h)->size);					\
+    (h)->sequence_number = le2me_32((h)->sequence_number);		\
+    (h)->unknown = le2me_16((h)->unknown);				\
+    (h)->size_confirm = le2me_16((h)->size_confirm);			\
+}
+#else
+#define	le2me_ASF_obj_header_t(h)	/**/
+#define	le2me_ASF_header_t(h)		/**/
+#define le2me_ASF_stream_header_t(h)	/**/
+#define le2me_ASF_file_header_t(h)	/**/
+#define le2me_ASF_content_description_t(h) /**/
+#define le2me_BITMAPINFOHEADER(h)   /**/
+#define le2me_WAVEFORMATEX(h)	    /**/
+#define le2me_ASF_stream_chunck_t(h) /**/
+#endif
+
+#endif
diff -Nur g2.pre30/stream/Makefile g2/stream/Makefile
--- g2.pre30/stream/Makefile	2003-05-25 14:52:10.000000000 +0200
+++ g2/stream/Makefile	2003-05-26 00:41:03.000000000 +0200
@@ -3,7 +3,7 @@
 
 include ../config.mak
 
-SRCS = stream.c cache2.c url.c stream_dvd.c stream_vcd.c stream_cdda.c stream_smb.c stream_cue.c
+SRCS = stream.c cache2.c url.c stream_dvd.c stream_vcd.c stream_cdda.c stream_smb.c stream_cue.c stream_mms.c
 
 ifeq ($(STREAMING),yes)
 SRCS += http.c network.c stream_http.c stream_pnm.c pnm.c stream_mmst.c rtp.c stream_rtp.c
diff -Nur g2.pre30/stream/network.h g2/stream/network.h
--- g2.pre30/stream/network.h	2003-03-30 23:13:42.000000000 +0200
+++ g2/stream/network.h	2003-05-26 00:43:34.000000000 +0200
@@ -19,6 +19,8 @@
 #include "http.h"
 #include "stream.h"
 
+#define BUFFER_SIZE             2048
+
 typedef enum {
 	streaming_stopped_e,
 	streaming_playing_e
diff -Nur g2.pre30/stream/stream.c g2/stream/stream.c
--- g2.pre30/stream/stream.c	2003-05-25 14:51:51.000000000 +0200
+++ g2/stream/stream.c	2003-05-26 00:41:18.000000000 +0200
@@ -30,6 +30,7 @@
 extern stream_driver_t stream_driver_cdda;
 extern stream_driver_t stream_driver_pnm;
 extern stream_driver_t stream_driver_mmst;
+extern stream_driver_t stream_driver_mms;
 extern stream_driver_t stream_driver_rtp;
 extern stream_driver_t stream_driver_smb;
 extern stream_driver_t stream_driver_cue;
@@ -52,6 +53,7 @@
     &stream_driver_http,
     &stream_driver_pnm,
     &stream_driver_mmst,
+    &stream_driver_mms,
     &stream_driver_rtp,
 #endif
     NULL
diff -Nur g2.pre30/stream/stream_mms.c g2/stream/stream_mms.c
--- g2.pre30/stream/stream_mms.c	1970-01-01 01:00:00.000000000 +0100
+++ g2/stream/stream_mms.c	2003-05-26 01:15:49.000000000 +0200
@@ -0,0 +1,701 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "../config.h"
+#include "../mp_msg.h"
+
+#include "asf.h"
+
+#include "stream.h"
+
+#include "network.h"
+
+#ifdef ARCH_X86
+#define	ASF_LOAD_GUID_PREFIX(guid)	(*(uint32_t *)(guid))
+#else
+#define	ASF_LOAD_GUID_PREFIX(guid)	\
+	((guid)[3] << 24 | (guid)[2] << 16 | (guid)[1] << 8 | (guid)[0])
+#endif
+
+extern int verbose;
+static int bandwidth=0; // FF: Define as not static ?
+
+static int 
+asf_streaming(ASF_stream_chunck_t *stream_chunck, int *drop_packet ) {
+/*	
+printf("ASF stream chunck size=%d\n", stream_chunck->size);
+printf("length: %d\n", length );
+printf("0x%02X\n", stream_chunck->type );
+*/
+	if( drop_packet!=NULL ) *drop_packet = 0;
+
+	if( stream_chunck->size<8 ) {
+		mp_msg(MSGT_NETWORK,MSGL_ERR,"Ahhhh, stream_chunck size is too small: %d\n", stream_chunck->size);
+		return -1;
+	}
+	if( stream_chunck->size!=stream_chunck->size_confirm ) {
+		mp_msg(MSGT_NETWORK,MSGL_ERR,"size_confirm mismatch!: %d %d\n", stream_chunck->size, stream_chunck->size_confirm);
+		return -1;
+	}
+/*	
+	printf("  type: 0x%02X\n", stream_chunck->type );
+	printf("  size: %d (0x%02X)\n", stream_chunck->size, stream_chunck->size );
+	printf("  sequence_number: 0x%04X\n", stream_chunck->sequence_number );
+	printf("  unknown: 0x%02X\n", stream_chunck->unknown );
+	printf("  size_confirm: 0x%02X\n", stream_chunck->size_confirm );
+*/
+	switch(stream_chunck->type) {
+		case ASF_STREAMING_CLEAR:	// $C	Clear ASF configuration
+			mp_msg(MSGT_NETWORK,MSGL_V,"=====> Clearing ASF stream configuration!\n");
+			if( drop_packet!=NULL ) *drop_packet = 1;
+			return stream_chunck->size;
+			break;
+		case ASF_STREAMING_DATA:	// $D	Data follows
+//			printf("=====> Data follows\n");
+			break;
+		case ASF_STREAMING_END_TRANS:	// $E	Transfer complete
+			mp_msg(MSGT_NETWORK,MSGL_V,"=====> Transfer complete\n");
+			if( drop_packet!=NULL ) *drop_packet = 1;
+			return stream_chunck->size;
+			break;
+		case ASF_STREAMING_HEADER:	// $H	ASF header chunk follows
+			mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF header chunk follows\n");
+			break;
+		default:
+			mp_msg(MSGT_NETWORK,MSGL_V,"=====> Unknown stream type 0x%x\n", stream_chunck->type );
+	}
+	return stream_chunck->size+4;
+}
+
+static int
+asf_streaming_parse_header(int fd, stream_t* stream) {
+  ASF_header_t asfh;
+  ASF_obj_header_t objh;
+  ASF_file_header_t fileh;
+  ASF_stream_header_t streamh;
+  ASF_stream_chunck_t chunk;
+  asf_http_streaming_ctrl_t* asf_ctrl = stream->priv;
+  char* buffer=NULL, *chunk_buffer=NULL;
+  int i,r,size,pos = 0;
+  int buffer_size = 0;
+  int chunk_size2read = 0;
+  
+  if(asf_ctrl == NULL) return -1;
+
+	// The ASF header can be in several network chunks. For example if the content description
+	// is big, the ASF header will be split in 2 network chunk.
+	// So we need to retrieve all the chunk before starting to parse the header.
+  do {
+	  for( r=0; r < (int)sizeof(ASF_stream_chunck_t) ; ) {
+		i = read(fd,((char*)&chunk)+r,sizeof(ASF_stream_chunck_t) - r);
+		if(i <= 0) return -1;
+		r += i;
+	  }
+	  // Endian handling of the stream chunk
+	  le2me_ASF_stream_chunck_t(&chunk);
+	  size = asf_streaming( &chunk, &r) - sizeof(ASF_stream_chunck_t);
+	  if(r) mp_msg(MSGT_NETWORK,MSGL_WARN,"Warning : drop header ????\n");
+	  if(size < 0){
+	    mp_msg(MSGT_NETWORK,MSGL_ERR,"Error while parsing chunk header\n");
+		return -1;
+	  }
+	  if (chunk.type != ASF_STREAMING_HEADER) {
+	    mp_msg(MSGT_NETWORK,MSGL_ERR,"Don't got a header as first chunk !!!!\n");
+	    return -1;
+	  }
+	  
+	  buffer = (char*) malloc(size+buffer_size);
+	  if(buffer == NULL) {
+	    mp_msg(MSGT_NETWORK,MSGL_FATAL,"Error can't allocate %d bytes buffer\n",size+buffer_size);
+	    return -1;
+	  }
+	  if( chunk_buffer!=NULL ) {
+	  	memcpy( buffer, chunk_buffer, buffer_size );
+		free( chunk_buffer );
+	  }
+	  chunk_buffer = buffer;
+	  buffer += buffer_size;
+	  buffer_size += size;
+	  
+	  for(r = 0; r < size;) {
+	    i = read(fd,buffer+r,size-r);
+	    if(i < 0) {
+		    mp_msg(MSGT_NETWORK,MSGL_ERR,"Error while reading network stream\n");
+		    return -1;
+	    }
+	    r += i;
+	  }  
+
+	  if( chunk_size2read==0 ) {
+		if(size < (int)sizeof(asfh)) {
+		    mp_msg(MSGT_NETWORK,MSGL_ERR,"Error chunk is too small\n");
+		    return -1;
+		} else mp_msg(MSGT_NETWORK,MSGL_DBG2,"Got chunk\n");
+	  	memcpy(&asfh,buffer,sizeof(asfh));
+	  	le2me_ASF_header_t(&asfh);
+		chunk_size2read = asfh.objh.size;
+		mp_msg(MSGT_NETWORK,MSGL_DBG2,"Size 2 read=%d\n", chunk_size2read);
+	  }
+  } while( buffer_size<chunk_size2read);
+  buffer = chunk_buffer;
+  size = buffer_size;
+	  
+  if(asfh.cno > 256) {
+    mp_msg(MSGT_NETWORK,MSGL_ERR,"Error sub chunks number is invalid\n");
+    return -1;
+  }
+
+  pos += sizeof(asfh);
+  
+  while(size - pos >= (int)sizeof(objh)) {
+    memcpy(&objh,buffer+pos,sizeof(objh));
+    le2me_ASF_obj_header_t(&objh);
+
+    switch(ASF_LOAD_GUID_PREFIX(objh.guid)) {
+    case 0x8CABDCA1 : // File header
+      pos += sizeof(objh);
+      memcpy(&fileh,buffer + pos,sizeof(fileh));
+      le2me_ASF_file_header_t(&fileh);
+/*
+      if(fileh.packetsize != fileh.packetsize2) {
+	printf("Error packetsize check don't match\n");
+	return -1;
+      }
+*/
+      asf_ctrl->packet_size = fileh.max_packet_size;
+      // before playing. 
+      // preroll: time in ms to bufferize before playing
+      //streaming_ctrl->prebuffer_size = (unsigned int)((double)((double)fileh.preroll/1000)*((double)fileh.max_bitrate/8)); // FIXME: Outcommented for g2
+      pos += sizeof(fileh);
+      break;
+    case 0xB7DC0791 : // stream header
+      pos += sizeof(objh);
+      memcpy(&streamh,buffer + pos,sizeof(streamh));
+      le2me_ASF_stream_header_t(&streamh);
+      pos += sizeof(streamh) + streamh.type_size;
+      switch(ASF_LOAD_GUID_PREFIX(streamh.type)) {
+      case 0xF8699E40 : // audio stream
+	if(asf_ctrl->audio_streams == NULL){
+	  asf_ctrl->audio_streams = (int*)malloc(sizeof(int));
+	  asf_ctrl->n_audio = 1;
+	} else {
+	  asf_ctrl->n_audio++;
+	  asf_ctrl->audio_streams = (int*)realloc(asf_ctrl->audio_streams,
+						     asf_ctrl->n_audio*sizeof(int));
+	}
+	asf_ctrl->audio_streams[asf_ctrl->n_audio-1] = streamh.stream_no;
+	pos += streamh.stream_size;
+	if( bandwidth==0 ) {
+	  asf_ctrl->audio_id = streamh.stream_no;
+	}
+	break;
+      case 0xBC19EFC0 : // video stream
+	if(asf_ctrl->video_streams == NULL){
+	  asf_ctrl->video_streams = (int*)malloc(sizeof(int));
+	  asf_ctrl->n_video = 1;
+	} else {
+	  asf_ctrl->n_video++;
+	  asf_ctrl->video_streams = (int*)realloc(asf_ctrl->video_streams,
+						     asf_ctrl->n_video*sizeof(int));
+	}
+	asf_ctrl->video_streams[asf_ctrl->n_video-1] = streamh.stream_no;
+	if( bandwidth==0 ) {
+	  asf_ctrl->video_id = streamh.stream_no;
+	}
+	break;
+      }
+      break;
+    case 0x7bf875ce :  // stream bitrate properties object
+	mp_msg(MSGT_NETWORK,MSGL_INFO,"Stream bitrate properties object\n");
+	mp_msg(MSGT_NETWORK,MSGL_INFO,"Max bandwidth set to %d\n", bandwidth);
+	asf_ctrl->audio_id = 0;
+	asf_ctrl->video_id = 0;
+	if( bandwidth!=0 ) {
+		int stream_count, stream_id, max_bitrate;
+		char *ptr = buffer+pos;
+		unsigned int total_bitrate=0, p_id=0, p_br=0;
+		int i;
+		ptr += sizeof(objh);
+		stream_count = le2me_16(*(uint16_t*)ptr);
+		ptr += sizeof(uint16_t);
+mp_msg(MSGT_NETWORK,MSGL_INFO," stream count=[0x%x][%u]\n", stream_count, stream_count );
+		for( i=0 ; i<stream_count && ptr<((char*)buffer+pos+objh.size) ; i++ ) {
+			stream_id = le2me_16(*(uint16_t*)ptr);
+			ptr += sizeof(uint16_t);
+			memcpy(&max_bitrate, ptr, sizeof(uint32_t));// workaround unaligment bug on sparc
+			max_bitrate = le2me_32(max_bitrate);
+			if( stream_id==1 ) total_bitrate = max_bitrate;
+			else if( total_bitrate+max_bitrate>bandwidth ) {
+				total_bitrate += p_br;
+mp_msg(MSGT_NETWORK,MSGL_INFO,"total_bitrate=%d\n", total_bitrate);
+mp_msg(MSGT_NETWORK,MSGL_INFO,"id=%d\n", p_id);
+				break;
+			}
+			ptr += sizeof(uint32_t);
+mp_msg(MSGT_NETWORK,MSGL_INFO,"   stream id=[0x%x][%u]\n", stream_id, stream_id );
+mp_msg(MSGT_NETWORK,MSGL_INFO,"   max bitrate=[0x%x][%u]\n", max_bitrate, max_bitrate );
+			p_id = stream_id;
+			p_br = max_bitrate;
+		}
+		asf_ctrl->audio_id = 1;
+		asf_ctrl->video_id = p_id;
+	}
+	pos += objh.size;
+	break;
+    default :
+      pos += objh.size;
+      break;
+    }
+  }
+  free(buffer);
+  return 1;
+}
+
+int
+asf_http_streaming_read( int fd, char *buffer, int size, stream_t *stream ) {
+  static ASF_stream_chunck_t chunk;
+  int g_read,chunk_size = 0;
+  static int rest = 0, drop_chunk = 0, waiting = 0;
+  asf_http_streaming_ctrl_t *asf_http_ctrl = stream->priv;
+
+  while(1) {
+    if (rest == 0 && waiting == 0) {
+      g_read = 0;
+      while(g_read < (int)sizeof(ASF_stream_chunck_t)){
+	int r = read( fd, ((char*)&chunk) + g_read, 
+				    sizeof(ASF_stream_chunck_t)-g_read);
+	if(r <= 0){
+	  if( r < 0) 
+	    mp_msg(MSGT_NETWORK,MSGL_ERR,"Error while reading chunk header\n");
+	  return -1;
+	}
+	g_read += r;
+      }
+      
+      // Endian handling of the stream chunk
+      le2me_ASF_stream_chunck_t(&chunk);
+      chunk_size = asf_streaming( &chunk, &drop_chunk );
+      if(chunk_size < 0) {
+	mp_msg(MSGT_NETWORK,MSGL_ERR,"Error while parsing chunk header\n");
+	return -1;
+      }
+      chunk_size -= sizeof(ASF_stream_chunck_t);
+	
+      if(chunk.type != ASF_STREAMING_HEADER && (!drop_chunk)) {
+	if (asf_http_ctrl->packet_size < chunk_size) {
+	  mp_msg(MSGT_NETWORK,MSGL_ERR,"Error chunk_size > packet_size\n");
+	  return -1;
+	}
+	waiting = asf_http_ctrl->packet_size;
+      } else {
+	waiting = chunk_size;
+      }
+
+    } else if (rest){
+      chunk_size = rest;
+      rest = 0;
+    }
+
+    g_read = 0;
+    if ( waiting >= chunk_size) {
+      if (chunk_size > size){
+	rest = chunk_size - size;
+	chunk_size = size;
+      }
+      while(g_read < chunk_size) {
+	int got = read( fd,buffer+g_read,chunk_size-g_read );
+	if(got <= 0) {
+	  if(got < 0)
+	    mp_msg(MSGT_NETWORK,MSGL_ERR,"Error while reading chunk\n");
+	  return -1;
+	}
+	g_read += got;
+      }
+      waiting -= g_read;
+      if (drop_chunk) continue;
+    }
+    if (rest == 0 && waiting > 0 && size-g_read > 0) {
+      int s = MIN(waiting,size-g_read);
+      memset(buffer+g_read,0,s);
+      waiting -= s;
+      g_read += s;
+    }
+    break;
+  }
+
+  return g_read;
+}
+
+int
+asf_header_check( HTTP_header_t *http_hdr ) {
+	ASF_obj_header_t *objh;
+	if( http_hdr==NULL ) return -1;
+	if( http_hdr->body==NULL || http_hdr->body_size<sizeof(ASF_obj_header_t) ) return -1;
+
+	objh = (ASF_obj_header_t*)http_hdr->body;
+	if( ASF_LOAD_GUID_PREFIX(objh->guid)==0x75B22630 ) return 0;
+	return -1;
+}
+
+int
+asf_http_streaming_type(char *content_type, char *features, HTTP_header_t *http_hdr ) {
+	if( content_type==NULL ) return ASF_Unknown_e;
+	if( 	!strcasecmp(content_type, "application/octet-stream") ||
+		!strcasecmp(content_type, "application/vnd.ms.wms-hdr.asfv1") ||        // New in Corona, first request
+		!strcasecmp(content_type, "application/x-mms-framed") ) {               // New in Corana, second request
+
+		if( strstr(features, "broadcast") ) {
+			mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF Live stream\n");
+			return ASF_Live_e;
+		} else {
+			mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF Prerecorded\n");
+			return ASF_Prerecorded_e;
+		}
+	} else {
+		// Ok in a perfect world, web servers should be well configured
+		// so we could used mime type to know the stream type,
+		// but guess what? All of them are not well configured.
+		// So we have to check for an asf header :(, but it works :p
+		if( http_hdr->body_size>sizeof(ASF_obj_header_t) ) {
+			if( asf_header_check( http_hdr )==0 ) {
+				mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF Plain text\n");
+				return ASF_PlainText_e;
+			} else if( (!strcasecmp(content_type, "text/html")) ) {
+				mp_msg(MSGT_NETWORK,MSGL_V,"=====> HTML, mplayer is not a browser...yet!\n");
+				return ASF_Unknown_e;
+			} else {
+				mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF Redirector\n");
+				return ASF_Redirector_e;
+			}
+		} else {
+			if(	(!strcasecmp(content_type, "audio/x-ms-wax")) ||
+				(!strcasecmp(content_type, "audio/x-ms-wma")) ||
+				(!strcasecmp(content_type, "video/x-ms-asf")) ||
+				(!strcasecmp(content_type, "video/x-ms-afs")) ||
+				(!strcasecmp(content_type, "video/x-ms-wvx")) ||
+				(!strcasecmp(content_type, "video/x-ms-wmv")) ||
+				(!strcasecmp(content_type, "video/x-ms-wma")) ) {
+				mp_msg(MSGT_NETWORK,MSGL_ERR,"=====> ASF Redirector\n");
+				return ASF_Redirector_e;
+			} else if( !strcasecmp(content_type, "text/plain") ) {
+				mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF Plain text\n");
+				return ASF_PlainText_e;
+			} else {
+				mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF unknown content-type: %s\n", content_type );
+				return ASF_Unknown_e;
+			}
+		}
+	}
+	return ASF_Unknown_e;
+}
+
+HTTP_header_t *
+asf_http_request(stream_t *stream) {
+	HTTP_header_t *http_hdr;
+	URL_t *url = NULL;
+	URL_t *server_url = NULL;
+	asf_http_streaming_ctrl_t *asf_http_ctrl;
+	char str[250];
+	char *ptr;
+	int i, enable;
+
+	int offset_hi=0, offset_lo=0, length=0;
+	int asf_nb_stream=0, stream_id;
+
+	// Sanity check
+	if( stream==NULL ) return NULL;
+	url = stream->url;
+	asf_http_ctrl = stream->priv;
+	if( url==NULL || asf_http_ctrl==NULL ) return NULL;
+
+	// Common header for all requests.
+	http_hdr = http_new_header();
+	http_set_field( http_hdr, "Accept: */*" );
+	http_set_field( http_hdr, "User-Agent: NSPlayer/4.1.0.3856" ); // FIXME: Should be settable as config option ?
+	http_add_basic_authentication( http_hdr, url->username, url->password );
+
+	// Check if we are using a proxy
+	if( !strcasecmp( url->protocol, "http_proxy" ) ) {
+		server_url = url_new( (url->file)+1 );
+		if( server_url==NULL ) {
+			mp_msg(MSGT_NETWORK,MSGL_ERR,"Invalid proxy URL\n");
+			http_free( http_hdr );
+			return NULL;
+		}
+		http_set_uri( http_hdr, server_url->url );
+		sprintf( str, "Host: %s:%d", server_url->hostname, server_url->port );
+		url_free( server_url );
+	} else {
+		http_set_uri( http_hdr, url->file );
+		sprintf( str, "Host: %s:%d", url->hostname, url->port );
+	}
+	
+	http_set_field( http_hdr, str );
+	http_set_field( http_hdr, "Pragma: xClientGUID={c77e7400-738a-11d2-9add-0020af0a3278}" );
+	sprintf(str, 
+		"Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=%u:%u,request-context=%d,max-duration=%u",
+		offset_hi, offset_lo, asf_http_ctrl->request, length );
+	http_set_field( http_hdr, str );
+
+	switch( asf_http_ctrl->streaming_type ) {
+		case ASF_Live_e:
+		case ASF_Prerecorded_e:
+			http_set_field( http_hdr, "Pragma: xPlayStrm=1" );
+			ptr = str;
+			ptr += sprintf( ptr, "Pragma: stream-switch-entry=");
+			if(asf_http_ctrl->n_audio > 0) {
+				for( i=0; i<asf_http_ctrl->n_audio ; i++ ) {
+					stream_id = asf_http_ctrl->audio_streams[i];
+					if(stream_id == asf_http_ctrl->audio_id) {
+						enable = 0;
+					} else {
+						enable = 2;
+					}
+					asf_nb_stream++;
+					ptr += sprintf(ptr, "ffff:%d:%d ", stream_id, enable);
+				}
+			}
+			if(asf_http_ctrl->n_video > 0) {
+				for( i=0; i<asf_http_ctrl->n_video ; i++ ) {
+					stream_id = asf_http_ctrl->video_streams[i];
+					if(stream_id == asf_http_ctrl->video_id) {
+						enable = 0;
+					} else {
+						enable = 2;
+					}
+					asf_nb_stream++;
+					ptr += sprintf(ptr, "ffff:%d:%d ", stream_id, enable);
+				}
+			}
+			http_set_field( http_hdr, str );
+			sprintf( str, "Pragma: stream-switch-count=%d", asf_nb_stream );
+			http_set_field( http_hdr, str );
+			break;
+		case ASF_Redirector_e:
+			break;
+		case ASF_Unknown_e:
+			// First request goes here.
+			break;
+		default:
+			mp_msg(MSGT_NETWORK,MSGL_ERR,"Unknown asf stream type\n");
+	}
+
+	http_set_field( http_hdr, "Connection: Close" );
+	http_build_request( http_hdr );
+
+	return http_hdr;
+}
+
+int
+asf_http_parse_response(asf_http_streaming_ctrl_t *asf_http_ctrl, HTTP_header_t *http_hdr ) {
+	char *content_type, *pragma;
+	char features[64] = "\0";
+	size_t len;
+	if( http_response_parse(http_hdr)<0 ) {
+		mp_msg(MSGT_NETWORK,MSGL_ERR,"Failed to parse HTTP response\n");
+		return -1;
+	}
+	switch( http_hdr->status_code ) {
+		case 200:
+			break;
+		case 401: // Authentication required
+			return ASF_Authenticate_e;
+		default:
+			mp_msg(MSGT_NETWORK,MSGL_ERR,"Server return %d:%s\n", http_hdr->status_code, http_hdr->reason_phrase);
+			return -1;
+	}
+
+	content_type = http_get_field( http_hdr, "Content-Type");
+//printf("Content-Type: [%s]\n", content_type);
+
+	pragma = http_get_field( http_hdr, "Pragma");
+	while( pragma!=NULL ) {
+		char *comma_ptr=NULL;
+		char *end;
+//printf("Pragma: [%s]\n", pragma );
+		// The pragma line can get severals attributes 
+		// separeted with a comma ','.
+		do {
+			if( !strncasecmp( pragma, "features=", 9) ) {
+				pragma += 9;
+				end = strstr( pragma, "," );
+				if( end==NULL ) {
+				  size_t s = strlen(pragma);
+				  if(s > sizeof(features)) {
+				    mp_msg(MSGT_NETWORK,MSGL_WARN,"ASF HTTP PARSE WARNING : Pragma %s cuted from %d bytes to %d\n",pragma,s,sizeof(features));
+				    len = sizeof(features);
+				  } else {				   
+				    len = s;
+				  }
+				} else { 
+				  len = MIN((unsigned int)(end-pragma),sizeof(features));
+				}
+				strncpy( features, pragma, len );
+				features[len]='\0';
+				break;
+			}
+			comma_ptr = strstr( pragma, "," );
+			if( comma_ptr!=NULL ) {
+				pragma = comma_ptr+1;
+				if( pragma[0]==' ' ) pragma++;
+			}
+		} while( comma_ptr!=NULL );
+		pragma = http_get_next_field( http_hdr );
+	}
+	asf_http_ctrl->streaming_type = asf_http_streaming_type( content_type, features, http_hdr );
+	return 0;
+}
+
+static int driver_open(stream_t *stream){
+	HTTP_header_t *http_hdr=NULL;
+	URL_t *url = stream->url;
+	asf_http_streaming_ctrl_t *asf_http_ctrl;
+	char buffer[BUFFER_SIZE];
+	int i, ret;
+	int fd = stream->fd;
+	int done;
+	int auth_retry = 0;
+
+	asf_http_ctrl = (asf_http_streaming_ctrl_t*)malloc(sizeof(asf_http_streaming_ctrl_t));
+	if( asf_http_ctrl==NULL ) {
+		mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n");
+		return 0;
+	}
+	asf_http_ctrl->streaming_type = ASF_Unknown_e;
+	asf_http_ctrl->request = 1;
+	asf_http_ctrl->audio_streams = asf_http_ctrl->video_streams = NULL;
+	asf_http_ctrl->n_audio = asf_http_ctrl->n_video = 0;
+	stream->priv = asf_http_ctrl;
+
+	do {
+		done = 1;
+		if( fd>0 ) close( fd );
+
+		if( !strcasecmp( url->protocol, "http_proxy" ) ) {
+			if( url->port==0 ) url->port = 8080;
+		} else {
+			if( url->port==0 ) url->port = 80;
+		}
+		fd = connect2Server( url->hostname, url->port );
+		if( fd<0 ) return fd;
+
+		http_hdr = asf_http_request( stream );
+		mp_msg(MSGT_NETWORK,MSGL_DBG2,"Request [%s]\n", http_hdr->buffer );
+		for(i=0; i < (int)http_hdr->buffer_size ; ) {
+			int r = write( fd, http_hdr->buffer+i, http_hdr->buffer_size-i );
+			if(r <0) {
+				mp_msg(MSGT_NETWORK,MSGL_ERR,"Socket write error : %s\n",strerror(errno));
+				return 0;
+			}
+			i += r;
+		}       
+		http_free( http_hdr );
+		http_hdr = http_new_header();
+		do {
+			i = read( fd, buffer, BUFFER_SIZE );
+//printf("read: %d\n", i );
+			if( i<=0 ) {
+				perror("read");
+				http_free( http_hdr );
+				return 0;
+			}
+			http_response_append( http_hdr, buffer, i );
+		} while( !http_is_header_entire( http_hdr ) );
+		if( verbose>0 ) {
+			http_hdr->buffer[http_hdr->buffer_size]='\0';
+			mp_msg(MSGT_NETWORK,MSGL_DBG2,"Response [%s]\n", http_hdr->buffer );
+		}
+		ret = asf_http_parse_response(asf_http_ctrl, http_hdr);
+		if( ret<0 ) {
+			mp_msg(MSGT_NETWORK,MSGL_ERR,"Failed to parse header\n");
+			http_free( http_hdr );
+			return 0;
+		}
+		switch( asf_http_ctrl->streaming_type ) {
+			case ASF_Live_e:
+			case ASF_Prerecorded_e:
+			case ASF_PlainText_e:
+				if( http_hdr->body_size>0 ) {
+					// FF: Following needed ?
+	/*				if( streaming_bufferize( stream->streaming_ctrl, http_hdr->body, http_hdr->body_size )<0 ) {
+						http_free( http_hdr );
+						return 0;
+					}*/
+				}
+				if( asf_http_ctrl->request==1 ) {
+					if( asf_http_ctrl->streaming_type!=ASF_PlainText_e ) {
+						// First request, we only got the ASF header.
+						ret = asf_streaming_parse_header(fd,stream);
+						if(ret < 0) return 0;
+						if(asf_http_ctrl->n_audio == 0 && asf_http_ctrl->n_video == 0) {
+							mp_msg(MSGT_NETWORK,MSGL_ERR,"No stream found\n");
+							return 0;
+						}
+						asf_http_ctrl->request++;
+						done = 0;
+					} else {
+						done = 1;
+					}
+				}
+				break;
+			case ASF_Redirector_e:
+				if( http_hdr->body_size>0 ) {
+				//FF: Following needed ?
+				/*	if( streaming_bufferize( stream->streaming_ctrl, http_hdr->body, http_hdr->body_size )<0 ) {
+						http_free( http_hdr );
+						return 0;
+					}*/
+				}
+				// FF: Hm, what to do ?
+				//*demuxer_type = DEMUXER_TYPE_PLAYLIST;
+				done = 1;
+				break;
+			case ASF_Authenticate_e:
+				if( http_authenticate( http_hdr, url, &auth_retry)<0 ) return 0;
+				asf_http_ctrl->streaming_type = ASF_Unknown_e;
+				done = 0;
+				break;
+			case ASF_Unknown_e:
+			default:
+				mp_msg(MSGT_NETWORK,MSGL_ERR,"Unknown ASF streaming type\n");
+				close(fd);
+				http_free( http_hdr );
+				return 0;
+		}
+	// Check if we got a redirect.	
+	} while(!done);
+
+	stream->fd = fd;
+	stream->buf_size = 4096; // FF: FIXME, what to put here ? (Get from asf headers ?)
+
+	http_free( http_hdr );
+	return 1;
+}
+
+static int driver_fill(stream_t *s){
+	if( s->priv->streaming_type==ASF_PlainText_e || s->priv->streaming_type==ASF_Redirector_e ) {
+		return read(s->fd, s->buffer, s->buf_size);
+	}
+	return asf_http_streaming_read(s->fd, s->buffer, s->buf_size, s);
+
+}
+
+static int driver_free(stream_t *stream) {
+	if (stream->priv)
+		free(stream->priv);
+	return 1;
+}
+
+stream_driver_t stream_driver_mms = {
+    "mms",
+    "Windows Media MMS-over-HTTP (mms://) Streaming",
+    "ported from g1 by Fabian Franz",
+    driver_open,
+    NULL, //reset,
+    driver_fill,
+    NULL, //driver_seek,
+    NULL //free
+};
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.