Commit 32cdd8cb authored by Derk-Jan Hartman's avatar Derk-Jan Hartman

* 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?)
parent a4f7a771
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
#include <vlc/vlc.h> #include <vlc/vlc.h>
#include <vlc/input.h> #include <vlc/input.h>
#include "vlc_interaction.h"
#include "network.h" #include "network.h"
#include <iostream> #include <iostream>
...@@ -106,7 +108,7 @@ vlc_module_begin(); ...@@ -106,7 +108,7 @@ vlc_module_begin();
N_("Port to use for tunneling the RTSP/RTP over HTTP."), N_("Port to use for tunneling the RTSP/RTP over HTTP."),
VLC_TRUE ); VLC_TRUE );
#endif #endif
add_integer( "rtsp-caching", 4 * DEFAULT_PTS_DELAY / 1000, NULL, add_integer("rtsp-caching", 4 * DEFAULT_PTS_DELAY / 1000, NULL,
CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE ); CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
add_bool( "rtsp-kasenna", VLC_FALSE, NULL, KASENNA_TEXT, add_bool( "rtsp-kasenna", VLC_FALSE, NULL, KASENNA_TEXT,
KASENNA_LONGTEXT, VLC_TRUE ); KASENNA_LONGTEXT, VLC_TRUE );
...@@ -116,14 +118,6 @@ vlc_module_begin(); ...@@ -116,14 +118,6 @@ vlc_module_begin();
PASS_LONGTEXT, VLC_TRUE ); PASS_LONGTEXT, VLC_TRUE );
vlc_module_end(); 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 * Local prototypes
...@@ -151,7 +145,7 @@ typedef struct ...@@ -151,7 +145,7 @@ typedef struct
char waiting; char waiting;
mtime_t i_pts; int64_t i_pts;
} live_track_t; } live_track_t;
...@@ -176,10 +170,10 @@ struct demux_sys_t ...@@ -176,10 +170,10 @@ struct demux_sys_t
/* */ /* */
int i_track; int i_track;
live_track_t **track; /* XXX mallocated */ live_track_t **track; /* XXX mallocated */
mtime_t i_pcr; int64_t i_pcr;
mtime_t i_pcr_start; int64_t i_pcr_start;
mtime_t i_pcr_previous; int64_t i_pcr_previous;
mtime_t i_pcr_repeatdate; int64_t i_pcr_repeatdate;
int i_pcr_repeats; int i_pcr_repeats;
/* Asf */ /* Asf */
...@@ -187,8 +181,8 @@ struct demux_sys_t ...@@ -187,8 +181,8 @@ struct demux_sys_t
stream_t *p_out_asf; stream_t *p_out_asf;
/* */ /* */
mtime_t i_length; int64_t i_length;
mtime_t i_start; int64_t i_start;
/* timeout thread information */ /* timeout thread information */
int i_timeout; /* session timeout value in seconds */ int i_timeout; /* session timeout value in seconds */
...@@ -206,12 +200,15 @@ struct demux_sys_t ...@@ -206,12 +200,15 @@ struct demux_sys_t
static int Demux ( demux_t * ); static int Demux ( demux_t * );
static int Control( demux_t *, int, va_list ); static int Control( demux_t *, int, va_list );
static int ParseASF( demux_t * ); static int Connect ( demux_t * );
static int RollOverTcp( 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, static void StreamRead ( void *, unsigned int, unsigned int,
struct timeval, unsigned int ); struct timeval, unsigned int );
static void StreamClose( void * ); static void StreamClose ( void * );
static void TaskInterrupt( void * ); static void TaskInterrupt( void * );
static void TimeoutPrevention( timeout_thread_t * ); static void TimeoutPrevention( timeout_thread_t * );
...@@ -229,23 +226,15 @@ static int Open ( vlc_object_t *p_this ) ...@@ -229,23 +226,15 @@ static int Open ( vlc_object_t *p_this )
demux_t *p_demux = (demux_t*)p_this; demux_t *p_demux = (demux_t*)p_this;
demux_sys_t *p_sys = NULL; demux_sys_t *p_sys = NULL;
MediaSubsessionIterator *iter; MediaSubsessionIterator *iter = NULL;
MediaSubsession *sub; MediaSubsession *sub = NULL;
int i_return;
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;
if( p_demux->s ) if( p_demux->s )
{ {
/* See if it looks like a SDP /* See if it looks like a SDP
v, o, s fields are mandatory and in this order */ 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( stream_Peek( p_demux->s, &p_peek, 7 ) < 7 ) return VLC_EGENERIC;
if( memcmp( (char*)p_peek, "v=0\r\n", 5 ) && if( memcmp( (char*)p_peek, "v=0\r\n", 5 ) &&
...@@ -286,8 +275,7 @@ static int Open ( vlc_object_t *p_this ) ...@@ -286,8 +275,7 @@ static int Open ( vlc_object_t *p_this )
p_sys->i_timeout = 0; p_sys->i_timeout = 0;
p_sys->b_timeout_call = VLC_FALSE; p_sys->b_timeout_call = VLC_FALSE;
p_sys->b_multicast = 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 ) if( ( p_sys->scheduler = BasicTaskScheduler::createNew() ) == NULL )
{ {
...@@ -306,68 +294,13 @@ static int Open ( vlc_object_t *p_this ) ...@@ -306,68 +294,13 @@ static int Open ( vlc_object_t *p_this )
while( (p = strchr( p, ' ' )) != NULL ) *p = '+'; while( (p = strchr( p, ' ' )) != NULL ) *p = '+';
} }
if( p_demux->s == NULL && !strcasecmp( p_demux->psz_access, "rtsp" ) ) if( p_demux->s != NULL )
{
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
{ {
/* Gather the complete sdp file */ /* Gather the complete sdp file */
i_sdp = 0; int i_sdp = 0;
i_sdp_max = 1000; int i_sdp_max = 1000;
p_sdp = (uint8_t*)malloc( i_sdp_max ); uint8_t *p_sdp = (uint8_t*) malloc( i_sdp_max );
for( ;; ) for( ;; )
{ {
int i_read = stream_Read( p_demux->s, &p_sdp[i_sdp], int i_read = stream_Read( p_demux->s, &p_sdp[i_sdp],
...@@ -392,119 +325,53 @@ static int Open ( vlc_object_t *p_this ) ...@@ -392,119 +325,53 @@ static int Open ( vlc_object_t *p_this )
p_sdp = (uint8_t*)realloc( p_sdp, i_sdp_max ); p_sdp = (uint8_t*)realloc( p_sdp, i_sdp_max );
} }
p_sys->p_sdp = (char*)p_sdp; 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" ) )
{ {
msg_Err( p_demux, "MediaSession::createNew failed" ); /* sdp:// link from SAP */
goto error; p_sys->p_sdp = strdup( p_sys->psz_path );
} }
else if( ( i_return = Connect( p_demux ) ) != VLC_SUCCESS )
b_rtsp_tcp = var_CreateGetBool( p_demux, "rtsp-tcp" );
/* Initialise each media subsession */
iter = new MediaSubsessionIterator( *p_sys->ms );
while( ( sub = iter->next() ) != NULL )
{ {
unsigned int i_buffer = 0; msg_Err( p_demux, "Failed to connect with rtsp://%s", p_sys->psz_path );
Boolean bInit; goto error;
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" ) ) if( p_sys->p_sdp == NULL )
{ {
msg_Info( p_demux, "real codec detected, using real-RTSP instead" ); msg_Err( p_demux, "Failed to retrieve the RTSP Session Description" );
delete iter;
goto error; goto error;
} }
if( !bInit ) /* Create the session from the SDP */
if( !( p_sys->ms = MediaSession::createNew( *p_sys->env, p_sys->p_sdp ) ) )
{ {
msg_Warn( p_demux, "RTP subsession '%s/%s' failed (%s)", msg_Err( p_demux, "Could not create the RTSP Session: %s",
sub->mediumName(), sub->codecName(),
p_sys->env->getResultMsg() ); p_sys->env->getResultMsg() );
} goto error;
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(), /* Retrieve the duration if possible */
sub->codecName() ); p_sys->i_length = (int64_t)( p_sys->ms->playEndTime() * 1000000.0 );
if( p_sys->i_length < 0 )
/* Issue the SETUP */ p_sys->i_length = -1;
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() );
}
}
}
if( p_sys->rtsp ) if( ( i_return = SessionsSetup( p_demux ) ) != VLC_SUCCESS )
{
/* The PLAY */
if( !p_sys->rtsp->playMediaSession( *p_sys->ms ) )
{ {
msg_Err( p_demux, "PLAY failed %s", p_sys->env->getResultMsg() ); msg_Err( p_demux, "Nothing to play for rtsp://%s", p_sys->psz_path );
delete iter;
goto error; goto error;
} }
/* Retrieve the timeout value and set up a timeout prevention thread */ if( ( i_return = Play( p_demux ) ) != VLC_SUCCESS )
#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; goto error;
}
msg_Dbg( p_demux, "spawned timeout thread" );
vlc_object_attach( p_sys->p_timeout, p_demux );
}
}
/* Create all es struct */ /* Create all es struct */
iter->reset(); iter = new MediaSubsessionIterator( *p_sys->ms );
while( ( sub = iter->next() ) != NULL ) while( ( sub = iter->next() ) != NULL )
{ {
live_track_t *tk; live_track_t *tk;
/* Check if we will receive data from this subsession for this track */
if( sub->readSource() == NULL ) continue; if( sub->readSource() == NULL ) continue;
tk = (live_track_t*)malloc( sizeof( live_track_t ) ); tk = (live_track_t*)malloc( sizeof( live_track_t ) );
...@@ -713,7 +580,10 @@ static int Open ( vlc_object_t *p_this ) ...@@ -713,7 +580,10 @@ static int Open ( vlc_object_t *p_this )
} }
} }
if( !tk->b_quicktime && !tk->b_muxed && !tk->b_asf )
{
tk->p_es = es_out_Add( p_demux->out, &tk->fmt ); tk->p_es = es_out_Add( p_demux->out, &tk->fmt );
}
if( sub->rtcpInstance() != NULL ) if( sub->rtcpInstance() != NULL )
{ {
...@@ -731,6 +601,8 @@ static int Open ( vlc_object_t *p_this ) ...@@ -731,6 +601,8 @@ static int Open ( vlc_object_t *p_this )
} }
else else
{ {
/* BUG ??? */
msg_Err( p_demux, "unusable RTSP track. this should not happen" );
free( tk ); free( tk );
} }
} }
...@@ -744,29 +616,15 @@ static int Open ( vlc_object_t *p_this ) ...@@ -744,29 +616,15 @@ static int Open ( vlc_object_t *p_this )
goto error; 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 ) if( p_sys->i_track <= 0 )
{
msg_Err( p_demux, "no codec supported, aborting" );
goto error; goto error;
}
return VLC_SUCCESS; return VLC_SUCCESS;
error: error:
if( p_sys->p_out_asf ) stream_DemuxDelete( p_sys->p_out_asf ); 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->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->env ) RECLAIM_ENV(p_sys->env);
if( p_sys->p_timeout ) if( p_sys->p_timeout )
{ {
...@@ -820,14 +678,251 @@ static void Close( vlc_object_t *p_this ) ...@@ -820,14 +678,251 @@ static void Close( vlc_object_t *p_this )
vlc_object_destroy( p_sys->p_timeout ); vlc_object_destroy( p_sys->p_timeout );
} }
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->env ) RECLAIM_ENV( p_sys->env );
if( p_sys->scheduler ) delete p_sys->scheduler; if( p_sys->scheduler ) delete p_sys->scheduler;
if( p_sys->p_sdp ) free( p_sys->p_sdp ); if( p_sys->p_sdp ) free( p_sys->p_sdp );
if( p_sys->psz_path ) free( p_sys->psz_path ); if( p_sys->psz_path ) free( p_sys->psz_path );
free( p_sys ); 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: * Demux:
*****************************************************************************/ *****************************************************************************/
...@@ -837,7 +932,7 @@ static int Demux( demux_t *p_demux ) ...@@ -837,7 +932,7 @@ static int Demux( demux_t *p_demux )
TaskToken task; TaskToken task;
vlc_bool_t b_send_pcr = VLC_TRUE; vlc_bool_t b_send_pcr = VLC_TRUE;
mtime_t i_pcr = 0; int64_t i_pcr = 0;
int i; int i;
/* Check if we need to send the server a Keep-A-Live signal */ /* Check if we need to send the server a Keep-A-Live signal */
...@@ -879,6 +974,9 @@ static int Demux( demux_t *p_demux ) ...@@ -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 */ /* 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 */ /* 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 ) if( i_pcr > 0 && p_sys->i_pcr == p_sys->i_pcr_previous )
...@@ -900,8 +998,9 @@ static int Demux( demux_t *p_demux ) ...@@ -900,8 +998,9 @@ static int Demux( demux_t *p_demux )
msg_Dbg( p_demux, "suspect EOF due to end of VoD session" ); msg_Dbg( p_demux, "suspect EOF due to end of VoD session" );
return 0; return 0;
} }
#endif
/* First warm we want to read data */ /* First warn we want to read data */
p_sys->event = 0; p_sys->event = 0;
for( i = 0; i < p_sys->i_track; i++ ) for( i = 0; i < p_sys->i_track; i++ )
{ {
...@@ -963,7 +1062,6 @@ static int Demux( demux_t *p_demux ) ...@@ -963,7 +1062,6 @@ static int Demux( demux_t *p_demux )
msg_Err( p_demux, "TCP rollover failed, aborting" ); msg_Err( p_demux, "TCP rollover failed, aborting" );
return 0; return 0;
} }
var_SetBool( p_demux, "rtsp-tcp", VLC_TRUE );
} }
else if( p_sys->i_no_data_ti > 34 ) else if( p_sys->i_no_data_ti > 34 )
{ {
...@@ -971,7 +1069,7 @@ static int Demux( demux_t *p_demux ) ...@@ -971,7 +1069,7 @@ static int Demux( demux_t *p_demux )
return 0; 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 ? */ /* EOF ? */
msg_Warn( p_demux, "no data received in 10s, eof ?" ); msg_Warn( p_demux, "no data received in 10s, eof ?" );
...@@ -1012,33 +1110,31 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) ...@@ -1012,33 +1110,31 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
} }
else else
{ {
*pf = 0; *pf = 0.0;
} }
return VLC_SUCCESS; return VLC_SUCCESS;
case DEMUX_SET_POSITION: case DEMUX_SET_POSITION:
{
float time; float time;
f = (double)va_arg( args, double ); 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 ) 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 ) ) if( !p_sys->rtsp->playMediaSession( *p_sys->ms, time ) )
{ {
msg_Err( p_demux, "PLAY failed %s", msg_Err( p_demux, "PLAY failed %s",
p_sys->env->getResultMsg() ); p_sys->env->getResultMsg() );
return VLC_EGENERIC; 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_start = 0;
p_sys->i_pcr = 0; p_sys->i_pcr = 0;
return VLC_SUCCESS; return VLC_SUCCESS;
} }
return VLC_SUCCESS; return VLC_SUCCESS;
}
/* Special for access_demux */ /* Special for access_demux */
case DEMUX_CAN_PAUSE: case DEMUX_CAN_PAUSE:
...@@ -1113,101 +1209,57 @@ static int RollOverTcp( demux_t *p_demux ) ...@@ -1113,101 +1209,57 @@ static int RollOverTcp( demux_t *p_demux )
demux_sys_t *p_sys = p_demux->p_sys; demux_sys_t *p_sys = p_demux->p_sys;
MediaSubsessionIterator *iter; MediaSubsessionIterator *iter;
MediaSubsession *sub; MediaSubsession *sub;
char *psz_url;
char *psz_options;
char *psz_user;
char *psz_pwd;
uint8_t *p_sdp;
int i_tk; int i_tk;
int i_return;
var_SetBool( p_demux, "rtsp-tcp", VLC_TRUE );
/* We close the old RTSP session */ /* We close the old RTSP session */
p_sys->rtsp->teardownMediaSession( *p_sys->ms ); p_sys->rtsp->teardownMediaSession( *p_sys->ms );
Medium::close( p_sys->ms ); Medium::close( p_sys->ms );
Medium::close( p_sys->rtsp ); RTSPClient::close( p_sys->rtsp );
p_sys->ms = NULL; p_sys->ms = NULL;
p_sys->rtsp = NULL; p_sys->rtsp = NULL;
/* Reopen rtsp client */ /* Reopen rtsp client */
if( ( p_sys->rtsp = RTSPClient::createNew(*p_sys->env, 1/*verbose*/, if( ( i_return = Connect( p_demux ) ) != VLC_SUCCESS )
"VLC media player" ) ) == NULL )
{ {
msg_Err( p_demux, "RTSPClient::createNew failed (%s)", msg_Err( p_demux, "Failed to connect with rtsp://%s", p_sys->psz_path );
p_sys->env->getResultMsg() ); goto error;
return VLC_EGENERIC;
} }
asprintf( &psz_url, "rtsp://%s", p_sys->psz_path ); if( p_sys->p_sdp == NULL )
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 )
{ {
msg_Err( p_demux, "describeURL failed (%s)", msg_Err( p_demux, "Failed to retrieve the RTSP Session Description" );
p_sys->env->getResultMsg() ); goto error;
return VLC_EGENERIC;
} }
/* malloc-ated copy */ /* Create the session from the SDP */
p_sys->p_sdp = strdup( (char*)p_sdp );
delete[] p_sdp;
if( !( p_sys->ms = MediaSession::createNew( *p_sys->env, p_sys->p_sdp ) ) ) if( !( p_sys->ms = MediaSession::createNew( *p_sys->env, p_sys->p_sdp ) ) )
{ {
msg_Err( p_demux, "MediaSession::createNew failed" ); msg_Err( p_demux, "Could not create the RTSP Session: %s",
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() ); p_sys->env->getResultMsg() );
continue; goto error;
} }
msg_Dbg( p_demux, "RTP subsession '%s/%s'", sub->mediumName(),
sub->codecName() );
/* Issue the SETUP */ /* Retrieve the duration if possible */
p_sys->rtsp->setupMediaSubsession( *sub, False, True /* tcp */ ); 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( ( i_return = SessionsSetup( p_demux ) ) != VLC_SUCCESS )
if( !p_sys->rtsp->playMediaSession( *p_sys->ms ) )
{ {
msg_Err( p_demux, "PLAY failed %s", p_sys->env->getResultMsg() ); msg_Err( p_demux, "Nothing to play for rtsp://%s", p_sys->psz_path );
return VLC_EGENERIC; goto error;
} }
if( ( i_return = Play( p_demux ) ) != VLC_SUCCESS )
goto error;
/* Update all tracks */ /* Update all tracks */
iter->reset(); iter = new MediaSubsessionIterator( *p_sys->ms );
i_tk = 0; i_tk = 0;
while( ( sub = iter->next() ) != NULL ) while( ( sub = iter->next() ) != NULL )
{ {
...@@ -1218,7 +1270,7 @@ static int RollOverTcp( demux_t *p_demux ) ...@@ -1218,7 +1270,7 @@ static int RollOverTcp( demux_t *p_demux )
if( i_tk >= p_sys->i_track ) if( i_tk >= p_sys->i_track )
{ {
msg_Err( p_demux, "WTF !" ); msg_Err( p_demux, "WTF !" );
break; goto error;
} }
tk = p_sys->track[i_tk]; tk = p_sys->track[i_tk];
...@@ -1236,10 +1288,13 @@ static int RollOverTcp( demux_t *p_demux ) ...@@ -1236,10 +1288,13 @@ static int RollOverTcp( demux_t *p_demux )
i_tk++; i_tk++;
} }
delete iter; delete iter;
return VLC_SUCCESS; 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, ...@@ -1255,7 +1310,7 @@ static void StreamRead( void *p_private, unsigned int i_size,
demux_sys_t *p_sys = p_demux->p_sys; demux_sys_t *p_sys = p_demux->p_sys;
block_t *p_block; 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; (uint64_t)pts.tv_usec;
/* XXX Beurk beurk beurk Avoid having negative value XXX */ /* XXX Beurk beurk beurk Avoid having negative value XXX */
...@@ -1366,8 +1421,6 @@ static void StreamRead( void *p_private, unsigned int i_size, ...@@ -1366,8 +1421,6 @@ static void StreamRead( void *p_private, unsigned int i_size,
memcpy( p_block->p_buffer, tk->p_buffer, 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 ) if( i_pts != tk->i_pts && !tk->b_muxed )
{ {
p_block->i_dts = ( tk->fmt.i_cat == VIDEO_ES ) ? 0 : i_pts; 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, ...@@ -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 ); es_out_Send( p_demux->out, tk->p_es, p_block );
} }
/* warm that's ok */ /* warn that's ok */
p_sys->event = 0xff; p_sys->event = 0xff;
/* we have read data */ /* we have read data */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment