2001-05-29 17:03:17 +00:00
/*
* Network layer for MPlayer
* by Bertrand BAUDET < bertrand_baudet @ yahoo . com >
* ( C ) 2001 , MPlayer team .
*/
2001-06-05 08:49:11 +00:00
//#define DUMP2FILE
2001-06-04 17:52:33 +00:00
2001-08-01 09:14:02 +00:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
2001-05-18 16:14:06 +00:00
# include <unistd.h>
2001-08-01 09:14:02 +00:00
2001-06-04 17:52:33 +00:00
# include <errno.h>
2001-05-29 17:03:17 +00:00
# include <ctype.h>
2001-05-18 16:14:06 +00:00
2001-10-30 17:03:11 +00:00
# include "config.h"
2001-06-04 17:52:33 +00:00
# include "stream.h"
# include "demuxer.h"
2002-01-20 21:39:56 +00:00
# include "../cfgparser.h"
2001-06-04 17:52:33 +00:00
2001-05-20 12:58:41 +00:00
# include "network.h"
2001-05-29 17:03:17 +00:00
# include "http.h"
# include "url.h"
# include "asf.h"
2002-08-05 00:39:07 +00:00
# ifndef STREAMING_LIVE_DOT_COM
2001-12-23 22:09:02 +00:00
# include "rtp.h"
2002-08-05 00:39:07 +00:00
# endif
2002-12-26 17:25:22 +00:00
# include "pnm.h"
2001-05-20 12:58:41 +00:00
2002-06-20 08:50:40 +00:00
# include "../version.h"
2002-01-12 21:08:12 +00:00
extern int verbose ;
2002-10-23 17:21:01 +00:00
extern int stream_cache_size ;
2002-01-12 21:08:12 +00:00
2002-10-23 14:46:20 +00:00
extern int mp_input_check_interrupt ( int time ) ;
2002-10-29 09:18:53 +00:00
int asf_streaming_start ( stream_t * stream ) ;
int rtsp_streaming_start ( stream_t * stream ) ;
2002-07-05 02:37:56 +00:00
/* Variables for the command line option -user, -passwd & -bandwidth */
2002-10-23 17:21:01 +00:00
char * network_username = NULL ;
char * network_password = NULL ;
int network_bandwidth = 0 ;
2002-06-25 08:04:52 +00:00
2001-11-20 22:20:20 +00:00
static struct {
char * mime_type ;
int demuxer_type ;
} mime_type_table [ ] = {
// MP3 streaming, some MP3 streaming server answer with audio/mpeg
2002-02-16 21:48:59 +00:00
{ " audio/mpeg " , DEMUXER_TYPE_AUDIO } ,
2001-11-20 22:20:20 +00:00
// MPEG streaming
{ " video/mpeg " , DEMUXER_TYPE_MPEG_PS } ,
2002-05-09 14:52:23 +00:00
{ " video/x-mpeg " , DEMUXER_TYPE_MPEG_PS } ,
{ " video/x-mpeg2 " , DEMUXER_TYPE_MPEG_PS } ,
2001-11-20 22:20:20 +00:00
// AVI ??? => video/x-msvideo
{ " video/x-msvideo " , DEMUXER_TYPE_AVI } ,
// MOV => video/quicktime
{ " video/quicktime " , DEMUXER_TYPE_MOV } ,
// ASF
{ " audio/x-ms-wax " , DEMUXER_TYPE_ASF } ,
{ " audio/x-ms-wma " , DEMUXER_TYPE_ASF } ,
{ " video/x-ms-asf " , DEMUXER_TYPE_ASF } ,
{ " video/x-ms-afs " , DEMUXER_TYPE_ASF } ,
{ " video/x-ms-wvx " , DEMUXER_TYPE_ASF } ,
{ " video/x-ms-wmv " , DEMUXER_TYPE_ASF } ,
{ " video/x-ms-wma " , DEMUXER_TYPE_ASF } ,
2002-02-21 13:14:52 +00:00
// Playlists
2002-09-13 22:39:48 +00:00
{ " video/x-ms-wmx " , DEMUXER_TYPE_PLAYLIST } ,
2002-02-21 13:14:52 +00:00
{ " audio/x-scpls " , DEMUXER_TYPE_PLAYLIST } ,
{ " audio/x-mpegurl " , DEMUXER_TYPE_PLAYLIST } ,
2002-05-09 14:52:23 +00:00
{ " audio/x-pls " , DEMUXER_TYPE_PLAYLIST } ,
// Real Media
2002-11-05 19:03:52 +00:00
{ " audio/x-pn-realaudio " , DEMUXER_TYPE_REAL } ,
// OGG Streaming
{ " application/x-ogg " , DEMUXER_TYPE_OGG }
2001-11-20 22:20:20 +00:00
} ;
2003-01-11 14:02:23 +00:00
/*
* An autodetection based on the extension is not a good idea .
*
2001-11-20 22:20:20 +00:00
static struct {
char * extension ;
int demuxer_type ;
} extensions_table [ ] = {
{ " mpeg " , DEMUXER_TYPE_MPEG_PS } ,
{ " mpg " , DEMUXER_TYPE_MPEG_PS } ,
2001-11-22 17:14:26 +00:00
{ " mpe " , DEMUXER_TYPE_MPEG_ES } ,
2001-11-20 22:20:20 +00:00
{ " avi " , DEMUXER_TYPE_AVI } ,
{ " mov " , DEMUXER_TYPE_MOV } ,
2001-11-22 17:14:26 +00:00
{ " qt " , DEMUXER_TYPE_MOV } ,
2001-11-20 22:20:20 +00:00
{ " asx " , DEMUXER_TYPE_ASF } ,
{ " asf " , DEMUXER_TYPE_ASF } ,
{ " wmv " , DEMUXER_TYPE_ASF } ,
{ " wma " , DEMUXER_TYPE_ASF } ,
2001-11-22 17:14:26 +00:00
{ " viv " , DEMUXER_TYPE_VIVO } ,
2002-01-18 11:05:29 +00:00
{ " rm " , DEMUXER_TYPE_REAL } ,
2002-05-09 14:52:23 +00:00
{ " ra " , DEMUXER_TYPE_REAL } ,
2002-01-18 11:05:29 +00:00
{ " y4m " , DEMUXER_TYPE_Y4M } ,
2002-02-16 21:48:59 +00:00
{ " mp3 " , DEMUXER_TYPE_AUDIO } ,
2002-11-05 19:03:52 +00:00
{ " ogg " , DEMUXER_TYPE_OGG } ,
2002-02-16 21:48:59 +00:00
{ " wav " , DEMUXER_TYPE_AUDIO } ,
2002-02-21 13:14:52 +00:00
{ " pls " , DEMUXER_TYPE_PLAYLIST } ,
{ " m3u " , DEMUXER_TYPE_PLAYLIST }
2001-11-20 22:20:20 +00:00
} ;
2003-01-11 14:02:23 +00:00
*/
2001-06-04 17:52:33 +00:00
streaming_ctrl_t *
streaming_ctrl_new ( ) {
streaming_ctrl_t * streaming_ctrl ;
streaming_ctrl = ( streaming_ctrl_t * ) malloc ( sizeof ( streaming_ctrl_t ) ) ;
if ( streaming_ctrl = = NULL ) {
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_FATAL , " Failed to allocate memory \n " ) ;
2001-06-04 17:52:33 +00:00
return NULL ;
}
memset ( streaming_ctrl , 0 , sizeof ( streaming_ctrl_t ) ) ;
return streaming_ctrl ;
}
void
streaming_ctrl_free ( streaming_ctrl_t * streaming_ctrl ) {
if ( streaming_ctrl = = NULL ) return ;
2002-01-19 09:04:02 +00:00
if ( streaming_ctrl - > url ) url_free ( streaming_ctrl - > url ) ;
if ( streaming_ctrl - > buffer ) free ( streaming_ctrl - > buffer ) ;
if ( streaming_ctrl - > data ) free ( streaming_ctrl - > data ) ;
2001-06-04 17:52:33 +00:00
free ( streaming_ctrl ) ;
}
2002-08-05 00:39:07 +00:00
# ifndef STREAMING_LIVE_DOT_COM
2001-12-23 22:09:02 +00:00
int
read_rtp_from_server ( int fd , char * buffer , int length ) {
struct rtpheader rh ;
char * data ;
int len ;
static int got_first = 0 ;
2002-02-06 20:30:34 +00:00
static unsigned short sequence ;
2001-12-23 22:09:02 +00:00
if ( buffer = = NULL | | length < 0 ) return - 1 ;
getrtp2 ( fd , & rh , & data , & len ) ;
2002-02-06 20:30:34 +00:00
if ( got_first & & rh . b . sequence ! = ( unsigned short ) ( sequence + 1 ) )
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " RTP packet sequence error! Expected: %d, received: %d \n " ,
2001-12-23 22:09:02 +00:00
sequence + 1 , rh . b . sequence ) ;
got_first = 1 ;
sequence = rh . b . sequence ;
memcpy ( buffer , data , len ) ;
return ( len ) ;
}
2002-08-05 00:39:07 +00:00
# endif
2001-12-23 22:09:02 +00:00
2001-05-29 17:03:17 +00:00
// Connect to a server using a TCP connection
2002-09-03 01:29:44 +00:00
// return -2 for fatal error, like unable to resolve name, connection timeout...
// return -1 is unable to connect to a particular port
2001-05-18 16:14:06 +00:00
int
connect2Server ( char * host , int port ) {
int socket_server_fd ;
2001-06-04 17:52:33 +00:00
int err , err_len ;
2002-02-23 21:22:55 +00:00
int ret , count = 0 ;
2001-06-04 17:52:33 +00:00
fd_set set ;
struct timeval tv ;
2001-05-18 16:14:06 +00:00
struct sockaddr_in server_address ;
2002-10-29 09:18:53 +00:00
struct hostent * hp = NULL ;
2001-06-04 17:52:33 +00:00
2001-05-18 16:14:06 +00:00
socket_server_fd = socket ( AF_INET , SOCK_STREAM , 0 ) ;
if ( socket_server_fd = = - 1 ) {
2002-06-17 08:16:47 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " Failed to create socket \n " ) ;
2002-09-03 01:29:44 +00:00
return - 2 ;
2001-05-18 16:14:06 +00:00
}
if ( isalpha ( host [ 0 ] ) ) {
2002-09-27 19:20:20 +00:00
mp_msg ( MSGT_NETWORK , MSGL_STATUS , " Resolving %s ... \n " , host ) ;
2001-11-20 22:20:20 +00:00
hp = ( struct hostent * ) gethostbyname ( host ) ;
2001-05-20 12:58:41 +00:00
if ( hp = = NULL ) {
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " Counldn't resolve name: %s \n " , host ) ;
2002-09-03 01:29:44 +00:00
return - 2 ;
2001-05-18 16:14:06 +00:00
}
2001-05-20 12:58:41 +00:00
memcpy ( ( void * ) & server_address . sin_addr . s_addr , ( void * ) hp - > h_addr , hp - > h_length ) ;
2001-05-18 16:14:06 +00:00
} else {
inet_pton ( AF_INET , host , & server_address . sin_addr ) ;
}
server_address . sin_family = AF_INET ;
server_address . sin_port = htons ( port ) ;
2001-11-20 22:20:20 +00:00
// Turn the socket as non blocking so we can timeout on the connection
2002-10-29 09:18:53 +00:00
if ( isalpha ( host [ 0 ] ) & & hp ! = NULL ) {
2002-09-27 19:20:20 +00:00
mp_msg ( MSGT_NETWORK , MSGL_STATUS , " Connecting to server %s[%d.%d.%d.%d]:%d ... \n " , host , ( hp - > h_addr_list [ 0 ] [ 0 ] ) & 0xff , ( hp - > h_addr_list [ 0 ] [ 1 ] ) & 0xff , ( hp - > h_addr_list [ 0 ] [ 2 ] ) & 0xff , ( hp - > h_addr_list [ 0 ] [ 3 ] ) & 0xff , port ) ;
} else {
mp_msg ( MSGT_NETWORK , MSGL_STATUS , " Connecting to server %s:%d ... \n " , host , port ) ;
}
2001-11-20 22:20:20 +00:00
fcntl ( socket_server_fd , F_SETFL , fcntl ( socket_server_fd , F_GETFL ) | O_NONBLOCK ) ;
2001-05-18 16:14:06 +00:00
if ( connect ( socket_server_fd , ( struct sockaddr * ) & server_address , sizeof ( server_address ) ) = = - 1 ) {
2001-06-04 17:52:33 +00:00
if ( errno ! = EINPROGRESS ) {
2002-06-17 08:16:47 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " Failed to connect to server \n " ) ;
2001-06-04 17:52:33 +00:00
close ( socket_server_fd ) ;
return - 1 ;
}
}
2002-06-21 07:06:46 +00:00
tv . tv_sec = 0 ;
tv . tv_usec = 500000 ;
2001-06-04 17:52:33 +00:00
FD_ZERO ( & set ) ;
FD_SET ( socket_server_fd , & set ) ;
2001-11-20 22:20:20 +00:00
// When the connection will be made, we will have a writable fd
2002-02-23 21:22:55 +00:00
while ( ( ret = select ( socket_server_fd + 1 , NULL , & set , NULL , & tv ) ) = = 0 ) {
2002-06-17 08:16:47 +00:00
if ( ret < 0 ) mp_msg ( MSGT_NETWORK , MSGL_ERR , " select failed \n " ) ;
2002-02-23 21:22:55 +00:00
else if ( ret > 0 ) break ;
2002-10-23 14:46:20 +00:00
else if ( count > 30 | | mp_input_check_interrupt ( 500 ) ) {
2002-06-21 07:06:46 +00:00
if ( count > 30 )
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " Connection timeout \n " ) ;
2002-02-23 21:22:55 +00:00
else
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_V , " Connection interuppted by user \n " ) ;
2003-01-06 16:43:42 +00:00
return - 3 ;
2002-02-23 21:22:55 +00:00
}
count + + ;
FD_ZERO ( & set ) ;
FD_SET ( socket_server_fd , & set ) ;
2002-06-21 07:06:46 +00:00
tv . tv_sec = 0 ;
tv . tv_usec = 500000 ;
2001-05-18 16:14:06 +00:00
}
2001-11-20 22:20:20 +00:00
// Turn back the socket as blocking
fcntl ( socket_server_fd , F_SETFL , fcntl ( socket_server_fd , F_GETFL ) & ~ O_NONBLOCK ) ;
2001-12-14 20:45:30 +00:00
// Check if there were any error
err_len = sizeof ( int ) ;
ret = getsockopt ( socket_server_fd , SOL_SOCKET , SO_ERROR , & err , & err_len ) ;
if ( ret < 0 ) {
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " getsockopt failed : %s \n " , strerror ( errno ) ) ;
2002-09-03 01:29:44 +00:00
return - 2 ;
2001-12-14 20:45:30 +00:00
}
if ( err > 0 ) {
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " Connect error : %s \n " , strerror ( err ) ) ;
2001-12-14 20:45:30 +00:00
return - 1 ;
}
2001-05-18 16:14:06 +00:00
return socket_server_fd ;
}
2002-01-14 06:44:30 +00:00
URL_t *
check4proxies ( URL_t * url ) {
2002-02-11 05:16:09 +00:00
URL_t * url_out = NULL ;
2002-01-19 09:04:02 +00:00
if ( url = = NULL ) return NULL ;
2002-02-11 05:16:09 +00:00
url_out = url_new ( url - > url ) ;
2002-01-14 06:44:30 +00:00
if ( ! strcasecmp ( url - > protocol , " http_proxy " ) ) {
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_V , " Using HTTP proxy: http://%s:%d \n " , url - > hostname , url - > port ) ;
2002-02-11 05:16:09 +00:00
return url_out ;
2002-01-14 06:44:30 +00:00
}
// Check if the http_proxy environment variable is set.
if ( ! strcasecmp ( url - > protocol , " http " ) ) {
char * proxy ;
proxy = getenv ( " http_proxy " ) ;
if ( proxy ! = NULL ) {
// We got a proxy, build the URL to use it
int len ;
char * new_url ;
URL_t * tmp_url ;
URL_t * proxy_url = url_new ( proxy ) ;
if ( proxy_url = = NULL ) {
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_WARN , " Invalid proxy setting...Trying without proxy. \n " ) ;
2002-02-11 05:16:09 +00:00
return url_out ;
2002-01-14 06:44:30 +00:00
}
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_V , " Using HTTP proxy: %s \n " , proxy_url - > url ) ;
2002-01-14 06:44:30 +00:00
len = strlen ( proxy_url - > hostname ) + strlen ( url - > url ) + 20 ; // 20 = http_proxy:// + port
new_url = malloc ( len + 1 ) ;
if ( new_url = = NULL ) {
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_FATAL , " Memory allocation failed \n " ) ;
2002-02-11 05:16:09 +00:00
return url_out ;
2002-01-14 06:44:30 +00:00
}
2002-04-30 16:58:54 +00:00
sprintf ( new_url , " http_proxy://%s:%d/%s " , proxy_url - > hostname , proxy_url - > port , url - > url ) ;
2002-01-14 06:44:30 +00:00
tmp_url = url_new ( new_url ) ;
if ( tmp_url = = NULL ) {
2002-02-11 05:16:09 +00:00
return url_out ;
2002-01-14 06:44:30 +00:00
}
2002-02-11 05:16:09 +00:00
url_free ( url_out ) ;
url_out = tmp_url ;
2002-01-14 06:44:30 +00:00
free ( new_url ) ;
url_free ( proxy_url ) ;
}
}
2002-02-11 05:16:09 +00:00
return url_out ;
2002-01-14 06:44:30 +00:00
}
2001-06-04 17:52:33 +00:00
int
http_send_request ( URL_t * url ) {
HTTP_header_t * http_hdr ;
2002-01-12 21:08:12 +00:00
URL_t * server_url ;
2001-12-18 18:45:00 +00:00
char str [ 80 ] ;
2001-06-04 17:52:33 +00:00
int fd ;
2002-01-12 21:08:12 +00:00
int ret ;
int proxy = 0 ; // Boolean
2001-06-04 17:52:33 +00:00
http_hdr = http_new_header ( ) ;
2002-01-12 21:08:12 +00:00
2002-01-14 01:12:44 +00:00
if ( ! strcasecmp ( url - > protocol , " http_proxy " ) ) {
2002-01-12 21:08:12 +00:00
proxy = 1 ;
server_url = url_new ( ( url - > file ) + 1 ) ;
http_set_uri ( http_hdr , server_url - > url ) ;
} else {
server_url = url ;
http_set_uri ( http_hdr , server_url - > file ) ;
}
snprintf ( str , 80 , " Host: %s " , server_url - > hostname ) ;
2001-12-18 18:45:00 +00:00
http_set_field ( http_hdr , str ) ;
2002-06-20 08:50:40 +00:00
http_set_field ( http_hdr , " User-Agent: MPlayer/ " VERSION ) ;
2001-06-04 17:52:33 +00:00
http_set_field ( http_hdr , " Connection: closed " ) ;
2002-06-23 09:17:52 +00:00
http_add_basic_authentication ( http_hdr , url - > username , url - > password ) ;
2001-06-04 17:52:33 +00:00
if ( http_build_request ( http_hdr ) = = NULL ) {
return - 1 ;
}
2002-01-12 21:08:12 +00:00
if ( proxy ) {
if ( url - > port = = 0 ) url - > port = 8080 ; // Default port for the proxy server
fd = connect2Server ( url - > hostname , url - > port ) ;
url_free ( server_url ) ;
} else {
if ( server_url - > port = = 0 ) server_url - > port = 80 ; // Default port for the web server
fd = connect2Server ( server_url - > hostname , server_url - > port ) ;
}
2001-06-04 17:52:33 +00:00
if ( fd < 0 ) {
return - 1 ;
}
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_DBG2 , " Request: [%s] \n " , http_hdr - > buffer ) ;
2002-01-12 21:08:12 +00:00
ret = write ( fd , http_hdr - > buffer , http_hdr - > buffer_size ) ;
2002-10-29 09:18:53 +00:00
if ( ret ! = ( int ) http_hdr - > buffer_size ) {
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " Error while sending HTTP request: didn't sent all the request \n " ) ;
2002-01-12 21:08:12 +00:00
return - 1 ;
}
2001-06-04 17:52:33 +00:00
http_free ( http_hdr ) ;
return fd ;
}
HTTP_header_t *
http_read_response ( int fd ) {
HTTP_header_t * http_hdr ;
char response [ BUFFER_SIZE ] ;
int i ;
http_hdr = http_new_header ( ) ;
if ( http_hdr = = NULL ) {
return NULL ;
}
do {
2001-11-20 22:20:20 +00:00
i = read ( fd , response , BUFFER_SIZE ) ;
2001-06-04 17:52:33 +00:00
if ( i < 0 ) {
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " Read failed \n " ) ;
2001-12-07 07:17:05 +00:00
http_free ( http_hdr ) ;
return NULL ;
}
if ( i = = 0 ) {
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " http_read_response read 0 -ie- EOF \n " ) ;
2001-12-07 07:17:05 +00:00
http_free ( http_hdr ) ;
return NULL ;
2001-06-04 17:52:33 +00:00
}
http_response_append ( http_hdr , response , i ) ;
2001-10-26 18:26:06 +00:00
} while ( ! http_is_header_entire ( http_hdr ) ) ;
2001-06-04 17:52:33 +00:00
http_response_parse ( http_hdr ) ;
return http_hdr ;
}
2002-06-24 20:12:18 +00:00
int
http_authenticate ( HTTP_header_t * http_hdr , URL_t * url , int * auth_retry ) {
char * aut ;
2002-10-29 09:18:53 +00:00
2002-06-25 08:04:52 +00:00
if ( * auth_retry = = 1 ) {
2002-06-24 20:12:18 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " Authentication failed \n " ) ;
2002-06-25 23:56:33 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " Please use the option -user and -passwd to provide your username/password for a list of URLs, \n " ) ;
2002-06-25 08:04:52 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " or form an URL like: http://username:password@hostname/file \n " ) ;
2002-06-24 20:12:18 +00:00
return - 1 ;
}
if ( * auth_retry > 0 ) {
if ( url - > username ) {
free ( url - > username ) ;
url - > username = NULL ;
}
if ( url - > password ) {
free ( url - > password ) ;
url - > password = NULL ;
}
}
2002-06-25 08:04:52 +00:00
2002-06-24 20:12:18 +00:00
aut = http_get_field ( http_hdr , " WWW-Authenticate " ) ;
if ( aut ! = NULL ) {
char * aut_space ;
aut_space = strstr ( aut , " realm= " ) ;
if ( aut_space ! = NULL ) aut_space + = 6 ;
2002-06-25 08:04:52 +00:00
mp_msg ( MSGT_NETWORK , MSGL_INFO , " Authentication required for %s \n " , aut_space ) ;
2002-06-24 20:12:18 +00:00
} else {
2002-06-25 08:04:52 +00:00
mp_msg ( MSGT_NETWORK , MSGL_INFO , " Authentication required \n " ) ;
2002-06-24 20:12:18 +00:00
}
2002-10-23 17:21:01 +00:00
if ( network_username ) {
url - > username = strdup ( network_username ) ;
2002-06-24 20:12:18 +00:00
if ( url - > username = = NULL ) {
mp_msg ( MSGT_NETWORK , MSGL_FATAL , " Memory allocation failed \n " ) ;
return - 1 ;
}
} else {
2002-06-25 08:04:52 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " Unable to read the username \n " ) ;
2002-06-25 23:56:33 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " Please use the option -user and -passwd to provide your username/password for a list of URLs, \n " ) ;
2002-06-25 08:04:52 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " or form an URL like: http://username:password@hostname/file \n " ) ;
2002-06-24 20:12:18 +00:00
return - 1 ;
}
2002-10-23 17:21:01 +00:00
if ( network_password ) {
url - > password = strdup ( network_password ) ;
2002-06-25 08:04:52 +00:00
if ( url - > password = = NULL ) {
mp_msg ( MSGT_NETWORK , MSGL_FATAL , " Memory allocation failed \n " ) ;
return - 1 ;
}
} else {
mp_msg ( MSGT_NETWORK , MSGL_INFO , " No password provided, trying blank password \n " ) ;
}
2002-06-24 20:12:18 +00:00
( * auth_retry ) + + ;
return 0 ;
}
2001-05-29 17:03:17 +00:00
// By using the protocol, the extension of the file or the content-type
// we might be able to guess the streaming type.
int
2002-01-08 07:31:29 +00:00
autodetectProtocol ( streaming_ctrl_t * streaming_ctrl , int * fd_out , int * file_format ) {
2001-05-29 17:03:17 +00:00
HTTP_header_t * http_hdr ;
2002-02-11 05:16:09 +00:00
unsigned int i ;
2001-05-29 17:03:17 +00:00
int fd = - 1 ;
2001-06-04 17:52:33 +00:00
int redirect ;
2002-06-23 09:39:09 +00:00
int auth_retry = 0 ;
2001-05-29 17:03:17 +00:00
char * extension ;
char * content_type ;
char * next_url ;
2002-01-08 07:31:29 +00:00
URL_t * url = streaming_ctrl - > url ;
* file_format = DEMUXER_TYPE_UNKNOWN ;
2001-06-04 17:52:33 +00:00
do {
2002-01-08 07:31:29 +00:00
* fd_out = - 1 ;
2001-06-04 17:52:33 +00:00
next_url = NULL ;
extension = NULL ;
content_type = NULL ;
redirect = 0 ;
2001-05-29 17:03:17 +00:00
2002-01-08 07:31:29 +00:00
if ( url = = NULL ) {
return - 1 ;
}
2001-05-29 17:03:17 +00:00
2002-12-26 17:25:22 +00:00
// Checking for PNM://
if ( ! strcasecmp ( url - > protocol , " pnm " ) ) {
* file_format = DEMUXER_TYPE_REAL ;
return 0 ;
}
2003-01-11 14:02:23 +00:00
/*
* An autodetection based on the extension is not a good idea .
*
2001-06-04 17:52:33 +00:00
// Get the extension of the file if present
if ( url - > file ! = NULL ) {
for ( i = strlen ( url - > file ) ; i > 0 ; i - - ) {
if ( url - > file [ i ] = = ' . ' ) {
extension = ( url - > file ) + i + 1 ;
break ;
}
2001-05-29 17:03:17 +00:00
}
}
2001-11-20 22:20:20 +00:00
extension = NULL ;
2001-06-04 17:52:33 +00:00
if ( extension ! = NULL ) {
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_DBG2 , " Extension: %s \n " , extension ) ;
2001-11-20 22:20:20 +00:00
// Look for the extension in the extensions table
for ( i = 0 ; i < ( sizeof ( extensions_table ) / sizeof ( extensions_table [ 0 ] ) ) ; i + + ) {
if ( ! strcasecmp ( extension , extensions_table [ i ] . extension ) ) {
2002-01-08 07:31:29 +00:00
* file_format = extensions_table [ i ] . demuxer_type ;
return 0 ;
2001-11-20 22:20:20 +00:00
}
2001-06-04 17:52:33 +00:00
}
}
2003-01-11 14:02:23 +00:00
*/
2001-06-04 17:52:33 +00:00
// Checking for RTSP
if ( ! strcasecmp ( url - > protocol , " rtsp " ) ) {
2002-08-05 00:39:07 +00:00
# ifdef STREAMING_LIVE_DOT_COM
* file_format = DEMUXER_TYPE_RTP ;
return 0 ;
# else
mp_msg ( MSGT_NETWORK , MSGL_ERR , " RTSP protocol support requires the \" LIVE.COM Streaming Media \" libraries! \n " ) ;
2002-01-08 07:31:29 +00:00
return - 1 ;
2002-08-05 00:39:07 +00:00
# endif
2001-06-04 17:52:33 +00:00
}
2002-08-05 00:39:07 +00:00
# ifndef STREAMING_LIVE_DOT_COM
// Old, hacked RTP support, which works for MPEG Program Streams
// RTP streams only:
2001-12-23 22:09:02 +00:00
// Checking for RTP
if ( ! strcasecmp ( url - > protocol , " rtp " ) ) {
2002-01-08 07:31:29 +00:00
if ( url - > port = = 0 ) {
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " You must enter a port number for RTP streams! \n " ) ;
2002-01-08 07:31:29 +00:00
return - 1 ;
2001-12-23 22:09:02 +00:00
}
2002-02-06 20:30:34 +00:00
return 0 ;
2001-12-23 22:09:02 +00:00
}
2002-08-05 00:39:07 +00:00
# endif
2001-12-23 22:09:02 +00:00
2001-06-04 17:52:33 +00:00
// Checking for ASF
2001-12-11 01:06:08 +00:00
if ( ! strncasecmp ( url - > protocol , " mms " , 3 ) ) {
2002-01-08 07:31:29 +00:00
* file_format = DEMUXER_TYPE_ASF ;
return 0 ;
2001-05-29 17:03:17 +00:00
}
2001-06-04 17:52:33 +00:00
// HTTP based protocol
2002-01-14 01:12:44 +00:00
if ( ! strcasecmp ( url - > protocol , " http " ) | | ! strcasecmp ( url - > protocol , " http_proxy " ) ) {
2001-06-04 17:52:33 +00:00
fd = http_send_request ( url ) ;
if ( fd < 0 ) {
2002-01-08 07:31:29 +00:00
return - 1 ;
2001-06-04 17:52:33 +00:00
}
2001-05-29 17:03:17 +00:00
2001-06-04 17:52:33 +00:00
http_hdr = http_read_response ( fd ) ;
if ( http_hdr = = NULL ) {
close ( fd ) ;
2001-11-20 22:20:20 +00:00
http_free ( http_hdr ) ;
2002-01-08 07:31:29 +00:00
return - 1 ;
2001-06-04 17:52:33 +00:00
}
2001-05-29 17:03:17 +00:00
2001-06-04 17:52:33 +00:00
* fd_out = fd ;
2002-11-01 17:46:45 +00:00
if ( verbose > 0 ) {
2002-01-12 21:08:12 +00:00
http_debug_hdr ( http_hdr ) ;
}
2002-01-08 07:31:29 +00:00
streaming_ctrl - > data = ( void * ) http_hdr ;
2001-06-04 17:52:33 +00:00
// Check if the response is an ICY status_code reason_phrase
if ( ! strcasecmp ( http_hdr - > protocol , " ICY " ) ) {
2002-04-27 20:42:02 +00:00
switch ( http_hdr - > status_code ) {
case 200 : { // OK
char * field_data = NULL ;
// note: I skip icy-notice1 and 2, as they contain html <BR>
// and are IMHO useless info ::atmos
if ( ( field_data = http_get_field ( http_hdr , " icy-name " ) ) ! = NULL )
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_INFO , " Name : %s \n " , field_data ) ; field_data = NULL ;
2002-04-27 20:42:02 +00:00
if ( ( field_data = http_get_field ( http_hdr , " icy-genre " ) ) ! = NULL )
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_INFO , " Genre : %s \n " , field_data ) ; field_data = NULL ;
2002-04-27 20:42:02 +00:00
if ( ( field_data = http_get_field ( http_hdr , " icy-url " ) ) ! = NULL )
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_INFO , " Website: %s \n " , field_data ) ; field_data = NULL ;
2002-04-27 20:42:02 +00:00
// XXX: does this really mean public server? ::atmos
if ( ( field_data = http_get_field ( http_hdr , " icy-pub " ) ) ! = NULL )
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_INFO , " Public : %s \n " , atoi ( field_data ) ? " yes " : " no " ) ; field_data = NULL ;
2002-04-27 20:42:02 +00:00
if ( ( field_data = http_get_field ( http_hdr , " icy-br " ) ) ! = NULL )
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_INFO , " Bitrate: %skbit/s \n " , field_data ) ; field_data = NULL ;
2002-04-27 20:42:02 +00:00
// Ok, we have detected an mp3 stream
* file_format = DEMUXER_TYPE_AUDIO ;
return 0 ;
}
2002-04-30 17:55:06 +00:00
case 400 : // Server Full
mp_msg ( MSGT_NETWORK , MSGL_ERR , " Error: ICY-Server is full, skipping! \n " ) ;
return - 1 ;
2002-04-28 22:37:35 +00:00
case 401 : // Service Unavailable
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " Error: ICY-Server return service unavailable, skipping! \n " ) ;
2002-04-28 22:37:35 +00:00
return - 1 ;
2003-01-04 11:52:17 +00:00
case 403 : // Service Forbidden
mp_msg ( MSGT_NETWORK , MSGL_ERR , " Error: ICY-Server return 'Service Forbidden' \n " ) ;
return - 1 ;
2002-04-27 20:42:02 +00:00
case 404 : // Resource Not Found
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " Error: ICY-Server couldn't find requested stream, skipping! \n " ) ;
2002-04-27 20:42:02 +00:00
return - 1 ;
default :
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " Error: unhandled ICY-Errorcode, contact MPlayer developers! \n " ) ;
2002-04-27 20:42:02 +00:00
return - 1 ;
}
2001-06-04 17:52:33 +00:00
}
2002-04-27 20:42:02 +00:00
// Assume standard http if not ICY
2001-06-04 17:52:33 +00:00
switch ( http_hdr - > status_code ) {
case 200 : // OK
// Look if we can use the Content-Type
content_type = http_get_field ( http_hdr , " Content-Type " ) ;
if ( content_type ! = NULL ) {
2002-04-27 20:42:02 +00:00
char * content_length = NULL ;
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_V , " Content-Type: [%s] \n " , content_type ) ;
2002-04-27 20:42:02 +00:00
if ( ( content_length = http_get_field ( http_hdr , " Content-Length " ) ) ! = NULL )
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_V , " Content-Length: [%s] \n " , http_get_field ( http_hdr , " Content-Length " ) ) ;
2001-11-20 22:20:20 +00:00
// Check in the mime type table for a demuxer type
for ( i = 0 ; i < ( sizeof ( mime_type_table ) / sizeof ( mime_type_table [ 0 ] ) ) ; i + + ) {
if ( ! strcasecmp ( content_type , mime_type_table [ i ] . mime_type ) ) {
2002-01-08 07:31:29 +00:00
* file_format = mime_type_table [ i ] . demuxer_type ;
return 0 ;
2001-11-20 22:20:20 +00:00
}
2001-06-04 17:52:33 +00:00
}
}
2002-02-23 07:40:25 +00:00
// Not found in the mime type table, don't fail,
// we should try raw HTTP
return 0 ;
2001-06-04 17:52:33 +00:00
// Redirect
case 301 : // Permanently
case 302 : // Temporarily
// TODO: RFC 2616, recommand to detect infinite redirection loops
next_url = http_get_field ( http_hdr , " Location " ) ;
if ( next_url ! = NULL ) {
close ( fd ) ;
url_free ( url ) ;
2002-02-22 14:05:41 +00:00
streaming_ctrl - > url = url = url_new ( next_url ) ;
2002-01-08 07:31:29 +00:00
http_free ( http_hdr ) ;
2001-06-04 17:52:33 +00:00
redirect = 1 ;
}
break ;
2002-06-25 08:04:52 +00:00
case 401 : // Authentication required
2002-06-24 20:12:18 +00:00
if ( http_authenticate ( http_hdr , url , & auth_retry ) < 0 ) return - 1 ;
2002-06-23 09:17:52 +00:00
redirect = 1 ;
break ;
2001-06-04 17:52:33 +00:00
default :
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " Server returned %d: %s \n " , http_hdr - > status_code , http_hdr - > reason_phrase ) ;
2002-01-08 07:31:29 +00:00
return - 1 ;
2001-06-04 17:52:33 +00:00
}
2001-12-11 01:06:08 +00:00
} else {
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " Unknown protocol '%s' \n " , url - > protocol ) ;
2002-01-08 07:31:29 +00:00
return - 1 ;
2001-05-29 17:03:17 +00:00
}
2001-06-04 17:52:33 +00:00
} while ( redirect ) ;
2001-05-29 17:03:17 +00:00
2002-01-08 07:31:29 +00:00
return - 1 ;
2001-06-04 17:52:33 +00:00
}
2001-05-29 17:03:17 +00:00
2001-06-04 17:52:33 +00:00
int
2001-11-20 22:20:20 +00:00
streaming_bufferize ( streaming_ctrl_t * streaming_ctrl , char * buffer , int size ) {
2002-01-19 09:04:02 +00:00
//printf("streaming_bufferize\n");
2001-11-20 22:20:20 +00:00
streaming_ctrl - > buffer = ( char * ) malloc ( size ) ;
if ( streaming_ctrl - > buffer = = NULL ) {
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_FATAL , " Memory allocation failed \n " ) ;
2001-11-20 22:20:20 +00:00
return - 1 ;
}
memcpy ( streaming_ctrl - > buffer , buffer , size ) ;
streaming_ctrl - > buffer_size = size ;
2001-12-19 01:59:25 +00:00
return size ;
2001-11-20 22:20:20 +00:00
}
int
nop_streaming_read ( int fd , char * buffer , int size , streaming_ctrl_t * stream_ctrl ) {
int len = 0 ;
//printf("nop_streaming_read\n");
if ( stream_ctrl - > buffer_size ! = 0 ) {
int buffer_len = stream_ctrl - > buffer_size - stream_ctrl - > buffer_pos ;
2002-01-19 09:04:02 +00:00
//printf("%d bytes in buffer\n", stream_ctrl->buffer_size);
2001-11-20 22:20:20 +00:00
len = ( size < buffer_len ) ? size : buffer_len ;
memcpy ( buffer , ( stream_ctrl - > buffer ) + ( stream_ctrl - > buffer_pos ) , len ) ;
stream_ctrl - > buffer_pos + = len ;
2002-01-19 09:04:02 +00:00
//printf("buffer_pos = %d\n", stream_ctrl->buffer_pos );
2001-11-20 22:20:20 +00:00
if ( stream_ctrl - > buffer_pos > = stream_ctrl - > buffer_size ) {
free ( stream_ctrl - > buffer ) ;
stream_ctrl - > buffer = NULL ;
stream_ctrl - > buffer_size = 0 ;
stream_ctrl - > buffer_pos = 0 ;
2002-01-19 09:04:02 +00:00
//printf("buffer cleaned\n");
2001-11-20 22:20:20 +00:00
}
2002-01-19 09:04:02 +00:00
//printf("read %d bytes from buffer\n", len );
2001-11-20 22:20:20 +00:00
}
if ( len < size ) {
2001-12-07 07:17:05 +00:00
int ret ;
ret = read ( fd , buffer + len , size - len ) ;
2001-12-14 20:45:30 +00:00
if ( ret < 0 ) {
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " nop_streaming_read error : %s \n " , strerror ( errno ) ) ;
2001-12-07 07:17:05 +00:00
}
len + = ret ;
2001-11-20 22:20:20 +00:00
//printf("read %d bytes from network\n", len );
}
2001-06-04 17:52:33 +00:00
return len ;
}
2001-05-29 17:03:17 +00:00
2001-06-04 17:52:33 +00:00
int
2001-11-20 22:20:20 +00:00
nop_streaming_seek ( int fd , off_t pos , streaming_ctrl_t * stream_ctrl ) {
return - 1 ;
2002-10-29 09:18:53 +00:00
// To shut up gcc warning
fd + + ;
pos + + ;
stream_ctrl = NULL ;
2001-11-20 22:20:20 +00:00
}
int
nop_streaming_start ( stream_t * stream ) {
2002-01-08 07:31:29 +00:00
HTTP_header_t * http_hdr = NULL ;
2001-06-04 17:52:33 +00:00
int fd ;
2001-11-20 22:20:20 +00:00
if ( stream = = NULL ) return - 1 ;
2001-06-04 17:52:33 +00:00
2001-11-20 22:20:20 +00:00
fd = stream - > fd ;
2001-06-04 17:52:33 +00:00
if ( fd < 0 ) {
2001-11-20 22:20:20 +00:00
fd = http_send_request ( stream - > streaming_ctrl - > url ) ;
2001-06-04 17:52:33 +00:00
if ( fd < 0 ) return - 1 ;
http_hdr = http_read_response ( fd ) ;
if ( http_hdr = = NULL ) return - 1 ;
2001-05-29 17:03:17 +00:00
switch ( http_hdr - > status_code ) {
case 200 : // OK
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_V , " Content-Type: [%s] \n " , http_get_field ( http_hdr , " Content-Type " ) ) ;
mp_msg ( MSGT_NETWORK , MSGL_V , " Content-Length: [%s] \n " , http_get_field ( http_hdr , " Content-Length " ) ) ;
2001-06-04 17:52:33 +00:00
if ( http_hdr - > body_size > 0 ) {
2001-11-20 22:20:20 +00:00
if ( streaming_bufferize ( stream - > streaming_ctrl , http_hdr - > body , http_hdr - > body_size ) < 0 ) {
http_free ( http_hdr ) ;
return - 1 ;
}
2001-05-29 17:03:17 +00:00
}
break ;
default :
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " Server return %d: %s \n " , http_hdr - > status_code , http_hdr - > reason_phrase ) ;
2001-05-29 17:03:17 +00:00
close ( fd ) ;
2001-06-04 17:52:33 +00:00
fd = - 1 ;
2001-05-29 17:03:17 +00:00
}
2001-11-20 22:20:20 +00:00
stream - > fd = fd ;
2002-01-08 07:31:29 +00:00
} else {
http_hdr = ( HTTP_header_t * ) stream - > streaming_ctrl - > data ;
if ( http_hdr - > body_size > 0 ) {
if ( streaming_bufferize ( stream - > streaming_ctrl , http_hdr - > body , http_hdr - > body_size ) < 0 ) {
http_free ( http_hdr ) ;
2002-01-19 09:04:02 +00:00
stream - > streaming_ctrl - > data = NULL ;
2002-01-08 07:31:29 +00:00
return - 1 ;
}
}
}
if ( http_hdr ) {
2001-12-25 16:35:57 +00:00
http_free ( http_hdr ) ;
2002-01-08 07:31:29 +00:00
stream - > streaming_ctrl - > data = NULL ;
2001-05-29 17:03:17 +00:00
}
2001-11-20 22:20:20 +00:00
stream - > streaming_ctrl - > streaming_read = nop_streaming_read ;
stream - > streaming_ctrl - > streaming_seek = nop_streaming_seek ;
2003-01-13 03:10:19 +00:00
stream - > streaming_ctrl - > prebuffer_size = 64 * 1024 ; // 64 KBytes
2001-11-20 22:20:20 +00:00
stream - > streaming_ctrl - > buffering = 1 ;
stream - > streaming_ctrl - > status = streaming_playing_e ;
2002-01-10 01:37:53 +00:00
return 0 ;
2001-06-04 17:52:33 +00:00
}
2001-05-29 17:03:17 +00:00
2002-12-26 17:25:22 +00:00
int
pnm_streaming_read ( int fd , char * buffer , int size , streaming_ctrl_t * stream_ctrl ) {
return pnm_read ( stream_ctrl - > data , buffer , size ) ;
}
int
pnm_streaming_start ( stream_t * stream ) {
int fd ;
pnm_t * pnm ;
if ( stream = = NULL ) return - 1 ;
fd = connect2Server ( stream - > streaming_ctrl - > url - > hostname ,
stream - > streaming_ctrl - > url - > port ? stream - > streaming_ctrl - > url - > port : 7070 ) ;
printf ( " PNM:// fd=%d \n " , fd ) ;
if ( fd < 0 ) return - 1 ;
pnm = pnm_connect ( fd , stream - > streaming_ctrl - > url - > file ) ;
if ( ! pnm ) return - 1 ;
stream - > fd = fd ;
stream - > streaming_ctrl - > data = pnm ;
stream - > streaming_ctrl - > streaming_read = pnm_streaming_read ;
// stream->streaming_ctrl->streaming_seek = nop_streaming_seek;
2003-01-13 03:10:19 +00:00
stream - > streaming_ctrl - > prebuffer_size = 8 * 1024 ; // 8 KBytes
2002-12-26 17:25:22 +00:00
stream - > streaming_ctrl - > buffering = 1 ;
stream - > streaming_ctrl - > status = streaming_playing_e ;
return 0 ;
}
2002-08-05 00:39:07 +00:00
# ifndef STREAMING_LIVE_DOT_COM
2001-12-23 22:09:02 +00:00
// Start listening on a UDP port. If multicast, join the group.
int
rtp_open_socket ( URL_t * url ) {
2002-01-10 01:37:53 +00:00
int socket_server_fd , rxsockbufsz ;
2001-12-23 22:09:02 +00:00
int err , err_len ;
fd_set set ;
struct sockaddr_in server_address ;
struct ip_mreq mcast ;
2002-02-06 20:30:34 +00:00
struct timeval tv ;
2001-12-23 22:09:02 +00:00
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_V , " Listening for traffic on %s:%d ... \n " , url - > hostname , url - > port ) ;
2001-12-23 22:09:02 +00:00
socket_server_fd = socket ( AF_INET , SOCK_DGRAM , 0 ) ;
// fcntl( socket_server_fd, F_SETFL, fcntl(socket_server_fd, F_GETFL) | O_NONBLOCK );
if ( socket_server_fd = = - 1 ) {
2002-06-17 08:16:47 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " Failed to create socket \n " ) ;
2001-12-23 22:09:02 +00:00
return - 1 ;
}
if ( isalpha ( url - > hostname [ 0 ] ) ) {
struct hostent * hp = ( struct hostent * ) gethostbyname ( url - > hostname ) ;
if ( hp = = NULL ) {
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " Counldn't resolve name: %s \n " , url - > hostname ) ;
2001-12-23 22:09:02 +00:00
return - 1 ;
}
memcpy ( ( void * ) & server_address . sin_addr . s_addr , ( void * ) hp - > h_addr , hp - > h_length ) ;
} else {
inet_pton ( AF_INET , url - > hostname , & server_address . sin_addr ) ;
}
server_address . sin_family = AF_INET ;
server_address . sin_port = htons ( url - > port ) ;
if ( bind ( socket_server_fd , ( struct sockaddr * ) & server_address , sizeof ( server_address ) ) = = - 1 ) {
if ( errno ! = EINPROGRESS ) {
2002-06-17 08:16:47 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " Failed to connect to server \n " ) ;
2001-12-23 22:09:02 +00:00
close ( socket_server_fd ) ;
return - 1 ;
}
}
2002-01-10 01:37:53 +00:00
// Increase the socket rx buffer size to maximum -- this is UDP
rxsockbufsz = 240 * 1024 ;
if ( setsockopt ( socket_server_fd , SOL_SOCKET , SO_RCVBUF , & rxsockbufsz , sizeof ( rxsockbufsz ) ) ) {
2002-06-17 08:16:47 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " Couldn't set receive socket buffer size \n " ) ;
2002-01-10 01:37:53 +00:00
}
2001-12-23 22:09:02 +00:00
if ( ( ntohl ( server_address . sin_addr . s_addr ) > > 28 ) = = 0xe ) {
mcast . imr_multiaddr . s_addr = server_address . sin_addr . s_addr ;
//mcast.imr_interface.s_addr = inet_addr("10.1.1.2");
mcast . imr_interface . s_addr = 0 ;
if ( setsockopt ( socket_server_fd , IPPROTO_IP , IP_ADD_MEMBERSHIP , & mcast , sizeof ( mcast ) ) ) {
2002-06-17 08:16:47 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " IP_ADD_MEMBERSHIP failed (do you have multicasting enabled in your kernel?) \n " ) ;
2001-12-23 22:09:02 +00:00
return - 1 ;
}
}
2002-02-06 20:30:34 +00:00
tv . tv_sec = 0 ;
tv . tv_usec = ( 1 * 1000000 ) ; // 1 second timeout
2001-12-23 22:09:02 +00:00
FD_ZERO ( & set ) ;
FD_SET ( socket_server_fd , & set ) ;
2002-02-06 20:30:34 +00:00
if ( select ( socket_server_fd + 1 , & set , NULL , NULL , & tv ) > 0 ) {
//if( select(socket_server_fd+1, &set, NULL, NULL, NULL)>0 ) {
2001-12-23 22:09:02 +00:00
err_len = sizeof ( err ) ;
getsockopt ( socket_server_fd , SOL_SOCKET , SO_ERROR , & err , & err_len ) ;
if ( err ) {
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " Timeout! No data from host %s \n " , url - > hostname ) ;
mp_msg ( MSGT_NETWORK , MSGL_DBG2 , " Socket error: %d \n " , err ) ;
2001-12-23 22:09:02 +00:00
close ( socket_server_fd ) ;
return - 1 ;
}
}
return socket_server_fd ;
}
int
rtp_streaming_read ( int fd , char * buffer , int size , streaming_ctrl_t * streaming_ctrl ) {
return read_rtp_from_server ( fd , buffer , size ) ;
}
int
rtp_streaming_start ( stream_t * stream ) {
streaming_ctrl_t * streaming_ctrl ;
int fd ;
2001-12-25 16:35:57 +00:00
if ( stream = = NULL ) return - 1 ;
2001-12-23 22:09:02 +00:00
streaming_ctrl = stream - > streaming_ctrl ;
fd = stream - > fd ;
if ( fd < 0 ) {
fd = rtp_open_socket ( ( streaming_ctrl - > url ) ) ;
if ( fd < 0 ) return - 1 ;
2002-01-10 01:37:53 +00:00
stream - > fd = fd ;
2001-12-23 22:09:02 +00:00
}
streaming_ctrl - > streaming_read = rtp_streaming_read ;
2002-01-10 01:37:53 +00:00
streaming_ctrl - > streaming_seek = nop_streaming_seek ;
2003-01-13 03:10:19 +00:00
streaming_ctrl - > prebuffer_size = 64 * 1024 ; // 64 KBytes
2002-01-20 21:39:56 +00:00
streaming_ctrl - > buffering = 0 ;
2001-12-23 22:09:02 +00:00
streaming_ctrl - > status = streaming_playing_e ;
2002-01-10 01:37:53 +00:00
return 0 ;
2001-12-23 22:09:02 +00:00
}
2002-08-05 00:39:07 +00:00
# endif
2001-12-23 22:09:02 +00:00
2001-05-29 17:03:17 +00:00
int
2002-02-16 21:48:59 +00:00
streaming_start ( stream_t * stream , int * demuxer_type , URL_t * url ) {
2002-10-29 09:18:53 +00:00
int ret ;
2001-11-20 22:20:20 +00:00
if ( stream = = NULL ) return - 1 ;
2002-01-19 09:04:02 +00:00
stream - > streaming_ctrl = streaming_ctrl_new ( ) ;
if ( stream - > streaming_ctrl = = NULL ) {
return - 1 ;
}
2002-02-11 05:16:09 +00:00
stream - > streaming_ctrl - > url = check4proxies ( url ) ;
2002-02-16 21:48:59 +00:00
ret = autodetectProtocol ( stream - > streaming_ctrl , & stream - > fd , demuxer_type ) ;
2002-01-19 09:04:02 +00:00
if ( ret < 0 ) {
return - 1 ;
}
ret = - 1 ;
2001-11-20 22:20:20 +00:00
2002-07-05 02:37:56 +00:00
// Get the bandwidth available
2002-10-23 17:21:01 +00:00
stream - > streaming_ctrl - > bandwidth = network_bandwidth ;
2002-07-05 02:37:56 +00:00
2002-08-05 00:39:07 +00:00
# ifndef STREAMING_LIVE_DOT_COM
2001-12-23 22:09:02 +00:00
// For RTP streams, we usually don't know the stream type until we open it.
2002-01-12 21:08:12 +00:00
if ( ! strcasecmp ( stream - > streaming_ctrl - > url - > protocol , " rtp " ) ) {
2002-01-08 07:31:29 +00:00
if ( stream - > fd > = 0 ) {
2002-01-08 01:13:22 +00:00
if ( close ( stream - > fd ) < 0 )
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " streaming_start : Closing socket %d failed %s \n " , stream - > fd , strerror ( errno ) ) ;
2002-01-08 01:13:22 +00:00
}
stream - > fd = - 1 ;
2002-01-10 01:37:53 +00:00
ret = rtp_streaming_start ( stream ) ;
2002-01-08 07:31:29 +00:00
} else
2002-08-05 00:39:07 +00:00
# endif
2002-12-26 17:25:22 +00:00
if ( ! strcasecmp ( stream - > streaming_ctrl - > url - > protocol , " pnm " ) ) {
stream - > fd = - 1 ;
ret = pnm_streaming_start ( stream ) ;
} else
2001-12-23 22:09:02 +00:00
// For connection-oriented streams, we can usually determine the streaming type.
2002-02-16 21:48:59 +00:00
switch ( * demuxer_type ) {
2001-06-04 17:52:33 +00:00
case DEMUXER_TYPE_ASF :
// Send the appropriate HTTP request
2001-11-20 22:20:20 +00:00
// Need to filter the network stream.
// ASF raw stream is encapsulated.
ret = asf_streaming_start ( stream ) ;
2001-12-19 09:04:03 +00:00
if ( ret < 0 ) {
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " asf_streaming_start failed \n " ) ;
2001-12-19 09:04:03 +00:00
}
2001-05-29 17:03:17 +00:00
break ;
2002-08-05 00:39:07 +00:00
# ifdef STREAMING_LIVE_DOT_COM
case DEMUXER_TYPE_RTP :
// RTSP/RTP streaming is handled separately:
ret = rtsp_streaming_start ( stream ) ;
if ( ret < 0 ) {
2002-08-14 21:55:48 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " rtsp_streaming_start failed \n " ) ;
2002-08-05 00:39:07 +00:00
}
break ;
# endif
2001-06-04 17:52:33 +00:00
case DEMUXER_TYPE_MPEG_ES :
case DEMUXER_TYPE_MPEG_PS :
2002-02-16 21:48:59 +00:00
case DEMUXER_TYPE_AVI :
case DEMUXER_TYPE_MOV :
case DEMUXER_TYPE_VIVO :
case DEMUXER_TYPE_FLI :
case DEMUXER_TYPE_REAL :
case DEMUXER_TYPE_Y4M :
case DEMUXER_TYPE_FILM :
case DEMUXER_TYPE_ROQ :
case DEMUXER_TYPE_AUDIO :
2002-11-05 19:03:52 +00:00
case DEMUXER_TYPE_OGG :
2002-02-21 13:14:52 +00:00
case DEMUXER_TYPE_PLAYLIST :
2001-12-19 09:04:03 +00:00
case DEMUXER_TYPE_UNKNOWN :
2001-11-20 22:20:20 +00:00
// Generic start, doesn't need to filter
// the network stream, it's a raw stream
ret = nop_streaming_start ( stream ) ;
2001-12-19 09:04:03 +00:00
if ( ret < 0 ) {
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " nop_streaming_start failed \n " ) ;
2001-12-19 09:04:03 +00:00
}
2002-02-21 13:14:52 +00:00
if ( ( * demuxer_type ) = = DEMUXER_TYPE_PLAYLIST )
stream - > type = STREAMTYPE_PLAYLIST ;
2001-05-29 17:03:17 +00:00
break ;
default :
2002-04-30 16:58:54 +00:00
mp_msg ( MSGT_NETWORK , MSGL_ERR , " Unable to detect the streaming type \n " ) ;
2001-11-20 22:20:20 +00:00
ret = - 1 ;
2001-06-04 17:52:33 +00:00
}
2001-11-20 22:20:20 +00:00
if ( ret < 0 ) {
2002-01-19 09:04:02 +00:00
streaming_ctrl_free ( stream - > streaming_ctrl ) ;
stream - > streaming_ctrl = NULL ;
2002-02-11 05:16:09 +00:00
} else if ( stream - > streaming_ctrl - > buffering ) {
2002-10-23 22:07:29 +00:00
if ( stream_cache_size < 0 ) {
2002-06-24 20:12:18 +00:00
// cache option not set, will use our computed value.
2002-01-22 06:12:18 +00:00
// buffer in KBytes, *5 because the prefill is 20% of the buffer.
2002-10-23 17:21:01 +00:00
stream_cache_size = ( stream - > streaming_ctrl - > prebuffer_size / 1024 ) * 5 ;
2003-01-13 03:10:19 +00:00
if ( stream_cache_size < 64 ) stream_cache_size = 64 ; // 16KBytes min buffer
2002-01-22 06:12:18 +00:00
}
2002-10-23 17:21:01 +00:00
mp_msg ( MSGT_NETWORK , MSGL_INFO , " Cache size set to %d KBytes \n " , stream_cache_size ) ;
2002-01-20 21:39:56 +00:00
}
2002-05-09 14:52:23 +00:00
2001-11-20 22:20:20 +00:00
return ret ;
2001-05-29 17:03:17 +00:00
}
int
2001-11-20 22:20:20 +00:00
streaming_stop ( stream_t * stream ) {
stream - > streaming_ctrl - > status = streaming_stopped_e ;
2001-06-04 17:52:33 +00:00
return 0 ;
2001-05-29 17:03:17 +00:00
}