view libmpdemux/asf_streaming.c @ 2694:2924350d92ed

bgr32to16, bgr32to15 (needed for palette stuff) paletteto 32,16,15bgr all in c, will be optimized as soon as they are tested (assuming opt. is possible)
author michael
date Sun, 04 Nov 2001 19:36:24 +0000
parents 66837325b929
children 6b6fa2be9b97
line wrap: on
line source

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "config.h"

#include "url.h"
#include "http.h"
#include "asf.h"
#include "network.h"

#include "stream.h"
//#include "demuxer.h"

//extern demuxer_t *demuxer;

static ASF_StreamType_e streaming_type = ASF_Unknown_e;

int
asf_http_streaming_read( streaming_ctrl_t *streaming_ctrl ) {
	char *buffer;
	int drop_packet;
	int ret;
printf("asf_http_streaming_read\n");
	ret = asf_streaming( streaming_ctrl->buffer->buffer, streaming_ctrl->buffer->length, &drop_packet );
printf("ret: %d\n", ret);
	if( ret<0 ) return -1;
	if( ret>streaming_ctrl->buffer->length ) return 0;
	buffer = (char*)malloc(ret);
	if( buffer==NULL ) {
		printf("Memory allocation failed\n");
		return -1;
	}
printf("buffer length: %d\n", streaming_ctrl->buffer->length );
	net_fifo_pop( streaming_ctrl->buffer, buffer, ret );
printf("  pop: 0x%02X\n", *((unsigned int*)buffer) );
printf("buffer length: %d\n", streaming_ctrl->buffer->length );
printf("0x%02X\n", *((unsigned int*)(buffer+sizeof(ASF_stream_chunck_t))) );
	if( !drop_packet ) {
		write( streaming_ctrl->fd_pipe_in, buffer+sizeof(ASF_stream_chunck_t), ret-sizeof(ASF_stream_chunck_t) );
	}
	free( buffer );
	return ret;
}

int
asf_http_read( streaming_ctrl_t *streaming_ctrl ) {
	char *buffer;
	unsigned int length = streaming_ctrl->buffer->length;

	buffer = (char*)malloc(length);
	if( buffer==NULL ) {
		printf("Memory allocation failed\n");
		return -1;
	}
	
	net_fifo_pop( streaming_ctrl->buffer, buffer, length );

	write( streaming_ctrl->fd_pipe_in, buffer, length );

	free( buffer );
	return length;
}

int 
asf_streaming(char *data, int length, int *drop_packet ) {
	ASF_stream_chunck_t *stream_chunck=(ASF_stream_chunck_t*)data;
	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( data==NULL || length<=0 ) return -1;

	if( stream_chunck->size<8 ) {
		printf("Ahhhh, stream_chunck size is too small: %d\n", stream_chunck->size);
		return -1;
	}
	if( stream_chunck->size!=stream_chunck->size_confirm ) {
		printf("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 0x4324:	// Clear ASF configuration
			printf("=====> Clearing ASF stream configuration!\n");
			if( drop_packet!=NULL ) *drop_packet = 1;
			return stream_chunck->size;
			break;
		case 0x4424:    // Data follows
			printf("=====> Data follows\n");
			break;
		case 0x4524:    // Transfer complete
			printf("=====> Transfer complete\n");
			if( drop_packet!=NULL ) *drop_packet = 1;
			return stream_chunck->size;
			break;
		case 0x4824:    // ASF header chunk follows
			printf("=====> ASF header chunk follows\n");
			break;
		default:
			printf("=====> Unknown stream type 0x%x\n", stream_chunck->type );
	}
	return stream_chunck->size+4;
}

int
asf_http_streaming_type(char *content_type, char *features) {
	if( content_type==NULL ) return ASF_Unknown_e;
	if( !strcasecmp(content_type, "application/octet-stream") ) {
		if( features==NULL ) {
			printf("=====> ASF Prerecorded\n");
			return ASF_Prerecorded_e;
		} else if( strstr(features, "broadcast")) {
			printf("=====> ASF Live stream\n");
			return ASF_Live_e;
		} else {
			printf("=====> ASF Prerecorded\n");
			return ASF_Prerecorded_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")) ) {
			printf("=====> ASF Redirector\n");
			return ASF_Redirector_e;
		} else if( !strcasecmp(content_type, "text/plain") ) {
			printf("=====> ASF Plain text\n");
			return ASF_PlainText_e;
		} else {
			printf("=====> ASF unknown content-type: %s\n", content_type );
			return ASF_Unknown_e;
		}
	}
	return ASF_Unknown_e;
}

HTTP_header_t *
asf_http_request(URL_t *url) {
	HTTP_header_t *http_hdr;
	char str[250];
	char *ptr;
	char *request;
	int i;

	int offset_hi=0, offset_lo=0, req_nb=1, length=0;
	int asf_nb_stream;

	// Common header for all requests.
	http_hdr = http_new_header();
	http_set_uri( http_hdr, url->file );
	http_set_field( http_hdr, "Accept: */*" );
	http_set_field( http_hdr, "User-Agent: NSPlayer/4.1.0.3856" );
        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, req_nb, length );
	http_set_field( http_hdr, str );

	switch( 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=");

// FIXME: why do you need demuxer here? if you really need it, pass it as
// parameter. -- A'rpi

#if 0
			for( i=0, asf_nb_stream=0 ; i<256 ; i++ ) {
				// FIXME START
				if( demuxer==NULL ) {
					ptr += sprintf( ptr, " ffff:1:0" );
					asf_nb_stream = 1;
					break;
				}
				// FIXME END
				if( demuxer->a_streams[i] ) {
					ptr += sprintf( ptr, " ffff:%d:0", i );
					asf_nb_stream++;
				}
				if( demuxer->v_streams[i] ) {
					ptr += sprintf( ptr, " ffff:%d:0", i );
					asf_nb_stream++;
				}
			}
#endif
			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:
			printf("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( HTTP_header_t *http_hdr ) {
	char *content_type, *pragma;
	char features[64] = "\0";
	int len;
	if( http_response_parse(http_hdr)<0 ) {
		printf("Failed to parse HTTP response\n");
		return -1;
	}
	if( http_hdr->status_code!=200 ) {
		printf("Server return %d:%s\n", http_hdr->status_code, http_hdr->reason_phrase);
		return -1;
	}

	content_type = http_get_field( http_hdr, "Content-Type");

	pragma = http_get_field( http_hdr, "Pragma");
	while( pragma!=NULL ) {
		char *comma_ptr=NULL;
		char *end;
		// 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 ) {
					len = strlen(pragma);
				}
				len = MIN(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 );
	}

	streaming_type = asf_http_streaming_type( content_type, features );
/*
	if( http_hdr->body_size>0 ) {
		asf_streaming( http_hdr->body, http_hdr->body_size, NULL);
	}
*/
	return 0;
}

URL_t *
asf_http_ASX_redirect( HTTP_header_t *http_hdr ) {
	URL_t *url_redirect=NULL;
	printf("=========>> ASX parser not yet implemented <<==========\n");

	printf("ASX=[%s]\n", http_hdr->body );

	return url_redirect;
}

int
asf_http_streaming_start( streaming_ctrl_t *streaming_ctrl ) {
	HTTP_header_t *http_hdr=NULL;
	URL_t *url_next=NULL;
	URL_t *url = *(streaming_ctrl->url);
	char buffer[BUFFER_SIZE];
	int i;
	int fd = streaming_ctrl->fd_net;
	int done=1;

streaming_type = ASF_Live_e;
	do {
		if( fd>0 ) close( fd );

		fd = connect2Server( url->hostname, url->port );
		if( fd<0 ) return -1;

		http_hdr = asf_http_request( url );
printf("[%s]\n", http_hdr->buffer );
		write( fd, http_hdr->buffer, http_hdr->buffer_size );
//		http_free( http_hdr );

		http_hdr = http_new_header();
		do {
			i = readFromServer( fd, buffer, BUFFER_SIZE );
printf("read: %d\n", i );
			if( i<0 ) {
				perror("read");
				http_free( http_hdr );
				return -1;
			}
			http_response_append( http_hdr, buffer, i );
		} while( !http_is_header_entire( http_hdr ) );
//http_hdr->buffer[http_hdr->buffer_len]='\0';
//printf("[%s]\n", http_hdr->buffer );
		if( asf_http_parse_response(http_hdr)<0 ) {
			printf("Failed to parse header\n");
			http_free( http_hdr );
			return -1;
		}
		switch( streaming_type ) {
			case ASF_Live_e:
			case ASF_Prerecorded_e:
			case ASF_PlainText_e:
				if( http_hdr->body_size>0 ) {
					net_fifo_push( streaming_ctrl->buffer, http_hdr->body, http_hdr->body_size );
				} else {
					ASF_stream_chunck_t *ptr;
					int ret;
					i = readFromServer( fd, buffer, sizeof(ASF_stream_chunck_t) );
printf("read: %d\n", i );
					ret = asf_streaming( buffer, i, NULL );
					net_fifo_push( streaming_ctrl->buffer, buffer, i );
					ptr = (ASF_stream_chunck_t*)buffer;
					if( ret==ptr->size ) {
					}
				}
//				done = 0;
				break;
			case ASF_Redirector_e:
				url_next = asf_http_ASX_redirect( http_hdr );
				if( url_next==NULL ) {
					printf("Failed to parse ASX file\n");
					close(fd);
					http_free( http_hdr );
					return -1;
				}
				if( url_next->port==0 ) url_next->port=80;
				url_free( url );
				url = url_next;
				*(streaming_ctrl->url) = url_next;
				url_next = NULL;
				break;
			case ASF_Unknown_e:
			default:
				printf("Unknown ASF streaming type\n");
				close(fd);
				http_free( http_hdr );
				return -1;
		}

		// Check if we got a redirect.	
	} while(!done);

	streaming_ctrl->fd_net = fd;
	if( streaming_type==ASF_PlainText_e ) {
		streaming_ctrl->streaming_read = asf_http_read;
	} else {
		streaming_ctrl->streaming_read = asf_http_streaming_read;
	}
        streaming_ctrl->prebuffer_size = 20000;
	streaming_ctrl->buffering = 1;
	streaming_ctrl->status = streaming_playing_e;

	http_free( http_hdr );
	return fd;
}