* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Derk-Jan Hartman <hartman at videolan. org>
* Derk-Jan Hartman <djhartman at m2x .dot. nl> for M2X
+ * Sébastien Escudier <sebastien-devel celeos eu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
"dialect of RTSP. With this parameter VLC will try this dialect, but "\
"then it cannot connect to normal RTSP servers." )
+#define WMSERVER_TEXT N_("WMServer RTSP dialect")
+#define WMSERVER_LONGTEXT N_("WMServer uses an unstandard dialect " \
+ "of RTSP. Selecting this parameter will tell VLC to assume some " \
+ "options contrary to RFC 2326 guidelines.")
+
#define USER_TEXT N_("RTSP user name")
#define USER_LONGTEXT N_("Sets the username for the connection, " \
"if no username or password are set in the url.")
set_capability( "demux", 50 )
set_shortname( "RTP/RTSP")
set_callbacks( Open, Close )
- add_shortcut( "live" )
- add_shortcut( "livedotcom" )
+ add_shortcut( "live", "livedotcom" )
set_category( CAT_INPUT )
set_subcategory( SUBCAT_INPUT_DEMUX )
add_submodule ()
set_description( N_("RTSP/RTP access and demux") )
- add_shortcut( "rtsp" )
- add_shortcut( "sdp" )
- add_shortcut( "live" )
- add_shortcut( "livedotcom" )
+ add_shortcut( "rtsp", "pnm", "sdp", "live", "livedotcom" )
set_capability( "access_demux", 0 )
set_callbacks( Open, Close )
- add_bool( "rtsp-tcp", 0, NULL,
+ add_bool( "rtsp-tcp", false, NULL,
N_("Use RTP over RTSP (TCP)"),
N_("Use RTP over RTSP (TCP)"), true )
change_safe()
N_("Force multicast RTP via RTSP"),
N_("Force multicast RTP via RTSP"), true )
change_safe()
- add_bool( "rtsp-http", 0, NULL,
+ add_bool( "rtsp-http", false, NULL,
N_("Tunnel RTSP and RTP over HTTP"),
N_("Tunnel RTSP and RTP over HTTP"), true )
change_safe()
change_safe()
add_bool( "rtsp-kasenna", false, NULL, KASENNA_TEXT,
KASENNA_LONGTEXT, true )
+ change_safe()
+ add_bool( "rtsp-wmserver", false, NULL, WMSERVER_TEXT,
+ WMSERVER_LONGTEXT, true)
+ change_safe()
add_string( "rtsp-user", NULL, NULL, USER_TEXT,
USER_LONGTEXT, true )
+ change_safe()
add_password( "rtsp-pwd", NULL, NULL, PASS_TEXT,
PASS_LONGTEXT, true )
+ change_safe()
vlc_module_end ()
bool b_muxed;
bool b_quicktime;
bool b_asf;
+ block_t *p_asf_block;
bool b_discard_trunc;
stream_t *p_out_muxed; /* for muxed stream */
bool b_handle_keep_alive;
};
+class RTSPClientVlc;
+
struct demux_sys_t
{
char *p_sdp; /* XXX mallocated */
MediaSession *ms;
TaskScheduler *scheduler;
UsageEnvironment *env ;
- RTSPClient *rtsp;
+ RTSPClientVlc *rtsp;
/* */
int i_track;
char event;
bool b_get_param; /* Does the server support GET_PARAMETER */
+ bool b_paused; /* Are we paused? */
+ bool b_error;
+ int i_live555_ret; /* live555 callback return code */
+
+ float f_seek_request;/* In case we receive a seek request while paused*/
+};
+
+
+class RTSPClientVlc : public RTSPClient
+{
+public:
+ RTSPClientVlc( UsageEnvironment& env, char const* rtspURL, int verbosityLevel,
+ char const* applicationName, portNumBits tunnelOverHTTPPortNum,
+ demux_sys_t *p_sys) :
+ RTSPClient( env, rtspURL, verbosityLevel, applicationName,
+ tunnelOverHTTPPortNum )
+ {
+ this->p_sys = p_sys;
+ }
+ demux_sys_t *p_sys;
};
static int Demux ( demux_t * );
return VLC_EGENERIC;
}
}
- else
- {
- var_Create( p_demux, "rtsp-caching", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
- }
+ var_Create( p_demux, "rtsp-caching", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
p_demux->pf_demux = Demux;
p_demux->pf_control= Control;
p_sys->b_timeout_call = false;
p_sys->b_multicast = false;
p_sys->b_real = false;
- p_sys->psz_path = strdup( p_demux->psz_path );
- p_sys->b_force_mcast = var_CreateGetBool( p_demux, "rtsp-mcast" );
+ p_sys->psz_path = strdup( p_demux->psz_location );
+ p_sys->b_force_mcast = var_InheritBool( p_demux, "rtsp-mcast" );
p_sys->b_get_param = false;
+ p_sys->b_paused = false;
+ p_sys->f_seek_request = -1;
+ p_sys->b_error = false;
+ p_sys->i_live555_ret = 0;
/* parse URL for rtsp://[user:[passwd]@]serverip:port/options */
vlc_UrlParse( &p_sys->url, p_sys->psz_path, 0 );
int i_read = stream_Read( p_demux->s, &p_sdp[i_sdp],
i_sdp_max - i_sdp - 1 );
- if( !vlc_object_alive (p_demux) || p_demux->b_error )
+ if( !vlc_object_alive (p_demux) )
{
free( p_sdp );
goto error;
}
i_sdp_max += 1000;
- p_sdp = (uint8_t*)realloc( p_sdp, i_sdp_max );
+ p_sdp = (uint8_t*)xrealloc( p_sdp, i_sdp_max );
}
p_sys->p_sdp = (char*)p_sdp;
}
{
demux_t *p_demux = (demux_t*)p_this;
demux_sys_t *p_sys = p_demux->p_sys;
- int i;
- for( i = 0; i < p_sys->i_track; i++ )
+ if( p_sys->rtsp && p_sys->ms ) p_sys->rtsp->sendTeardownCommand( *p_sys->ms, NULL );
+ if( p_sys->ms ) Medium::close( p_sys->ms );
+ if( p_sys->rtsp ) RTSPClient::close( p_sys->rtsp );
+ if( p_sys->env ) p_sys->env->reclaim();
+
+ for( int i = 0; i < p_sys->i_track; i++ )
{
live_track_t *tk = p_sys->track[i];
if( p_sys->i_track ) free( p_sys->track );
if( p_sys->p_out_asf ) stream_Delete( p_sys->p_out_asf );
- if( p_sys->rtsp && p_sys->ms ) p_sys->rtsp->teardownMediaSession( *p_sys->ms );
if( p_sys->p_timeout )
{
vlc_cancel( p_sys->p_timeout->handle );
vlc_join( p_sys->p_timeout->handle, NULL );
free( p_sys->p_timeout );
}
- if( p_sys->ms ) Medium::close( p_sys->ms );
- if( p_sys->rtsp ) RTSPClient::close( p_sys->rtsp );
- if( p_sys->env ) p_sys->env->reclaim();
delete p_sys->scheduler;
free( p_sys->p_sdp );
free( p_sys->psz_path );
free( p_sys );
}
+static inline const char *strempty( const char *s ) { return s?s:""; }
+static inline Boolean toBool( bool b ) { return b?True:False; } // silly, no?
+
+static void default_live555_callback( RTSPClient* client, int result_code, char* result_string )
+{
+ RTSPClientVlc *client_vlc = static_cast<RTSPClientVlc *> ( client );
+ demux_sys_t *p_sys = client_vlc->p_sys;
+ delete []result_string;
+ p_sys->i_live555_ret = result_code;
+ p_sys->b_error = p_sys->i_live555_ret != 0;
+ p_sys->event = 1;
+}
+
+/* return true if the RTSP command succeeded */
+static bool wait_Live555_response( demux_t *p_demux, int i_timeout = 0 /* ms */ )
+{
+ TaskToken task;
+ demux_sys_t * p_sys = p_demux->p_sys;
+ p_sys->event = 0;
+ if( i_timeout > 0 )
+ {
+ /* Create a task that will be called if we wait more than timeout ms */
+ task = p_sys->scheduler->scheduleDelayedTask( i_timeout*1000, TaskInterrupt,
+ p_demux );
+ }
+ p_sys->event = 0;
+ p_sys->b_error = true;
+ p_sys->i_live555_ret = 0;
+ p_sys->scheduler->doEventLoop( &p_sys->event );
+ //here, if b_error is true and i_live555_ret = 0 we didn't receive a response
+ if( i_timeout > 0 )
+ {
+ /* remove the task */
+ p_sys->scheduler->unscheduleDelayedTask( task );
+ }
+ return !p_sys->b_error;
+}
+
+static void continueAfterDESCRIBE( RTSPClient* client, int result_code,
+ char* result_string )
+{
+ RTSPClientVlc *client_vlc = static_cast<RTSPClientVlc *> ( client );
+ demux_sys_t *p_sys = client_vlc->p_sys;
+ char* sdpDescription = result_string;
+ p_sys->i_live555_ret = result_code;
+ if ( result_code != 0 )
+ {
+ delete[] sdpDescription;
+ return;
+ }
+ free( p_sys->p_sdp );
+ p_sys->p_sdp = NULL;
+ if( sdpDescription )
+ {
+ p_sys->p_sdp = strdup( sdpDescription );
+ delete[] sdpDescription;
+ }
+ p_sys->b_error = false;
+ p_sys->event = 1;
+}
+
+static void continueAfterOPTIONS( RTSPClient* client, int result_code,
+ char* result_string )
+{
+ RTSPClientVlc *client_vlc = static_cast<RTSPClientVlc *> (client);
+ demux_sys_t *p_sys = client_vlc->p_sys;
+ p_sys->i_live555_ret = result_code;
+ if ( result_code != 0 )
+ {
+ p_sys->b_error = true;
+ p_sys->event = 1;
+ }
+ else
+ {
+ p_sys->b_get_param = (bool)strstr( result_string, "GET_PARAMETER" );
+ client->sendDescribeCommand( continueAfterDESCRIBE );
+ }
+ delete[] result_string;
+}
+
/*****************************************************************************
* Connect: connects to the RTSP server to setup the session DESCRIBE
*****************************************************************************/
{
demux_sys_t *p_sys = p_demux->p_sys;
Authenticator authenticator;
- bool b_firstpass = true;
char *psz_user = NULL;
char *psz_pwd = NULL;
char *psz_url = NULL;
char *p_sdp = NULL;
int i_http_port = 0;
int i_ret = VLC_SUCCESS;
+ const int i_timeout = var_InheritInteger( p_demux, "ipv4-timeout" );
- if( p_sys->url.i_port == 0 ) p_sys->url.i_port = 554;
+ /* Get the user name and password */
if( p_sys->url.psz_username || p_sys->url.psz_password )
{
- int err;
- err = asprintf( &psz_url, "rtsp://%s:%d%s", p_sys->url.psz_host,
- p_sys->url.i_port, p_sys->url.psz_path );
- if( err == -1 ) return VLC_ENOMEM;
-
- psz_user = strdup( p_sys->url.psz_username ? p_sys->url.psz_username : "" );
- psz_pwd = strdup( p_sys->url.psz_password ? p_sys->url.psz_password : "");
+ /* Create the URL by stripping away the username/password part */
+ if( p_sys->url.i_port == 0 )
+ p_sys->url.i_port = 554;
+ if( asprintf( &psz_url, "rtsp://%s:%d%s",
+ strempty( p_sys->url.psz_host ),
+ p_sys->url.i_port,
+ strempty( p_sys->url.psz_path ) ) == -1 )
+ return VLC_ENOMEM;
+
+ psz_user = strdup( strempty( p_sys->url.psz_username ) );
+ psz_pwd = strdup( strempty( p_sys->url.psz_password ) );
}
else
{
- int err;
- err = asprintf( &psz_url, "rtsp://%s", p_sys->psz_path );
- if( err == -1 ) return VLC_ENOMEM;
+ if( asprintf( &psz_url, "rtsp://%s", p_sys->psz_path ) == -1 )
+ return VLC_ENOMEM;
- psz_user = var_CreateGetString( p_demux, "rtsp-user" );
- psz_pwd = var_CreateGetString( p_demux, "rtsp-pwd" );
+ psz_user = var_InheritString( p_demux, "rtsp-user" );
+ psz_pwd = var_InheritString( p_demux, "rtsp-pwd" );
}
createnew:
- if( !vlc_object_alive (p_demux) || p_demux->b_error )
+ if( !vlc_object_alive (p_demux) )
{
- free( psz_user );
- free( psz_pwd );
- free( psz_url );
- return VLC_EGENERIC;
+ i_ret = VLC_EGENERIC;
+ goto bailout;
}
- if( var_CreateGetBool( p_demux, "rtsp-http" ) )
- i_http_port = var_CreateGetInteger( p_demux, "rtsp-http-port" );
+ if( var_InheritBool( p_demux, "rtsp-http" ) )
+ i_http_port = var_InheritInteger( p_demux, "rtsp-http-port" );
- if( ( p_sys->rtsp = RTSPClient::createNew( *p_sys->env,
- var_CreateGetInteger( p_demux, "verbose" ) > 1,
- "VLC media player", i_http_port ) ) == NULL )
+ p_sys->rtsp = new RTSPClientVlc( *p_sys->env, psz_url,
+ var_InheritInteger( p_demux, "verbose" ) > 1 ? 1 : 0,
+ "LibVLC/"VERSION, i_http_port, p_sys );
+ if( !p_sys->rtsp )
{
msg_Err( p_demux, "RTSPClient::createNew failed (%s)",
p_sys->env->getResultMsg() );
- free( psz_user );
- free( psz_pwd );
- free( psz_url );
- return VLC_EGENERIC;
+ i_ret = VLC_EGENERIC;
+ goto bailout;
}
/* Kasenna enables KeepAlive by analysing the User-Agent string.
* to spaces in the string or the string being too long. Here we override
* the default string with a more compact version.
*/
- if( var_CreateGetBool( p_demux, "rtsp-kasenna" ))
+ if( var_InheritBool( p_demux, "rtsp-kasenna" ))
{
p_sys->rtsp->setUserAgentString( "VLC_MEDIA_PLAYER_KA" );
}
describe:
authenticator.setUsernameAndPassword( psz_user, psz_pwd );
- /* */
-#if LIVEMEDIA_LIBRARY_VERSION_INT >= 1223337600
- const int i_timeout = var_CreateGetInteger(p_demux, "ipv4-timeout") / 1000;
- psz_options = p_sys->rtsp->sendOptionsCmd( psz_url, psz_user, psz_pwd,
- &authenticator, i_timeout );
-#else
- psz_options = p_sys->rtsp->sendOptionsCmd( psz_url, psz_user, psz_pwd,
- &authenticator );
-#endif
- if( psz_options == NULL && authenticator.realm() != NULL )
- {
- // try again, with the realm set this time
-#if LIVEMEDIA_LIBRARY_VERSION_INT >= 1223337600
- psz_options = p_sys->rtsp->sendOptionsCmd( psz_url, psz_user, psz_pwd,
- &authenticator, i_timeout );
-#else
- psz_options = p_sys->rtsp->sendOptionsCmd( psz_url, psz_user, psz_pwd,
- &authenticator );
-#endif
- }
- if( psz_options )
- p_sys->b_get_param = strstr( psz_options, "GET_PARAMETER" ) ? true : false ;
- delete [] psz_options;
+ p_sys->rtsp->sendOptionsCommand( &continueAfterOPTIONS, &authenticator );
-#if LIVEMEDIA_LIBRARY_VERSION_INT >= 1223337600
- p_sdp = p_sys->rtsp->describeWithPassword( psz_url, (const char*)psz_user, (const char*)psz_pwd,
- var_GetBool( p_demux, "rtsp-kasenna" ), i_timeout );
-#else
- p_sdp = p_sys->rtsp->describeWithPassword( psz_url, (const char*)psz_user, (const char*)psz_pwd,
- var_GetBool( p_demux, "rtsp-kasenna" ) );
-#endif
-
- if( p_sdp == NULL )
+ if( !wait_Live555_response( p_demux, i_timeout ) )
{
- /* failure occurred */
- int i_code = 0;
- const char *psz_error = p_sys->env->getResultMsg();
-
- if( var_GetBool( p_demux, "rtsp-http" ) )
- sscanf( psz_error, "%*s %*s HTTP GET %*s HTTP/%*u.%*u %3u %*s",
- &i_code );
- else
- {
- const char *psz_tmp = strstr( psz_error, "RTSP" );
- if( psz_tmp )
- sscanf( psz_tmp, "RTSP/%*s%3u", &i_code );
- else
- i_code = 0;
- }
- msg_Dbg( p_demux, "DESCRIBE failed with %d: %s", i_code, psz_error );
-
- if( b_firstpass )
- { /* describeURL always returns an "RTSP/1.0 401 Unauthorized" the
- * first time. This is a workaround to avoid asking for a
- * user/passwd the first time the code passess here. */
- i_code = 0;
- b_firstpass = false;
- }
-
+ int i_code = p_sys->i_live555_ret;
if( i_code == 401 )
{
msg_Dbg( p_demux, "authentication failed" );
free( psz_user );
free( psz_pwd );
dialog_Login( p_demux, &psz_user, &psz_pwd,
- _("RTSP authentication"),
+ _("RTSP authentication"), "%s",
_("Please enter a valid login name and a password.") );
if( psz_user != NULL && psz_pwd != NULL )
{
goto describe;
}
}
- else if( (i_code != 0) && !var_GetBool( p_demux, "rtsp-http" ) )
+ else if( (i_code > 0) && !var_GetBool( p_demux, "rtsp-http" ) )
{
/* Perhaps a firewall is being annoying. Try HTTP tunneling mode */
msg_Dbg( p_demux, "we will now try HTTP tunneling mode" );
}
else
{
- msg_Dbg( p_demux, "connection timeout" );
+ if( i_code == 0 )
+ msg_Dbg( p_demux, "connection timeout" );
if( p_sys->rtsp ) RTSPClient::close( p_sys->rtsp );
p_sys->rtsp = NULL;
}
i_ret = VLC_EGENERIC;
}
+bailout:
/* malloc-ated copy */
free( psz_url );
free( psz_user );
free( psz_pwd );
- free( p_sys->p_sdp );
- p_sys->p_sdp = NULL;
- if( p_sdp ) p_sys->p_sdp = strdup( (char*)p_sdp );
- delete[] p_sdp;
-
return i_ret;
}
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" ) ||
- var_GetBool( p_demux, "rtsp-http" );
- i_client_port = var_CreateGetInteger( p_demux, "rtp-client-port" );
+ b_rtsp_tcp = var_InheritBool( p_demux, "rtsp-tcp" ) ||
+ var_InheritBool( p_demux, "rtsp-http" );
+ i_client_port = var_InheritInteger( p_demux, "rtp-client-port" );
/* Create the session from the SDP */
if( !( p_sys->ms = MediaSession::createNew( *p_sys->env, p_sys->p_sdp ) ) )
Boolean bInit;
live_track_t *tk;
- if( !vlc_object_alive (p_demux) || p_demux->b_error )
+ if( !vlc_object_alive (p_demux) )
{
delete iter;
return VLC_EGENERIC;
i_buffer = 100000;
else if( !strcmp( sub->mediumName(), "video" ) )
i_buffer = 2000000;
+ else if( !strcmp( sub->mediumName(), "text" ) )
+ ;
else continue;
if( i_client_port != -1 )
}
if( !strcmp( sub->codecName(), "X-ASF-PF" ) )
- bInit = sub->initiate( 4 ); /* Constant ? */
+ bInit = sub->initiate( 0 );
else
bInit = sub->initiate();
/* Issue the SETUP */
if( p_sys->rtsp )
{
- if( !p_sys->rtsp->setupMediaSubsession( *sub, False,
- b_rtsp_tcp ? True : False,
- ( p_sys->b_force_mcast && !b_rtsp_tcp ) ? True : False ) )
+ p_sys->rtsp->sendSetupCommand( *sub, default_live555_callback, False,
+ toBool( b_rtsp_tcp ),
+ toBool( p_sys->b_force_mcast && !b_rtsp_tcp ) );
+ if( !wait_Live555_response( p_demux ) )
{
- /* if we get an unsupported transport error, toggle TCP use and try again */
- if( !strstr(p_sys->env->getResultMsg(), "461 Unsupported Transport")
- || !p_sys->rtsp->setupMediaSubsession( *sub, False,
- b_rtsp_tcp ? False : True,
- False ) )
+ /* if we get an unsupported transport error, toggle TCP
+ * use and try again */
+ if( p_sys->i_live555_ret == 461 )
+ p_sys->rtsp->sendSetupCommand( *sub, default_live555_callback, False,
+ toBool( b_rtsp_tcp ), False );
+ if( p_sys->i_live555_ret != 461 || !wait_Live555_response( p_demux ) )
{
- msg_Err( p_demux, "SETUP of'%s/%s' failed %s", sub->mediumName(),
- sub->codecName(), p_sys->env->getResultMsg() );
+ msg_Err( p_demux, "SETUP of'%s/%s' failed %s",
+ sub->mediumName(), sub->codecName(),
+ p_sys->env->getResultMsg() );
continue;
}
}
}
- /* Check if we will receive data from this subsession for this track */
+ /* Check if we will receive data from this subsession for
+ * this track */
if( sub->readSource() == NULL ) continue;
if( !p_sys->b_multicast )
{
- /* Check, because we need diff. rollover behaviour for multicast */
+ /* We need different rollover behaviour for multicast */
p_sys->b_multicast = IsMulticastAddress( sub->connectionEndpointAddress() );
}
tk->p_es = NULL;
tk->b_quicktime = false;
tk->b_asf = false;
+ tk->p_asf_block = NULL;
tk->b_muxed = false;
tk->b_discard_trunc = false;
tk->p_out_muxed = NULL;
tk->waiting = 0;
tk->b_rtcp_sync = false;
- tk->i_pts = 0;
+ tk->i_pts = VLC_TS_INVALID;
tk->i_npt = 0.;
tk->i_buffer = 65536;
tk->p_buffer = (uint8_t *)malloc( 65536 );
i_extra ) ) )
{
tk->fmt.i_extra = i_extra;
- tk->fmt.p_extra = malloc( i_extra );
+ tk->fmt.p_extra = xmalloc( i_extra );
memcpy( tk->fmt.p_extra, p_extra, i_extra );
delete[] p_extra;
}
- /* Because the "faad" decoder does not handle the LATM data length field
- at the start of each returned LATM frame, tell the RTP source to omit it. */
+ /* Because the "faad" decoder does not handle the LATM
+ * data length field at the start of each returned LATM
+ * frame, tell the RTP source to omit it. */
((MPEG4LATMAudioRTPSource*)sub->rtpSource())->omitLATMDataLengthField();
}
else if( !strcmp( sub->codecName(), "MPEG4-GENERIC" ) )
i_extra ) ) )
{
tk->fmt.i_extra = i_extra;
- tk->fmt.p_extra = malloc( i_extra );
+ tk->fmt.p_extra = xmalloc( i_extra );
memcpy( tk->fmt.p_extra, p_extra, i_extra );
delete[] p_extra;
}
if( !strcmp( sub->codecName(), "MPV" ) )
{
tk->fmt.i_codec = VLC_CODEC_MPGV;
+ tk->fmt.b_packetized = false;
}
else if( !strcmp( sub->codecName(), "H263" ) ||
!strcmp( sub->codecName(), "H263-1998" ) ||
i_extra ) ) )
{
tk->fmt.i_extra = i_extra;
- tk->fmt.p_extra = malloc( i_extra );
+ tk->fmt.p_extra = xmalloc( i_extra );
memcpy( tk->fmt.p_extra, p_extra, i_extra );
delete[] p_extra;
i_extra ) ) )
{
tk->fmt.i_extra = i_extra;
- tk->fmt.p_extra = malloc( i_extra );
+ tk->fmt.p_extra = xmalloc( i_extra );
memcpy( tk->fmt.p_extra, p_extra, i_extra );
delete[] p_extra;
}
p_demux->out );
}
}
+ else if( !strcmp( sub->mediumName(), "text" ) )
+ {
+ es_format_Init( &tk->fmt, SPU_ES, VLC_FOURCC('u','n','d','f') );
+
+ if( !strcmp( sub->codecName(), "T140" ) )
+ {
+ tk->fmt.i_codec = VLC_CODEC_ITU_T140;
+ }
+ }
if( !tk->b_quicktime && !tk->b_muxed && !tk->b_asf )
{
if( tk->p_es || tk->b_quicktime || tk->b_muxed || tk->b_asf )
{
/* Append */
- p_sys->track = (live_track_t**)realloc( p_sys->track, sizeof( live_track_t ) * ( p_sys->i_track + 1 ) );
+ p_sys->track = (live_track_t**)xrealloc( p_sys->track,
+ sizeof( live_track_t ) * ( p_sys->i_track + 1 ) );
p_sys->track[p_sys->i_track++] = tk;
}
else
if( p_sys->rtsp )
{
/* The PLAY */
- if( !p_sys->rtsp->playMediaSession( *p_sys->ms, p_sys->i_npt_start, -1, 1 ) )
+ p_sys->rtsp->sendPlayCommand( *p_sys->ms, default_live555_callback, p_sys->i_npt_start, -1, 1 );
+
+ if( !wait_Live555_response(p_demux) )
{
msg_Err( p_demux, "RTSP PLAY failed %s", p_sys->env->getResultMsg() );
return VLC_EGENERIC;
/* Retrieve the starttime if possible */
p_sys->i_npt_start = p_sys->ms->playStartTime();
- p_sys->i_npt_length = p_sys->ms->playEndTime();
+ if( p_sys->ms->playEndTime() > 0 )
+ p_sys->i_npt_length = p_sys->ms->playEndTime();
msg_Dbg( p_demux, "play start: %f stop:%f", p_sys->i_npt_start, p_sys->i_npt_length );
return VLC_SUCCESS;
if( p_sys->b_timeout_call && p_sys->rtsp && p_sys->ms )
{
char *psz_bye = NULL;
- p_sys->rtsp->getMediaSessionParameter( *p_sys->ms, NULL, psz_bye );
+ p_sys->rtsp->sendGetParameterCommand( *p_sys->ms, NULL, psz_bye );
p_sys->b_timeout_call = false;
}
if( p_sys->i_pcr > 0 )
{
if( b_send_pcr )
- es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_pcr );
+ es_out_Control( p_demux->out, ES_OUT_SET_PCR, 1 + p_sys->i_pcr );
}
/* First warn we want to read data */
es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
tk->b_rtcp_sync = true;
/* reset PCR */
- tk->i_pts = 0;
+ tk->i_pts = VLC_TS_INVALID;
tk->i_npt = 0.;
p_sys->i_pcr = 0;
p_sys->i_npt = 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_paused &&
+ p_sys->b_no_data && ( p_sys->i_no_data_ti > 34 ) )
{
bool b_rtsp_tcp = var_GetBool( p_demux, "rtsp-tcp" ) ||
var_GetBool( p_demux, "rtsp-http" );
msg_Err( p_demux, "no data received in 10s, aborting" );
return 0;
}
- else if( !p_sys->b_multicast && p_sys->i_no_data_ti > 34 )
+ else if( !p_sys->b_multicast && !p_sys->b_paused &&
+ ( p_sys->i_no_data_ti > 34 ) )
{
/* EOF ? */
msg_Warn( p_demux, "no data received in 10s, eof ?" );
return 0;
}
- return p_demux->b_error ? 0 : 1;
+ return p_sys->b_error ? 0 : 1;
}
/*****************************************************************************
demux_sys_t *p_sys = p_demux->p_sys;
int64_t *pi64, i64;
double *pf, f;
- bool *pb, *pb2, b_bool;
+ bool *pb, *pb2;
int *pi_int;
switch( i_query )
time = f * (double)p_sys->i_npt_length; /* in second */
}
- if( !p_sys->rtsp->playMediaSession( *p_sys->ms, time, -1, 1 ) )
+ if( p_sys->b_paused )
+ {
+ p_sys->f_seek_request = time;
+ return VLC_SUCCESS;
+ }
+
+ p_sys->rtsp->sendPauseCommand( *p_sys->ms, default_live555_callback );
+
+ if( !wait_Live555_response( p_demux ) )
{
- msg_Err( p_demux, "PLAY failed %s",
+ msg_Err( p_demux, "PAUSE before seek failed %s",
+ p_sys->env->getResultMsg() );
+ return VLC_EGENERIC;
+ }
+
+ p_sys->rtsp->sendPlayCommand( *p_sys->ms, default_live555_callback, time, -1, 1 );
+
+ if( !wait_Live555_response( p_demux ) )
+ {
+ msg_Err( p_demux, "seek PLAY failed %s",
p_sys->env->getResultMsg() );
return VLC_EGENERIC;
}
for( i = 0; i < p_sys->i_track; i++ )
{
p_sys->track[i]->b_rtcp_sync = false;
- p_sys->track[i]->i_pts = 0;
+ p_sys->track[i]->i_pts = VLC_TS_INVALID;
}
/* Retrieve the starttime if possible */
p_sys->i_npt = p_sys->i_npt_start = p_sys->ms->playStartTime();
/* Retrieve the duration if possible */
- p_sys->i_npt_length = p_sys->ms->playEndTime();
+ if( p_sys->ms->playEndTime() > 0 )
+ p_sys->i_npt_length = p_sys->ms->playEndTime();
msg_Dbg( p_demux, "seek start: %f stop:%f", p_sys->i_npt_start, p_sys->i_npt_length );
return VLC_SUCCESS;
*pb = (p_sys->rtsp != NULL) &&
(p_sys->i_npt_length > 0) &&
- !var_GetBool( p_demux, "rtsp-kasenna" );
+ ( !var_GetBool( p_demux, "rtsp-kasenna" ) ||
+ !var_GetBool( p_demux, "rtsp-wmserver" ) );
*pb2 = false;
return VLC_SUCCESS;
double f_scale, f_old_scale;
if( !p_sys->rtsp || (p_sys->i_npt_length <= 0) ||
- var_GetBool( p_demux, "rtsp-kasenna" ) )
+ var_GetBool( p_demux, "rtsp-kasenna" ) ||
+ var_GetBool( p_demux, "rtsp-wmserver" ) )
return VLC_EGENERIC;
/* According to RFC 2326 p56 chapter 12.35 a RTSP server that
/* Passing -1 for the start and end time will mean liveMedia won't
* create a Range: section for the RTSP message. The server should
* pick up from the current position */
- if( !p_sys->rtsp->playMediaSession( *p_sys->ms, -1, -1, f_scale ) )
+ p_sys->rtsp->sendPlayCommand( *p_sys->ms, default_live555_callback, -1, -1, f_scale );
+
+ if( !wait_Live555_response( p_demux ) )
{
msg_Err( p_demux, "PLAY with Scale %0.2f failed %s", f_scale,
p_sys->env->getResultMsg() );
case DEMUX_SET_PAUSE_STATE:
{
- int i;
-
- b_bool = (bool)va_arg( args, int );
+ bool b_pause = (bool)va_arg( args, int );
if( p_sys->rtsp == NULL )
return VLC_EGENERIC;
- /* FIXME */
- if( ( b_bool && !p_sys->rtsp->pauseMediaSession( *p_sys->ms ) ) ||
- ( !b_bool && !p_sys->rtsp->playMediaSession( *p_sys->ms,
- -1 ) ) )
+ if( b_pause == p_sys->b_paused )
+ return VLC_SUCCESS;
+ if( b_pause )
+ p_sys->rtsp->sendPauseCommand( *p_sys->ms, default_live555_callback );
+ else
+ p_sys->rtsp->sendPlayCommand( *p_sys->ms, default_live555_callback, p_sys->f_seek_request,
+ -1.0f, p_sys->ms->scale() );
+
+ if( !wait_Live555_response( p_demux ) )
{
- msg_Err( p_demux, "PLAY or PAUSE failed %s", p_sys->env->getResultMsg() );
- return VLC_EGENERIC;
+ msg_Err( p_demux, "PLAY or PAUSE failed %s", p_sys->env->getResultMsg() );
+ return VLC_EGENERIC;
}
+ p_sys->f_seek_request = -1;
+ p_sys->b_paused = b_pause;
/* When we Pause, we'll need the TimeoutPrevention thread to
* handle sending the "Keep Alive" message to the server.
* waiting for a response from the server. So when we PAUSE
* we set a flag that the TimeoutPrevention function will check
* and if it's set, it will trigger the GET_PARAMETER message */
- if( b_bool && p_sys->p_timeout != NULL )
+ if( p_sys->b_paused && p_sys->p_timeout != NULL )
p_sys->p_timeout->b_handle_keep_alive = true;
- else if( !b_bool && p_sys->p_timeout != NULL )
+ else if( !p_sys->b_paused && p_sys->p_timeout != NULL )
p_sys->p_timeout->b_handle_keep_alive = false;
- for( i = 0; !b_bool && i < p_sys->i_track; i++ )
+ if( !p_sys->b_paused )
{
- live_track_t *tk = p_sys->track[i];
- tk->b_rtcp_sync = false;
- tk->i_pts = 0;
- p_sys->i_pcr = 0;
- es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
+ for( int i = 0; i < p_sys->i_track; i++ )
+ {
+ live_track_t *tk = p_sys->track[i];
+ tk->b_rtcp_sync = false;
+ tk->i_pts = VLC_TS_INVALID;
+ p_sys->i_pcr = 0;
+ es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
+ }
}
+ /* Reset data received counter */
+ p_sys->i_no_data_ti = 0;
+
/* Retrieve the starttime if possible */
p_sys->i_npt_start = p_sys->ms->playStartTime();
/* Retrieve the duration if possible */
- p_sys->i_npt_length = p_sys->ms->playEndTime();
+ if( p_sys->ms->playEndTime() )
+ p_sys->i_npt_length = p_sys->ms->playEndTime();
msg_Dbg( p_demux, "pause start: %f stop:%f", p_sys->i_npt_start, p_sys->i_npt_length );
return VLC_SUCCESS;
case DEMUX_GET_PTS_DELAY:
pi64 = (int64_t*)va_arg( args, int64_t * );
- *pi64 = (int64_t)var_GetInteger( p_demux, "rtsp-caching" ) * 1000;
+ *pi64 = var_GetInteger( p_demux, "rtsp-caching" ) * 1000;
return VLC_SUCCESS;
default:
if( tk->b_muxed ) stream_Delete( tk->p_out_muxed );
if( tk->p_es ) es_out_Del( p_demux->out, tk->p_es );
+ if( tk->p_asf_block ) block_Release( tk->p_asf_block );
es_format_Clean( &tk->fmt );
free( tk->p_buffer );
free( tk );
if( p_sys->i_track ) free( p_sys->track );
if( p_sys->p_out_asf ) stream_Delete( p_sys->p_out_asf );
- p_sys->rtsp->teardownMediaSession( *p_sys->ms );
+ p_sys->rtsp->sendTeardownCommand( *p_sys->ms, NULL );
Medium::close( p_sys->ms );
RTSPClient::close( p_sys->rtsp );
p_sys->i_track = 0;
p_sys->b_no_data = true;
p_sys->i_no_data_ti = 0;
+ p_sys->p_out_asf = NULL;
/* Reopen rtsp client */
if( ( i_return = Connect( p_demux ) ) != VLC_SUCCESS )
}
+/*****************************************************************************
+ *
+ *****************************************************************************/
+static block_t *StreamParseAsf( demux_t *p_demux, live_track_t *tk,
+ bool b_marker,
+ const uint8_t *p_data, unsigned i_size )
+{
+ const unsigned i_packet_size = p_demux->p_sys->asfh.i_min_data_packet_size;
+ block_t *p_list = NULL;
+
+ while( i_size >= 4 )
+ {
+ unsigned i_flags = p_data[0];
+ unsigned i_length_offset = (p_data[1] << 16) |
+ (p_data[2] << 8) |
+ (p_data[3] );
+ bool b_key = i_flags & 0x80;
+ bool b_length = i_flags & 0x40;
+ bool b_relative_ts = i_flags & 0x20;
+ bool b_duration = i_flags & 0x10;
+ bool b_location_id = i_flags & 0x08;
+
+ //msg_Dbg( p_demux, "ASF: marker=%d size=%d : %c=%d id=%d",
+ // b_marker, i_size, b_length ? 'L' : 'O', i_length_offset );
+ unsigned i_header_size = 4;
+ if( b_relative_ts )
+ i_header_size += 4;
+ if( b_duration )
+ i_header_size += 4;
+ if( b_location_id )
+ i_header_size += 4;
+
+ if( i_header_size > i_size )
+ {
+ msg_Warn( p_demux, "Invalid header size" );
+ break;
+ }
+
+ /* XXX
+ * When b_length is true, the streams I found do not seems to respect
+ * the documentation.
+ * From them, I have failed to find which choice between '__MIN()' or
+ * 'i_length_offset - i_header_size' is the right one.
+ */
+ unsigned i_payload;
+ if( b_length )
+ i_payload = __MIN( i_length_offset, i_size - i_header_size);
+ else
+ i_payload = i_size - i_header_size;
+
+ if( !tk->p_asf_block )
+ {
+ tk->p_asf_block = block_New( p_demux, i_packet_size );
+ if( !tk->p_asf_block )
+ break;
+ tk->p_asf_block->i_buffer = 0;
+ }
+ unsigned i_offset = b_length ? 0 : i_length_offset;
+ if( i_offset == tk->p_asf_block->i_buffer && i_offset + i_payload <= i_packet_size )
+ {
+ memcpy( &tk->p_asf_block->p_buffer[i_offset], &p_data[i_header_size], i_payload );
+ tk->p_asf_block->i_buffer += i_payload;
+ if( b_marker )
+ {
+ /* We have a complete packet */
+ tk->p_asf_block->i_buffer = i_packet_size;
+ block_ChainAppend( &p_list, tk->p_asf_block );
+ tk->p_asf_block = NULL;
+ }
+ }
+ else
+ {
+ /* Reset on broken stream */
+ msg_Err( p_demux, "Broken packet detected (%d vs %zu or %d + %d vs %d)",
+ i_offset, tk->p_asf_block->i_buffer, i_offset, i_payload, i_packet_size);
+ tk->p_asf_block->i_buffer = 0;
+ }
+
+ /* */
+ p_data += i_header_size + i_payload;
+ i_size -= i_header_size + i_payload;
+ }
+ return p_list;
+}
+
/*****************************************************************************
*
*****************************************************************************/
atomLength <= INT_MAX )
{
tk->fmt.i_extra = atomLength-8;
- tk->fmt.p_extra = malloc( tk->fmt.i_extra );
+ tk->fmt.p_extra = xmalloc( tk->fmt.i_extra );
memcpy(tk->fmt.p_extra, pos+8, atomLength-8);
break;
}
else
{
tk->fmt.i_extra = qtState.sdAtomSize - 16;
- tk->fmt.p_extra = malloc( tk->fmt.i_extra );
+ tk->fmt.p_extra = xmalloc( tk->fmt.i_extra );
memcpy( tk->fmt.p_extra, &sdAtom[12], tk->fmt.i_extra );
}
}
}
else if( tk->b_asf )
{
- int i_copy = __MIN( p_sys->asfh.i_min_data_packet_size, (int)i_size );
- p_block = block_New( p_demux, p_sys->asfh.i_min_data_packet_size );
-
- memcpy( p_block->p_buffer, tk->p_buffer, i_copy );
+ p_block = StreamParseAsf( p_demux, tk,
+ tk->sub->rtpSource()->curPacketMarkerBit(),
+ tk->p_buffer, i_size );
}
else
{
p_sys->i_pcr = i_pts;
}
- if( (i_pts != tk->i_pts) && (!tk->b_muxed) )
- {
- p_block->i_pts = i_pts;
- }
-
/* Update our global npt value */
if( tk->i_npt > 0 && tk->i_npt > p_sys->i_npt && tk->i_npt < p_sys->i_npt_length)
p_sys->i_npt = tk->i_npt;
- if( !tk->b_muxed )
+ if( p_block )
{
- /*FIXME: for h264 you should check that packetization-mode=1 in sdp-file */
- p_block->i_dts = ( tk->fmt.i_codec == VLC_CODEC_MPGV ) ? 0 : i_pts;
- }
+ if( !tk->b_muxed && !tk->b_asf )
+ {
+ if( i_pts != tk->i_pts )
+ p_block->i_pts = VLC_TS_0 + i_pts;
+ /*FIXME: for h264 you should check that packetization-mode=1 in sdp-file */
+ p_block->i_dts = ( tk->fmt.i_codec == VLC_CODEC_MPGV ) ? VLC_TS_INVALID : (VLC_TS_0 + i_pts);
+ }
- if( tk->b_muxed )
- {
- stream_DemuxSend( tk->p_out_muxed, p_block );
- }
- else if( tk->b_asf )
- {
- stream_DemuxSend( p_sys->p_out_asf, p_block );
- }
- else
- {
- es_out_Send( p_demux->out, tk->p_es, p_block );
+ if( tk->b_muxed )
+ stream_DemuxSend( tk->p_out_muxed, p_block );
+ else if( tk->b_asf )
+ stream_DemuxSend( p_sys->p_out_asf, p_block );
+ else
+ es_out_Send( p_demux->out, tk->p_es, p_block );
}
/* warn that's ok */
msg_Dbg( p_demux, "StreamClose" );
p_sys->event = 0xff;
- p_demux->b_error = true;
+ p_sys->b_error = true;
}
char *psz_bye = NULL;
int canc = vlc_savecancel ();
- p_timeout->p_sys->rtsp->getMediaSessionParameter( *p_timeout->p_sys->ms, NULL, psz_bye );
+ p_timeout->p_sys->rtsp->sendGetParameterCommand( *p_timeout->p_sys->ms, NULL, psz_bye );
vlc_restorecancel (canc);
}
p_timeout->p_sys->b_timeout_call = !p_timeout->b_handle_keep_alive;