Commit 4cf2f458 authored by Laurent Aimar's avatar Laurent Aimar
Browse files

* asf: fixed unintialised variable, cleaned up some stuffs.

 * mmsh: big rework of the mmsh module.
parent a9ddba27
......@@ -2,7 +2,7 @@
* asf.c: MMS access plug-in
*****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN
* $Id: asf.c,v 1.3 2004/02/12 20:09:38 fenrir Exp $
* $Id$
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
......@@ -73,6 +73,8 @@ void E_( asf_HeaderParse ) ( asf_header_t *hdr,
for( i = 0; i < 128; i++ )
{
hdr->stream[i].i_cat = ASF_STREAM_UNKNOWN;
hdr->stream[i].i_selected = 0;
hdr->stream[i].i_bitrate = -1;
}
//fprintf( stderr, " ---------------------header:%d\n", i_header );
......
......@@ -2,7 +2,7 @@
* asf.h: MMS access plug-in
*****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN
* $Id: asf.h,v 1.5 2003/04/20 19:29:43 fenrir Exp $
* $Id$
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
......@@ -34,11 +34,9 @@
typedef struct asf_stream_s
{
int i_id; /* 1 -> 127 */
int i_cat; /* ASF_STREAM_VIDEO, ASF_STREAM_AUDIO */
int i_bitrate; /* -1 if unknown */
int i_selected;
} asf_stream_t;
typedef struct
......
......@@ -2,7 +2,7 @@
* mmsh.c:
*****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN
* $Id: mmsh.c,v 1.8 2004/01/26 16:30:34 fenrir Exp $
* $Id$
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
......@@ -21,12 +21,6 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*
* TODO:
* * http_proxy
*
*/
/*****************************************************************************
* Preamble
*****************************************************************************/
......@@ -35,6 +29,8 @@
#include <vlc/vlc.h>
#include <vlc/input.h>
#include "vlc_playlist.h"
#include "network.h"
#include "asf.h"
#include "buffer.h"
......@@ -42,25 +38,24 @@
#include "mms.h"
#include "mmsh.h"
/* TODO:
* - http_proxy
* - authentication
*/
/*****************************************************************************
* Local prototypes
*****************************************************************************/
int E_(MMSHOpen) ( input_thread_t * );
void E_(MMSHClose) ( input_thread_t * );
static ssize_t Read( input_thread_t *, byte_t *, size_t );
static void Seek( input_thread_t *, off_t );
static ssize_t NetFill( input_thread_t *, access_sys_t *, int );
static int mmsh_start ( input_thread_t *, off_t );
static void mmsh_stop ( input_thread_t * );
static int mmsh_get_packet( input_thread_t *, chunk_t * );
static http_answer_t *http_answer_parse( uint8_t *, int );
static void http_answer_free ( http_answer_t * );
static http_field_t *http_field_find ( http_field_t *, char * );
static ssize_t Read( input_thread_t *, byte_t *, size_t );
static ssize_t ReadRedirect( input_thread_t *, byte_t *, size_t );
static void Seek( input_thread_t *, off_t );
static int chunk_parse( chunk_t *, uint8_t *, int );
static int Start( input_thread_t *, off_t );
static void Stop( input_thread_t * );
static int GetPacket( input_thread_t *, chunk_t * );
/****************************************************************************
* Open: connect to ftp server and ask for file
......@@ -69,10 +64,9 @@ int E_( MMSHOpen ) ( input_thread_t *p_input )
{
access_sys_t *p_sys;
uint8_t *p;
http_answer_t *p_ans;
http_field_t *p_field;
chunk_t ck;
char *psz;
char *psz_location = NULL;
int i_code;
vlc_value_t val;
......@@ -82,8 +76,6 @@ int E_( MMSHOpen ) ( input_thread_t *p_input )
p_sys->fd = -1;
p_sys->i_request_context = 1;
p_sys->i_buffer = 0;
p_sys->i_buffer_pos = 0;
p_sys->b_broadcast = VLC_TRUE;
p_sys->p_packet = NULL;
p_sys->i_packet_sequence = 0;
......@@ -94,141 +86,191 @@ int E_( MMSHOpen ) ( input_thread_t *p_input )
E_( GenerateGuid )( &p_sys->guid );
/* open a tcp connection */
p_sys->p_url = E_( url_new )( p_input->psz_name );
if( *p_sys->p_url->psz_host == '\0' )
vlc_UrlParse( &p_sys->url, p_input->psz_name, 0 );
if( p_sys->url.psz_host == NULL && *p_sys->url.psz_host == '\0' )
{
msg_Err( p_input, "invalid server addresse" );
goto exit_error;
msg_Err( p_input, "invalid host" );
goto error;
}
if( p_sys->p_url->i_port <= 0 )
if( p_sys->url.i_port <= 0 )
{
p_sys->p_url->i_port = 80;
p_sys->url.i_port = 80;
}
if( ( p_sys->fd = net_OpenTCP( p_input, p_sys->p_url->psz_host,
p_sys->p_url->i_port ) ) < 0 )
if( ( p_sys->fd = net_OpenTCP( p_input, p_sys->url.psz_host,
p_sys->url.i_port ) ) < 0 )
{
msg_Err( p_input, "cannot connect" );
goto exit_error;
msg_Err( p_input, "cannot connect to%s:%d", p_sys->url.psz_host, p_sys->url.i_port );
goto error;
}
/* *** send first request *** */
p = &p_sys->buffer[0];
p += sprintf( p, "GET %s HTTP/1.0\r\n", p_sys->p_url->psz_path );
p += sprintf( p,"Accept: */*\r\n" );
p += sprintf( p, "User-Agent: NSPlayer/4.1.0.3856\r\n" );
p += sprintf( p, "Host: %s:%d\r\n",
p_sys->p_url->psz_host, p_sys->p_url->i_port );
p += sprintf( p, "Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=0:0,request-context=%d,max-duration=0\r\n",
p_sys->i_request_context++ );
p += sprintf( p, "Pragma: xClientGUID={"GUID_FMT"}\r\n",
GUID_PRINT( p_sys->guid ) );
p += sprintf( p, "Connection: Close\r\n\r\n" );
net_Write( p_input, p_sys->fd, p_sys->buffer, p - p_sys->buffer );
/* send first request */
net_Printf( VLC_OBJECT(p_input), p_sys->fd,
"GET %s HTTP/1.0\r\n"
"Accept: */*\r\n"
"User-Agent: NSPlayer/4.1.0.3856\r\n"
"Host: %s:%d\r\n"
"Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=0:0,request-context=%d,max-duration=0\r\n"
"Pragma: xClientGUID={"GUID_FMT"}\r\n"
"Connection: Close\r\n",
( p_sys->url.psz_path == NULL || *p_sys->url.psz_path == '\0' ) ? "/" : p_sys->url.psz_path,
p_sys->url.psz_host, p_sys->url.i_port,
p_sys->i_request_context++,
GUID_PRINT( p_sys->guid ) );
if( NetFill ( p_input, p_sys, BUFFER_SIZE ) <= 0 )
if( net_Printf( VLC_OBJECT(p_input), p_sys->fd, "\r\n" ) < 0 )
{
msg_Err( p_input, "cannot read answer" );
goto exit_error;
msg_Err( p_input, "failed to send request" );
goto error;
}
net_Close( p_sys->fd ); p_sys->fd = -1;
p_ans = http_answer_parse( p_sys->buffer, p_sys->i_buffer );
if( !p_ans )
/* Receive the http header */
if( ( psz = net_Gets( VLC_OBJECT(p_input), p_sys->fd ) ) == NULL )
{
msg_Err( p_input, "cannot parse answer" );
goto exit_error;
msg_Err( p_input, "failed to read answer" );
goto error;
}
if( p_ans->i_error >= 400 )
if( strncmp( psz, "HTTP/1.", 7 ) )
{
msg_Err( p_input, "error %d (server return=`%s')",
p_ans->i_error, p_ans->psz_answer );
http_answer_free( p_ans );
goto exit_error;
msg_Err( p_input, "invalid HTTP reply '%s'", psz );
free( psz );
goto error;
}
else if( p_ans->i_error >= 300 )
i_code = atoi( &psz[9] );
if( i_code >= 400 )
{
msg_Err( p_input, "FIXME redirect unsuported %d (server return=`%s')",
p_ans->i_error, p_ans->psz_answer );
http_answer_free( p_ans );
goto exit_error;
}
else if( p_ans->i_body <= 0 )
{
msg_Err( p_input, "empty answer" );
http_answer_free( p_ans );
goto exit_error;
msg_Err( p_input, "error: %s", psz );
free( psz );
goto error;
}
/* now get features */
/* FIXME FIXME test Content-Type to see if it's a plain stream or an
* asx FIXME */
for( p_field = p_ans->p_fields;
p_field != NULL;
p_field = http_field_find( p_field->p_next, "Pragma" ) )
msg_Dbg( p_input, "HTTP reply '%s'", psz );
free( psz );
for( ;; )
{
if( !strncasecmp( p_field->psz_value, "features", 8 ) )
char *psz = net_Gets( p_input, p_sys->fd );
char *p;
if( psz == NULL )
{
if( strstr( p_field->psz_value, "broadcast" ) )
{
msg_Dbg( p_input, "stream type = broadcast" );
p_sys->b_broadcast = VLC_TRUE;
}
else if( strstr( p_field->psz_value, "seekable" ) )
{
msg_Dbg( p_input, "stream type = seekable" );
p_sys->b_broadcast = VLC_FALSE;
}
else
msg_Err( p_input, "failed to read answer" );
goto error;
}
if( *psz == '\0' )
{
free( psz );
break;
}
if( ( p = strchr( psz, ':' ) ) == NULL )
{
msg_Err( p_input, "malformed header line: %s", psz );
free( psz );
goto error;
}
*p++ = '\0';
while( *p == ' ' ) p++;
/* FIXME FIXME test Content-Type to see if it's a plain stream or an
* asx FIXME */
if( !strcasecmp( psz, "Pragma" ) )
{
if( !strncasecmp( p, "features", 8 ) )
{
msg_Warn( p_input, "unknow stream types (%s)",
p_field->psz_value );
p_sys->b_broadcast = VLC_FALSE;
if( strstr( p, "broadcast" ) )
{
msg_Dbg( p_input, "stream type = broadcast" );
p_sys->b_broadcast = VLC_TRUE;
}
else if( strstr( p, "seekable" ) )
{
msg_Dbg( p_input, "stream type = seekable" );
p_sys->b_broadcast = VLC_FALSE;
}
else
{
msg_Warn( p_input, "unknow stream types (%s)", p );
p_sys->b_broadcast = VLC_FALSE;
}
}
}
else if( !strcasecmp( psz, "Location" ) )
{
psz_location = strdup( p );
}
free( psz );
}
/* gather header */
p_sys->i_header = 0;
p_sys->p_header = malloc( p_ans->i_body );
do
/* Handle the redirection */
if( ( i_code == 301 || i_code == 302 ||
i_code == 303 || i_code == 307 ) &&
psz_location && *psz_location )
{
if( chunk_parse( &ck, p_ans->p_body, p_ans->i_body ) )
playlist_t * p_playlist;
msg_Dbg( p_input, "redirection to %s", psz_location );
net_Close( p_sys->fd ); p_sys->fd = -1;
p_playlist = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST, FIND_PARENT );
if( !p_playlist )
{
msg_Err( p_input, "invalid chunk answer" );
goto exit_error;
msg_Err( p_input, "redirection failed: can't find playlist" );
goto error;
}
if( ck.i_type != 0x4824 )
p_playlist->pp_items[p_playlist->i_index]->b_autodeletion = VLC_TRUE;
playlist_Add( p_playlist, psz_location, psz_location,
PLAYLIST_INSERT | PLAYLIST_GO,
p_playlist->i_index + 1 );
vlc_object_release( p_playlist );
p_input->pf_read = ReadRedirect;
p_input->pf_seek = NULL;
p_input->pf_set_program = input_SetProgram;
p_input->pf_set_area = NULL;
/* *** finished to set some variable *** */
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.b_pace_control = 0;
p_input->stream.p_selected_area->i_size = 0;
p_input->stream.b_seekable = 0;
p_input->stream.p_selected_area->i_tell = 0;
p_input->stream.i_method = INPUT_METHOD_NETWORK;
vlc_mutex_unlock( &p_input->stream.stream_lock );
return VLC_SUCCESS;
}
/* Read the asf header */
p_sys->i_header = 0;
p_sys->p_header = NULL;
for( ;; )
{
chunk_t ck;
if( GetPacket( p_input, &ck ) ||
ck.i_type != 0x4824 )
{
msg_Err( p_input, "invalid chunk (0x%x)", ck.i_type );
break;
}
if( ck.i_data > 0 )
{
memcpy( &p_sys->p_header[p_sys->i_header],
ck.p_data,
ck.i_data );
p_sys->i_header += ck.i_data;
p_sys->p_header = realloc( p_sys->p_header, p_sys->i_header );
memcpy( &p_sys->p_header[p_sys->i_header - ck.i_data],
ck.p_data, ck.i_data );
}
/* BEURK */
p_ans->p_body += 12 + ck.i_data;
p_ans->i_body -= 12 + ck.i_data;
} while( p_ans->i_body > 12 );
http_answer_free( p_ans );
}
msg_Dbg( p_input, "complete header size=%d", p_sys->i_header );
if( p_sys->i_header <= 0 )
{
msg_Err( p_input, "header size == 0" );
goto exit_error;
goto error;
}
/* close this connection */
net_Close( p_sys->fd ); p_sys->fd = -1;
/* *** parse header and get stream and their id *** */
/* get all streams properties,
*
......@@ -246,10 +288,10 @@ int E_( MMSHOpen ) ( input_thread_t *p_input )
config_GetInt( p_input, "audio" ),
config_GetInt( p_input, "video" ) );
if( mmsh_start( p_input, 0 ) )
if( Start( p_input, 0 ) )
{
msg_Err( p_input, "cannot start stream" );
goto exit_error;
goto error;
}
/* *** set exported functions *** */
......@@ -284,9 +326,8 @@ int E_( MMSHOpen ) ( input_thread_t *p_input )
return VLC_SUCCESS;
exit_error:
E_( url_free )( p_sys->p_url );
error:
vlc_UrlClean( &p_sys->url );
if( p_sys->fd > 0 )
{
net_Close( p_sys->fd );
......@@ -298,13 +339,13 @@ exit_error:
/*****************************************************************************
* Close: free unused data structures
*****************************************************************************/
void E_( MMSHClose ) ( input_thread_t *p_input )
void E_( MMSHClose )( input_thread_t *p_input )
{
access_sys_t *p_sys = p_input->p_access_data;
msg_Dbg( p_input, "stopping stream" );
mmsh_stop( p_input );
Stop( p_input );
free( p_sys );
}
......@@ -326,12 +367,12 @@ static void Seek( input_thread_t * p_input, off_t i_pos )
vlc_mutex_lock( &p_input->stream.stream_lock );
mmsh_stop( p_input );
mmsh_start( p_input, i_packet * p_sys->asfh.i_min_data_packet_size );
Stop( p_input );
Start( p_input, i_packet * p_sys->asfh.i_min_data_packet_size );
for( ;; )
{
if( mmsh_get_packet( p_input, &ck ) )
if( GetPacket( p_input, &ck ) )
{
break;
}
......@@ -351,6 +392,14 @@ static void Seek( input_thread_t * p_input, off_t i_pos )
vlc_mutex_unlock( &p_input->stream.stream_lock );
}
/*****************************************************************************
* Read:
*****************************************************************************/
static ssize_t ReadRedirect( input_thread_t *p_input, byte_t *p, size_t i )
{
return 0;
}
/*****************************************************************************
* Read:
*****************************************************************************/
......@@ -389,14 +438,9 @@ static ssize_t Read ( input_thread_t * p_input, byte_t * p_buffer,
else
{
chunk_t ck;
/* get a new packet */
/* fill enought data (>12) */
msg_Dbg( p_input, "waiting data (buffer = %d bytes)",
p_sys->i_buffer );
if( mmsh_get_packet( p_input, &ck ) )
if( GetPacket( p_input, &ck ) )
{
return 0;
return -1;
}
}
}
......@@ -406,71 +450,20 @@ static ssize_t Read ( input_thread_t * p_input, byte_t * p_buffer,
return( i_data );
}
/*****************************************************************************
* NetFill:
*****************************************************************************/
static ssize_t NetFill( input_thread_t *p_input, access_sys_t *p_sys, int i_size )
{
int i_try = 0;
int i_total = 0;
i_size = __MIN( i_size, BUFFER_SIZE - p_sys->i_buffer );
if( i_size <= 0 )
{
return 0;
}
for( ;; )
{
int i_read;
i_read = net_Read( p_input, p_sys->fd,
&p_sys->buffer[p_sys->i_buffer], i_size, VLC_FALSE );
if( i_read == 0 )
{
if( i_try++ > 2 )
{
break;
}
msg_Dbg( p_input, "another try %d/2", i_try );
continue;
}
if( i_read < 0 || p_input->b_die || p_input->b_error )
{
break;
}
i_total += i_read;
p_sys->i_buffer += i_read;
if( i_total >= i_size )
{
break;
}
}
p_sys->buffer[p_sys->i_buffer] = '\0';
return i_total;
}
/*****************************************************************************
*
*****************************************************************************/
static int mmsh_start( input_thread_t *p_input, off_t i_pos )
static int Start( input_thread_t *p_input, off_t i_pos )
{
access_sys_t *p_sys = p_input->p_access_data;
uint8_t *p;
int i_streams = 0;
int i;
http_answer_t *p_ans;
int i_streams = 0;
int i;
char *psz;
msg_Dbg( p_input, "starting stream" );
if( ( p_sys->fd = net_OpenTCP( p_input, p_sys->p_url->psz_host,
p_sys->p_url->i_port ) ) < 0 )
if( ( p_sys->fd = net_OpenTCP( p_input, p_sys->url.psz_host,
p_sys->url.i_port ) ) < 0 )
{
/* should not occur */
msg_Err( p_input, "cannot connect to the server" );
......@@ -490,113 +483,89 @@ static int mmsh_start( input_thread_t *p_input, off_t i_pos )
msg_Err( p_input, "no stream selected" );
return VLC_EGENERIC;
}
p = &p_sys->buffer[0];
p += sprintf( p, "GET %s HTTP/1.0\r\n", p_sys->p_url->psz_path );
p += sprintf( p,"Accept: */*\r\n" );
p += sprintf( p, "User-Agent: NSPlayer/4.1.0.3856\r\n" );
p += sprintf( p, "Host: %s:%d\r\n",
p_sys->p_url->psz_host, p_sys->p_url->i_port );
net_Printf( VLC_OBJECT(p_input), p_sys->fd,
"GET %s HTTP/1.0\r\n"
"Accept: */*\r\n"
"User-Agent: NSPlayer/4.1.0.3856\r\n"
"Host: %s:%d\r\n",
( p_sys->url.psz_path == NULL || *p_sys->url.psz_path == '\0' ) ? "/" : p_sys->url.psz_path,
p_sys->url.psz_host, p_sys->url.i_port );
if( p_sys->b_broadcast )
{
p += sprintf( p,"Pragma: no-cache,rate=1.000000,request-context=%d\r\n",
p_sys->i_request_context++ );
net_Printf( VLC_OBJECT(p_input), p_sys->fd,
"Pragma: no-cache,rate=1.000000,request-context=%d\r\n",
p_sys->i_request_context++ );
}
else
{
p += sprintf( p, "Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=%u:%u,request-context=%d,max-duration=0\r\n",
(uint32_t)((i_pos >> 32)&0xffffffff),
(uint32_t)(i_pos&0xffffffff),
p_sys->i_request_context++ );
net_Printf( VLC_OBJECT(p_input), p_sys->fd,
"Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=%u:%u,request-context=%d,max-duration=0\r\n",
(uint32_t)((i_pos >> 32)&0xffffffff),