Commit e0c8d4ac authored by Laurent Aimar's avatar Laurent Aimar
Browse files

* mms/* : begining of a m$-http-for-asf-streaming support.

 Proxy aren't yet supported. Use mmsh to force it, else mms will try it
at the end (after mmst and mmsu). Some http url are in fact mmsh but
not yet auto-detected.
 *Please report* not working url and any regression for mmst and mmsu.
parent 3b768aef
SOURCES_access_mms = \
modules/access/mms/mms.c \
modules/access/mms/mms.h \
modules/access/mms/mmsh.c \
modules/access/mms/mmsh.h \
modules/access/mms/mmstu.c \
modules/access/mms/mmstu.h \
modules/access/mms/buffer.c \
modules/access/mms/buffer.h \
modules/access/mms/asf.h \
modules/access/mms/asf.c \
$(NULL)
/*****************************************************************************
* asf.c: MMS access plug-in
*****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN
* $Id: asf.c,v 1.1 2003/04/20 19:29:43 fenrir Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
#include <stdlib.h>
#include <vlc/vlc.h>
#include "asf.h"
#include "buffer.h"
static int CmpGuid( const guid_t *p_guid1, const guid_t *p_guid2 )
{
return( ( p_guid1->v1 == p_guid2->v1 &&
p_guid1->v2 == p_guid2->v2 &&
p_guid1->v3 == p_guid2->v3 &&
p_guid1->v4[0] == p_guid2->v4[0] &&
p_guid1->v4[1] == p_guid2->v4[1] &&
p_guid1->v4[2] == p_guid2->v4[2] &&
p_guid1->v4[3] == p_guid2->v4[3] &&
p_guid1->v4[4] == p_guid2->v4[4] &&
p_guid1->v4[5] == p_guid2->v4[5] &&
p_guid1->v4[6] == p_guid2->v4[6] &&
p_guid1->v4[7] == p_guid2->v4[7] ) ? 1 : 0 );
}
void E_( GenerateGuid )( guid_t *p_guid )
{
int i;
srand( mdate() & 0xffffffff );
/* FIXME should be generated using random data */
p_guid->v1 = 0xbabac001;
p_guid->v2 = ( (uint64_t)rand() << 16 ) / RAND_MAX;
p_guid->v3 = ( (uint64_t)rand() << 16 ) / RAND_MAX;
for( i = 0; i < 8; i++ )
{
p_guid->v4[i] = ( (uint64_t)rand() * 256 ) / RAND_MAX;
}
}
void E_( asf_HeaderParse ) ( asf_header_t *hdr,
uint8_t *p_header, int i_header )
{
var_buffer_t buffer;
guid_t guid;
uint64_t i_size;
int i;
for( i = 0; i < 128; i++ )
{
hdr->stream[i].i_cat = ASF_STREAM_UNKNOWN;
}
//fprintf( stderr, " ---------------------header:%d\n", i_header );
var_buffer_initread( &buffer, p_header, i_header );
var_buffer_getguid( &buffer, &guid );
if( !CmpGuid( &guid, &asf_object_header_guid ) )
{
// XXX Error
// fprintf( stderr, " ---------------------ERROR------\n" );
}
var_buffer_getmemory( &buffer, NULL, 30 - 16 );
for( ;; )
{
//fprintf( stderr, " ---------------------data:%d\n", buffer.i_data );
var_buffer_getguid( &buffer, &guid );
i_size = var_buffer_get64( &buffer );
//fprintf( stderr, " guid=0x%8.8x-0x%4.4x-0x%4.4x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x size=%lld\n",
// guid.v1,guid.v2, guid.v3,
// guid.v4[0],guid.v4[1],guid.v4[2],guid.v4[3],
// guid.v4[4],guid.v4[5],guid.v4[6],guid.v4[7],
// i_size );
if( CmpGuid( &guid, &asf_object_file_properties_guid ) )
{
var_buffer_getmemory( &buffer, NULL, 16 );
hdr->i_file_size = var_buffer_get64( &buffer );
var_buffer_getmemory( &buffer, NULL, 8 );
hdr->i_data_packets_count = var_buffer_get64( &buffer );
var_buffer_getmemory( &buffer, NULL, 8+8+8+4);
hdr->i_min_data_packet_size = var_buffer_get32( &buffer );
var_buffer_getmemory( &buffer, NULL, i_size - 24 - 16 - 8 - 8 - 8 - 8-8-8-4 - 4);
}
else if( CmpGuid( &guid, &asf_object_stream_properties_guid ) )
{
int i_stream_id;
guid_t stream_type;
//msg_Dbg( p_input, "found stream_properties" );
var_buffer_getguid( &buffer, &stream_type );
var_buffer_getmemory( &buffer, NULL, 32 );
i_stream_id = var_buffer_get8( &buffer ) & 0x7f;
//fprintf( stderr, " 1---------------------skip:%lld\n", i_size - 24 - 32 - 16 - 1 );
var_buffer_getmemory( &buffer, NULL, i_size - 24 - 32 - 16 - 1);
if( CmpGuid( &stream_type, &asf_object_stream_type_video ) )
{
//fprintf( stderr, "\nvideo stream[%d] found\n", i_stream_id );
//msg_Dbg( p_input, "video stream[%d] found", i_stream_id );
hdr->stream[i_stream_id].i_cat = ASF_STREAM_VIDEO;
}
else if( CmpGuid( &stream_type, &asf_object_stream_type_audio ) )
{
//fprintf( stderr, "\naudio stream[%d] found\n", i_stream_id );
//msg_Dbg( p_input, "audio stream[%d] found", i_stream_id );
hdr->stream[i_stream_id].i_cat = ASF_STREAM_AUDIO;
}
else
{
// msg_Dbg( p_input, "unknown stream[%d] found", i_stream_id );
hdr->stream[i_stream_id].i_cat = ASF_STREAM_UNKNOWN;
}
}
else if ( CmpGuid( &guid, &asf_object_bitrate_properties_guid ) )
{
int i_count;
uint8_t i_stream_id;
i_count = var_buffer_get16( &buffer );
i_size -= 2;
while( i_count > 0 )
{
i_stream_id = var_buffer_get16( &buffer )&0x7f;
hdr->stream[i_stream_id].i_bitrate = var_buffer_get32( &buffer );
i_count--;
i_size -= 6;
}
//fprintf( stderr, " 2---------------------skip:%lld\n", i_size - 24);
var_buffer_getmemory( &buffer, NULL, i_size - 24 );
}
else
{
//fprintf( stderr, " 3---------------------skip:%lld\n", i_size - 24);
// skip unknown guid
var_buffer_getmemory( &buffer, NULL, i_size - 24 );
}
if( var_buffer_readempty( &buffer ) )
{
return;
}
}
}
void E_( asf_StreamSelect ) ( asf_header_t *hdr,
int i_bitrate_max,
vlc_bool_t b_all, vlc_bool_t b_audio, vlc_bool_t b_video )
{
/* XXX FIXME use mututal eclusion information */
int i;
int i_audio, i_video;
int i_bitrate_total;
char *psz_stream;
i_audio = 0;
i_video = 0;
i_bitrate_total = 0;
if( b_all )
{
/* select all valid stream */
for( i = 1; i < 128; i++ )
{
if( hdr->stream[i].i_cat != ASF_STREAM_UNKNOWN )
{
hdr->stream[i].i_selected = 1;
}
}
return;
}
else
{
for( i = 0; i < 128; i++ )
{
hdr->stream[i].i_selected = 0; /* by default, not selected */
}
}
#if 0
psz_stream = config_GetPsz( p_input, "mms-stream" );
if( psz_stream && *psz_stream )
{
char *psz_tmp = psz_stream;
while( *psz_tmp )
{
if( *psz_tmp == ',' )
{
psz_tmp++;
}
else
{
int i_stream;
i_stream = atoi( psz_tmp );
while( *psz_tmp != '\0' && *psz_tmp != ',' )
{
psz_tmp++;
}
if( i_stream > 0 && i_stream < 128 &&
stream[i_stream].i_cat != MMS_STREAM_UNKNOWN )
{
stream[i_stream].i_selected = 1;
}
}
}
FREE( psz_stream );
return;
}
FREE( psz_stream );
#endif
/* big test:
* select a stream if
* - no audio nor video stream
* - or:
* - if i_bitrate_max not set keep the highest bitrate
* - if i_bitrate_max is set, keep stream that make we used best
* quality regarding i_bitrate_max
*
* XXX: little buggy:
* - it doesn't use mutual exclusion info..
* - when selecting a better stream we could select
* something that make i_bitrate_total> i_bitrate_max
*/
for( i = 1; i < 128; i++ )
{
if( hdr->stream[i].i_cat == ASF_STREAM_UNKNOWN )
{
continue;
}
else if( hdr->stream[i].i_cat == ASF_STREAM_AUDIO && b_audio &&
( i_audio <= 0 ||
( ( ( hdr->stream[i].i_bitrate > hdr->stream[i_audio].i_bitrate &&
( i_bitrate_total + hdr->stream[i].i_bitrate - hdr->stream[i_audio].i_bitrate
< i_bitrate_max || !i_bitrate_max) ) ||
( hdr->stream[i].i_bitrate < hdr->stream[i_audio].i_bitrate &&
i_bitrate_max != 0 && i_bitrate_total > i_bitrate_max )
) ) ) )
{
/* unselect old stream */
if( i_audio > 0 )
{
hdr->stream[i_audio].i_selected = 0;
if( hdr->stream[i_audio].i_bitrate> 0 )
{
i_bitrate_total -= hdr->stream[i_audio].i_bitrate;
}
}
hdr->stream[i].i_selected = 1;
if( hdr->stream[i].i_bitrate> 0 )
{
i_bitrate_total += hdr->stream[i].i_bitrate;
}
i_audio = i;
}
else if( hdr->stream[i].i_cat == ASF_STREAM_VIDEO && b_video &&
( i_video <= 0 ||
(
( ( hdr->stream[i].i_bitrate > hdr->stream[i_video].i_bitrate &&
( i_bitrate_total + hdr->stream[i].i_bitrate - hdr->stream[i_video].i_bitrate
< i_bitrate_max || !i_bitrate_max) ) ||
( hdr->stream[i].i_bitrate < hdr->stream[i_video].i_bitrate &&
i_bitrate_max != 0 && i_bitrate_total > i_bitrate_max )
) ) ) )
{
/* unselect old stream */
if( i_video > 0 )
{
hdr->stream[i_video].i_selected = 0;
if( hdr->stream[i_video].i_bitrate> 0 )
{
i_bitrate_total -= hdr->stream[i_video].i_bitrate;
}
}
hdr->stream[i].i_selected = 1;
if( hdr->stream[i].i_bitrate> 0 )
{
i_bitrate_total += hdr->stream[i].i_bitrate;
}
i_video = i;
}
}
#if 0
if( i_bitrate_max > 0 )
{
msg_Dbg( p_input,
"requested bitrate:%d real bitrate:%d",
i_bitrate_max, i_bitrate_total );
}
else
{
msg_Dbg( p_input,
"total bitrate:%d",
i_bitrate_total );
}
#endif
}
......@@ -2,7 +2,7 @@
* asf.h: MMS access plug-in
*****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN
* $Id: asf.h,v 1.4 2003/03/02 18:17:58 fenrir Exp $
* $Id: asf.h,v 1.5 2003/04/20 19:29:43 fenrir Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
......@@ -28,6 +28,30 @@
*
****************************************************************************/
#define ASF_STREAM_VIDEO 0x0001
#define ASF_STREAM_AUDIO 0x0002
#define ASF_STREAM_UNKNOWN 0xffff
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
{
int64_t i_file_size;
int64_t i_data_packets_count;
int32_t i_min_data_packet_size;
asf_stream_t stream[128];
} asf_header_t;
typedef struct guid_s
{
uint32_t v1; /* le */
......@@ -36,36 +60,13 @@ typedef struct guid_s
uint8_t v4[8];
} guid_t;
static inline int CmpGuid( const guid_t *p_guid1, const guid_t *p_guid2 )
{
return( ( p_guid1->v1 == p_guid2->v1 &&
p_guid1->v2 == p_guid2->v2 &&
p_guid1->v3 == p_guid2->v3 &&
p_guid1->v4[0] == p_guid2->v4[0] &&
p_guid1->v4[1] == p_guid2->v4[1] &&
p_guid1->v4[2] == p_guid2->v4[2] &&
p_guid1->v4[3] == p_guid2->v4[3] &&
p_guid1->v4[4] == p_guid2->v4[4] &&
p_guid1->v4[5] == p_guid2->v4[5] &&
p_guid1->v4[6] == p_guid2->v4[6] &&
p_guid1->v4[7] == p_guid2->v4[7] ) ? 1 : 0 );
}
static void GenerateGuid( guid_t *p_guid )
{
int i;
srand( mdate() & 0xffffffff );
/* FIXME should be generated using random data */
p_guid->v1 = 0xbabac001;
p_guid->v2 = ( (uint64_t)rand() << 16 ) / RAND_MAX;
p_guid->v3 = ( (uint64_t)rand() << 16 ) / RAND_MAX;
for( i = 0; i < 8; i++ )
{
p_guid->v4[i] = ( (uint64_t)rand() * 256 ) / RAND_MAX;
}
}
void E_( GenerateGuid ) ( guid_t * );
void E_( asf_HeaderParse ) ( asf_header_t *, uint8_t *, int );
void E_( asf_StreamSelect ) ( asf_header_t *,
int i_bitrate_max, vlc_bool_t b_all, vlc_bool_t b_audio,
vlc_bool_t b_video );
#define GUID_FMT "%8.8x-%4.4x-%4.4x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x"
#define GUID_PRINT( guid ) \
......
This diff is collapsed.
......@@ -2,7 +2,7 @@
* mms.h: MMS access plug-in
*****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN
* $Id: mms.h,v 1.8 2003/03/03 01:38:07 fenrir Exp $
* $Id: mms.h,v 1.9 2003/04/20 19:29:43 fenrir Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
......@@ -21,112 +21,19 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/* url: [/]host[:port][/path] */
typedef struct url_s
{
char *psz_server_addr;
int i_server_port;
char *psz_bind_addr;
int i_bind_port;
char *psz_path;
/* private */
char *psz_private;
} url_t;
#define FREE( p ) if( p ) { free( p ); (p ) = NULL; }
#define MMS_PROTO_AUTO 0
#define MMS_PROTO_TCP 1
#define MMS_PROTO_UDP 2
#define MMS_PROTO_HTTP 3
#define MMS_PACKET_ANY 0
#define MMS_PACKET_CMD 1
#define MMS_PACKET_HEADER 2
#define MMS_PACKET_MEDIA 3
#define MMS_PACKET_UDP_TIMING 4
#define MMS_STREAM_VIDEO 0x0001
#define MMS_STREAM_AUDIO 0x0002
#define MMS_STREAM_UNKNOWN 0xffff
#define MMS_CMD_HEADERSIZE 48
typedef struct mms_stream_s
{
int i_id; /* 1 -> 127 */
int i_cat; /* MMS_STREAM_VIDEO, MMS_STREAM_AUDIO */
int i_bitrate; /* -1 if unknown */
int i_selected;
} mms_stream_t;
#define MMS_BUFFER_SIZE 100000
typedef struct access_s
{
int i_proto; /* MMS_PROTO_TCP, MMS_PROTO_UDP */
input_socket_t socket_tcp; /* TCP socket for communication with server */
input_socket_t socket_udp; /* Optional UDP socket for data(media/header packet) */
/* send by server */
char *psz_bind_addr; /* used by udp */
url_t url; /* connect to this server */
mms_stream_t stream[128]; /* in asf never more than 1->127 streams */
off_t i_pos; /* position of next byte to be read */
/* */
uint8_t buffer_tcp[MMS_BUFFER_SIZE];
int i_buffer_tcp;
uint8_t buffer_udp[MMS_BUFFER_SIZE];
int i_buffer_udp;
/* data necessary to send data to server */
guid_t guid;
int i_command_level;
int i_seq_num;
uint32_t i_header_packet_id_type;
uint32_t i_media_packet_id_type;
int i_packet_seq_num;
uint8_t *p_cmd; /* latest command read */
int i_cmd; /* allocated at the begining */
uint8_t *p_header; /* allocated by mms_ReadPacket */
int i_header;
uint8_t *p_media; /* allocated by mms_ReadPacket */
size_t i_media;
size_t i_media_used;
/* extracted informations */
int i_command;
int i_eos;
/* from 0x01 answer (not yet set) */
char *psz_server_version;
char *psz_tool_version;
char *psz_update_player_url;
char *psz_encryption_type;
/* from 0x06 answer */
uint32_t i_flags_broadcast;
uint32_t i_media_length;
size_t i_packet_length;
uint32_t i_packet_count;
int i_max_bit_rate;
int i_header_size;
} access_t;
/* mmst and mmsu */
int E_( MMSTUOpen ) ( input_thread_t * );
void E_( MMSTUClose ) ( input_thread_t * );
/* mmsh */
int E_( MMSHOpen ) ( input_thread_t * );
void E_( MMSHClose ) ( input_thread_t * );
static inline uint16_t GetWLE( uint8_t *p_buff )
{
......@@ -139,3 +46,20 @@ static inline uint32_t GetDWLE( uint8_t *p_buff )
( p_buff[2] <<16 ) + ( p_buff[3] <<24 ) );
}
#define FREE( p ) if( p ) { free( p ); (p) = NULL; }
/* url: [/]host[:port][/path][@username[:password]] */
typedef struct url_s
{
char *psz_host;
int i_port;
char *psz_path;
char *psz_username;
char *psz_password;
} url_t;
url_t *E_( url_new ) ( char * );
void E_( url_free ) ( url_t * );
/*****************************************************************************
* mmsh.c:
*****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN
* $Id: mmsh.c,v 1.1 2003/04/20 19:29:43 fenrir Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*
* TODO:
* * http_proxy
*
*/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#ifdef HAVE_ERRNO_H
# include <errno.h>
#endif
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif