X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fstream_out%2Frtsp.c;h=0939d5e05ef3b2a2c5856c4e52f1b4ee0ce9e54e;hb=c00886df508aa4874e5e28754508022e723b9b1c;hp=7a6fa0fe90022e43a19fba86dd93f95f534e2ed2;hpb=7f761a39c29ea4bc9f6c7bac350aff777894cda4;p=vlc diff --git a/modules/stream_out/rtsp.c b/modules/stream_out/rtsp.c index 7a6fa0fe90..0939d5e05e 100644 --- a/modules/stream_out/rtsp.c +++ b/modules/stream_out/rtsp.c @@ -1,7 +1,7 @@ /***************************************************************************** * rtsp.c: RTSP support for RTP stream output module ***************************************************************************** - * Copyright (C) 2003-2004, 2010 the VideoLAN team + * Copyright (C) 2003-2004, 2010 VLC authors and VideoLAN * Copyright © 2007 Rémi Denis-Courmont * * $Id$ @@ -9,19 +9,19 @@ * Authors: Laurent Aimar * Pierre Ynard * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** @@ -43,8 +43,9 @@ #include #include #include +#include -#ifndef WIN32 +#ifndef _WIN32 # include #endif #ifdef HAVE_XLOCALE_H @@ -64,7 +65,6 @@ struct rtsp_stream_t httpd_url_t *url; char *psz_path; unsigned track_id; - unsigned port; int sessionc; rtsp_session_t **sessionv; @@ -85,11 +85,11 @@ static void RtspClientDel( rtsp_stream_t *rtsp, rtsp_session_t *session ); static void RtspTimeOut( void *data ); rtsp_stream_t *RtspSetup( vlc_object_t *owner, vod_media_t *media, - const vlc_url_t *url ) + const char *path ) { rtsp_stream_t *rtsp = malloc( sizeof( *rtsp ) ); - if( rtsp == NULL || ( url->i_port > 99999 ) ) + if( rtsp == NULL ) { free( rtsp ); return NULL; @@ -112,21 +112,22 @@ rtsp_stream_t *RtspSetup( vlc_object_t *owner, vod_media_t *media, goto error; } - rtsp->port = (url->i_port > 0) ? url->i_port : 554; - rtsp->psz_path = strdup( ( url->psz_path != NULL ) ? url->psz_path : "/" ); + rtsp->psz_path = strdup( (path != NULL) ? path : "/" ); if( rtsp->psz_path == NULL ) goto error; - msg_Dbg( owner, "RTSP stream: host %s port %d at %s", - url->psz_host, rtsp->port, rtsp->psz_path ); + msg_Dbg( owner, "RTSP stream at %s", rtsp->psz_path ); - rtsp->host = httpd_HostNew( VLC_OBJECT(owner), url->psz_host, - rtsp->port ); + rtsp->host = vlc_rtsp_HostNew( VLC_OBJECT(owner) ); if( rtsp->host == NULL ) goto error; - rtsp->url = httpd_UrlNewUnique( rtsp->host, rtsp->psz_path, - NULL, NULL, NULL ); + char *user = var_InheritString(owner, "sout-rtsp-user"); + char *pwd = var_InheritString(owner, "sout-rtsp-pwd"); + + rtsp->url = httpd_UrlNew( rtsp->host, rtsp->psz_path, user, pwd ); + free(user); + free(pwd); if( rtsp->url == NULL ) goto error; @@ -169,7 +170,7 @@ void RtspUnsetup( rtsp_stream_t *rtsp ) struct rtsp_stream_id_t { rtsp_stream_t *stream; - sout_stream_id_t *sout_id; + sout_stream_id_sys_t *sout_id; httpd_url_t *url; unsigned track_id; uint32_t ssrc; @@ -186,7 +187,6 @@ struct rtsp_session_t rtsp_stream_t *stream; uint64_t id; mtime_t last_seen; /* for timeouts */ - bool vod_started; /* true if the VoD media instance was created */ /* output (id-access) */ int trackc; @@ -198,7 +198,7 @@ struct rtsp_session_t struct rtsp_strack_t { rtsp_stream_id_t *id; - sout_stream_id_t *sout_id; + sout_stream_id_sys_t *sout_id; int setup_fd; /* socket created by the SETUP request */ int rtp_fd; /* socket used by the RTP output, when playing */ uint32_t ssrc; @@ -221,7 +221,7 @@ char *RtspAppendTrackPath( rtsp_stream_id_t *id, const char *base ) } -rtsp_stream_id_t *RtspAddId( rtsp_stream_t *rtsp, sout_stream_id_t *sid, +rtsp_stream_id_t *RtspAddId( rtsp_stream_t *rtsp, sout_stream_id_sys_t *sid, uint32_t ssrc, unsigned clock_rate, int mcast_fd) { @@ -253,7 +253,13 @@ rtsp_stream_id_t *RtspAddId( rtsp_stream_t *rtsp, sout_stream_id_t *sid, } msg_Dbg( rtsp->owner, "RTSP: adding %s", urlbuf ); - url = id->url = httpd_UrlNewUnique( rtsp->host, urlbuf, NULL, NULL, NULL ); + + char *user = var_InheritString(rtsp->owner, "sout-rtsp-user"); + char *pwd = var_InheritString(rtsp->owner, "sout-rtsp-pwd"); + + url = id->url = httpd_UrlNew( rtsp->host, urlbuf, user, pwd ); + free( user ); + free( pwd ); free( urlbuf ); if( url == NULL ) @@ -353,7 +359,6 @@ rtsp_session_t *RtspClientNew( rtsp_stream_t *rtsp ) s->stream = rtsp; vlc_rand_bytes (&s->id, sizeof (s->id)); - s->vod_started = false; s->trackc = 0; s->trackv = NULL; @@ -417,7 +422,7 @@ static void RtspClientAlive( rtsp_session_t *session ) static int dup_socket(int oldfd) { int newfd; -#if !defined(WIN32) || defined(UNDER_CE) +#ifndef _WIN32 newfd = vlc_dup(oldfd); #else WSAPROTOCOL_INFO info; @@ -431,7 +436,7 @@ static int dup_socket(int oldfd) /* Attach a starting VoD RTP id to its RTSP track, and let it * initialize with the parameters of the SETUP request */ int RtspTrackAttach( rtsp_stream_t *rtsp, const char *name, - rtsp_stream_id_t *id, sout_stream_id_t *sout_id, + rtsp_stream_id_t *id, sout_stream_id_sys_t *sout_id, uint32_t *ssrc, uint16_t *seq_init ) { int val = VLC_EGENERIC; @@ -444,7 +449,7 @@ int RtspTrackAttach( rtsp_stream_t *rtsp, const char *name, goto out; rtsp_strack_t *tr = NULL; - for (int i = 0; session->trackc; i++) + for (int i = 0; i < session->trackc; i++) { if (session->trackv[i].id == id) { @@ -468,6 +473,7 @@ int RtspTrackAttach( rtsp_stream_t *rtsp, const char *name, vlc_rand_bytes (&track.ssrc, sizeof (track.ssrc)); INSERT_ELEM(session->trackv, session->trackc, session->trackc, track); + tr = session->trackv + session->trackc - 1; } *ssrc = ntohl(tr->ssrc); @@ -492,7 +498,7 @@ out: /* Remove references to the RTP id when it is stopped */ void RtspTrackDetach( rtsp_stream_t *rtsp, const char *name, - sout_stream_id_t *sout_id ) + sout_stream_id_sys_t *sout_id ) { rtsp_session_t *session; @@ -502,7 +508,7 @@ void RtspTrackDetach( rtsp_stream_t *rtsp, const char *name, if (session == NULL) goto out; - for (int i = 0; session->trackc; i++) + for (int i = 0; i < session->trackc; i++) { rtsp_strack_t *tr = session->trackv + i; if (tr->sout_id == sout_id) @@ -584,14 +590,14 @@ static int64_t ParseNPT (const char *str) sec += ((hour * 60) + min) * 60; else if (sscanf (str, "%f", &sec) != 1) - sec = 0.; + sec = -1; if (loc != (locale_t)0) { uselocale (oldloc); freelocale (loc); } - return sec * CLOCK_FREQ; + return sec < 0 ? -1 : sec * CLOCK_FREQ; } @@ -620,18 +626,17 @@ static int RtspHandler( rtsp_stream_t *rtsp, rtsp_stream_id_t *id, { /* Build self-referential control URL */ char ip[NI_MAXNUMERICHOST], *ptr; + int port; - httpd_ServerIP( cl, ip ); + httpd_ServerIP( cl, ip, &port ); ptr = strchr( ip, '%' ); if( ptr != NULL ) *ptr = '\0'; if( strchr( ip, ':' ) != NULL ) - sprintf( control, "rtsp://[%s]:%u%s", ip, rtsp->port, - rtsp->psz_path ); + sprintf( control, "rtsp://[%s]:%d%s", ip, port, rtsp->psz_path ); else - sprintf( control, "rtsp://%s:%u%s", ip, rtsp->port, - rtsp->psz_path ); + sprintf( control, "rtsp://%s:%d%s", ip, port, rtsp->psz_path ); } /* */ @@ -812,7 +817,7 @@ static int RtspHandler( rtsp_stream_t *rtsp, rtsp_stream_id_t *id, int fd, sport; uint32_t ssrc; - if( httpd_ClientIP( cl, ip ) == NULL ) + if( httpd_ClientIP( cl, ip, NULL ) == NULL ) { answer->i_status = 500; continue; @@ -905,31 +910,24 @@ static int RtspHandler( rtsp_stream_t *rtsp, rtsp_stream_id_t *id, } vlc_mutex_unlock( &rtsp->lock ); - httpd_ServerIP( cl, ip ); + httpd_ServerIP( cl, ip, NULL ); + /* Specify source IP only if it is different from the + * RTSP control connection server address */ if( strcmp( src, ip ) ) { - /* Specify source IP if it is different from the RTSP - * control connection server address */ char *ptr = strchr( src, '%' ); if( ptr != NULL ) *ptr = '\0'; /* remove scope ID */ - - httpd_MsgAdd( answer, "Transport", - "RTP/AVP/UDP;unicast;source=%s;" - "client_port=%u-%u;server_port=%u-%u;" - "ssrc=%08X;mode=play", - src, loport, loport + 1, sport, - sport + 1, ssrc ); } else - { - httpd_MsgAdd( answer, "Transport", - "RTP/AVP/UDP;unicast;" - "client_port=%u-%u;server_port=%u-%u;" - "ssrc=%08X;mode=play", - loport, loport + 1, sport, sport + 1, - ssrc ); - } + src[0] = '\0'; + + httpd_MsgAdd( answer, "Transport", + "RTP/AVP/UDP;unicast%s%s;" + "client_port=%u-%u;server_port=%u-%u;" + "ssrc=%08X;mode=play", + src[0] ? ";source=" : "", src, + loport, loport + 1, sport, sport + 1, ssrc ); answer->i_status = 200; } @@ -943,13 +941,44 @@ static int RtspHandler( rtsp_stream_t *rtsp, rtsp_stream_id_t *id, answer->i_status = 200; psz_session = httpd_MsgGet( query, "Session" ); + int64_t start = -1, end = -1, npt; const char *range = httpd_MsgGet (query, "Range"); - if (range != NULL && strncmp (range, "npt=", 4)) + if (range != NULL) { - answer->i_status = 501; - break; - } + if (strncmp (range, "npt=", 4)) + { + answer->i_status = 501; + break; + } + start = ParseNPT (range + 4); + range = strchr(range, '-'); + if (range != NULL && *(range + 1)) + end = ParseNPT (range + 1); + + if (end >= 0 && end < start) + { + answer->i_status = 457; + break; + } + + if (vod) + { + if (vod_check_range(rtsp->vod_media, psz_session, + start, end) != VLC_SUCCESS) + { + answer->i_status = 457; + break; + } + } + /* We accept start times of 0 even for broadcast streams + * that already started */ + else if (start > 0 || end >= 0) + { + answer->i_status = 456; + break; + } + } vlc_mutex_lock( &rtsp->lock ); ses = RtspClientGet( rtsp, psz_session ); if( ses != NULL ) @@ -960,7 +989,7 @@ static int RtspHandler( rtsp_stream_t *rtsp, rtsp_stream_id_t *id, size_t infolen = 0; RtspClientAlive(ses); - sout_stream_id_t *sout_id = NULL; + sout_stream_id_sys_t *sout_id = NULL; if (vod) { /* We don't keep a reference to the sout_stream_t, @@ -973,7 +1002,8 @@ static int RtspHandler( rtsp_stream_t *rtsp, rtsp_stream_id_t *id, } } int64_t ts = rtp_get_ts(vod ? NULL : (sout_stream_t *)owner, - sout_id, rtsp->vod_media, psz_session); + sout_id, rtsp->vod_media, psz_session, + vod ? NULL : &npt); for( int i = 0; i < ses->trackc; i++ ) { @@ -1021,27 +1051,20 @@ static int RtspHandler( rtsp_stream_t *rtsp, rtsp_stream_id_t *id, info[infolen - 2] = '\0'; /* remove trailing ", " */ httpd_MsgAdd( answer, "RTP-Info", "%s", info ); } + } + vlc_mutex_unlock( &rtsp->lock ); + + if (ses != NULL) + { if (vod) { - /* TODO: fix that crap, this is barely RTSP */ - if (!ses->vod_started) - { - vod_start(rtsp->vod_media, psz_session); - ses->vod_started = true; - } - else - { - if (range != NULL) - { - int64_t time = ParseNPT (range + 4); - vod_seek(rtsp->vod_media, psz_session, time); - } - /* This is the thing to do to unpause... */ - vod_start(rtsp->vod_media, psz_session); - } + vod_play(rtsp->vod_media, psz_session, &start, end); + npt = start; } + + double f_npt = (double) npt / CLOCK_FREQ; + httpd_MsgAdd( answer, "Range", "npt=%f-", f_npt ); } - vlc_mutex_unlock( &rtsp->lock ); if( httpd_MsgGet( query, "Scale" ) != NULL ) httpd_MsgAdd( answer, "Scale", "1." ); @@ -1054,8 +1077,7 @@ static int RtspHandler( rtsp_stream_t *rtsp, rtsp_stream_id_t *id, { answer->i_status = 405; httpd_MsgAdd( answer, "Allow", - "%s, TEARDOWN, PLAY, GET_PARAMETER", - ( id != NULL ) ? "SETUP" : "DESCRIBE" ); + "DESCRIBE, TEARDOWN, PLAY, GET_PARAMETER" ); break; } @@ -1066,12 +1088,7 @@ static int RtspHandler( rtsp_stream_t *rtsp, rtsp_stream_id_t *id, ses = RtspClientGet( rtsp, psz_session ); if (ses != NULL) { - if (id == NULL) - { - if (vod) - vod_pause(rtsp->vod_media, psz_session); - } - else /* "Mute" the selected track */ + if (id != NULL) /* "Mute" the selected track */ { bool found = false; for (int i = 0; i < ses->trackc; i++) @@ -1097,6 +1114,15 @@ static int RtspHandler( rtsp_stream_t *rtsp, rtsp_stream_id_t *id, RtspClientAlive(ses); } vlc_mutex_unlock( &rtsp->lock ); + + if (ses != NULL && id == NULL) + { + assert(vod); + int64_t npt = 0; + vod_pause(rtsp->vod_media, psz_session, &npt); + double f_npt = (double) npt / CLOCK_FREQ; + httpd_MsgAdd( answer, "Range", "npt=%f-", f_npt ); + } break; }