From 32cdd8cbac60ad4103b03255762423cf062dc418 Mon Sep 17 00:00:00 2001 From: Derk-Jan Hartman Date: Sat, 12 Aug 2006 00:10:37 +0000 Subject: [PATCH] * refactoring of live555 module. - less code duplication - automaticly try HTTP tunneling if describe fails - upon authentication failure, ask for a new user/passwd and try again (untested due to lack of a rtsp source) - fix a bug with adding tracks introduced in [16114] - fix a bug closing the RTSPClient - disabled the QT VoD detection because it's unreliable like hell. TODO: - test with a WMS RTSP session - test against a paswd. protected RTSP session - find a better way for error communication with live (parsing random strings is so 1990) - find a way to relay Control() calls to a subdemux (for time/pos in TS) - add the HREF support of the 0.8.5-href branch - better flushing etc. during the PAUSE (ideas anyone?) --- modules/demux/live555.cpp | 669 ++++++++++++++++++++------------------ 1 file changed, 361 insertions(+), 308 deletions(-) diff --git a/modules/demux/live555.cpp b/modules/demux/live555.cpp index 2a1c68fec5..07bd7b00e1 100644 --- a/modules/demux/live555.cpp +++ b/modules/demux/live555.cpp @@ -28,6 +28,8 @@ #include #include + +#include "vlc_interaction.h" #include "network.h" #include @@ -106,24 +108,16 @@ vlc_module_begin(); N_("Port to use for tunneling the RTSP/RTP over HTTP."), VLC_TRUE ); #endif - add_integer( "rtsp-caching", 4 * DEFAULT_PTS_DELAY / 1000, NULL, - CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE ); - add_bool( "rtsp-kasenna", VLC_FALSE, NULL, KASENNA_TEXT, - KASENNA_LONGTEXT, VLC_TRUE ); + add_integer("rtsp-caching", 4 * DEFAULT_PTS_DELAY / 1000, NULL, + CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE ); + add_bool( "rtsp-kasenna", VLC_FALSE, NULL, KASENNA_TEXT, + KASENNA_LONGTEXT, VLC_TRUE ); add_string( "rtsp-user", NULL, NULL, USER_TEXT, - USER_LONGTEXT, VLC_TRUE ); + USER_LONGTEXT, VLC_TRUE ); add_string( "rtsp-pwd", NULL, NULL, PASS_TEXT, - PASS_LONGTEXT, VLC_TRUE ); + PASS_LONGTEXT, VLC_TRUE ); vlc_module_end(); -/* TODO: - * - Improve support of PS/TS - * - Support X-QT/X-QUICKTIME generic codec for audio. - * - * - Check memory leak, delete/free -> still one when using rtsp-tcp but I'm - * not sure if it comes from me. - * - */ /***************************************************************************** * Local prototypes @@ -151,7 +145,7 @@ typedef struct char waiting; - mtime_t i_pts; + int64_t i_pts; } live_track_t; @@ -165,8 +159,8 @@ struct timeout_thread_t struct demux_sys_t { - char *p_sdp; /* XXX mallocated */ - char *psz_path; /* URL-encoded path */ + char *p_sdp; /* XXX mallocated */ + char *psz_path; /* URL-encoded path */ MediaSession *ms; TaskScheduler *scheduler; @@ -176,10 +170,10 @@ struct demux_sys_t /* */ int i_track; live_track_t **track; /* XXX mallocated */ - mtime_t i_pcr; - mtime_t i_pcr_start; - mtime_t i_pcr_previous; - mtime_t i_pcr_repeatdate; + int64_t i_pcr; + int64_t i_pcr_start; + int64_t i_pcr_previous; + int64_t i_pcr_repeatdate; int i_pcr_repeats; /* Asf */ @@ -187,8 +181,8 @@ struct demux_sys_t stream_t *p_out_asf; /* */ - mtime_t i_length; - mtime_t i_start; + int64_t i_length; + int64_t i_start; /* timeout thread information */ int i_timeout; /* session timeout value in seconds */ @@ -206,12 +200,15 @@ struct demux_sys_t static int Demux ( demux_t * ); static int Control( demux_t *, int, va_list ); -static int ParseASF( demux_t * ); -static int RollOverTcp( demux_t * ); +static int Connect ( demux_t * ); +static int SessionsSetup( demux_t * ); +static int Play ( demux_t *); +static int ParseASF ( demux_t * ); +static int RollOverTcp ( demux_t * ); -static void StreamRead( void *, unsigned int, unsigned int, - struct timeval, unsigned int ); -static void StreamClose( void * ); +static void StreamRead ( void *, unsigned int, unsigned int, + struct timeval, unsigned int ); +static void StreamClose ( void * ); static void TaskInterrupt( void * ); static void TimeoutPrevention( timeout_thread_t * ); @@ -228,24 +225,16 @@ static int Open ( vlc_object_t *p_this ) { demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys = NULL; - - MediaSubsessionIterator *iter; - MediaSubsession *sub; - - vlc_bool_t b_rtsp_tcp; - uint8_t *p_peek; - - char *psz_user = NULL; - char *psz_pwd = NULL; - - int i_sdp; - int i_sdp_max; - uint8_t *p_sdp; + + MediaSubsessionIterator *iter = NULL; + MediaSubsession *sub = NULL; + int i_return; if( p_demux->s ) { /* See if it looks like a SDP v, o, s fields are mandatory and in this order */ + uint8_t *p_peek; if( stream_Peek( p_demux->s, &p_peek, 7 ) < 7 ) return VLC_EGENERIC; if( memcmp( (char*)p_peek, "v=0\r\n", 5 ) && @@ -286,8 +275,7 @@ static int Open ( vlc_object_t *p_this ) p_sys->i_timeout = 0; p_sys->b_timeout_call = VLC_FALSE; p_sys->b_multicast = VLC_FALSE; - p_sys->psz_path = strdup(p_demux->psz_path); - + p_sys->psz_path = strdup( p_demux->psz_path ); if( ( p_sys->scheduler = BasicTaskScheduler::createNew() ) == NULL ) { @@ -306,68 +294,13 @@ static int Open ( vlc_object_t *p_this ) while( (p = strchr( p, ' ' )) != NULL ) *p = '+'; } - if( p_demux->s == NULL && !strcasecmp( p_demux->psz_access, "rtsp" ) ) - { - char *psz_url; - char *psz_options; -#if LIVEMEDIA_LIBRARY_VERSION_INT > 1130457500 - int i_http_port = 0; - - if( var_CreateGetBool( p_demux, "rtsp-http" ) ) - i_http_port = var_CreateGetInteger( p_demux, "rtsp-http-port" ); - - if( ( p_sys->rtsp = RTSPClient::createNew(*p_sys->env, 1/*verbose*/, - "VLC media player", i_http_port ) ) == NULL ) -#else - if( ( p_sys->rtsp = RTSPClient::createNew(*p_sys->env, 1/*verbose*/, - "VLC media player" ) ) == NULL ) -#endif - { - msg_Err( p_demux, "RTSPClient::createNew failed (%s)", - p_sys->env->getResultMsg() ); - goto error; - } - psz_url = (char*)malloc( strlen( p_sys->psz_path ) + 8 ); - sprintf( psz_url, "rtsp://%s", p_sys->psz_path ); - - psz_options = p_sys->rtsp->sendOptionsCmd( psz_url ); - if( psz_options ) delete [] psz_options; - - psz_user = var_CreateGetString( p_demux, "rtsp-user" ); - psz_pwd = var_CreateGetString( p_demux, "rtsp-pwd" ); - - if ((*psz_user) && (*psz_pwd)) - p_sdp = (uint8_t*)p_sys->rtsp->describeWithPassword( psz_url, - psz_user, psz_pwd); - else - p_sdp = (uint8_t*)p_sys->rtsp->describeURL( psz_url, - NULL, var_CreateGetBool( p_demux, "rtsp-kasenna" ) ); - if( p_sdp == NULL ) - { - msg_Err( p_demux, "describeURL failed (%s)", - p_sys->env->getResultMsg() ); - free( psz_url ); - goto error; - } - free( psz_url ); - free( psz_user ); - free( psz_pwd ); - - /* malloc-ated copy */ - p_sys->p_sdp = strdup( (char*)p_sdp ); - delete[] p_sdp; - msg_Dbg( p_demux, "sdp=%s\n", p_sys->p_sdp ); - } - else if( p_demux->s == NULL && !strcasecmp( p_demux->psz_access, "sdp" ) ) - { - p_sys->p_sdp = strdup( p_sys->psz_path ); - } - else + if( p_demux->s != NULL ) { /* Gather the complete sdp file */ - i_sdp = 0; - i_sdp_max = 1000; - p_sdp = (uint8_t*)malloc( i_sdp_max ); + int i_sdp = 0; + int i_sdp_max = 1000; + uint8_t *p_sdp = (uint8_t*) malloc( i_sdp_max ); + for( ;; ) { int i_read = stream_Read( p_demux->s, &p_sdp[i_sdp], @@ -392,119 +325,53 @@ static int Open ( vlc_object_t *p_this ) p_sdp = (uint8_t*)realloc( p_sdp, i_sdp_max ); } p_sys->p_sdp = (char*)p_sdp; - - msg_Dbg( p_demux, "sdp=%s\n", p_sys->p_sdp ); } - if( !( p_sys->ms = MediaSession::createNew( *p_sys->env, p_sys->p_sdp ) ) ) + else if( p_demux->s == NULL && !strcasecmp( p_demux->psz_access, "sdp" ) ) + { + /* sdp:// link from SAP */ + p_sys->p_sdp = strdup( p_sys->psz_path ); + } + else if( ( i_return = Connect( p_demux ) ) != VLC_SUCCESS ) { - msg_Err( p_demux, "MediaSession::createNew failed" ); + msg_Err( p_demux, "Failed to connect with rtsp://%s", p_sys->psz_path ); goto error; } - - b_rtsp_tcp = var_CreateGetBool( p_demux, "rtsp-tcp" ); - - /* Initialise each media subsession */ - iter = new MediaSubsessionIterator( *p_sys->ms ); - while( ( sub = iter->next() ) != NULL ) + + if( p_sys->p_sdp == NULL ) { - unsigned int i_buffer = 0; - Boolean bInit; - int i_client_port; - - i_client_port = var_CreateGetInteger( p_demux, "rtp-client-port" ); - if( i_client_port != -1 ) - sub->setClientPortNum( i_client_port ); - - /* Value taken from mplayer */ - if( !strcmp( sub->mediumName(), "audio" ) ) - i_buffer = 100000; - else if( !strcmp( sub->mediumName(), "video" ) ) - i_buffer = 2000000; - else - continue; - - if( !strcmp( sub->codecName(), "X-ASF-PF" ) ) - bInit = sub->initiate( 4 ); /* Constant ? */ - else - bInit = sub->initiate(); - - if( strcasestr( sub->codecName(), "REAL" ) ) - { - msg_Info( p_demux, "real codec detected, using real-RTSP instead" ); - delete iter; - goto error; - } - - if( !bInit ) - { - msg_Warn( p_demux, "RTP subsession '%s/%s' failed (%s)", - sub->mediumName(), sub->codecName(), - p_sys->env->getResultMsg() ); - } - else - { - if( sub->rtpSource() ) - { - int fd = sub->rtpSource()->RTPgs()->socketNum(); - /* Increase the buffer size */ - increaseReceiveBufferTo( *p_sys->env, fd, i_buffer ); - } - - msg_Dbg( p_demux, "RTP subsession '%s/%s'", sub->mediumName(), - sub->codecName() ); - - /* Issue the SETUP */ - if( p_sys->rtsp ) - { - p_sys->rtsp->setupMediaSubsession( *sub, False, - b_rtsp_tcp ? True : False ); - } - if( !p_sys->b_multicast ) - { - /* Check, because we need diff. rollover behaviour for multicast */ - p_sys->b_multicast = IsMulticastAddress( sub->connectionEndpointAddress() ); - } - } + msg_Err( p_demux, "Failed to retrieve the RTSP Session Description" ); + goto error; } - if( p_sys->rtsp ) + /* Create the session from the SDP */ + if( !( p_sys->ms = MediaSession::createNew( *p_sys->env, p_sys->p_sdp ) ) ) { - /* The PLAY */ - if( !p_sys->rtsp->playMediaSession( *p_sys->ms ) ) - { - msg_Err( p_demux, "PLAY failed %s", p_sys->env->getResultMsg() ); - delete iter; - goto error; - } - - /* Retrieve the timeout value and set up a timeout prevention thread */ -#if LIVEMEDIA_LIBRARY_VERSION_INT >= 1138089600 - p_sys->i_timeout = p_sys->rtsp->sessionTimeoutParameter(); -#endif - if( p_sys->i_timeout > 0 ) - { - msg_Dbg( p_demux, "We have a timeout of %d seconds", p_sys->i_timeout ); - p_sys->p_timeout = (timeout_thread_t *)vlc_object_create( p_demux, sizeof(timeout_thread_t) ); - p_sys->p_timeout->p_sys = p_demux->p_sys; /* lol, object recursion :D */ - if( vlc_thread_create( p_sys->p_timeout, "liveMedia-timeout", TimeoutPrevention, - VLC_THREAD_PRIORITY_LOW, VLC_TRUE ) ) - { - msg_Err( p_demux, "cannot spawn liveMedia timeout thread" ); - delete iter; - vlc_object_destroy( p_sys->p_timeout ); - goto error; - } - msg_Dbg( p_demux, "spawned timeout thread" ); - vlc_object_attach( p_sys->p_timeout, p_demux ); - } + msg_Err( p_demux, "Could not create the RTSP Session: %s", + p_sys->env->getResultMsg() ); + goto error; } + + /* Retrieve the duration if possible */ + p_sys->i_length = (int64_t)( p_sys->ms->playEndTime() * 1000000.0 ); + if( p_sys->i_length < 0 ) + p_sys->i_length = -1; + if( ( i_return = SessionsSetup( p_demux ) ) != VLC_SUCCESS ) + { + msg_Err( p_demux, "Nothing to play for rtsp://%s", p_sys->psz_path ); + goto error; + } + + if( ( i_return = Play( p_demux ) ) != VLC_SUCCESS ) + goto error; + /* Create all es struct */ - iter->reset(); + iter = new MediaSubsessionIterator( *p_sys->ms ); while( ( sub = iter->next() ) != NULL ) { live_track_t *tk; + /* Check if we will receive data from this subsession for this track */ if( sub->readSource() == NULL ) continue; tk = (live_track_t*)malloc( sizeof( live_track_t ) ); @@ -713,7 +580,10 @@ static int Open ( vlc_object_t *p_this ) } } - tk->p_es = es_out_Add( p_demux->out, &tk->fmt ); + if( !tk->b_quicktime && !tk->b_muxed && !tk->b_asf ) + { + tk->p_es = es_out_Add( p_demux->out, &tk->fmt ); + } if( sub->rtcpInstance() != NULL ) { @@ -724,13 +594,15 @@ static int Open ( vlc_object_t *p_this ) { tk->readSource = sub->readSource(); tk->rtpSource = sub->rtpSource(); - + /* Append */ p_sys->track = (live_track_t**)realloc( p_sys->track, sizeof( live_track_t ) * ( p_sys->i_track + 1 ) ); p_sys->track[p_sys->i_track++] = tk; } else { + /* BUG ??? */ + msg_Err( p_demux, "unusable RTSP track. this should not happen" ); free( tk ); } } @@ -744,29 +616,15 @@ static int Open ( vlc_object_t *p_this ) goto error; } - p_sys->i_length = (mtime_t)(p_sys->ms->playEndTime() * 1000000.0); - if( p_sys->i_length < 0 ) - { - p_sys->i_length = 0; - } - else if( p_sys->i_length > 0 ) - { - /* FIXME */ - /* p_input->stream.p_selected_area->i_size = 1000;*/ /* needed for now */ - } - if( p_sys->i_track <= 0 ) - { - msg_Err( p_demux, "no codec supported, aborting" ); goto error; - } return VLC_SUCCESS; error: if( p_sys->p_out_asf ) stream_DemuxDelete( p_sys->p_out_asf ); if( p_sys->ms ) Medium::close( p_sys->ms ); - if( p_sys->rtsp ) Medium::close( p_sys->rtsp ); + if( p_sys->rtsp ) RTSPClient::close( p_sys->rtsp ); if( p_sys->env ) RECLAIM_ENV(p_sys->env); if( p_sys->p_timeout ) { @@ -820,14 +678,251 @@ static void Close( vlc_object_t *p_this ) vlc_object_destroy( p_sys->p_timeout ); } - if( p_sys->rtsp ) Medium::close( p_sys->rtsp ); - if( p_sys->env ) RECLAIM_ENV(p_sys->env); + if( p_sys->rtsp ) RTSPClient::close( p_sys->rtsp ); + if( p_sys->env ) RECLAIM_ENV( p_sys->env ); if( p_sys->scheduler ) delete p_sys->scheduler; if( p_sys->p_sdp ) free( p_sys->p_sdp ); if( p_sys->psz_path ) free( p_sys->psz_path ); free( p_sys ); } +/***************************************************************************** + * Connect: connects to the RTSP server to setup the session DESCRIBE + *****************************************************************************/ +static int Connect( demux_t *p_demux ) +{ + demux_sys_t *p_sys = p_demux->p_sys; + Authenticator authenticator; + + char *psz_user = NULL; + char *psz_pwd = NULL; + char *psz_url = NULL; + char *psz_options = NULL; + char *p_sdp = NULL; + int i_http_port = 0; + int i_ret = VLC_SUCCESS; + +createnew: + if( var_CreateGetBool( p_demux, "rtsp-http" ) ) + i_http_port = var_CreateGetInteger( p_demux, "rtsp-http-port" ); + +#if LIVEMEDIA_LIBRARY_VERSION_INT > 1130457500 + if( ( p_sys->rtsp = RTSPClient::createNew(*p_sys->env, 1 /*verbose*/, + "VLC media player", i_http_port ) ) == NULL ) +#else + if( ( p_sys->rtsp = RTSPClient::createNew(*p_sys->env, 1 /*verbose*/, + "VLC media player" ) ) == NULL ) +#endif + { + msg_Err( p_demux, "RTSPClient::createNew failed (%s)", + p_sys->env->getResultMsg() ); + return VLC_EGENERIC; + } + psz_url = (char*)malloc( strlen( p_sys->psz_path ) + 8 ); + sprintf( psz_url, "rtsp://%s", p_sys->psz_path ); + + psz_options = p_sys->rtsp->sendOptionsCmd( psz_url ); + if( psz_options ) delete [] psz_options; + + psz_user = var_CreateGetString( p_demux, "rtsp-user" ); + psz_pwd = var_CreateGetString( p_demux, "rtsp-pwd" ); + +describe: + authenticator.setUsernameAndPassword( (const char*)psz_user, (const char*)psz_pwd ); + p_sdp = p_sys->rtsp->describeURL( psz_url, + &authenticator, var_CreateGetBool( p_demux, "rtsp-kasenna" ) ); + + if( psz_user ) free( psz_user ); + if( psz_pwd ) free( psz_pwd ); + + if( p_sdp == NULL ) + { + /* failure occured */ + int i_code = 0; + const char *psz_error = p_sys->env->getResultMsg(); + + msg_Dbg( p_demux, "DESCRIBE failed with %d: %s", i_code, psz_error ); + sscanf( psz_error, "%*sRTSP/%*s%3u", &i_code ); + + if( i_code == 401 ) + { + char *psz_login = NULL; char *psz_password = NULL; + msg_Dbg( p_demux, "authentication failed" ); + + i_ret = intf_UserLoginPassword( p_demux, _("RTSP authentication"), + _("Please enter a valid login name and a password."), + &psz_login, &psz_password ); + if( i_ret == DIALOG_OK_YES ) + { + msg_Dbg( p_demux, "retrying with user=%s, pwd=%s", + psz_login, psz_password ); + + if( psz_login ) psz_user = psz_login; + if( psz_password ) psz_pwd = psz_password; + goto describe; + } + if( psz_login ) free( psz_login ); + if( psz_password ) free( psz_password ); + } + else if( !var_CreateGetBool( p_demux, "rtsp-http" ) ) + { + /* Perhaps a firewall is being annoying. Try HTTP tunneling mode */ + vlc_value_t val; + val.b_bool = VLC_TRUE; + msg_Dbg( p_demux, "we will now try HTTP tunneling mode" ); + var_Set( p_demux, "rtsp-http", val ); + if( psz_url ) free( psz_url ); + if( p_sys->rtsp ) RTSPClient::close( p_sys->rtsp ); + goto createnew; + } + i_ret = VLC_EGENERIC; + } + if( psz_url ) free( psz_url ); + + /* malloc-ated copy */ + if( p_sys->p_sdp ) free( p_sys->p_sdp ); + p_sys->p_sdp = strdup( (char*)p_sdp ); + delete[] p_sdp; + + return i_ret; +} + +/***************************************************************************** + * Connect: prepares the subsessions and does the SETUP + *****************************************************************************/ +static int SessionsSetup( demux_t *p_demux ) +{ + demux_sys_t *p_sys = p_demux->p_sys; + MediaSubsessionIterator *iter = NULL; + MediaSubsession *sub = NULL; + + vlc_bool_t b_rtsp_tcp = VLC_FALSE; + int i_client_port; + int i_active_sessions = 0; + int i_return = VLC_SUCCESS; + unsigned int i_buffer = 0; + unsigned const thresh = 200000; /* RTP reorder threshold .2 second (default .1) */ + + b_rtsp_tcp = var_CreateGetBool( p_demux, "rtsp-tcp" ); + i_client_port = var_CreateGetInteger( p_demux, "rtp-client-port" ); + + /* Initialise each media subsession */ + iter = new MediaSubsessionIterator( *p_sys->ms ); + while( ( sub = iter->next() ) != NULL ) + { + Boolean bInit; + + /* Value taken from mplayer */ + if( !strcmp( sub->mediumName(), "audio" ) ) + i_buffer = 100000; + else if( !strcmp( sub->mediumName(), "video" ) ) + i_buffer = 2000000; + else continue; + + if( i_client_port != -1 ) + { + sub->setClientPortNum( i_client_port ); + i_client_port += 2; + } + + if( strcasestr( sub->codecName(), "REAL" ) ) + { + msg_Info( p_demux, "real codec detected, using real-RTSP instead" ); + i_return = VLC_EGENERIC; + break; + } + + if( !strcmp( sub->codecName(), "X-ASF-PF" ) ) + bInit = sub->initiate( 4 ); /* Constant ? */ + else + bInit = sub->initiate(); + + if( !bInit ) + { + msg_Warn( p_demux, "RTP subsession '%s/%s' failed (%s)", + sub->mediumName(), sub->codecName(), + p_sys->env->getResultMsg() ); + } + else + { + if( sub->rtpSource() != NULL ) + { + int fd = sub->rtpSource()->RTPgs()->socketNum(); + + /* Increase the buffer size */ + if( i_buffer > 0 ) + increaseReceiveBufferTo( *p_sys->env, fd, i_buffer ); + + /* Increase the RTP reorder timebuffer just a bit */ + sub->rtpSource()->setPacketReorderingThresholdTime(thresh); + } + + msg_Dbg( p_demux, "RTP subsession '%s/%s'", sub->mediumName(), + sub->codecName() ); + + /* Issue the SETUP */ + if( p_sys->rtsp ) + { + if( !( p_sys->rtsp->setupMediaSubsession( *sub, False, + b_rtsp_tcp ? True : False ) ) ) + { + msg_Err( p_demux, "SETUP of'%s/%s' failed %s", sub->mediumName(), + sub->codecName(), p_sys->env->getResultMsg() ); + } + else i_active_sessions++; + } else i_active_sessions++; /* we don't really know, let's just hope it's there */ + + if( !p_sys->b_multicast ) + { + /* Check, because we need diff. rollover behaviour for multicast */ + p_sys->b_multicast = IsMulticastAddress( sub->connectionEndpointAddress() ); + } + } + } + delete iter; + if( i_active_sessions <= 0 ) i_return = VLC_EGENERIC; + return i_return; +} + +/***************************************************************************** + * Play: starts the actual playback of the stream + *****************************************************************************/ +static int Play( demux_t *p_demux ) +{ + demux_sys_t *p_sys = p_demux->p_sys; + + if( p_sys->rtsp ) + { + /* The PLAY */ + if( !p_sys->rtsp->playMediaSession( *p_sys->ms ) ) + { + msg_Err( p_demux, "RTSP PLAY failed %s", p_sys->env->getResultMsg() ); + return VLC_EGENERIC; + } + + /* Retrieve the timeout value and set up a timeout prevention thread */ +#if LIVEMEDIA_LIBRARY_VERSION_INT >= 1138089600 + p_sys->i_timeout = p_sys->rtsp->sessionTimeoutParameter(); +#endif + if( p_sys->i_timeout > 0 && !p_sys->p_timeout ) + { + msg_Dbg( p_demux, "We have a timeout of %d seconds", p_sys->i_timeout ); + p_sys->p_timeout = (timeout_thread_t *)vlc_object_create( p_demux, sizeof(timeout_thread_t) ); + p_sys->p_timeout->p_sys = p_demux->p_sys; /* lol, object recursion :D */ + if( vlc_thread_create( p_sys->p_timeout, "liveMedia-timeout", TimeoutPrevention, + VLC_THREAD_PRIORITY_LOW, VLC_TRUE ) ) + { + msg_Err( p_demux, "cannot spawn liveMedia timeout thread" ); + vlc_object_destroy( p_sys->p_timeout ); + } + msg_Dbg( p_demux, "spawned timeout thread" ); + vlc_object_attach( p_sys->p_timeout, p_demux ); + } + } + return VLC_SUCCESS; +} + + /***************************************************************************** * Demux: *****************************************************************************/ @@ -837,7 +932,7 @@ static int Demux( demux_t *p_demux ) TaskToken task; vlc_bool_t b_send_pcr = VLC_TRUE; - mtime_t i_pcr = 0; + int64_t i_pcr = 0; int i; /* Check if we need to send the server a Keep-A-Live signal */ @@ -879,6 +974,9 @@ static int Demux( demux_t *p_demux ) } } +#if 0 + /* Disabled because it's simply not reliable enough */ + /* When a On Demand QT stream ends, the last frame keeps going with the same PCR/PTS value */ /* This tests for that, so we can later decide to end this session */ if( i_pcr > 0 && p_sys->i_pcr == p_sys->i_pcr_previous ) @@ -900,8 +998,9 @@ static int Demux( demux_t *p_demux ) msg_Dbg( p_demux, "suspect EOF due to end of VoD session" ); return 0; } +#endif - /* First warm we want to read data */ + /* First warn we want to read data */ p_sys->event = 0; for( i = 0; i < p_sys->i_track; i++ ) { @@ -963,7 +1062,6 @@ static int Demux( demux_t *p_demux ) msg_Err( p_demux, "TCP rollover failed, aborting" ); return 0; } - var_SetBool( p_demux, "rtsp-tcp", VLC_TRUE ); } else if( p_sys->i_no_data_ti > 34 ) { @@ -971,11 +1069,11 @@ static int Demux( demux_t *p_demux ) return 0; } } - else if( !p_sys->b_multicast && p_sys->b_no_data&& p_sys->i_no_data_ti > 34 ) + else if( !p_sys->b_multicast && p_sys->b_no_data && p_sys->i_no_data_ti > 34 ) { /* EOF ? */ msg_Warn( p_demux, "no data received in 10s, eof ?" ); - return 0; + return 0; } return p_demux->b_error ? 0 : 1; @@ -1012,33 +1110,31 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) } else { - *pf = 0; + *pf = 0.0; } return VLC_SUCCESS; case DEMUX_SET_POSITION: - { float time; f = (double)va_arg( args, double ); - time = f * (double)p_sys->i_length / 1000000.0; /* in second */ - + if( p_sys->rtsp && p_sys->i_length > 0 ) { + time = f * (double)p_sys->i_length / 1000000.0; /* in second */ if( !p_sys->rtsp->playMediaSession( *p_sys->ms, time ) ) { msg_Err( p_demux, "PLAY failed %s", p_sys->env->getResultMsg() ); return VLC_EGENERIC; } - p_sys->i_start = (mtime_t)(f * (double)p_sys->i_length); + p_sys->i_start = (int64_t)(f * (double)p_sys->i_length); p_sys->i_pcr_start = 0; p_sys->i_pcr = 0; return VLC_SUCCESS; } return VLC_SUCCESS; - } /* Special for access_demux */ case DEMUX_CAN_PAUSE: @@ -1113,101 +1209,57 @@ static int RollOverTcp( demux_t *p_demux ) demux_sys_t *p_sys = p_demux->p_sys; MediaSubsessionIterator *iter; MediaSubsession *sub; - char *psz_url; - char *psz_options; - char *psz_user; - char *psz_pwd; - uint8_t *p_sdp; int i_tk; + int i_return; + var_SetBool( p_demux, "rtsp-tcp", VLC_TRUE ); + /* We close the old RTSP session */ p_sys->rtsp->teardownMediaSession( *p_sys->ms ); Medium::close( p_sys->ms ); - Medium::close( p_sys->rtsp ); + RTSPClient::close( p_sys->rtsp ); p_sys->ms = NULL; p_sys->rtsp = NULL; /* Reopen rtsp client */ - if( ( p_sys->rtsp = RTSPClient::createNew(*p_sys->env, 1/*verbose*/, - "VLC media player" ) ) == NULL ) + if( ( i_return = Connect( p_demux ) ) != VLC_SUCCESS ) { - msg_Err( p_demux, "RTSPClient::createNew failed (%s)", - p_sys->env->getResultMsg() ); - return VLC_EGENERIC; + msg_Err( p_demux, "Failed to connect with rtsp://%s", p_sys->psz_path ); + goto error; } - - asprintf( &psz_url, "rtsp://%s", p_sys->psz_path ); - - if( ( psz_options = p_sys->rtsp->sendOptionsCmd( psz_url ) ) ) - delete [] psz_options; - - psz_user = var_CreateGetString( p_demux, "rtsp-user" ); - psz_pwd = var_CreateGetString( p_demux, "rtsp-pwd" ); - - if ((*psz_user) && (*psz_pwd)) - p_sdp = (uint8_t*)p_sys->rtsp->describeWithPassword( psz_url, - psz_user, psz_pwd); - else - p_sdp = (uint8_t*)p_sys->rtsp->describeURL( psz_url, - NULL, var_CreateGetBool( p_demux, "rtsp-kasenna" ) ); - - free( psz_url ); - free( psz_user ); - free( psz_pwd ); - - if( p_sdp == NULL ) + + if( p_sys->p_sdp == NULL ) { - msg_Err( p_demux, "describeURL failed (%s)", - p_sys->env->getResultMsg() ); - return VLC_EGENERIC; + msg_Err( p_demux, "Failed to retrieve the RTSP Session Description" ); + goto error; } - /* malloc-ated copy */ - p_sys->p_sdp = strdup( (char*)p_sdp ); - delete[] p_sdp; - + /* Create the session from the SDP */ if( !( p_sys->ms = MediaSession::createNew( *p_sys->env, p_sys->p_sdp ) ) ) { - msg_Err( p_demux, "MediaSession::createNew failed" ); - return VLC_EGENERIC; - } - - /* Initialise each media subsession */ - iter = new MediaSubsessionIterator( *p_sys->ms ); - while( ( sub = iter->next() ) != NULL ) - { - Boolean bInit; - - if( !strcmp( sub->codecName(), "X-ASF-PF" ) ) - bInit = sub->initiate( 4 ); /* Constant ? */ - else - bInit = sub->initiate(); - - if( !bInit ) - { - msg_Warn( p_demux, "RTP subsession '%s/%s' failed (%s)", - sub->mediumName(), sub->codecName(), - p_sys->env->getResultMsg() ); - continue; - } - msg_Dbg( p_demux, "RTP subsession '%s/%s'", sub->mediumName(), - sub->codecName() ); - - /* Issue the SETUP */ - p_sys->rtsp->setupMediaSubsession( *sub, False, True /* tcp */ ); + msg_Err( p_demux, "Could not create the RTSP Session: %s", + p_sys->env->getResultMsg() ); + goto error; } + + /* Retrieve the duration if possible */ + p_sys->i_length = (int64_t)( p_sys->ms->playEndTime() * 1000000.0 ); + if( p_sys->i_length < 0 ) + p_sys->i_length = -1; - /* The PLAY */ - if( !p_sys->rtsp->playMediaSession( *p_sys->ms ) ) + if( ( i_return = SessionsSetup( p_demux ) ) != VLC_SUCCESS ) { - msg_Err( p_demux, "PLAY failed %s", p_sys->env->getResultMsg() ); - return VLC_EGENERIC; + msg_Err( p_demux, "Nothing to play for rtsp://%s", p_sys->psz_path ); + goto error; } + + if( ( i_return = Play( p_demux ) ) != VLC_SUCCESS ) + goto error; /* Update all tracks */ - iter->reset(); + iter = new MediaSubsessionIterator( *p_sys->ms ); i_tk = 0; while( ( sub = iter->next() ) != NULL ) { @@ -1218,7 +1270,7 @@ static int RollOverTcp( demux_t *p_demux ) if( i_tk >= p_sys->i_track ) { msg_Err( p_demux, "WTF !" ); - break; + goto error; } tk = p_sys->track[i_tk]; @@ -1236,10 +1288,13 @@ static int RollOverTcp( demux_t *p_demux ) i_tk++; } - delete iter; return VLC_SUCCESS; + +error: + if( iter ) delete iter; + return VLC_EGENERIC; } @@ -1255,7 +1310,7 @@ static void StreamRead( void *p_private, unsigned int i_size, demux_sys_t *p_sys = p_demux->p_sys; block_t *p_block; - mtime_t i_pts = (uint64_t)pts.tv_sec * UI64C(1000000) + + int64_t i_pts = (uint64_t)pts.tv_sec * UI64C(1000000) + (uint64_t)pts.tv_usec; /* XXX Beurk beurk beurk Avoid having negative value XXX */ @@ -1366,8 +1421,6 @@ static void StreamRead( void *p_private, unsigned int i_size, memcpy( p_block->p_buffer, tk->p_buffer, i_size ); } - //p_block->i_rate = p_input->stream.control.i_rate; - if( i_pts != tk->i_pts && !tk->b_muxed ) { p_block->i_dts = ( tk->fmt.i_cat == VIDEO_ES ) ? 0 : i_pts; @@ -1387,7 +1440,7 @@ static void StreamRead( void *p_private, unsigned int i_size, es_out_Send( p_demux->out, tk->p_es, p_block ); } - /* warm that's ok */ + /* warn that's ok */ p_sys->event = 0xff; /* we have read data */ -- 2.39.5