Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

rtp.c

00001 /*****************************************************************************
00002  * rtp.c: rtp stream output module
00003  *****************************************************************************
00004  * Copyright (C) 2003-2004 the VideoLAN team
00005  * $Id: rtp.c 12985 2005-10-27 13:39:50Z md $
00006  *
00007  * Authors: Laurent Aimar <[email protected]>
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00022  *****************************************************************************/
00023 
00024 /*****************************************************************************
00025  * Preamble
00026  *****************************************************************************/
00027 #include <stdlib.h>
00028 
00029 #include <errno.h>
00030 
00031 #include <vlc/vlc.h>
00032 #include <vlc/input.h>
00033 #include <vlc/sout.h>
00034 
00035 #include "vlc_httpd.h"
00036 #include "network.h"
00037 
00038 /*****************************************************************************
00039  * Module descriptor
00040  *****************************************************************************/
00041 
00042 #define MTU_REDUCE 50
00043 
00044 #define DST_TEXT N_("Destination")
00045 #define DST_LONGTEXT N_( \
00046     "Allows you to specify the output URL used for the streaming output." )
00047 #define SDP_TEXT N_("SDP")
00048 #define SDP_LONGTEXT N_( \
00049     "Allows you to specify the SDP used for the streaming output. " \
00050     "You must use an url: http://location to access the SDP via HTTP, " \
00051     "rtsp://location for RTSP access, and sap:// for the SDP to be " \
00052     "announced via SAP." )
00053 #define MUX_TEXT N_("Muxer")
00054 #define MUX_LONGTEXT N_( \
00055     "Allows you to specify the muxer used for the streaming output." )
00056 
00057 #define NAME_TEXT N_("Session name")
00058 #define NAME_LONGTEXT N_( \
00059     "Allows you to specify the session name used for the streaming output." )
00060 #define DESC_TEXT N_("Session description")
00061 #define DESC_LONGTEXT N_( \
00062     "Allows you to give a broader description of the stream." )
00063 #define URL_TEXT N_("Session URL")
00064 #define URL_LONGTEXT N_( \
00065     "Allows you to specify a URL with additional information on the stream." )
00066 #define EMAIL_TEXT N_("Session email")
00067 #define EMAIL_LONGTEXT N_( \
00068     "Allows you to specify contact e-mail address for this session." )
00069 
00070 #define PORT_TEXT N_("Port")
00071 #define PORT_LONGTEXT N_( \
00072     "Allows you to specify the base port used for the RTP streaming." )
00073 #define PORT_AUDIO_TEXT N_("Audio port")
00074 #define PORT_AUDIO_LONGTEXT N_( \
00075     "Allows you to specify the default audio port used for the RTP streaming." )
00076 #define PORT_VIDEO_TEXT N_("Video port")
00077 #define PORT_VIDEO_LONGTEXT N_( \
00078     "Allows you to specify the default video port used for the RTP streaming." )
00079 
00080 #define TTL_TEXT N_("Time To Live")
00081 #define TTL_LONGTEXT N_( \
00082     "Allows you to specify the time to live for the output stream." )
00083 
00084 static int  Open ( vlc_object_t * );
00085 static void Close( vlc_object_t * );
00086 
00087 #define SOUT_CFG_PREFIX "sout-rtp-"
00088 
00089 vlc_module_begin();
00090     set_shortname( _("RTP"));
00091     set_description( _("RTP stream output") );
00092     set_capability( "sout stream", 0 );
00093     add_shortcut( "rtp" );
00094     set_category( CAT_SOUT );
00095     set_subcategory( SUBCAT_SOUT_STREAM );
00096 
00097     add_string( SOUT_CFG_PREFIX "dst", "", NULL, DST_TEXT,
00098                 DST_LONGTEXT, VLC_TRUE );
00099     add_string( SOUT_CFG_PREFIX "sdp", "", NULL, SDP_TEXT,
00100                 SDP_LONGTEXT, VLC_TRUE );
00101     add_string( SOUT_CFG_PREFIX "mux", "", NULL, MUX_TEXT,
00102                 MUX_LONGTEXT, VLC_TRUE );
00103 
00104     add_string( SOUT_CFG_PREFIX "name", "NONE", NULL, NAME_TEXT,
00105                 NAME_LONGTEXT, VLC_TRUE );
00106     add_string( SOUT_CFG_PREFIX "description", "", NULL, DESC_TEXT,
00107                 DESC_LONGTEXT, VLC_TRUE );
00108     add_string( SOUT_CFG_PREFIX "url", "", NULL, URL_TEXT,
00109                 URL_LONGTEXT, VLC_TRUE );
00110     add_string( SOUT_CFG_PREFIX "email", "", NULL, EMAIL_TEXT,
00111                 EMAIL_LONGTEXT, VLC_TRUE );
00112 
00113     add_integer( SOUT_CFG_PREFIX "port", 1234, NULL, PORT_TEXT,
00114                  PORT_LONGTEXT, VLC_TRUE );
00115     add_integer( SOUT_CFG_PREFIX "port-audio", 1230, NULL, PORT_AUDIO_TEXT,
00116                  PORT_AUDIO_LONGTEXT, VLC_TRUE );
00117     add_integer( SOUT_CFG_PREFIX "port-video", 1232, NULL, PORT_VIDEO_TEXT,
00118                  PORT_VIDEO_LONGTEXT, VLC_TRUE );
00119 
00120     add_integer( SOUT_CFG_PREFIX "ttl", 0, NULL, TTL_TEXT,
00121                  TTL_LONGTEXT, VLC_TRUE );
00122 
00123     set_callbacks( Open, Close );
00124 vlc_module_end();
00125 
00126 /*****************************************************************************
00127  * Exported prototypes
00128  *****************************************************************************/
00129 static const char *ppsz_sout_options[] = {
00130     "dst", "name", "port", "port-audio", "port-video", "*sdp", "ttl", "mux",
00131     "description", "url","email", NULL
00132 };
00133 
00134 static sout_stream_id_t *Add ( sout_stream_t *, es_format_t * );
00135 static int               Del ( sout_stream_t *, sout_stream_id_t * );
00136 static int               Send( sout_stream_t *, sout_stream_id_t *,
00137                                block_t* );
00138 
00139 /* For unicast/interleaved streaming */
00140 typedef struct
00141 {
00142     char    *psz_session;
00143     int64_t i_last; /* for timeout */
00144 
00145     /* is it in "play" state */
00146     vlc_bool_t b_playing;
00147 
00148     /* output (id-access) */
00149     int               i_id;
00150     sout_stream_id_t  **id;
00151     int               i_access;
00152     sout_access_out_t **access;
00153 } rtsp_client_t;
00154 
00155 struct sout_stream_sys_t
00156 {
00157     /* sdp */
00158     int64_t i_sdp_id;
00159     int     i_sdp_version;
00160     char    *psz_sdp;
00161     vlc_mutex_t  lock_sdp;
00162 
00163     char        *psz_session_name;
00164     char        *psz_session_description;
00165     char        *psz_session_url;
00166     char        *psz_session_email;
00167 
00168     /* */
00169     vlc_bool_t b_export_sdp_file;
00170     char *psz_sdp_file;
00171     /* sap */
00172     vlc_bool_t b_export_sap;
00173     session_descriptor_t *p_session;
00174 
00175     httpd_host_t *p_httpd_host;
00176     httpd_file_t *p_httpd_file;
00177 
00178     httpd_host_t *p_rtsp_host;
00179     httpd_url_t  *p_rtsp_url;
00180     char         *psz_rtsp_control;
00181     char         *psz_rtsp_path;
00182 
00183     /* */
00184     char *psz_destination;
00185     int  i_port;
00186     int  i_port_audio;
00187     int  i_port_video;
00188     int  i_ttl;
00189 
00190     /* when need to use a private one or when using muxer */
00191     int i_payload_type;
00192 
00193     /* in case we do TS/PS over rtp */
00194     sout_mux_t        *p_mux;
00195     sout_access_out_t *p_access;
00196     int               i_mtu;
00197     sout_access_out_t *p_grab;
00198     uint16_t          i_sequence;
00199     uint32_t          i_timestamp_start;
00200     uint8_t           ssrc[4];
00201     block_t           *packet;
00202 
00203     /* */
00204     vlc_mutex_t      lock_es;
00205     int              i_es;
00206     sout_stream_id_t **es;
00207 
00208     /* */
00209     int              i_rtsp;
00210     rtsp_client_t    **rtsp;
00211 };
00212 
00213 typedef int (*pf_rtp_packetizer_t)( sout_stream_t *, sout_stream_id_t *,
00214                                     block_t * );
00215 
00216 struct sout_stream_id_t
00217 {
00218     sout_stream_t *p_stream;
00219     /* rtp field */
00220     uint8_t     i_payload_type;
00221     uint16_t    i_sequence;
00222     uint32_t    i_timestamp_start;
00223     uint8_t     ssrc[4];
00224 
00225     /* for sdp */
00226     int         i_clock_rate;
00227     char        *psz_rtpmap;
00228     char        *psz_fmtp;
00229     char        *psz_destination;
00230     int         i_port;
00231     int         i_cat;
00232 
00233     /* Packetizer specific fields */
00234     pf_rtp_packetizer_t pf_packetize;
00235     int           i_mtu;
00236 
00237     /* for sending the packets */
00238     sout_access_out_t *p_access;
00239 
00240     vlc_mutex_t       lock_rtsp;
00241     int               i_rtsp_access;
00242     sout_access_out_t **rtsp_access;
00243 
00244     /* */
00245     sout_input_t      *p_input;
00246 
00247     /* RTSP url control */
00248     httpd_url_t  *p_rtsp_url;
00249 };
00250 
00251 static int AccessOutGrabberWrite( sout_access_out_t *, block_t * );
00252 
00253 static void SDPHandleUrl( sout_stream_t *, char * );
00254 
00255 static int SapSetup( sout_stream_t *p_stream );
00256 static int FileSetup( sout_stream_t *p_stream );
00257 static int HttpSetup( sout_stream_t *p_stream, vlc_url_t * );
00258 static int RtspSetup( sout_stream_t *p_stream, vlc_url_t * );
00259 
00260 static int  RtspCallback( httpd_callback_sys_t *, httpd_client_t *,
00261                           httpd_message_t *, httpd_message_t * );
00262 static int  RtspCallbackId( httpd_callback_sys_t *, httpd_client_t *,
00263                             httpd_message_t *, httpd_message_t * );
00264 
00265 
00266 static rtsp_client_t *RtspClientNew( sout_stream_t *, char *psz_session );
00267 static rtsp_client_t *RtspClientGet( sout_stream_t *, char *psz_session );
00268 static void           RtspClientDel( sout_stream_t *, rtsp_client_t * );
00269 
00270 /*****************************************************************************
00271  * Open:
00272  *****************************************************************************/
00273 static int Open( vlc_object_t *p_this )
00274 {
00275     sout_stream_t       *p_stream = (sout_stream_t*)p_this;
00276     sout_instance_t     *p_sout = p_stream->p_sout;
00277     sout_stream_sys_t   *p_sys;
00278     vlc_value_t         val;
00279 
00280     sout_CfgParse( p_stream, SOUT_CFG_PREFIX, ppsz_sout_options, p_stream->p_cfg );
00281 
00282     p_sys = malloc( sizeof( sout_stream_sys_t ) );
00283 
00284     p_sys->psz_destination = var_GetString( p_stream, SOUT_CFG_PREFIX "dst" );
00285     if( *p_sys->psz_destination == '\0' )
00286     {
00287         free( p_sys->psz_destination );
00288         p_sys->psz_destination = NULL;
00289     }
00290 
00291     p_sys->psz_session_name = var_GetString( p_stream, SOUT_CFG_PREFIX "name" );
00292     p_sys->psz_session_description = var_GetString( p_stream, SOUT_CFG_PREFIX "description" );
00293     p_sys->psz_session_url = var_GetString( p_stream, SOUT_CFG_PREFIX "url" );
00294     p_sys->psz_session_email = var_GetString( p_stream, SOUT_CFG_PREFIX "email" );
00295 
00296     p_sys->i_port       = var_GetInteger( p_stream, SOUT_CFG_PREFIX "port" );
00297     p_sys->i_port_audio = var_GetInteger( p_stream, SOUT_CFG_PREFIX "port-audio" );
00298     p_sys->i_port_video = var_GetInteger( p_stream, SOUT_CFG_PREFIX "port-video" );
00299 
00300     p_sys->psz_sdp_file = NULL;
00301 
00302     if( p_sys->i_port_audio == p_sys->i_port_video )
00303     {
00304         msg_Err( p_stream, "audio and video port cannot be the same" );
00305         p_sys->i_port_audio = 0;
00306         p_sys->i_port_video = 0;
00307     }
00308 
00309     if( !p_sys->psz_session_name )
00310     {
00311         if( p_sys->psz_destination )
00312             p_sys->psz_session_name = strdup( p_sys->psz_destination );
00313         else
00314            p_sys->psz_session_name = strdup( "NONE" );
00315     }
00316 
00317     if( !p_sys->psz_destination || *p_sys->psz_destination == '\0' )
00318     {
00319         sout_cfg_t *p_cfg;
00320         vlc_bool_t b_ok = VLC_FALSE;
00321 
00322         for( p_cfg = p_stream->p_cfg; p_cfg != NULL; p_cfg = p_cfg->p_next )
00323         {
00324             if( !strcmp( p_cfg->psz_name, "sdp" ) )
00325             {
00326                 if( p_cfg->psz_value && !strncasecmp( p_cfg->psz_value, "rtsp", 4 ) )
00327                 {
00328                     b_ok = VLC_TRUE;
00329                     break;
00330                 }
00331             }
00332         }
00333         if( !b_ok )
00334         {
00335             vlc_value_t val2;
00336             var_Get( p_stream, SOUT_CFG_PREFIX "sdp", &val2 );
00337             if( !strncasecmp( val2.psz_string, "rtsp", 4 ) )
00338                 b_ok = VLC_TRUE;
00339             free( val2.psz_string );
00340         }
00341 
00342         if( !b_ok )
00343         {
00344             msg_Err( p_stream, "missing destination and not in rtsp mode" );
00345             free( p_sys );
00346             return VLC_EGENERIC;
00347         }
00348         p_sys->psz_destination = NULL;
00349     }
00350     else if( p_sys->i_port <= 0 )
00351     {
00352         msg_Err( p_stream, "invalid port" );
00353         free( p_sys );
00354         return VLC_EGENERIC;
00355     }
00356 
00357     var_Get( p_stream, SOUT_CFG_PREFIX "ttl", &val );
00358     if( ( val.i_int > 255 ) || ( val.i_int < 0 ) )
00359     {
00360         msg_Err( p_stream, "illegal TTL %d", val.i_int );
00361         free( p_sys );
00362         return VLC_EGENERIC;
00363     }
00364     p_sys->i_ttl = val.i_int;
00365 
00366     p_sys->i_payload_type = 96;
00367     p_sys->i_es = 0;
00368     p_sys->es   = NULL;
00369     p_sys->i_rtsp = 0;
00370     p_sys->rtsp   = NULL;
00371     p_sys->psz_sdp = NULL;
00372 
00373     p_sys->i_sdp_id = mdate();
00374     p_sys->i_sdp_version = 1;
00375     p_sys->psz_sdp = NULL;
00376 
00377     p_sys->b_export_sap = VLC_FALSE;
00378     p_sys->b_export_sdp_file = VLC_FALSE;
00379     p_sys->p_session = NULL;
00380 
00381     p_sys->p_httpd_host = NULL;
00382     p_sys->p_httpd_file = NULL;
00383     p_sys->p_rtsp_host  = NULL;
00384     p_sys->p_rtsp_url   = NULL;
00385     p_sys->psz_rtsp_control = NULL;
00386     p_sys->psz_rtsp_path = NULL;
00387 
00388     vlc_mutex_init( p_stream, &p_sys->lock_sdp );
00389     vlc_mutex_init( p_stream, &p_sys->lock_es );
00390 
00391     p_stream->pf_add    = Add;
00392     p_stream->pf_del    = Del;
00393     p_stream->pf_send   = Send;
00394 
00395     p_stream->p_sys     = p_sys;
00396 
00397     var_Get( p_stream, SOUT_CFG_PREFIX "mux", &val );
00398     if( *val.psz_string )
00399     {
00400         sout_access_out_t *p_grab;
00401         char *psz_rtpmap, url[NI_MAXHOST + 8], access[17], psz_ttl[5], ipv;
00402 
00403         if( !p_sys->psz_destination || *p_sys->psz_destination == '\0' )
00404         {
00405             msg_Err( p_stream, "rtp needs a destination when muxing" );
00406             free( p_sys );
00407             return VLC_EGENERIC;
00408         }
00409 
00410         /* Check muxer type */
00411         if( !strncasecmp( val.psz_string, "ps", 2 ) || !strncasecmp( val.psz_string, "mpeg1", 5 ) )
00412         {
00413             psz_rtpmap = "MP2P/90000";
00414         }
00415         else if( !strncasecmp( val.psz_string, "ts", 2 ) )
00416         {
00417             psz_rtpmap = "MP2T/90000";
00418             p_sys->i_payload_type = 33;
00419         }
00420         else
00421         {
00422             msg_Err( p_stream, "unsupported muxer type with rtp (only ts/ps)" );
00423             free( p_sys );
00424             return VLC_EGENERIC;
00425         }
00426 
00427         /* create the access out */
00428         if( p_sys->i_ttl > 0 )
00429         {
00430             sprintf( access, "udp{raw,ttl=%d}", p_sys->i_ttl );
00431         }
00432         else
00433         {
00434             sprintf( access, "udp{raw}" );
00435         }
00436 
00437         /* IPv6 needs brackets if not already present */
00438         snprintf( url, sizeof( url ),
00439                   ( ( p_sys->psz_destination[0] != '[' ) 
00440                  && ( strchr( p_sys->psz_destination, ':' ) != NULL ) )
00441                   ? "[%s]:%d" : "%s:%d", p_sys->psz_destination,
00442                   p_sys->i_port );
00443         url[sizeof( url ) - 1] = '\0';
00444         /* FIXME: we should check that url is a numerical address, otherwise
00445          * the SDP will be quite broken (regardless of the IP protocol version)
00446          */
00447         ipv = ( strchr( p_sys->psz_destination, ':' ) != NULL ) ? '6' : '4';
00448 
00449         if( !( p_sys->p_access = sout_AccessOutNew( p_sout, access, url ) ) )
00450         {
00451             msg_Err( p_stream, "cannot create the access out for %s://%s",
00452                      access, url );
00453             free( p_sys );
00454             return VLC_EGENERIC;
00455         }
00456         p_sys->i_mtu = config_GetInt( p_stream, "mtu" );  /* XXX beurk */
00457         if( p_sys->i_mtu <= 16 + MTU_REDUCE )
00458         {
00459             /* better than nothing */
00460             p_sys->i_mtu = 1500;
00461         }
00462         p_sys->i_mtu -= MTU_REDUCE;
00463 
00464         /* the access out grabber TODO export it as sout_AccessOutGrabberNew */
00465         p_grab = p_sys->p_grab =
00466             vlc_object_create( p_sout, sizeof( sout_access_out_t ) );
00467         p_grab->p_module    = NULL;
00468         p_grab->p_sout      = p_sout;
00469         p_grab->psz_access  = strdup( "grab" );
00470         p_grab->p_cfg       = NULL;
00471         p_grab->psz_name    = strdup( "" );
00472         p_grab->p_sys       = (sout_access_out_sys_t*)p_stream;
00473         p_grab->pf_seek     = NULL;
00474         p_grab->pf_write    = AccessOutGrabberWrite;
00475 
00476         /* the muxer */
00477         if( !( p_sys->p_mux = sout_MuxNew( p_sout, val.psz_string, p_sys->p_grab ) ) )
00478         {
00479             msg_Err( p_stream, "cannot create the muxer (%s)", val.psz_string );
00480             sout_AccessOutDelete( p_sys->p_grab );
00481             sout_AccessOutDelete( p_sys->p_access );
00482             free( p_sys );
00483             return VLC_EGENERIC;
00484         }
00485 
00486         /* create the SDP for a muxed stream (only once) */
00487         /* FIXME  http://www.faqs.org/rfcs/rfc2327.html
00488            All text fields should be UTF-8 encoded. Use global a:charset to announce this.
00489            o= - should be local username (no spaces allowed)
00490            o= time should be hashed with some other value to garantue uniqueness
00491            o= we need IP6 support?
00492            o= don't use the localhost address. use fully qualified domain name or IP4 address
00493            p= international phone number (pass via vars?)
00494            c= IP6 support
00495            a= recvonly (missing)
00496            a= type:broadcast (missing)
00497            a= charset: (normally charset should be UTF-8, this can be used to override s= and i=)
00498            a= x-plgroup: (missing)
00499            RTP packets need to get the correct src IP address  */
00500         if( net_AddressIsMulticast( (vlc_object_t *)p_stream, p_sys->psz_destination ) )
00501         {
00502             snprintf( psz_ttl, sizeof( psz_ttl ), "/%d", p_sys->i_ttl ? 
00503                 p_sys->i_ttl : config_GetInt( p_sout, "ttl" ) );
00504             psz_ttl[sizeof( psz_ttl ) - 1] = '\0';
00505         }
00506         else
00507         {
00508             psz_ttl[0] = '\0'; 
00509         }
00510 
00511         asprintf( &p_sys->psz_sdp,
00512                   "v=0\r\n"
00513                   /* FIXME: source address not known :( */
00514                   "o=- "I64Fd" %d IN IP%c %s\r\n"
00515                   "s=%s\r\n"
00516                   "i=%s\r\n"
00517                   "u=%s\r\n"
00518                   "e=%s\r\n"
00519                   "t=0 0\r\n" /* permanent stream */ /* when scheduled from vlm, we should set this info correctly */
00520                   "a=tool:"PACKAGE_STRING"\r\n"
00521                   "c=IN IP%c %s%s\r\n"
00522                   "m=video %d RTP/AVP %d\r\n"
00523                   "a=rtpmap:%d %s\r\n",
00524                   p_sys->i_sdp_id, p_sys->i_sdp_version,
00525                   ipv, ipv == '6' ? "::1" : "127.0.0.1" /* FIXME */,
00526                   p_sys->psz_session_name,
00527                   p_sys->psz_session_description,
00528                   p_sys->psz_session_url,
00529                   p_sys->psz_session_email,
00530                   ipv, p_sys->psz_destination, psz_ttl,
00531                   p_sys->i_port, p_sys->i_payload_type,
00532                   p_sys->i_payload_type, psz_rtpmap );
00533         fprintf( stderr, "sdp=%s", p_sys->psz_sdp );
00534 
00535         /* create the rtp context */
00536         p_sys->ssrc[0] = rand()&0xff;
00537         p_sys->ssrc[1] = rand()&0xff;
00538         p_sys->ssrc[2] = rand()&0xff;
00539         p_sys->ssrc[3] = rand()&0xff;
00540         p_sys->i_sequence = rand()&0xffff;
00541         p_sys->i_timestamp_start = rand()&0xffffffff;
00542         p_sys->packet = NULL;
00543     }
00544     else
00545     {
00546         p_sys->p_mux    = NULL;
00547         p_sys->p_access = NULL;
00548         p_sys->p_grab   = NULL;
00549     }
00550     free( val.psz_string );
00551 
00552 
00553     var_Get( p_stream, SOUT_CFG_PREFIX "sdp", &val );
00554     if( *val.psz_string )
00555     {
00556         sout_cfg_t *p_cfg;
00557 
00558         SDPHandleUrl( p_stream, val.psz_string );
00559 
00560         for( p_cfg = p_stream->p_cfg; p_cfg != NULL; p_cfg = p_cfg->p_next )
00561         {
00562             if( !strcmp( p_cfg->psz_name, "sdp" ) )
00563             {
00564                 if( p_cfg->psz_value == NULL || *p_cfg->psz_value == '\0' )
00565                     continue;
00566 
00567                 if( !strcmp( p_cfg->psz_value, val.psz_string ) )   /* needed both :sout-rtp-sdp= and rtp{sdp=} can be used */
00568                     continue;
00569 
00570                 SDPHandleUrl( p_stream, p_cfg->psz_value );
00571             }
00572         }
00573     }
00574     free( val.psz_string );
00575 
00576     /* update p_sout->i_out_pace_nocontrol */
00577     p_stream->p_sout->i_out_pace_nocontrol++;
00578 
00579     return VLC_SUCCESS;
00580 }
00581 
00582 /*****************************************************************************
00583  * Close:
00584  *****************************************************************************/
00585 static void Close( vlc_object_t * p_this )
00586 {
00587     sout_stream_t     *p_stream = (sout_stream_t*)p_this;
00588     sout_stream_sys_t *p_sys = p_stream->p_sys;
00589 
00590     /* update p_sout->i_out_pace_nocontrol */
00591     p_stream->p_sout->i_out_pace_nocontrol--;
00592 
00593     if( p_sys->p_mux )
00594     {
00595         sout_MuxDelete( p_sys->p_mux );
00596         sout_AccessOutDelete( p_sys->p_access );
00597         sout_AccessOutDelete( p_sys->p_grab );
00598         if( p_sys->packet )
00599         {
00600             block_Release( p_sys->packet );
00601         }
00602         if( p_sys->b_export_sap )
00603         {   
00604             p_sys->p_mux = NULL;
00605             SapSetup( p_stream );
00606         }
00607     }
00608 
00609     while( p_sys->i_rtsp > 0 )
00610     {
00611         RtspClientDel( p_stream, p_sys->rtsp[0] );
00612     }
00613 
00614     vlc_mutex_destroy( &p_sys->lock_sdp );
00615 
00616     if( p_sys->p_httpd_file )
00617     {
00618         httpd_FileDelete( p_sys->p_httpd_file );
00619     }
00620     if( p_sys->p_httpd_host )
00621     {
00622         httpd_HostDelete( p_sys->p_httpd_host );
00623     }
00624     if( p_sys->p_rtsp_url )
00625     {
00626         httpd_UrlDelete( p_sys->p_rtsp_url );
00627     }
00628     if( p_sys->p_rtsp_host )
00629     {
00630         httpd_HostDelete( p_sys->p_rtsp_host );
00631     }
00632 #if 0
00633     /* why? is this disabled? */
00634     if( p_sys->psz_session_name )
00635     {
00636         free( p_sys->psz_session_name );
00637         p_sys->psz_session_name = NULL;
00638     }
00639     if( p_sys->psz_session_description )
00640     {
00641         free( p_sys->psz_session_description );
00642         p_sys->psz_session_description = NULL;
00643     }
00644     if( p_sys->psz_session_url )
00645     {
00646         free( p_sys->psz_session_url );
00647         p_sys->psz_session_url = NULL;
00648     }
00649     if( p_sys->psz_session_email )
00650     {
00651         free( p_sys->psz_session_email );
00652         p_sys->psz_session_email = NULL;
00653     }
00654 #endif
00655     if( p_sys->psz_sdp )
00656     {
00657         free( p_sys->psz_sdp );
00658     }
00659     free( p_sys );
00660 }
00661 
00662 /*****************************************************************************
00663  * SDPHandleUrl:
00664  *****************************************************************************/
00665 static void SDPHandleUrl( sout_stream_t *p_stream, char *psz_url )
00666 {
00667     sout_stream_sys_t *p_sys = p_stream->p_sys;
00668     vlc_url_t url;
00669 
00670     vlc_UrlParse( &url, psz_url, 0 );
00671     if( url.psz_protocol && !strcasecmp( url.psz_protocol, "http" ) )
00672     {
00673         if( p_sys->p_httpd_file )
00674         {
00675             msg_Err( p_stream, "You can used sdp=http:// only once" );
00676             return;
00677         }
00678 
00679         if( HttpSetup( p_stream, &url ) )
00680         {
00681             msg_Err( p_stream, "cannot export sdp as http" );
00682         }
00683     }
00684     else if( url.psz_protocol && !strcasecmp( url.psz_protocol, "rtsp" ) )
00685     {
00686         if( p_sys->p_rtsp_url )
00687         {
00688             msg_Err( p_stream, "You can used sdp=rtsp:// only once" );
00689             return;
00690         }
00691 
00692         /* FIXME test if destination is multicast or no destination at all FIXME */
00693         if( RtspSetup( p_stream, &url ) )
00694         {
00695             msg_Err( p_stream, "cannot export sdp as rtsp" );
00696         }
00697     }
00698     else if( ( url.psz_protocol && !strcasecmp( url.psz_protocol, "sap" ) ) || 
00699              ( url.psz_host && !strcasecmp( url.psz_host, "sap" ) ) )
00700     {
00701         p_sys->b_export_sap = VLC_TRUE;
00702         SapSetup( p_stream );
00703     }
00704     else if( url.psz_protocol && !strcasecmp( url.psz_protocol, "file" ) )
00705     {
00706         if( p_sys->b_export_sdp_file )
00707         {
00708             msg_Err( p_stream, "You can used sdp=file:// only once" );
00709             return;
00710         }
00711         p_sys->b_export_sdp_file = VLC_TRUE;
00712         psz_url = &psz_url[5];
00713         if( psz_url[0] == '/' && psz_url[1] == '/' )
00714             psz_url += 2;
00715         p_sys->psz_sdp_file = strdup( psz_url );
00716     }
00717     else
00718     {
00719         msg_Warn( p_stream, "unknown protocol for SDP (%s)",
00720                   url.psz_protocol );
00721     }
00722     vlc_UrlClean( &url );
00723 }
00724 
00725 /*****************************************************************************
00726  * SDPGenerate
00727  *****************************************************************************/
00728         /* FIXME  http://www.faqs.org/rfcs/rfc2327.html
00729            All text fields should be UTF-8 encoded. Use global a:charset to announce this.
00730            o= - should be local username (no spaces allowed)
00731            o= time should be hashed with some other value to garantue uniqueness
00732            o= we need IP6 support?
00733            o= don't use the localhost address. use fully qualified domain name or IP4 address
00734            p= international phone number (pass via vars?)
00735            c= IP6 support
00736            a= recvonly (missing)
00737            a= type:broadcast (missing)
00738            a= charset: (normally charset should be UTF-8, this can be used to override s= and i=)
00739            a= x-plgroup: (missing)
00740            RTP packets need to get the correct src IP address  */
00741 static char *SDPGenerate( const sout_stream_t *p_stream,
00742                           const char *psz_destination, vlc_bool_t b_rtsp )
00743 {
00744     sout_stream_sys_t *p_sys = p_stream->p_sys;
00745     sout_instance_t  *p_sout = p_stream->p_sout;
00746     int i_size;
00747     char *psz_sdp, *p, ipv;
00748     int i;
00749 
00750     /* FIXME: breaks IP version check on unknown destination */
00751     if( psz_destination == NULL )
00752         psz_destination = "0.0.0.0";
00753 
00754     i_size = sizeof( "v=0\r\n" ) +
00755              sizeof( "o=- * * IN IP4 127.0.0.1\r\n" ) + 10 + 10 +
00756              sizeof( "s=*\r\n" ) + strlen( p_sys->psz_session_name ) +
00757              sizeof( "i=*\r\n" ) + strlen( p_sys->psz_session_description ) +
00758              sizeof( "u=*\r\n" ) + strlen( p_sys->psz_session_url ) +
00759              sizeof( "e=*\r\n" ) + strlen( p_sys->psz_session_email ) +
00760              sizeof( "t=0 0\r\n" ) + /* permanent stream */ /* when scheduled from vlm, we should set this info correctly */
00761              sizeof( "a=tool:"PACKAGE_STRING"\r\n" ) +
00762              sizeof( "c=IN IP4 */*\r\n" ) + 20 + 10 +
00763              strlen( psz_destination ) ;
00764     for( i = 0; i < p_sys->i_es; i++ )
00765     {
00766         sout_stream_id_t *id = p_sys->es[i];
00767 
00768         i_size += strlen( "m=**d*o * RTP/AVP *\r\n" ) + 10 + 10;
00769         if( id->psz_rtpmap )
00770         {
00771             i_size += strlen( "a=rtpmap:* *\r\n" ) + strlen( id->psz_rtpmap )+10;
00772         }
00773         if( id->psz_fmtp )
00774         {
00775             i_size += strlen( "a=fmtp:* *\r\n" ) + strlen( id->psz_fmtp ) + 10;
00776         }
00777         if( b_rtsp )
00778         {
00779             i_size += strlen( "a=control:*/trackid=*\r\n" ) + strlen( p_sys->psz_rtsp_control ) + 10;
00780         }
00781     }
00782 
00783     ipv = ( strchr( psz_destination, ':' ) != NULL ) ? '6' : '4';
00784 
00785     p = psz_sdp = malloc( i_size );
00786     p += sprintf( p, "v=0\r\n" );
00787     p += sprintf( p, "o=- "I64Fd" %d IN IP%c %s\r\n",
00788                   p_sys->i_sdp_id, p_sys->i_sdp_version,
00789                   ipv, ipv == '6' ? "::" : "127.0.0.1" );
00790     if( *p_sys->psz_session_name )
00791         p += sprintf( p, "s=%s\r\n", p_sys->psz_session_name );
00792     if( *p_sys->psz_session_description )
00793         p += sprintf( p, "i=%s\r\n", p_sys->psz_session_description );
00794     if( *p_sys->psz_session_url )
00795         p += sprintf( p, "u=%s\r\n", p_sys->psz_session_url );
00796     if( *p_sys->psz_session_email )
00797         p += sprintf( p, "e=%s\r\n", p_sys->psz_session_email );
00798 
00799     p += sprintf( p, "t=0 0\r\n" ); /* permanent stream */ /* when scheduled from vlm, we should set this info correctly */
00800     p += sprintf( p, "a=tool:"PACKAGE_STRING"\r\n" );
00801 
00802     p += sprintf( p, "c=IN IP%c %s", ipv, psz_destination );
00803 
00804     if( net_AddressIsMulticast( (vlc_object_t *)p_stream, psz_destination ) )
00805     {
00806         /* Add the ttl if it is a multicast address */
00807         p += sprintf( p, "/%d\r\n", p_sys->i_ttl ? p_sys->i_ttl :
00808                 config_GetInt( p_sout, "ttl" ) );
00809     }
00810     else
00811     {
00812         p += sprintf( p, "\r\n" );
00813     }
00814 
00815     for( i = 0; i < p_sys->i_es; i++ )
00816     {
00817         sout_stream_id_t *id = p_sys->es[i];
00818 
00819         if( id->i_cat == AUDIO_ES )
00820         {
00821             p += sprintf( p, "m=audio %d RTP/AVP %d\r\n",
00822                           id->i_port, id->i_payload_type );
00823         }
00824         else if( id->i_cat == VIDEO_ES )
00825         {
00826             p += sprintf( p, "m=video %d RTP/AVP %d\r\n",
00827                           id->i_port, id->i_payload_type );
00828         }
00829         else
00830         {
00831             continue;
00832         }
00833         if( id->psz_rtpmap )
00834         {
00835             p += sprintf( p, "a=rtpmap:%d %s\r\n", id->i_payload_type,
00836                           id->psz_rtpmap );
00837         }
00838         if( id->psz_fmtp )
00839         {
00840             p += sprintf( p, "a=fmtp:%d %s\r\n", id->i_payload_type,
00841                           id->psz_fmtp );
00842         }
00843         if( b_rtsp )
00844         {
00845             p += sprintf( p, "a=control:%s/trackid=%d\r\n", p_sys->psz_rtsp_control, i );
00846         }
00847     }
00848 
00849     return psz_sdp;
00850 }
00851 
00852 /*****************************************************************************
00853  *
00854  *****************************************************************************/
00855 static int rtp_packetize_l16  ( sout_stream_t *, sout_stream_id_t *, block_t * );
00856 static int rtp_packetize_l8   ( sout_stream_t *, sout_stream_id_t *, block_t * );
00857 static int rtp_packetize_mpa  ( sout_stream_t *, sout_stream_id_t *, block_t * );
00858 static int rtp_packetize_mpv  ( sout_stream_t *, sout_stream_id_t *, block_t * );
00859 static int rtp_packetize_ac3  ( sout_stream_t *, sout_stream_id_t *, block_t * );
00860 static int rtp_packetize_split( sout_stream_t *, sout_stream_id_t *, block_t * );
00861 static int rtp_packetize_mp4a ( sout_stream_t *, sout_stream_id_t *, block_t * );
00862 static int rtp_packetize_h263 ( sout_stream_t *, sout_stream_id_t *, block_t * );
00863 static int rtp_packetize_amr  ( sout_stream_t *, sout_stream_id_t *, block_t * );
00864 
00865 static void sprintf_hexa( char *s, uint8_t *p_data, int i_data )
00866 {
00867     static const char hex[16] = "0123456789abcdef";
00868     int i;
00869 
00870     for( i = 0; i < i_data; i++ )
00871     {
00872         s[2*i+0] = hex[(p_data[i]>>4)&0xf];
00873         s[2*i+1] = hex[(p_data[i]   )&0xf];
00874     }
00875     s[2*i_data] = '\0';
00876 }
00877 
00878 static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
00879 {
00880     sout_instance_t   *p_sout = p_stream->p_sout;
00881     sout_stream_sys_t *p_sys = p_stream->p_sys;
00882     sout_stream_id_t  *id;
00883     sout_access_out_t *p_access = NULL;
00884     int               i_port;
00885     char              *psz_sdp;
00886 
00887     if( p_sys->p_mux != NULL )
00888     {
00889         sout_input_t      *p_input  = NULL;
00890         if( ( p_input = sout_MuxAddStream( p_sys->p_mux, p_fmt ) ) == NULL )
00891         {
00892             msg_Err( p_stream, "cannot add this stream to the muxer" );
00893             return NULL;
00894         }
00895 
00896         id = malloc( sizeof( sout_stream_id_t ) );
00897         memset( id, 0, sizeof( sout_stream_id_t ) );
00898         id->p_access    = NULL;
00899         id->p_input     = p_input;
00900         id->pf_packetize= NULL;
00901         id->p_rtsp_url  = NULL;
00902         id->i_port      = 0;
00903         return id;
00904     }
00905 
00906 
00907     /* Choose the port */
00908     i_port = 0;
00909     if( p_fmt->i_cat == AUDIO_ES && p_sys->i_port_audio > 0 )
00910     {
00911         i_port = p_sys->i_port_audio;
00912         p_sys->i_port_audio = 0;
00913     }
00914     else if( p_fmt->i_cat == VIDEO_ES && p_sys->i_port_video > 0 )
00915     {
00916         i_port = p_sys->i_port_video;
00917         p_sys->i_port_video = 0;
00918     }
00919     while( i_port == 0 )
00920     {
00921         if( p_sys->i_port != p_sys->i_port_audio && p_sys->i_port != p_sys->i_port_video )
00922         {
00923             i_port = p_sys->i_port;
00924             p_sys->i_port += 2;
00925             break;
00926         }
00927         p_sys->i_port += 2;
00928     }
00929 
00930     if( p_sys->psz_destination )
00931     {
00932         char access[17];
00933         char url[NI_MAXHOST + 8];
00934 
00935         /* first try to create the access out */
00936         if( p_sys->i_ttl > 0 )
00937         {
00938             snprintf( access, sizeof( access ), "udp{raw,ttl=%d}",
00939                       p_sys->i_ttl );
00940             access[sizeof( access ) - 1] = '\0';
00941         }
00942         else
00943             strcpy( access, "udp{raw}" );
00944 
00945         snprintf( url, sizeof( url ), (( p_sys->psz_destination[0] != '[' ) &&
00946                  strchr( p_sys->psz_destination, ':' )) ? "[%s]:%d" : "%s:%d",
00947                  p_sys->psz_destination, i_port );
00948         url[sizeof( url ) - 1] = '\0';
00949 
00950         if( ( p_access = sout_AccessOutNew( p_sout, access, url ) ) == NULL )
00951         {
00952             msg_Err( p_stream, "cannot create the access out for %s://%s",
00953                      access, url );
00954             return NULL;
00955         }
00956         msg_Dbg( p_stream, "access out %s:%s", access, url );
00957     }
00958 
00959     /* not create the rtp specific stuff */
00960     id = malloc( sizeof( sout_stream_id_t ) );
00961     memset( id, 0, sizeof( sout_stream_id_t ) );
00962     id->p_stream   = p_stream;
00963     id->p_access   = p_access;
00964     id->p_input    = NULL;
00965     id->psz_rtpmap = NULL;
00966     id->psz_fmtp   = NULL;
00967     id->psz_destination = p_sys->psz_destination ? strdup( p_sys->psz_destination ) : NULL;
00968     id->i_port = i_port;
00969     id->p_rtsp_url = NULL;
00970     vlc_mutex_init( p_stream, &id->lock_rtsp );
00971     id->i_rtsp_access = 0;
00972     id->rtsp_access = NULL;
00973 
00974     switch( p_fmt->i_codec )
00975     {
00976         case VLC_FOURCC( 's', '1', '6', 'b' ):
00977             if( p_fmt->audio.i_channels == 1 && p_fmt->audio.i_rate == 44100 )
00978             {
00979                 id->i_payload_type = 11;
00980             }
00981             else if( p_fmt->audio.i_channels == 2 &&
00982                      p_fmt->audio.i_rate == 44100 )
00983             {
00984                 id->i_payload_type = 10;
00985             }
00986             else
00987             {
00988                 id->i_payload_type = p_sys->i_payload_type++;
00989             }
00990             id->psz_rtpmap = malloc( strlen( "L16/*/*" ) + 20+1 );
00991             sprintf( id->psz_rtpmap, "L16/%d/%d", p_fmt->audio.i_rate,
00992                      p_fmt->audio.i_channels );
00993             id->i_clock_rate = p_fmt->audio.i_rate;
00994             id->pf_packetize = rtp_packetize_l16;
00995             break;
00996         case VLC_FOURCC( 'u', '8', ' ', ' ' ):
00997             id->i_payload_type = p_sys->i_payload_type++;
00998             id->psz_rtpmap = malloc( strlen( "L8/*/*" ) + 20+1 );
00999             sprintf( id->psz_rtpmap, "L8/%d/%d", p_fmt->audio.i_rate,
01000                      p_fmt->audio.i_channels );
01001             id->i_clock_rate = p_fmt->audio.i_rate;
01002             id->pf_packetize = rtp_packetize_l8;
01003             break;
01004         case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
01005             id->i_payload_type = 14;
01006             id->i_clock_rate = 90000;
01007             id->psz_rtpmap = strdup( "MPA/90000" );
01008             id->pf_packetize = rtp_packetize_mpa;
01009             break;
01010         case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
01011             id->i_payload_type = 32;
01012             id->i_clock_rate = 90000;
01013             id->psz_rtpmap = strdup( "MPV/90000" );
01014             id->pf_packetize = rtp_packetize_mpv;
01015             break;
01016         case VLC_FOURCC( 'a', '5', '2', ' ' ):
01017             id->i_payload_type = p_sys->i_payload_type++;
01018             id->i_clock_rate = 90000;
01019             id->psz_rtpmap = strdup( "ac3/90000" );
01020             id->pf_packetize = rtp_packetize_ac3;
01021             break;
01022         case VLC_FOURCC( 'H', '2', '6', '3' ):
01023             id->i_payload_type = p_sys->i_payload_type++;
01024             id->i_clock_rate = 90000;
01025             id->psz_rtpmap = strdup( "H263-1998/90000" );
01026             id->pf_packetize = rtp_packetize_h263;
01027             break;
01028 
01029         case VLC_FOURCC( 'm', 'p', '4', 'v' ):
01030         {
01031             char hexa[2*p_fmt->i_extra +1];
01032 
01033             id->i_payload_type = p_sys->i_payload_type++;
01034             id->i_clock_rate = 90000;
01035             id->psz_rtpmap = strdup( "MP4V-ES/90000" );
01036             id->pf_packetize = rtp_packetize_split;
01037             if( p_fmt->i_extra > 0 )
01038             {
01039                 id->psz_fmtp = malloc( 100 + 2 * p_fmt->i_extra );
01040                 sprintf_hexa( hexa, p_fmt->p_extra, p_fmt->i_extra );
01041                 sprintf( id->psz_fmtp,
01042                          "profile-level-id=3; config=%s;", hexa );
01043             }
01044             break;
01045         }
01046         case VLC_FOURCC( 'm', 'p', '4', 'a' ):
01047         {
01048             char hexa[2*p_fmt->i_extra +1];
01049 
01050             id->i_payload_type = p_sys->i_payload_type++;
01051             id->i_clock_rate = p_fmt->audio.i_rate;
01052             id->psz_rtpmap = malloc( strlen( "mpeg4-generic/" ) + 12 );
01053             sprintf( id->psz_rtpmap, "mpeg4-generic/%d", p_fmt->audio.i_rate );
01054             id->pf_packetize = rtp_packetize_mp4a;
01055             id->psz_fmtp = malloc( 200 + 2 * p_fmt->i_extra );
01056             sprintf_hexa( hexa, p_fmt->p_extra, p_fmt->i_extra );
01057             sprintf( id->psz_fmtp,
01058                      "streamtype=5; profile-level-id=15; mode=AAC-hbr; "
01059                      "config=%s; SizeLength=13;IndexLength=3; "
01060                      "IndexDeltaLength=3; Profile=1;", hexa );
01061             break;
01062         }
01063         case VLC_FOURCC( 's', 'a', 'm', 'r' ):
01064             id->i_payload_type = p_sys->i_payload_type++;
01065             id->psz_rtpmap = strdup( p_fmt->audio.i_channels == 2 ?
01066                                      "AMR/8000/2" : "AMR/8000" );
01067             id->psz_fmtp = strdup( "octet-align=1" );
01068             id->i_clock_rate = p_fmt->audio.i_rate;
01069             id->pf_packetize = rtp_packetize_amr;
01070             break; 
01071         case VLC_FOURCC( 's', 'a', 'w', 'b' ):
01072             id->i_payload_type = p_sys->i_payload_type++;
01073             id->psz_rtpmap = strdup( p_fmt->audio.i_channels == 2 ?
01074                                      "AMR-WB/16000/2" : "AMR-WB/16000" );
01075             id->psz_fmtp = strdup( "octet-align=1" );
01076             id->i_clock_rate = p_fmt->audio.i_rate;
01077             id->pf_packetize = rtp_packetize_amr;
01078             break; 
01079 
01080         default:
01081             msg_Err( p_stream, "cannot add this stream (unsupported "
01082                      "codec:%4.4s)", (char*)&p_fmt->i_codec );
01083             if( p_access )
01084             {
01085                 sout_AccessOutDelete( p_access );
01086             }
01087             free( id );
01088             return NULL;
01089     }
01090     id->i_cat = p_fmt->i_cat;
01091 
01092     id->ssrc[0] = rand()&0xff;
01093     id->ssrc[1] = rand()&0xff;
01094     id->ssrc[2] = rand()&0xff;
01095     id->ssrc[3] = rand()&0xff;
01096     id->i_sequence = rand()&0xffff;
01097     id->i_timestamp_start = rand()&0xffffffff;
01098 
01099     id->i_mtu    = config_GetInt( p_stream, "mtu" );  /* XXX beuk */
01100     if( id->i_mtu <= 16 + MTU_REDUCE )
01101     {
01102         /* better than nothing */
01103         id->i_mtu = 1500;
01104     }
01105     id->i_mtu -= MTU_REDUCE;
01106     msg_Dbg( p_stream, "maximum RTP packet size: %d bytes", id->i_mtu );
01107 
01108     if( p_sys->p_rtsp_url )
01109     {
01110         char psz_urlc[strlen( p_sys->psz_rtsp_control ) + 1 + 10];
01111 
01112         sprintf( psz_urlc, "%s/trackid=%d", p_sys->psz_rtsp_path, p_sys->i_es );
01113         fprintf( stderr, "rtsp: adding %s\n", psz_urlc );
01114         id->p_rtsp_url = httpd_UrlNewUnique( p_sys->p_rtsp_host, psz_urlc, NULL, NULL, NULL );
01115 
01116         if( id->p_rtsp_url )
01117         {
01118             httpd_UrlCatch( id->p_rtsp_url, HTTPD_MSG_SETUP,    RtspCallbackId, (void*)id );
01119             //httpd_UrlCatch( id->p_rtsp_url, HTTPD_MSG_PLAY,     RtspCallback, (void*)p_stream );
01120             //httpd_UrlCatch( id->p_rtsp_url, HTTPD_MSG_PAUSE,    RtspCallback, (void*)p_stream );
01121         }
01122     }
01123 
01124 
01125     /* Update p_sys context */
01126     vlc_mutex_lock( &p_sys->lock_es );
01127     TAB_APPEND( p_sys->i_es, p_sys->es, id );
01128     vlc_mutex_unlock( &p_sys->lock_es );
01129 
01130     psz_sdp = SDPGenerate( p_stream, p_sys->psz_destination, VLC_FALSE );
01131 
01132     vlc_mutex_lock( &p_sys->lock_sdp );
01133     free( p_sys->psz_sdp );
01134     p_sys->psz_sdp = psz_sdp;
01135     vlc_mutex_unlock( &p_sys->lock_sdp );
01136 
01137     p_sys->i_sdp_version++;
01138 
01139     fprintf( stderr, "sdp=%s", p_sys->psz_sdp );
01140 
01141     /* Update SDP (sap/file) */
01142     if( p_sys->b_export_sap ) SapSetup( p_stream );
01143     if( p_sys->b_export_sdp_file ) FileSetup( p_stream );
01144 
01145     return id;
01146 }
01147 
01148 static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
01149 {
01150     sout_stream_sys_t *p_sys = p_stream->p_sys;
01151 
01152     vlc_mutex_lock( &p_sys->lock_es );
01153     TAB_REMOVE( p_sys->i_es, p_sys->es, id );
01154     vlc_mutex_unlock( &p_sys->lock_es );
01155 
01156     /* Release port */
01157     if( id->i_port > 0 )
01158     {
01159         if( id->i_cat == AUDIO_ES && p_sys->i_port_audio == 0 )
01160             p_sys->i_port_audio = id->i_port;
01161         else if( id->i_cat == VIDEO_ES && p_sys->i_port_video == 0 )
01162             p_sys->i_port_video = id->i_port;
01163     }
01164 
01165     if( id->p_access )
01166     {
01167         if( id->psz_rtpmap )
01168         {
01169             free( id->psz_rtpmap );
01170         }
01171         if( id->psz_fmtp )
01172         {
01173             free( id->psz_fmtp );
01174         }
01175         if( id->psz_destination )
01176             free( id->psz_destination );
01177         sout_AccessOutDelete( id->p_access );
01178     }
01179     else if( id->p_input )
01180     {
01181         sout_MuxDeleteStream( p_sys->p_mux, id->p_input );
01182     }
01183     if( id->p_rtsp_url )
01184     {
01185         httpd_UrlDelete( id->p_rtsp_url );
01186     }
01187     vlc_mutex_destroy( &id->lock_rtsp );
01188     if( id->rtsp_access ) free( id->rtsp_access );
01189 
01190     /* Update SDP (sap/file) */
01191     if( p_sys->b_export_sap && !p_sys->p_mux ) SapSetup( p_stream );
01192     if( p_sys->b_export_sdp_file ) FileSetup( p_stream );
01193 
01194     free( id );
01195     return VLC_SUCCESS;
01196 }
01197 
01198 static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
01199                  block_t *p_buffer )
01200 {
01201     block_t *p_next;
01202 
01203     if( p_stream->p_sys->p_mux )
01204     {
01205         sout_MuxSendBuffer( p_stream->p_sys->p_mux, id->p_input, p_buffer );
01206     }
01207     else
01208     {
01209         while( p_buffer )
01210         {
01211             p_next = p_buffer->p_next;
01212             if( id->pf_packetize( p_stream, id, p_buffer ) )
01213             {
01214                 break;
01215             }
01216             block_Release( p_buffer );
01217             p_buffer = p_next;
01218         }
01219     }
01220     return VLC_SUCCESS;
01221 }
01222 
01223 
01224 static int AccessOutGrabberWriteBuffer( sout_stream_t *p_stream,
01225                                         block_t *p_buffer )
01226 {
01227     sout_stream_sys_t *p_sys = p_stream->p_sys;
01228 
01229     int64_t  i_dts = p_buffer->i_dts;
01230     uint32_t i_timestamp = i_dts * 9 / 100;
01231 
01232     uint8_t         *p_data = p_buffer->p_buffer;
01233     unsigned int    i_data  = p_buffer->i_buffer;
01234     unsigned int    i_max   = p_sys->i_mtu - 12;
01235 
01236     unsigned i_packet = ( p_buffer->i_buffer + i_max - 1 ) / i_max;
01237 
01238     while( i_data > 0 )
01239     {
01240         unsigned int i_size;
01241 
01242         /* output complete packet */
01243         if( p_sys->packet &&
01244             p_sys->packet->i_buffer + i_data > i_max )
01245         {
01246             sout_AccessOutWrite( p_sys->p_access, p_sys->packet );
01247             p_sys->packet = NULL;
01248         }
01249 
01250         if( p_sys->packet == NULL )
01251         {
01252             /* allocate a new packet */
01253             p_sys->packet = block_New( p_stream, p_sys->i_mtu );
01254             p_sys->packet->p_buffer[ 0] = 0x80;
01255             p_sys->packet->p_buffer[ 1] = 0x80|p_sys->i_payload_type;
01256             p_sys->packet->p_buffer[ 2] = ( p_sys->i_sequence >> 8)&0xff;
01257             p_sys->packet->p_buffer[ 3] = ( p_sys->i_sequence     )&0xff;
01258             p_sys->packet->p_buffer[ 4] = ( i_timestamp >> 24 )&0xff;
01259             p_sys->packet->p_buffer[ 5] = ( i_timestamp >> 16 )&0xff;
01260             p_sys->packet->p_buffer[ 6] = ( i_timestamp >>  8 )&0xff;
01261             p_sys->packet->p_buffer[ 7] = ( i_timestamp       )&0xff;
01262             p_sys->packet->p_buffer[ 8] = p_sys->ssrc[0];
01263             p_sys->packet->p_buffer[ 9] = p_sys->ssrc[1];
01264             p_sys->packet->p_buffer[10] = p_sys->ssrc[2];
01265             p_sys->packet->p_buffer[11] = p_sys->ssrc[3];
01266             p_sys->packet->i_buffer = 12;
01267 
01268             p_sys->packet->i_dts = i_dts;
01269             p_sys->packet->i_length = p_buffer->i_length / i_packet;
01270             i_dts += p_sys->packet->i_length;
01271 
01272             p_sys->i_sequence++;
01273         }
01274 
01275         i_size = __MIN( i_data,
01276                         (unsigned)(p_sys->i_mtu - p_sys->packet->i_buffer) );
01277 
01278         memcpy( &p_sys->packet->p_buffer[p_sys->packet->i_buffer],
01279                 p_data, i_size );
01280 
01281         p_sys->packet->i_buffer += i_size;
01282         p_data += i_size;
01283         i_data -= i_size;
01284     }
01285 
01286     return VLC_SUCCESS;
01287 }
01288 
01289 static int AccessOutGrabberWrite( sout_access_out_t *p_access,
01290                                   block_t *p_buffer )
01291 {
01292     sout_stream_t *p_stream = (sout_stream_t*)p_access->p_sys;
01293 
01294     //fprintf( stderr, "received buffer size=%d\n", p_buffer->i_buffer );
01295     //
01296     while( p_buffer )
01297     {
01298         block_t *p_next;
01299 
01300         AccessOutGrabberWriteBuffer( p_stream, p_buffer );
01301 
01302         p_next = p_buffer->p_next;
01303         block_Release( p_buffer );
01304         p_buffer = p_next;
01305     }
01306 
01307     return VLC_SUCCESS;
01308 }
01309 
01310 /****************************************************************************
01311  * SAP:
01312  ****************************************************************************/
01313 static int SapSetup( sout_stream_t *p_stream )
01314 {
01315     sout_stream_sys_t *p_sys = p_stream->p_sys;
01316     sout_instance_t   *p_sout = p_stream->p_sout;
01317     announce_method_t *p_method = sout_AnnounceMethodCreate( METHOD_TYPE_SAP );
01318 
01319     /* Remove the previous session */
01320     if( p_sys->p_session != NULL)
01321     {
01322         sout_AnnounceUnRegister( p_sout, p_sys->p_session);
01323         sout_AnnounceSessionDestroy( p_sys->p_session );
01324         p_sys->p_session = NULL;
01325     }
01326 
01327     if( ( p_sys->i_es > 0 || p_sys->p_mux ) && p_sys->psz_sdp && *p_sys->psz_sdp )
01328     {
01329         p_sys->p_session = sout_AnnounceRegisterSDP( p_sout, p_sys->psz_sdp,
01330                                                      p_sys->psz_destination,
01331                                                      p_method );
01332     }
01333 
01334     free( p_method );
01335     return VLC_SUCCESS;
01336 }
01337 
01338 /****************************************************************************
01339 * File:
01340 ****************************************************************************/
01341 static int FileSetup( sout_stream_t *p_stream )
01342 {
01343     sout_stream_sys_t *p_sys = p_stream->p_sys;
01344     FILE            *f;
01345 
01346     if( ( f = fopen( p_sys->psz_sdp_file, "wt" ) ) == NULL )
01347     {
01348         msg_Err( p_stream, "cannot open file '%s' (%s)",
01349                  p_sys->psz_sdp_file, strerror(errno) );
01350         return VLC_EGENERIC;
01351     }
01352 
01353     fprintf( f, "%s", p_sys->psz_sdp );
01354     fclose( f );
01355 
01356     return VLC_SUCCESS;
01357 }
01358 
01359 /****************************************************************************
01360  * HTTP:
01361  ****************************************************************************/
01362 static int  HttpCallback( httpd_file_sys_t *p_args,
01363                           httpd_file_t *, uint8_t *p_request,
01364                           uint8_t **pp_data, int *pi_data );
01365 
01366 static int HttpSetup( sout_stream_t *p_stream, vlc_url_t *url)
01367 {
01368     sout_stream_sys_t *p_sys = p_stream->p_sys;
01369 
01370     p_sys->p_httpd_host = httpd_HostNew( VLC_OBJECT(p_stream), url->psz_host, url->i_port > 0 ? url->i_port : 80 );
01371     if( p_sys->p_httpd_host )
01372     {
01373         p_sys->p_httpd_file = httpd_FileNew( p_sys->p_httpd_host,
01374                                              url->psz_path ? url->psz_path : "/",
01375                                              "application/sdp",
01376                                              NULL, NULL, NULL,
01377                                              HttpCallback, (void*)p_sys );
01378     }
01379     if( p_sys->p_httpd_file == NULL )
01380     {
01381         return VLC_EGENERIC;
01382     }
01383     return VLC_SUCCESS;
01384 }
01385 
01386 static int  HttpCallback( httpd_file_sys_t *p_args,
01387                           httpd_file_t *f, uint8_t *p_request,
01388                           uint8_t **pp_data, int *pi_data )
01389 {
01390     sout_stream_sys_t *p_sys = (sout_stream_sys_t*)p_args;
01391 
01392     vlc_mutex_lock( &p_sys->lock_sdp );
01393     if( p_sys->psz_sdp && *p_sys->psz_sdp )
01394     {
01395         *pi_data = strlen( p_sys->psz_sdp );
01396         *pp_data = malloc( *pi_data );
01397         memcpy( *pp_data, p_sys->psz_sdp, *pi_data );
01398     }
01399     else
01400     {
01401         *pp_data = NULL;
01402         *pi_data = 0;
01403     }
01404     vlc_mutex_unlock( &p_sys->lock_sdp );
01405 
01406     return VLC_SUCCESS;
01407 }
01408 
01409 /****************************************************************************
01410  * RTSP:
01411  ****************************************************************************/
01412 static rtsp_client_t *RtspClientNew( sout_stream_t *p_stream, char *psz_session )
01413 {
01414     rtsp_client_t *rtsp = malloc( sizeof( rtsp_client_t ));
01415 
01416     rtsp->psz_session = psz_session;
01417     rtsp->i_last = 0;
01418     rtsp->b_playing = VLC_FALSE;
01419     rtsp->i_id = 0;
01420     rtsp->id = NULL;
01421     rtsp->i_access = 0;
01422     rtsp->access = NULL;
01423 
01424     TAB_APPEND( p_stream->p_sys->i_rtsp, p_stream->p_sys->rtsp, rtsp );
01425 
01426     return rtsp;
01427 }
01428 static rtsp_client_t *RtspClientGet( sout_stream_t *p_stream, char *psz_session )
01429 {
01430     int i;
01431     for( i = 0; i < p_stream->p_sys->i_rtsp; i++ )
01432     {
01433         if( !strcmp( p_stream->p_sys->rtsp[i]->psz_session, psz_session ) )
01434         {
01435             return p_stream->p_sys->rtsp[i];
01436         }
01437     }
01438     return NULL;
01439 }
01440 
01441 static void RtspClientDel( sout_stream_t *p_stream, rtsp_client_t *rtsp )
01442 {
01443     int i;
01444     TAB_REMOVE( p_stream->p_sys->i_rtsp, p_stream->p_sys->rtsp, rtsp );
01445 
01446     for( i = 0; i < rtsp->i_access; i++ )
01447     {
01448         sout_AccessOutDelete( rtsp->access[i] );
01449     }
01450     if( rtsp->id )     free( rtsp->id );
01451     if( rtsp->access ) free( rtsp->access );
01452 
01453     free( rtsp->psz_session );
01454     free( rtsp );
01455 }
01456 
01457 static int RtspSetup( sout_stream_t *p_stream, vlc_url_t *url )
01458 {
01459     sout_stream_sys_t *p_sys = p_stream->p_sys;
01460 
01461     fprintf( stderr, "rtsp setup: %s : %d / %s\n", url->psz_host, url->i_port, url->psz_path );
01462 
01463     p_sys->p_rtsp_host = httpd_HostNew( VLC_OBJECT(p_stream), url->psz_host, url->i_port > 0 ? url->i_port : 554 );
01464     if( p_sys->p_rtsp_host == NULL )
01465     {
01466         return VLC_EGENERIC;
01467     }
01468 
01469     p_sys->psz_rtsp_path = strdup( url->psz_path ? url->psz_path : "/" );
01470     p_sys->psz_rtsp_control = malloc (strlen( url->psz_host ) + 20 + strlen( p_sys->psz_rtsp_path ) + 1 );
01471     sprintf( p_sys->psz_rtsp_control, "rtsp://%s:%d%s",
01472              url->psz_host,  url->i_port > 0 ? url->i_port : 554, p_sys->psz_rtsp_path );
01473 
01474     p_sys->p_rtsp_url = httpd_UrlNewUnique( p_sys->p_rtsp_host, p_sys->psz_rtsp_path, NULL, NULL, NULL );
01475     if( p_sys->p_rtsp_url == 0 )
01476     {
01477         return VLC_EGENERIC;
01478     }
01479     httpd_UrlCatch( p_sys->p_rtsp_url, HTTPD_MSG_DESCRIBE, RtspCallback, (void*)p_stream );
01480     httpd_UrlCatch( p_sys->p_rtsp_url, HTTPD_MSG_PLAY,     RtspCallback, (void*)p_stream );
01481     httpd_UrlCatch( p_sys->p_rtsp_url, HTTPD_MSG_PAUSE,    RtspCallback, (void*)p_stream );
01482     httpd_UrlCatch( p_sys->p_rtsp_url, HTTPD_MSG_TEARDOWN, RtspCallback, (void*)p_stream );
01483 
01484     return VLC_SUCCESS;
01485 }
01486 
01487 static int  RtspCallback( httpd_callback_sys_t *p_args,
01488                           httpd_client_t *cl,
01489                           httpd_message_t *answer, httpd_message_t *query )
01490 {
01491     sout_stream_t *p_stream = (sout_stream_t*)p_args;
01492     sout_stream_sys_t *p_sys = p_stream->p_sys;
01493     char          *psz_destination = p_sys->psz_destination;
01494     char          *psz_session = NULL;
01495 
01496     if( answer == NULL || query == NULL )
01497     {
01498         return VLC_SUCCESS;
01499     }
01500     fprintf( stderr, "RtspCallback query: type=%d\n", query->i_type );
01501 
01502     answer->i_proto = HTTPD_PROTO_RTSP;
01503     answer->i_version= query->i_version;
01504     answer->i_type   = HTTPD_MSG_ANSWER;
01505 
01506     switch( query->i_type )
01507     {
01508         case HTTPD_MSG_DESCRIBE:
01509         {
01510             char *psz_sdp = SDPGenerate( p_stream, psz_destination ? psz_destination : "0.0.0.0", VLC_TRUE );
01511 
01512             answer->i_status = 200;
01513             answer->psz_status = strdup( "OK" );
01514             httpd_MsgAdd( answer, "Content-type",  "%s", "application/sdp" );
01515 
01516             answer->p_body = (uint8_t *)psz_sdp;
01517             answer->i_body = strlen( psz_sdp );
01518             break;
01519         }
01520 
01521         case HTTPD_MSG_PLAY:
01522         {
01523             rtsp_client_t *rtsp;
01524             /* for now only multicast so easy */
01525             answer->i_status = 200;
01526             answer->psz_status = strdup( "OK" );
01527             answer->i_body = 0;
01528             answer->p_body = NULL;
01529 
01530             psz_session = httpd_MsgGet( query, "Session" );
01531             rtsp = RtspClientGet( p_stream, psz_session );
01532             if( rtsp && !rtsp->b_playing )
01533             {
01534                 int i_id;
01535                 /* FIXME */
01536                 rtsp->b_playing = VLC_TRUE;
01537 
01538                 vlc_mutex_lock( &p_sys->lock_es );
01539                 for( i_id = 0; i_id < rtsp->i_id; i_id++ )
01540                 {
01541                     sout_stream_id_t *id = rtsp->id[i_id];
01542                     int i;
01543 
01544                     for( i = 0; i < p_sys->i_es; i++ )
01545                     {
01546                         if( id == p_sys->es[i] )
01547                             break;
01548                     }
01549                     if( i >= p_sys->i_es ) continue;
01550 
01551                     vlc_mutex_lock( &id->lock_rtsp );
01552                     TAB_APPEND( id->i_rtsp_access, id->rtsp_access, rtsp->access[i_id] );
01553                     vlc_mutex_unlock( &id->lock_rtsp );
01554                 }
01555                 vlc_mutex_unlock( &p_sys->lock_es );
01556             }
01557             break;
01558         }
01559         case HTTPD_MSG_PAUSE:
01560             /* FIXME */
01561             return VLC_EGENERIC;
01562         case HTTPD_MSG_TEARDOWN:
01563         {
01564             rtsp_client_t *rtsp;
01565 
01566             /* for now only multicast so easy again */
01567             answer->i_status = 200;
01568             answer->psz_status = strdup( "OK" );
01569             answer->i_body = 0;
01570             answer->p_body = NULL;
01571 
01572             psz_session = httpd_MsgGet( query, "Session" );
01573             rtsp = RtspClientGet( p_stream, psz_session );
01574             if( rtsp )
01575             {
01576                 int i_id;
01577 
01578                 vlc_mutex_lock( &p_sys->lock_es );
01579                 for( i_id = 0; i_id < rtsp->i_id; i_id++ )
01580                 {
01581                     sout_stream_id_t *id = rtsp->id[i_id];
01582                     int i;
01583 
01584                     for( i = 0; i < p_sys->i_es; i++ )
01585                     {
01586                         if( id == p_sys->es[i] )
01587                             break;
01588                     }
01589                     if( i >= p_sys->i_es ) continue;
01590 
01591                     vlc_mutex_lock( &id->lock_rtsp );
01592                     TAB_REMOVE( id->i_rtsp_access, id->rtsp_access, rtsp->access[i_id] );
01593                     vlc_mutex_unlock( &id->lock_rtsp );
01594                 }
01595                 vlc_mutex_unlock( &p_sys->lock_es );
01596 
01597                 RtspClientDel( p_stream, rtsp );
01598             }
01599             break;
01600         }
01601 
01602         default:
01603             return VLC_EGENERIC;
01604     }
01605     httpd_MsgAdd( answer, "Server", "VLC Server" );
01606     httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body );
01607     httpd_MsgAdd( answer, "Cseq", "%d", atoi( httpd_MsgGet( query, "Cseq" ) ) );
01608     httpd_MsgAdd( answer, "Cache-Control", "%s", "no-cache" );
01609 
01610     if( psz_session )
01611     {
01612         httpd_MsgAdd( answer, "Session", "%s;timeout=5", psz_session );
01613     }
01614     return VLC_SUCCESS;
01615 }
01616 
01617 static int  RtspCallbackId( httpd_callback_sys_t *p_args,
01618                           httpd_client_t *cl,
01619                           httpd_message_t *answer, httpd_message_t *query )
01620 {
01621     sout_stream_id_t *id = (sout_stream_id_t*)p_args;
01622     sout_stream_t    *p_stream = id->p_stream;
01623     sout_instance_t    *p_sout = p_stream->p_sout;
01624     sout_stream_sys_t *p_sys = p_stream->p_sys;
01625     char          *psz_session = NULL;
01626 
01627     if( answer == NULL || query == NULL )
01628     {
01629         return VLC_SUCCESS;
01630     }
01631     fprintf( stderr, "RtspCallback query: type=%d\n", query->i_type );
01632 
01633     answer->i_proto = HTTPD_PROTO_RTSP;
01634     answer->i_version= query->i_version;
01635     answer->i_type   = HTTPD_MSG_ANSWER;
01636 
01637     switch( query->i_type )
01638     {
01639         case HTTPD_MSG_SETUP:
01640         {
01641             char *psz_transport = httpd_MsgGet( query, "Transport" );
01642 
01643             fprintf( stderr, "HTTPD_MSG_SETUP: transport=%s\n", psz_transport );
01644 
01645             if( strstr( psz_transport, "multicast" ) && id->psz_destination )
01646             {
01647                 fprintf( stderr, "HTTPD_MSG_SETUP: multicast\n" );
01648                 answer->i_status = 200;
01649                 answer->psz_status = strdup( "OK" );
01650                 answer->i_body = 0;
01651                 answer->p_body = NULL;
01652                 psz_session = httpd_MsgGet( query, "Session" );
01653                 if( *psz_session == 0 )
01654                 {
01655                     psz_session = malloc( 100 );
01656                     sprintf( psz_session, "%d", rand() );
01657                 }
01658                 httpd_MsgAdd( answer, "Transport",
01659                               "RTP/AVP/UDP;destination=%s;port=%d-%d;ttl=%d",
01660                               id->psz_destination, id->i_port,id->i_port+1,
01661                               p_sys->i_ttl ? p_sys->i_ttl : 
01662                               config_GetInt( p_sout, "ttl" ) );
01663             }
01664             else if( strstr( psz_transport, "unicast" ) && strstr( psz_transport, "client_port=" ) )
01665             {
01666                 int  i_port = atoi( strstr( psz_transport, "client_port=" ) + strlen("client_port=") );
01667                 char ip[NI_MAXNUMERICHOST], psz_access[17], psz_url[NI_MAXNUMERICHOST + 8];
01668 
01669                 sout_access_out_t *p_access;
01670 
01671                 rtsp_client_t *rtsp = NULL;
01672 
01673                 if( httpd_ClientIP( cl, ip ) == NULL )
01674                 {
01675                     answer->i_status = 500;
01676                     answer->psz_status = strdup( "Internal server error" );
01677                     answer->i_body = 0;
01678                     answer->p_body = NULL;
01679                     break;
01680                 }
01681 
01682                 fprintf( stderr, "HTTPD_MSG_SETUP: unicast ip=%s port=%d\n",
01683                          ip, i_port );
01684 
01685                 psz_session = httpd_MsgGet( query, "Session" );
01686                 if( *psz_session == 0 )
01687                 {
01688                     psz_session = malloc( 100 );
01689                     sprintf( psz_session, "%d", rand() );
01690 
01691                     rtsp = RtspClientNew( p_stream, psz_session );
01692                 }
01693                 else
01694                 {
01695                     rtsp = RtspClientGet( p_stream, psz_session );
01696                     if( rtsp == NULL )
01697                     {
01698                         answer->i_status = 454;
01699                         answer->psz_status = strdup( "Unknown session id" );
01700                         answer->i_body = 0;
01701                         answer->p_body = NULL;
01702                         break;
01703                     }
01704                 }
01705 
01706                 /* first try to create the access out */
01707                 if( p_sys->i_ttl > 0 )
01708                     snprintf( psz_access, sizeof( psz_access ),
01709                               "udp{raw,ttl=%d}", p_sys->i_ttl );
01710                 else
01711                     strncpy( psz_access, "udp{raw}", sizeof( psz_access ) );
01712                 psz_access[sizeof( psz_access ) - 1] = '\0';
01713 
01714                 snprintf( psz_url, sizeof( psz_url ),
01715                          ( strchr( ip, ':' ) != NULL ) ? "[%s]:%d" : "%s:%d",
01716                          ip, i_port );
01717 
01718                 if( ( p_access = sout_AccessOutNew( p_stream->p_sout, psz_access, psz_url ) ) == NULL )
01719                 {
01720                     msg_Err( p_stream, "cannot create the access out for %s://%s",
01721                              psz_access, psz_url );
01722                     answer->i_status = 500;
01723                     answer->psz_status = strdup( "Internal server error" );
01724                     answer->i_body = 0;
01725                     answer->p_body = NULL;
01726                     break;
01727                 }
01728 
01729                 TAB_APPEND( rtsp->i_id, rtsp->id, id );
01730                 TAB_APPEND( rtsp->i_access, rtsp->access, p_access );
01731 
01732                 answer->i_status = 200;
01733                 answer->psz_status = strdup( "OK" );
01734                 answer->i_body = 0;
01735                 answer->p_body = NULL;
01736 
01737                 httpd_MsgAdd( answer, "Transport",
01738                               "RTP/AVP/UDP;client_port=%d-%d", i_port, i_port + 1 );
01739             }
01740             else /* TODO  strstr( psz_transport, "interleaved" ) ) */
01741             {
01742                 answer->i_status = 461;
01743                 answer->psz_status = strdup( "Unsupported Transport" );
01744                 answer->i_body = 0;
01745                 answer->p_body = NULL;
01746             }
01747             break;
01748         }
01749 
01750         default:
01751             return VLC_EGENERIC;
01752     }
01753     httpd_MsgAdd( answer, "Server", "VLC Server" );
01754     httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body );
01755     httpd_MsgAdd( answer, "Cseq", "%d", atoi( httpd_MsgGet( query, "Cseq" ) ) );
01756     httpd_MsgAdd( answer, "Cache-Control", "%s", "no-cache" );
01757 
01758     if( psz_session )
01759     {
01760         httpd_MsgAdd( answer, "Session", "%s"/*;timeout=5*/, psz_session );
01761     }
01762     return VLC_SUCCESS;
01763 }
01764 
01765 /****************************************************************************
01766  * rtp_packetize_*:
01767  ****************************************************************************/
01768 static void rtp_packetize_common( sout_stream_id_t *id, block_t *out,
01769                                   int b_marker, int64_t i_pts )
01770 {
01771     uint32_t i_timestamp = i_pts * (int64_t)id->i_clock_rate / I64C(1000000);
01772 
01773     out->p_buffer[0] = 0x80;
01774     out->p_buffer[1] = (b_marker?0x80:0x00)|id->i_payload_type;
01775     out->p_buffer[2] = ( id->i_sequence >> 8)&0xff;
01776     out->p_buffer[3] = ( id->i_sequence     )&0xff;
01777     out->p_buffer[4] = ( i_timestamp >> 24 )&0xff;
01778     out->p_buffer[5] = ( i_timestamp >> 16 )&0xff;
01779     out->p_buffer[6] = ( i_timestamp >>  8 )&0xff;
01780     out->p_buffer[7] = ( i_timestamp       )&0xff;
01781 
01782     out->p_buffer[ 8] = id->ssrc[0];
01783     out->p_buffer[ 9] = id->ssrc[1];
01784     out->p_buffer[10] = id->ssrc[2];
01785     out->p_buffer[11] = id->ssrc[3];
01786 
01787     out->i_buffer = 12;
01788     id->i_sequence++;
01789 }
01790 
01791 static void rtp_packetize_send( sout_stream_id_t *id, block_t *out )
01792 {
01793     int i;
01794     vlc_mutex_lock( &id->lock_rtsp );
01795     for( i = 0; i < id->i_rtsp_access; i++ )
01796     {
01797         sout_AccessOutWrite( id->rtsp_access[i], block_Duplicate( out ) );
01798     }
01799     vlc_mutex_unlock( &id->lock_rtsp );
01800 
01801     if( id->p_access )
01802     {
01803         sout_AccessOutWrite( id->p_access, out );
01804     }
01805     else
01806     {
01807         block_Release( out );
01808     }
01809 }
01810 
01811 static int rtp_packetize_mpa( sout_stream_t *p_stream, sout_stream_id_t *id,
01812                               block_t *in )
01813 {
01814     int     i_max   = id->i_mtu - 12 - 4; /* payload max in one packet */
01815     int     i_count = ( in->i_buffer + i_max - 1 ) / i_max;
01816 
01817     uint8_t *p_data = in->p_buffer;
01818     int     i_data  = in->i_buffer;
01819     int     i;
01820 
01821     for( i = 0; i < i_count; i++ )
01822     {
01823         int           i_payload = __MIN( i_max, i_data );
01824         block_t *out = block_New( p_stream, 16 + i_payload );
01825 
01826         /* rtp common header */
01827         rtp_packetize_common( id, out, (i == i_count - 1)?1:0, in->i_pts );
01828         /* mbz set to 0 */
01829         out->p_buffer[12] = 0;
01830         out->p_buffer[13] = 0;
01831         /* fragment offset in the current frame */
01832         out->p_buffer[14] = ( (i*i_max) >> 8 )&0xff;
01833         out->p_buffer[15] = ( (i*i_max)      )&0xff;
01834         memcpy( &out->p_buffer[16], p_data, i_payload );
01835 
01836         out->i_buffer   = 16 + i_payload;
01837         out->i_dts    = in->i_dts + i * in->i_length / i_count;
01838         out->i_length = in->i_length / i_count;
01839 
01840         rtp_packetize_send( id, out );
01841 
01842         p_data += i_payload;
01843         i_data -= i_payload;
01844     }
01845 
01846     return VLC_SUCCESS;
01847 }
01848 
01849 /* rfc2250 */
01850 static int rtp_packetize_mpv( sout_stream_t *p_stream, sout_stream_id_t *id,
01851                               block_t *in )
01852 {
01853     int     i_max   = id->i_mtu - 12 - 4; /* payload max in one packet */
01854     int     i_count = ( in->i_buffer + i_max - 1 ) / i_max;
01855 
01856     uint8_t *p_data = in->p_buffer;
01857     int     i_data  = in->i_buffer;
01858     int     i;
01859     int     b_sequence_start = 0;
01860     int     i_temporal_ref = 0;
01861     int     i_picture_coding_type = 0;
01862     int     i_fbv = 0, i_bfc = 0, i_ffv = 0, i_ffc = 0;
01863     int     b_start_slice = 0;
01864 
01865     /* preparse this packet to get some info */
01866     if( in->i_buffer > 4 )
01867     {
01868         uint8_t *p = p_data;
01869         int      i_rest = in->i_buffer;
01870 
01871         for( ;; )
01872         {
01873             while( i_rest > 4 &&
01874                    ( p[0] != 0x00 || p[1] != 0x00 || p[2] != 0x01 ) )
01875             {
01876                 p++;
01877                 i_rest--;
01878             }
01879             if( i_rest <= 4 )
01880             {
01881                 break;
01882             }
01883             p += 3;
01884             i_rest -= 4;
01885 
01886             if( *p == 0xb3 )
01887             {
01888                 /* sequence start code */
01889                 b_sequence_start = 1;
01890             }
01891             else if( *p == 0x00 && i_rest >= 4 )
01892             {
01893                 /* picture */
01894                 i_temporal_ref = ( p[1] << 2) |((p[2]>>6)&0x03);
01895                 i_picture_coding_type = (p[2] >> 3)&0x07;
01896 
01897                 if( i_rest >= 4 && ( i_picture_coding_type == 2 ||
01898                                     i_picture_coding_type == 3 ) )
01899                 {
01900                     i_ffv = (p[3] >> 2)&0x01;
01901                     i_ffc = ((p[3]&0x03) << 1)|((p[4]>>7)&0x01);
01902                     if( i_rest > 4 && i_picture_coding_type == 3 )
01903                     {
01904                         i_fbv = (p[4]>>6)&0x01;
01905                         i_bfc = (p[4]>>3)&0x07;
01906                     }
01907                 }
01908             }
01909             else if( *p <= 0xaf )
01910             {
01911                 b_start_slice = 1;
01912             }
01913         }
01914     }
01915 
01916     for( i = 0; i < i_count; i++ )
01917     {
01918         int           i_payload = __MIN( i_max, i_data );
01919         block_t *out = block_New( p_stream,
01920                                              16 + i_payload );
01921         uint32_t      h = ( i_temporal_ref << 16 )|
01922                           ( b_sequence_start << 13 )|
01923                           ( b_start_slice << 12 )|
01924                           ( i == i_count - 1 ? 1 << 11 : 0 )|
01925                           ( i_picture_coding_type << 8 )|
01926                           ( i_fbv << 7 )|( i_bfc << 4 )|( i_ffv << 3 )|i_ffc;
01927 
01928         /* rtp common header */
01929         rtp_packetize_common( id, out, (i == i_count - 1)?1:0,
01930                               in->i_pts > 0 ? in->i_pts : in->i_dts );
01931 
01932         /* MBZ:5 T:1 TR:10 AN:1 N:1 S:1 B:1 E:1 P:3 FBV:1 BFC:3 FFV:1 FFC:3 */
01933         out->p_buffer[12] = ( h >> 24 )&0xff;
01934         out->p_buffer[13] = ( h >> 16 )&0xff;
01935         out->p_buffer[14] = ( h >>  8 )&0xff;
01936         out->p_buffer[15] = ( h       )&0xff;
01937 
01938         memcpy( &out->p_buffer[16], p_data, i_payload );
01939 
01940         out->i_buffer   = 16 + i_payload;
01941         out->i_dts    = in->i_dts + i * in->i_length / i_count;
01942         out->i_length = in->i_length / i_count;
01943 
01944         rtp_packetize_send( id, out );
01945 
01946         p_data += i_payload;
01947         i_data -= i_payload;
01948     }
01949 
01950     return VLC_SUCCESS;
01951 }
01952 static int rtp_packetize_ac3( sout_stream_t *p_stream, sout_stream_id_t *id,
01953                               block_t *in )
01954 {
01955     int     i_max   = id->i_mtu - 12 - 2; /* payload max in one packet */
01956     int     i_count = ( in->i_buffer + i_max - 1 ) / i_max;
01957 
01958     uint8_t *p_data = in->p_buffer;
01959     int     i_data  = in->i_buffer;
01960     int     i;
01961 
01962     for( i = 0; i < i_count; i++ )
01963     {
01964         int           i_payload = __MIN( i_max, i_data );
01965         block_t *out = block_New( p_stream, 14 + i_payload );
01966 
01967         /* rtp common header */
01968         rtp_packetize_common( id, out, (i == i_count - 1)?1:0, in->i_pts );
01969         /* unit count */
01970         out->p_buffer[12] = 1;
01971         /* unit header */
01972         out->p_buffer[13] = 0x00;
01973         /* data */
01974         memcpy( &out->p_buffer[14], p_data, i_payload );
01975 
01976         out->i_buffer   = 14 + i_payload;
01977         out->i_dts    = in->i_dts + i * in->i_length / i_count;
01978         out->i_length = in->i_length / i_count;
01979 
01980         rtp_packetize_send( id, out );
01981 
01982         p_data += i_payload;
01983         i_data -= i_payload;
01984     }
01985 
01986     return VLC_SUCCESS;
01987 }
01988 
01989 static int rtp_packetize_split( sout_stream_t *p_stream, sout_stream_id_t *id,
01990                                 block_t *in )
01991 {
01992     int     i_max   = id->i_mtu - 12; /* payload max in one packet */
01993     int     i_count = ( in->i_buffer + i_max - 1 ) / i_max;
01994 
01995     uint8_t *p_data = in->p_buffer;
01996     int     i_data  = in->i_buffer;
01997     int     i;
01998 
01999     for( i = 0; i < i_count; i++ )
02000     {
02001         int           i_payload = __MIN( i_max, i_data );
02002         block_t *out = block_New( p_stream, 12 + i_payload );
02003 
02004         /* rtp common header */
02005         rtp_packetize_common( id, out, ((i == i_count - 1)?1:0),
02006                               (in->i_pts > 0 ? in->i_pts : in->i_dts) );
02007         memcpy( &out->p_buffer[12], p_data, i_payload );
02008 
02009         out->i_buffer   = 12 + i_payload;
02010         out->i_dts    = in->i_dts + i * in->i_length / i_count;
02011         out->i_length = in->i_length / i_count;
02012 
02013         rtp_packetize_send( id, out );
02014 
02015         p_data += i_payload;
02016         i_data -= i_payload;
02017     }
02018 
02019     return VLC_SUCCESS;
02020 }
02021 
02022 static int rtp_packetize_l16( sout_stream_t *p_stream, sout_stream_id_t *id,
02023                               block_t *in )
02024 {
02025     int     i_max   = id->i_mtu - 12; /* payload max in one packet */
02026     int     i_count = ( in->i_buffer + i_max - 1 ) / i_max;
02027 
02028     uint8_t *p_data = in->p_buffer;
02029     int     i_data  = in->i_buffer;
02030     int     i_packet = 0;
02031 
02032     while( i_data > 0 )
02033     {
02034         int           i_payload = (__MIN( i_max, i_data )/4)*4;
02035         block_t *out = block_New( p_stream, 12 + i_payload );
02036 
02037         /* rtp common header */
02038         rtp_packetize_common( id, out, 0,
02039                               (in->i_pts > 0 ? in->i_pts : in->i_dts) );
02040         memcpy( &out->p_buffer[12], p_data, i_payload );
02041 
02042         out->i_buffer   = 12 + i_payload;
02043         out->i_dts    = in->i_dts + i_packet * in->i_length / i_count;
02044         out->i_length = in->i_length / i_count;
02045 
02046         rtp_packetize_send( id, out );
02047 
02048         p_data += i_payload;
02049         i_data -= i_payload;
02050         i_packet++;
02051     }
02052 
02053     return VLC_SUCCESS;
02054 }
02055 
02056 static int rtp_packetize_l8( sout_stream_t *p_stream, sout_stream_id_t *id,
02057                              block_t *in )
02058 {
02059     int     i_max   = id->i_mtu - 12; /* payload max in one packet */
02060     int     i_count = ( in->i_buffer + i_max - 1 ) / i_max;
02061 
02062     uint8_t *p_data = in->p_buffer;
02063     int     i_data  = in->i_buffer;
02064     int     i_packet = 0;
02065 
02066     while( i_data > 0 )
02067     {
02068         int           i_payload = (__MIN( i_max, i_data )/2)*2;
02069         block_t *out = block_New( p_stream, 12 + i_payload );
02070 
02071         /* rtp common header */
02072         rtp_packetize_common( id, out, 0,
02073                               (in->i_pts > 0 ? in->i_pts : in->i_dts) );
02074         memcpy( &out->p_buffer[12], p_data, i_payload );
02075 
02076         out->i_buffer   = 12 + i_payload;
02077         out->i_dts    = in->i_dts + i_packet * in->i_length / i_count;
02078         out->i_length = in->i_length / i_count;
02079 
02080         rtp_packetize_send( id, out );
02081 
02082         p_data += i_payload;
02083         i_data -= i_payload;
02084         i_packet++;
02085     }
02086 
02087     return VLC_SUCCESS;
02088 }
02089 static int rtp_packetize_mp4a( sout_stream_t *p_stream, sout_stream_id_t *id,
02090                                block_t *in )
02091 {
02092     int     i_max   = id->i_mtu - 16; /* payload max in one packet */
02093     int     i_count = ( in->i_buffer + i_max - 1 ) / i_max;
02094 
02095     uint8_t *p_data = in->p_buffer;
02096     int     i_data  = in->i_buffer;
02097     int     i;
02098 
02099     for( i = 0; i < i_count; i++ )
02100     {
02101         int           i_payload = __MIN( i_max, i_data );
02102         block_t *out = block_New( p_stream, 16 + i_payload );
02103 
02104         /* rtp common header */
02105         rtp_packetize_common( id, out, ((i == i_count - 1)?1:0),
02106                               (in->i_pts > 0 ? in->i_pts : in->i_dts) );
02107         /* AU headers */
02108         /* AU headers length (bits) */
02109         out->p_buffer[12] = 0;
02110         out->p_buffer[13] = 2*8;
02111         /* for each AU length 13 bits + idx 3bits, */
02112         out->p_buffer[14] = ( in->i_buffer >> 5 )&0xff;
02113         out->p_buffer[15] = ( (in->i_buffer&0xff)<<3 )|0;
02114 
02115         memcpy( &out->p_buffer[16], p_data, i_payload );
02116 
02117         out->i_buffer   = 16 + i_payload;
02118         out->i_dts    = in->i_dts + i * in->i_length / i_count;
02119         out->i_length = in->i_length / i_count;
02120 
02121         rtp_packetize_send( id, out );
02122 
02123         p_data += i_payload;
02124         i_data -= i_payload;
02125     }
02126 
02127     return VLC_SUCCESS;
02128 }
02129 
02130 
02131 /* rfc2429 */
02132 #define RTP_H263_HEADER_SIZE (2)  // plen = 0
02133 #define RTP_H263_PAYLOAD_START (14)  // plen = 0
02134 static int rtp_packetize_h263( sout_stream_t *p_stream, sout_stream_id_t *id,
02135                                block_t *in )
02136 {
02137     uint8_t *p_data = in->p_buffer;
02138     int     i_data  = in->i_buffer;
02139     int     i;
02140     int     i_max   = id->i_mtu - 12 - RTP_H263_HEADER_SIZE; /* payload max in one packet */
02141     int     i_count;
02142     int     b_p_bit;
02143     int     b_v_bit = 0; // no pesky error resilience
02144     int     i_plen = 0; // normally plen=0 for PSC packet
02145     int     i_pebit = 0; // because plen=0
02146     uint16_t h;
02147 
02148     if( i_data < 2 )
02149     {
02150         return VLC_EGENERIC;
02151     }
02152     if( p_data[0] || p_data[1] )
02153     {
02154         return VLC_EGENERIC;
02155     }
02156     /* remove 2 leading 0 bytes */
02157     p_data += 2;
02158     i_data -= 2;
02159     i_count = ( i_data + i_max - 1 ) / i_max;
02160 
02161     for( i = 0; i < i_count; i++ )
02162     {
02163         int      i_payload = __MIN( i_max, i_data );
02164         block_t *out = block_New( p_stream,
02165                                   RTP_H263_PAYLOAD_START + i_payload );
02166         b_p_bit = (i == 0) ? 1 : 0;
02167         h = ( b_p_bit << 10 )|
02168             ( b_v_bit << 9  )|
02169             ( i_plen  << 3  )|
02170               i_pebit;
02171 
02172         /* rtp common header */
02173         //b_m_bit = 1; // always contains end of frame
02174         rtp_packetize_common( id, out, (i == i_count - 1)?1:0,
02175                               in->i_pts > 0 ? in->i_pts : in->i_dts );
02176 
02177         /* h263 header */
02178         out->p_buffer[12] = ( h >>  8 )&0xff;
02179         out->p_buffer[13] = ( h       )&0xff;
02180         memcpy( &out->p_buffer[RTP_H263_PAYLOAD_START], p_data, i_payload );
02181 
02182         out->i_buffer = RTP_H263_PAYLOAD_START + i_payload;
02183         out->i_dts    = in->i_dts + i * in->i_length / i_count;
02184         out->i_length = in->i_length / i_count;
02185 
02186         rtp_packetize_send( id, out );
02187 
02188         p_data += i_payload;
02189         i_data -= i_payload;
02190     }
02191 
02192     return VLC_SUCCESS;
02193 }
02194 
02195 static int rtp_packetize_amr( sout_stream_t *p_stream, sout_stream_id_t *id,
02196                               block_t *in )
02197 {
02198     int     i_max   = id->i_mtu - 14; /* payload max in one packet */
02199     int     i_count = ( in->i_buffer + i_max - 1 ) / i_max;
02200 
02201     uint8_t *p_data = in->p_buffer;
02202     int     i_data  = in->i_buffer;
02203     int     i;
02204 
02205     /* Only supports octet-aligned mode */
02206     for( i = 0; i < i_count; i++ )
02207     {
02208         int           i_payload = __MIN( i_max, i_data );
02209         block_t *out = block_New( p_stream, 14 + i_payload );
02210 
02211         /* rtp common header */
02212         rtp_packetize_common( id, out, ((i == i_count - 1)?1:0),
02213                               (in->i_pts > 0 ? in->i_pts : in->i_dts) );
02214         /* Payload header */
02215         out->p_buffer[12] = 0xF0; /* CMR */
02216         out->p_buffer[13] = 0x00; /* ToC */ /* FIXME: frame type */
02217 
02218         /* FIXME: are we fed multiple frames ? */
02219         memcpy( &out->p_buffer[14], p_data, i_payload );
02220 
02221         out->i_buffer   = 14 + i_payload;
02222         out->i_dts    = in->i_dts + i * in->i_length / i_count;
02223         out->i_length = in->i_length / i_count;
02224 
02225         rtp_packetize_send( id, out );
02226 
02227         p_data += i_payload;
02228         i_data -= i_payload;
02229     }
02230 
02231     return VLC_SUCCESS;
02232 }

Generated on Tue Dec 20 10:14:49 2005 for vlc-0.8.4a by  doxygen 1.4.2