]> git.sesse.net Git - vlc/blob - modules/stream_out/rtp.c
* provide the SPS and PPS in the SDP when doing h264 packetization (sprop-parameters)
[vlc] / modules / stream_out / rtp.c
1 /*****************************************************************************
2  * rtp.c: rtp stream output module
3  *****************************************************************************
4  * Copyright (C) 2003-2004 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>
28
29 #include <errno.h>
30
31 #include <vlc/vlc.h>
32 #include <vlc/input.h>
33 #include <vlc/sout.h>
34
35 #include "vlc_httpd.h"
36 #include "vlc_url.h"
37 #include "network.h"
38 #include "charset.h"
39
40 /*****************************************************************************
41  * Module descriptor
42  *****************************************************************************/
43
44 #define MTU_REDUCE 50
45
46 #define DST_TEXT N_("Destination")
47 #define DST_LONGTEXT N_( \
48     "This is the output URL that will be used." )
49 #define SDP_TEXT N_("SDP")
50 #define SDP_LONGTEXT N_( \
51     "This allows you to specify how the SDP (Session Descriptor) for this RTP "\
52     "session will be made available. You must use an url: http://location to " \
53     "access the SDP via HTTP, rtsp://location for RTSP access, and sap:// " \
54     "for the SDP to be announced via SAP." )
55 #define MUX_TEXT N_("Muxer")
56 #define MUX_LONGTEXT N_( \
57     "This allows you to specify the muxer used for the streaming output. " \
58     "Default is to use no muxer (standard RTP stream)." )
59
60 #define NAME_TEXT N_("Session name")
61 #define NAME_LONGTEXT N_( \
62     "This is the name of the session that will be announced in the SDP " \
63     "(Session Descriptor)." )
64 #define DESC_TEXT N_("Session description")
65 #define DESC_LONGTEXT N_( \
66     "This allows you to give a broader description of the stream, that will " \
67     "be announced in the SDP (Session Descriptor)." )
68 #define URL_TEXT N_("Session URL")
69 #define URL_LONGTEXT N_( \
70     "This allows you to give an URL with more details about the stream " \
71     "(often the website of the streaming organization), that will " \
72     "be announced in the SDP (Session Descriptor)." )
73 #define EMAIL_TEXT N_("Session email")
74 #define EMAIL_LONGTEXT N_( \
75    "This allows you to give a contact mail address for the stream, that will " \
76    "be announced in the SDP (Session Descriptor)." )
77 #define PORT_TEXT N_("Port")
78 #define PORT_LONGTEXT N_( \
79     "This allows you to specify the base port for the RTP streaming." )
80 #define PORT_AUDIO_TEXT N_("Audio port")
81 #define PORT_AUDIO_LONGTEXT N_( \
82     "This allows you to specify the default audio port for the RTP streaming." )
83 #define PORT_VIDEO_TEXT N_("Video port")
84 #define PORT_VIDEO_LONGTEXT N_( \
85     "This allows you to specify the default video port for the RTP streaming." )
86
87 #define TTL_TEXT N_("Time-To-Live (TTL)")
88 #define TTL_LONGTEXT N_( \
89     "This allows you to specify the Time-To-Live for the output stream." )
90
91 #define RFC3016_TEXT N_("MP4A LATM")
92 #define RFC3016_LONGTEXT N_( \
93     "This allows you to stream MPEG4 LATM audio streams (see RFC3016)." )
94
95 static int  Open ( vlc_object_t * );
96 static void Close( vlc_object_t * );
97
98 #define SOUT_CFG_PREFIX "sout-rtp-"
99
100 vlc_module_begin();
101     set_shortname( _("RTP"));
102     set_description( _("RTP stream output") );
103     set_capability( "sout stream", 0 );
104     add_shortcut( "rtp" );
105     set_category( CAT_SOUT );
106     set_subcategory( SUBCAT_SOUT_STREAM );
107
108     add_string( SOUT_CFG_PREFIX "dst", "", NULL, DST_TEXT,
109                 DST_LONGTEXT, VLC_TRUE );
110     add_string( SOUT_CFG_PREFIX "sdp", "", NULL, SDP_TEXT,
111                 SDP_LONGTEXT, VLC_TRUE );
112     add_string( SOUT_CFG_PREFIX "mux", "", NULL, MUX_TEXT,
113                 MUX_LONGTEXT, VLC_TRUE );
114
115     add_string( SOUT_CFG_PREFIX "name", "NONE", NULL, NAME_TEXT,
116                 NAME_LONGTEXT, VLC_TRUE );
117     add_string( SOUT_CFG_PREFIX "description", "", NULL, DESC_TEXT,
118                 DESC_LONGTEXT, VLC_TRUE );
119     add_string( SOUT_CFG_PREFIX "url", "", NULL, URL_TEXT,
120                 URL_LONGTEXT, VLC_TRUE );
121     add_string( SOUT_CFG_PREFIX "email", "", NULL, EMAIL_TEXT,
122                 EMAIL_LONGTEXT, VLC_TRUE );
123
124     add_integer( SOUT_CFG_PREFIX "port", 1234, NULL, PORT_TEXT,
125                  PORT_LONGTEXT, VLC_TRUE );
126     add_integer( SOUT_CFG_PREFIX "port-audio", 1230, NULL, PORT_AUDIO_TEXT,
127                  PORT_AUDIO_LONGTEXT, VLC_TRUE );
128     add_integer( SOUT_CFG_PREFIX "port-video", 1232, NULL, PORT_VIDEO_TEXT,
129                  PORT_VIDEO_LONGTEXT, VLC_TRUE );
130
131     add_integer( SOUT_CFG_PREFIX "ttl", 0, NULL, TTL_TEXT,
132                  TTL_LONGTEXT, VLC_TRUE );
133
134     add_bool( SOUT_CFG_PREFIX "mp4a-latm", 0, NULL, RFC3016_TEXT,
135                  RFC3016_LONGTEXT, VLC_FALSE );
136
137     set_callbacks( Open, Close );
138 vlc_module_end();
139
140 /*****************************************************************************
141  * Exported prototypes
142  *****************************************************************************/
143 static const char *ppsz_sout_options[] = {
144     "dst", "name", "port", "port-audio", "port-video", "*sdp", "ttl", "mux",
145     "description", "url","email", "mp4a-latm", NULL
146 };
147
148 static sout_stream_id_t *Add ( sout_stream_t *, es_format_t * );
149 static int               Del ( sout_stream_t *, sout_stream_id_t * );
150 static int               Send( sout_stream_t *, sout_stream_id_t *,
151                                block_t* );
152
153 /* For unicast/interleaved streaming */
154 typedef struct
155 {
156     char    *psz_session;
157     int64_t i_last; /* for timeout */
158
159     /* is it in "play" state */
160     vlc_bool_t b_playing;
161
162     /* output (id-access) */
163     int               i_id;
164     sout_stream_id_t  **id;
165     int               i_access;
166     sout_access_out_t **access;
167 } rtsp_client_t;
168
169 struct sout_stream_sys_t
170 {
171     /* sdp */
172     int64_t i_sdp_id;
173     int     i_sdp_version;
174     char    *psz_sdp;
175     vlc_mutex_t  lock_sdp;
176
177     char        *psz_session_name;
178     char        *psz_session_description;
179     char        *psz_session_url;
180     char        *psz_session_email;
181
182     /* */
183     vlc_bool_t b_export_sdp_file;
184     char *psz_sdp_file;
185     /* sap */
186     vlc_bool_t b_export_sap;
187     session_descriptor_t *p_session;
188
189     httpd_host_t *p_httpd_host;
190     httpd_file_t *p_httpd_file;
191
192     httpd_host_t *p_rtsp_host;
193     httpd_url_t  *p_rtsp_url;
194     char         *psz_rtsp_control;
195     char         *psz_rtsp_path;
196
197     /* */
198     char *psz_destination;
199     int  i_port;
200     int  i_port_audio;
201     int  i_port_video;
202     int  i_ttl;
203     vlc_bool_t b_latm;
204
205     /* when need to use a private one or when using muxer */
206     int i_payload_type;
207
208     /* in case we do TS/PS over rtp */
209     sout_mux_t        *p_mux;
210     sout_access_out_t *p_access;
211     int               i_mtu;
212     sout_access_out_t *p_grab;
213     uint16_t          i_sequence;
214     uint32_t          i_timestamp_start;
215     uint8_t           ssrc[4];
216     block_t           *packet;
217
218     /* */
219     vlc_mutex_t      lock_es;
220     int              i_es;
221     sout_stream_id_t **es;
222
223     /* */
224     int              i_rtsp;
225     rtsp_client_t    **rtsp;
226 };
227
228 typedef int (*pf_rtp_packetizer_t)( sout_stream_t *, sout_stream_id_t *,
229                                     block_t * );
230
231 struct sout_stream_id_t
232 {
233     sout_stream_t *p_stream;
234     /* rtp field */
235     uint8_t     i_payload_type;
236     uint16_t    i_sequence;
237     uint32_t    i_timestamp_start;
238     uint8_t     ssrc[4];
239
240     /* for sdp */
241     int         i_clock_rate;
242     char        *psz_rtpmap;
243     char        *psz_fmtp;
244     char        *psz_destination;
245     int         i_port;
246     int         i_cat;
247     int         i_bitrate;
248
249     /* Packetizer specific fields */
250     pf_rtp_packetizer_t pf_packetize;
251     int           i_mtu;
252
253     /* for sending the packets */
254     sout_access_out_t *p_access;
255
256     vlc_mutex_t       lock_rtsp;
257     int               i_rtsp_access;
258     sout_access_out_t **rtsp_access;
259
260     /* */
261     sout_input_t      *p_input;
262
263     /* RTSP url control */
264     httpd_url_t  *p_rtsp_url;
265 };
266
267 static int AccessOutGrabberWrite( sout_access_out_t *, block_t * );
268
269 static void SDPHandleUrl( sout_stream_t *, char * );
270
271 static int SapSetup( sout_stream_t *p_stream );
272 static int FileSetup( sout_stream_t *p_stream );
273 static int HttpSetup( sout_stream_t *p_stream, vlc_url_t * );
274 static int RtspSetup( sout_stream_t *p_stream, vlc_url_t * );
275
276 static int  RtspCallback( httpd_callback_sys_t *, httpd_client_t *,
277                           httpd_message_t *, httpd_message_t * );
278 static int  RtspCallbackId( httpd_callback_sys_t *, httpd_client_t *,
279                             httpd_message_t *, httpd_message_t * );
280
281
282 static rtsp_client_t *RtspClientNew( sout_stream_t *, char *psz_session );
283 static rtsp_client_t *RtspClientGet( sout_stream_t *, char *psz_session );
284 static void           RtspClientDel( sout_stream_t *, rtsp_client_t * );
285
286 /*****************************************************************************
287  * Open:
288  *****************************************************************************/
289 static int Open( vlc_object_t *p_this )
290 {
291     sout_stream_t       *p_stream = (sout_stream_t*)p_this;
292     sout_instance_t     *p_sout = p_stream->p_sout;
293     sout_stream_sys_t   *p_sys = NULL;
294     sout_cfg_t          *p_cfg = NULL;
295     vlc_value_t         val;
296     vlc_bool_t          b_rtsp = VLC_FALSE;
297
298     sout_CfgParse( p_stream, SOUT_CFG_PREFIX, ppsz_sout_options, p_stream->p_cfg );
299
300     p_sys = malloc( sizeof( sout_stream_sys_t ) );
301
302     p_sys->psz_destination = var_GetString( p_stream, SOUT_CFG_PREFIX "dst" );
303     if( *p_sys->psz_destination == '\0' )
304     {
305         free( p_sys->psz_destination );
306         p_sys->psz_destination = NULL;
307     }
308
309     p_sys->psz_session_name = var_GetString( p_stream, SOUT_CFG_PREFIX "name" );
310     p_sys->psz_session_description = var_GetString( p_stream, SOUT_CFG_PREFIX "description" );
311     p_sys->psz_session_url = var_GetString( p_stream, SOUT_CFG_PREFIX "url" );
312     p_sys->psz_session_email = var_GetString( p_stream, SOUT_CFG_PREFIX "email" );
313
314     p_sys->i_port       = var_GetInteger( p_stream, SOUT_CFG_PREFIX "port" );
315     p_sys->i_port_audio = var_GetInteger( p_stream, SOUT_CFG_PREFIX "port-audio" );
316     p_sys->i_port_video = var_GetInteger( p_stream, SOUT_CFG_PREFIX "port-video" );
317
318     p_sys->psz_sdp_file = NULL;
319
320     if( p_sys->i_port_audio == p_sys->i_port_video )
321     {
322         msg_Err( p_stream, "audio and video port cannot be the same" );
323         p_sys->i_port_audio = 0;
324         p_sys->i_port_video = 0;
325     }
326
327     if( !p_sys->psz_session_name )
328     {
329         if( p_sys->psz_destination )
330             p_sys->psz_session_name = strdup( p_sys->psz_destination );
331         else
332            p_sys->psz_session_name = strdup( "NONE" );
333     }
334
335     for( p_cfg = p_stream->p_cfg; p_cfg != NULL; p_cfg = p_cfg->p_next )
336     {
337         if( !strcmp( p_cfg->psz_name, "sdp" ) )
338         {
339             if( p_cfg->psz_value && !strncasecmp( p_cfg->psz_value, "rtsp", 4 ) )
340             {
341                 b_rtsp = VLC_TRUE;
342                 break;
343             }
344         }
345     }
346     if( !b_rtsp )
347     {
348         vlc_value_t val2;
349         var_Get( p_stream, SOUT_CFG_PREFIX "sdp", &val2 );
350         if( !strncasecmp( val2.psz_string, "rtsp", 4 ) )
351             b_rtsp = VLC_TRUE;
352         free( val2.psz_string );
353     }
354
355     if( !p_sys->psz_destination || *p_sys->psz_destination == '\0' )
356     {
357         if( !b_rtsp )
358         {
359             msg_Err( p_stream, "missing destination and not in rtsp mode" );
360             free( p_sys );
361             return VLC_EGENERIC;
362         }
363         p_sys->psz_destination = NULL;
364     }
365     else if( p_sys->i_port <= 0 )
366     {
367         msg_Err( p_stream, "invalid port" );
368         free( p_sys );
369         return VLC_EGENERIC;
370     }
371
372     var_Get( p_stream, SOUT_CFG_PREFIX "ttl", &val );
373     if( val.i_int == 0 )
374     {
375         /* Normally, we should let the default hop limit up to the core,
376          * but we have to know it to build our SDP properly, which is why
377          * we ask the core. FIXME: broken when neither sout-rtp-ttl nor
378          * ttl are set. */
379         val.i_int = config_GetInt( p_stream, "ttl" );
380     }
381     if( val.i_int > 255 ) val.i_int = 255;
382     /* must not exceed 999 once formatted */
383
384     if( val.i_int < 0 )
385     {
386         msg_Err( p_stream, "illegal TTL %d", val.i_int );
387         free( p_sys );
388         return VLC_EGENERIC;
389     }
390     p_sys->i_ttl = val.i_int;
391
392
393     var_Get( p_stream, SOUT_CFG_PREFIX "mp4a-latm", &val );
394     p_sys->b_latm = val.b_bool;
395
396     p_sys->i_payload_type = 96;
397     p_sys->i_es = 0;
398     p_sys->es   = NULL;
399     p_sys->i_rtsp = 0;
400     p_sys->rtsp   = NULL;
401     p_sys->psz_sdp = NULL;
402
403     p_sys->i_sdp_id = mdate();
404     p_sys->i_sdp_version = 1;
405     p_sys->psz_sdp = NULL;
406
407     p_sys->b_export_sap = VLC_FALSE;
408     p_sys->b_export_sdp_file = VLC_FALSE;
409     p_sys->p_session = NULL;
410
411     p_sys->p_httpd_host = NULL;
412     p_sys->p_httpd_file = NULL;
413     p_sys->p_rtsp_host  = NULL;
414     p_sys->p_rtsp_url   = NULL;
415     p_sys->psz_rtsp_control = NULL;
416     p_sys->psz_rtsp_path = NULL;
417
418     vlc_mutex_init( p_stream, &p_sys->lock_sdp );
419     vlc_mutex_init( p_stream, &p_sys->lock_es );
420
421     p_stream->pf_add    = Add;
422     p_stream->pf_del    = Del;
423     p_stream->pf_send   = Send;
424
425     p_stream->p_sys     = p_sys;
426
427     var_Get( p_stream, SOUT_CFG_PREFIX "mux", &val );
428     if( *val.psz_string )
429     {
430         sout_access_out_t *p_grab;
431         char *psz_rtpmap, url[NI_MAXHOST + 8], access[17], psz_ttl[5], ipv;
432
433         if( b_rtsp )
434         {
435             msg_Err( p_stream, "muxing is not supported in RTSP mode" );
436             free( p_sys );
437             return VLC_EGENERIC;
438         }
439         else if( !p_sys->psz_destination || *p_sys->psz_destination == '\0' )
440         {
441             msg_Err( p_stream, "rtp needs a destination when muxing" );
442             free( p_sys );
443             return VLC_EGENERIC;
444         }
445
446         /* Check muxer type */
447         if( !strncasecmp( val.psz_string, "ps", 2 ) || !strncasecmp( val.psz_string, "mpeg1", 5 ) )
448         {
449             psz_rtpmap = "MP2P/90000";
450         }
451         else if( !strncasecmp( val.psz_string, "ts", 2 ) )
452         {
453             psz_rtpmap = "MP2T/90000";
454             p_sys->i_payload_type = 33;
455         }
456         else
457         {
458             msg_Err( p_stream, "unsupported muxer type with rtp (only ts/ps)" );
459             free( p_sys );
460             return VLC_EGENERIC;
461         }
462
463         /* create the access out */
464         if( p_sys->i_ttl > 0 )
465         {
466             sprintf( access, "udp{raw,ttl=%d}", p_sys->i_ttl );
467         }
468         else
469         {
470             sprintf( access, "udp{raw}" );
471         }
472
473         /* IPv6 needs brackets if not already present */
474         snprintf( url, sizeof( url ),
475                   ( ( p_sys->psz_destination[0] != '[' ) 
476                  && ( strchr( p_sys->psz_destination, ':' ) != NULL ) )
477                   ? "[%s]:%d" : "%s:%d", p_sys->psz_destination,
478                   p_sys->i_port );
479         url[sizeof( url ) - 1] = '\0';
480         /* FIXME: we should check that url is a numerical address, otherwise
481          * the SDP will be quite broken (regardless of the IP protocol version)
482          * Also it might be IPv6 with no ':' if it is a DNS name.
483          */
484         ipv = ( strchr( p_sys->psz_destination, ':' ) != NULL ) ? '6' : '4';
485
486         if( !( p_sys->p_access = sout_AccessOutNew( p_sout, access, url ) ) )
487         {
488             msg_Err( p_stream, "cannot create the access out for %s://%s",
489                      access, url );
490             free( p_sys );
491             return VLC_EGENERIC;
492         }
493         p_sys->i_mtu = config_GetInt( p_stream, "mtu" );  /* XXX beurk */
494         if( p_sys->i_mtu <= 16 + MTU_REDUCE )
495         {
496             /* better than nothing */
497             p_sys->i_mtu = 1500;
498         }
499         p_sys->i_mtu -= MTU_REDUCE;
500
501         /* the access out grabber TODO export it as sout_AccessOutGrabberNew */
502         p_grab = p_sys->p_grab =
503             vlc_object_create( p_sout, sizeof( sout_access_out_t ) );
504         p_grab->p_module    = NULL;
505         p_grab->p_sout      = p_sout;
506         p_grab->psz_access  = strdup( "grab" );
507         p_grab->p_cfg       = NULL;
508         p_grab->psz_name    = strdup( "" );
509         p_grab->p_sys       = (sout_access_out_sys_t*)p_stream;
510         p_grab->pf_seek     = NULL;
511         p_grab->pf_write    = AccessOutGrabberWrite;
512
513         /* the muxer */
514         if( !( p_sys->p_mux = sout_MuxNew( p_sout, val.psz_string, p_sys->p_grab ) ) )
515         {
516             msg_Err( p_stream, "cannot create the muxer (%s)", val.psz_string );
517             sout_AccessOutDelete( p_sys->p_grab );
518             sout_AccessOutDelete( p_sys->p_access );
519             free( p_sys );
520             return VLC_EGENERIC;
521         }
522
523         /* create the SDP for a muxed stream (only once) */
524         /* FIXME  http://www.faqs.org/rfcs/rfc2327.html
525            All text fields should be UTF-8 encoded. Use global a:charset to announce this.
526            o= - should be local username (no spaces allowed)
527            o= time should be hashed with some other value to garantue uniqueness
528            o= we need IP6 support?
529            o= don't use the localhost address. use fully qualified domain name or IP4 address
530            p= international phone number (pass via vars?)
531            c= IP6 support
532            a= recvonly (missing)
533            a= type:broadcast (missing)
534            a= charset: (normally charset should be UTF-8, this can be used to override s= and i=)
535            a= x-plgroup: (missing)
536            RTP packets need to get the correct src IP address  */
537         if( net_AddressIsMulticast( (vlc_object_t *)p_stream, p_sys->psz_destination ) )
538         {
539             snprintf( psz_ttl, sizeof( psz_ttl ), "/%d", p_sys->i_ttl );
540             psz_ttl[sizeof( psz_ttl ) - 1] = '\0';
541         }
542         else
543         {
544             psz_ttl[0] = '\0'; 
545         }
546
547         asprintf( &p_sys->psz_sdp,
548                   "v=0\r\n"
549                   /* FIXME: source address not known :( */
550                   "o=- "I64Fd" %d IN IP%c %s\r\n"
551                   "s=%s\r\n"
552                   "i=%s\r\n"
553                   "u=%s\r\n"
554                   "e=%s\r\n"
555                   "t=0 0\r\n" /* permanent stream */ /* when scheduled from vlm, we should set this info correctly */
556                   "a=tool:"PACKAGE_STRING"\r\n"
557                   "c=IN IP%c %s%s\r\n"
558                   "m=video %d RTP/AVP %d\r\n"
559                   "a=rtpmap:%d %s\r\n",
560                   p_sys->i_sdp_id, p_sys->i_sdp_version,
561                   ipv, ipv == '6' ? "::1" : "127.0.0.1" /* FIXME */,
562                   p_sys->psz_session_name,
563                   p_sys->psz_session_description,
564                   p_sys->psz_session_url,
565                   p_sys->psz_session_email,
566                   ipv, p_sys->psz_destination, psz_ttl,
567                   p_sys->i_port, p_sys->i_payload_type,
568                   p_sys->i_payload_type, psz_rtpmap );
569         msg_Dbg( p_stream, "sdp=%s", p_sys->psz_sdp );
570
571         /* create the rtp context */
572         p_sys->ssrc[0] = rand()&0xff;
573         p_sys->ssrc[1] = rand()&0xff;
574         p_sys->ssrc[2] = rand()&0xff;
575         p_sys->ssrc[3] = rand()&0xff;
576         p_sys->i_sequence = rand()&0xffff;
577         p_sys->i_timestamp_start = rand()&0xffffffff;
578         p_sys->packet = NULL;
579     }
580     else
581     {
582         p_sys->p_mux    = NULL;
583         p_sys->p_access = NULL;
584         p_sys->p_grab   = NULL;
585     }
586     free( val.psz_string );
587
588
589     var_Get( p_stream, SOUT_CFG_PREFIX "sdp", &val );
590     if( *val.psz_string )
591     {
592         sout_cfg_t *p_cfg;
593
594         SDPHandleUrl( p_stream, val.psz_string );
595
596         for( p_cfg = p_stream->p_cfg; p_cfg != NULL; p_cfg = p_cfg->p_next )
597         {
598             if( !strcmp( p_cfg->psz_name, "sdp" ) )
599             {
600                 if( p_cfg->psz_value == NULL || *p_cfg->psz_value == '\0' )
601                     continue;
602
603                 if( !strcmp( p_cfg->psz_value, val.psz_string ) )   /* needed both :sout-rtp-sdp= and rtp{sdp=} can be used */
604                     continue;
605
606                 SDPHandleUrl( p_stream, p_cfg->psz_value );
607             }
608         }
609     }
610     free( val.psz_string );
611
612     /* update p_sout->i_out_pace_nocontrol */
613     p_stream->p_sout->i_out_pace_nocontrol++;
614
615     return VLC_SUCCESS;
616 }
617
618 /*****************************************************************************
619  * Close:
620  *****************************************************************************/
621 static void Close( vlc_object_t * p_this )
622 {
623     sout_stream_t     *p_stream = (sout_stream_t*)p_this;
624     sout_stream_sys_t *p_sys = p_stream->p_sys;
625
626     /* update p_sout->i_out_pace_nocontrol */
627     p_stream->p_sout->i_out_pace_nocontrol--;
628
629     if( p_sys->p_mux )
630     {
631         sout_MuxDelete( p_sys->p_mux );
632         sout_AccessOutDelete( p_sys->p_access );
633         sout_AccessOutDelete( p_sys->p_grab );
634         if( p_sys->packet )
635         {
636             block_Release( p_sys->packet );
637         }
638         if( p_sys->b_export_sap )
639         {   
640             p_sys->p_mux = NULL;
641             SapSetup( p_stream );
642         }
643     }
644
645     while( p_sys->i_rtsp > 0 )
646     {
647         RtspClientDel( p_stream, p_sys->rtsp[0] );
648     }
649
650     vlc_mutex_destroy( &p_sys->lock_sdp );
651
652     if( p_sys->p_httpd_file )
653     {
654         httpd_FileDelete( p_sys->p_httpd_file );
655     }
656     if( p_sys->p_httpd_host )
657     {
658         httpd_HostDelete( p_sys->p_httpd_host );
659     }
660     if( p_sys->p_rtsp_url )
661     {
662         httpd_UrlDelete( p_sys->p_rtsp_url );
663     }
664     if( p_sys->p_rtsp_host )
665     {
666         httpd_HostDelete( p_sys->p_rtsp_host );
667     }
668     if( p_sys->psz_session_name )
669     {
670         free( p_sys->psz_session_name );
671         p_sys->psz_session_name = NULL;
672     }
673     if( p_sys->psz_session_description )
674     {
675         free( p_sys->psz_session_description );
676         p_sys->psz_session_description = NULL;
677     }
678     if( p_sys->psz_session_url )
679     {
680         free( p_sys->psz_session_url );
681         p_sys->psz_session_url = NULL;
682     }
683     if( p_sys->psz_session_email )
684     {
685         free( p_sys->psz_session_email );
686         p_sys->psz_session_email = NULL;
687     }
688     if( p_sys->psz_sdp )
689     {
690         free( p_sys->psz_sdp );
691         p_sys->psz_sdp = NULL;
692     }
693     free( p_sys );
694 }
695
696 /*****************************************************************************
697  * SDPHandleUrl:
698  *****************************************************************************/
699 static void SDPHandleUrl( sout_stream_t *p_stream, char *psz_url )
700 {
701     sout_stream_sys_t *p_sys = p_stream->p_sys;
702     vlc_url_t url;
703
704     vlc_UrlParse( &url, psz_url, 0 );
705     if( url.psz_protocol && !strcasecmp( url.psz_protocol, "http" ) )
706     {
707         if( p_sys->p_httpd_file )
708         {
709             msg_Err( p_stream, "you can use sdp=http:// only once" );
710             return;
711         }
712
713         if( HttpSetup( p_stream, &url ) )
714         {
715             msg_Err( p_stream, "cannot export sdp as http" );
716         }
717     }
718     else if( url.psz_protocol && !strcasecmp( url.psz_protocol, "rtsp" ) )
719     {
720         if( p_sys->p_rtsp_url )
721         {
722             msg_Err( p_stream, "you can use sdp=rtsp:// only once" );
723             return;
724         }
725
726         /* FIXME test if destination is multicast or no destination at all FIXME */
727         if( RtspSetup( p_stream, &url ) )
728         {
729             msg_Err( p_stream, "cannot export sdp as rtsp" );
730         }
731     }
732     else if( ( url.psz_protocol && !strcasecmp( url.psz_protocol, "sap" ) ) || 
733              ( url.psz_host && !strcasecmp( url.psz_host, "sap" ) ) )
734     {
735         p_sys->b_export_sap = VLC_TRUE;
736         SapSetup( p_stream );
737     }
738     else if( url.psz_protocol && !strcasecmp( url.psz_protocol, "file" ) )
739     {
740         if( p_sys->b_export_sdp_file )
741         {
742             msg_Err( p_stream, "you can use sdp=file:// only once" );
743             return;
744         }
745         p_sys->b_export_sdp_file = VLC_TRUE;
746         psz_url = &psz_url[5];
747         if( psz_url[0] == '/' && psz_url[1] == '/' )
748             psz_url += 2;
749         p_sys->psz_sdp_file = strdup( psz_url );
750     }
751     else
752     {
753         msg_Warn( p_stream, "unknown protocol for SDP (%s)",
754                   url.psz_protocol );
755     }
756     vlc_UrlClean( &url );
757 }
758
759 /*****************************************************************************
760  * SDPGenerate
761  *****************************************************************************/
762         /* FIXME  http://www.faqs.org/rfcs/rfc2327.html
763            All text fields should be UTF-8 encoded. Use global a:charset to announce this.
764            o= - should be local username (no spaces allowed)
765            o= time should be hashed with some other value to garantue uniqueness
766            o= we need IP6 support?
767            o= don't use the localhost address. use fully qualified domain name or IP4 address
768            p= international phone number (pass via vars?)
769            c= IP6 support
770            a= recvonly (missing)
771            a= type:broadcast (missing)
772            a= charset: (normally charset should be UTF-8, this can be used to override s= and i=)
773            a= x-plgroup: (missing)
774            RTP packets need to get the correct src IP address  */
775 static char *SDPGenerate( const sout_stream_t *p_stream,
776                           const char *psz_destination, vlc_bool_t b_rtsp )
777 {
778     sout_stream_sys_t *p_sys = p_stream->p_sys;
779     int i_size;
780     char *psz_sdp, *p, ipv;
781     int i;
782
783     /* FIXME: breaks IP version check on unknown destination */
784     if( psz_destination == NULL )
785         psz_destination = "0.0.0.0";
786
787     i_size = sizeof( "v=0\r\n" ) +
788              sizeof( "o=- * * IN IP4 127.0.0.1\r\n" ) + 10 + 10 +
789              sizeof( "s=*\r\n" ) + strlen( p_sys->psz_session_name ) +
790              sizeof( "i=*\r\n" ) + strlen( p_sys->psz_session_description ) +
791              sizeof( "u=*\r\n" ) + strlen( p_sys->psz_session_url ) +
792              sizeof( "e=*\r\n" ) + strlen( p_sys->psz_session_email ) +
793              sizeof( "t=0 0\r\n" ) + /* permanent stream */ /* when scheduled from vlm, we should set this info correctly */
794              sizeof( "a=tool:"PACKAGE_STRING"\r\n" ) +
795              sizeof( "c=IN IP4 */*\r\n" ) + 20 + 10 +
796              strlen( psz_destination ) ;
797     for( i = 0; i < p_sys->i_es; i++ )
798     {
799         sout_stream_id_t *id = p_sys->es[i];
800
801         i_size += strlen( "m=**d*o * RTP/AVP *\r\n" ) + 10 + 10;
802         if( id->psz_rtpmap )
803         {
804             i_size += strlen( "a=rtpmap:* *\r\n" ) + strlen( id->psz_rtpmap )+10;
805         }
806         if( id->psz_fmtp )
807         {
808             i_size += strlen( "a=fmtp:* *\r\n" ) + strlen( id->psz_fmtp ) + 10;
809         }
810         if ( id->i_bitrate)
811         {
812             i_size += strlen( "b=AS: *\r\n") + 10;
813         }
814         if( b_rtsp )
815         {
816             i_size += strlen( "a=control:*/trackID=*\r\n" ) + strlen( p_sys->psz_rtsp_control ) + 10;
817         }
818     }
819     if( p_sys->p_mux )
820     {
821         i_size += strlen( "m=video %d RTP/AVP %d\r\n" ) +10 +10;
822     }
823
824     ipv = ( strchr( psz_destination, ':' ) != NULL ) ? '6' : '4';
825
826     p = psz_sdp = malloc( i_size );
827     p += sprintf( p, "v=0\r\n" );
828     p += sprintf( p, "o=- "I64Fd" %d IN IP%c %s\r\n",
829                   p_sys->i_sdp_id, p_sys->i_sdp_version,
830                   ipv, ipv == '6' ? "::" : "127.0.0.1" );
831     if( *p_sys->psz_session_name )
832         p += sprintf( p, "s=%s\r\n", p_sys->psz_session_name );
833     if( *p_sys->psz_session_description )
834         p += sprintf( p, "i=%s\r\n", p_sys->psz_session_description );
835     if( *p_sys->psz_session_url )
836         p += sprintf( p, "u=%s\r\n", p_sys->psz_session_url );
837     if( *p_sys->psz_session_email )
838         p += sprintf( p, "e=%s\r\n", p_sys->psz_session_email );
839
840     p += sprintf( p, "t=0 0\r\n" ); /* permanent stream */ /* when scheduled from vlm, we should set this info correctly */
841     p += sprintf( p, "a=tool:"PACKAGE_STRING"\r\n" );
842
843     p += sprintf( p, "c=IN IP%c %s", ipv, psz_destination );
844
845     if( net_AddressIsMulticast( (vlc_object_t *)p_stream, psz_destination ) )
846     {
847         /* Add the ttl if it is a multicast address */
848         /* FIXME: 1 is not a correct default value in the case of IPv6 */
849         p += sprintf( p, "/%d\r\n", p_sys->i_ttl ?: 1 );
850     }
851     else
852     {
853         p += sprintf( p, "\r\n" );
854     }
855
856     for( i = 0; i < p_sys->i_es; i++ )
857     {
858         sout_stream_id_t *id = p_sys->es[i];
859
860         if( id->i_cat == AUDIO_ES )
861         {
862             p += sprintf( p, "m=audio %d RTP/AVP %d\r\n",
863                           id->i_port, id->i_payload_type );
864         }
865         else if( id->i_cat == VIDEO_ES )
866         {
867             p += sprintf( p, "m=video %d RTP/AVP %d\r\n",
868                           id->i_port, id->i_payload_type );
869         }
870         else
871         {
872             continue;
873         }
874         if( id->psz_rtpmap )
875         {
876             p += sprintf( p, "a=rtpmap:%d %s\r\n", id->i_payload_type,
877                           id->psz_rtpmap );
878         }
879         if( id->psz_fmtp )
880         {
881             p += sprintf( p, "a=fmtp:%d %s\r\n", id->i_payload_type,
882                           id->psz_fmtp );
883         }
884         if ( id->i_bitrate)
885         {
886             p += sprintf(p,"b=AS:%d\r\n",id->i_bitrate);
887         }
888         if( b_rtsp )
889         {
890             p += sprintf( p, "a=control:trackID=%d\r\n", i );
891         }
892     }
893     if( p_sys->p_mux )
894     {
895        p += sprintf( p, "m=video %d RTP/AVP %d\r\n",
896                  p_sys->i_port, p_sys->i_payload_type );
897     }
898
899     return psz_sdp;
900 }
901
902 /*****************************************************************************
903  *
904  *****************************************************************************/
905 static int rtp_packetize_l16  ( sout_stream_t *, sout_stream_id_t *, block_t * );
906 static int rtp_packetize_l8   ( sout_stream_t *, sout_stream_id_t *, block_t * );
907 static int rtp_packetize_mpa  ( sout_stream_t *, sout_stream_id_t *, block_t * );
908 static int rtp_packetize_mpv  ( sout_stream_t *, sout_stream_id_t *, block_t * );
909 static int rtp_packetize_ac3  ( sout_stream_t *, sout_stream_id_t *, block_t * );
910 static int rtp_packetize_split( sout_stream_t *, sout_stream_id_t *, block_t * );
911 static int rtp_packetize_mp4a ( sout_stream_t *, sout_stream_id_t *, block_t * );
912 static int rtp_packetize_mp4a_latm ( sout_stream_t *, sout_stream_id_t *, block_t * );
913 static int rtp_packetize_h263 ( sout_stream_t *, sout_stream_id_t *, block_t * );
914 static int rtp_packetize_h264 ( sout_stream_t *, sout_stream_id_t *, block_t * );
915 static int rtp_packetize_amr  ( sout_stream_t *, sout_stream_id_t *, block_t * );
916
917 static void sprintf_hexa( char *s, uint8_t *p_data, int i_data )
918 {
919     static const char hex[16] = "0123456789abcdef";
920     int i;
921
922     for( i = 0; i < i_data; i++ )
923     {
924         s[2*i+0] = hex[(p_data[i]>>4)&0xf];
925         s[2*i+1] = hex[(p_data[i]   )&0xf];
926     }
927     s[2*i_data] = '\0';
928 }
929
930 static const char basis_64[] =
931     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
932
933 int ap_base64encode_len(int len)
934 {
935     return ((len + 2) / 3 * 4) + 1;
936 }
937
938 int ap_base64encode_binary(char *encoded,
939                                        const unsigned char *string, int len)
940 {
941     int i;
942     char *p;
943
944     p = encoded;
945     for (i = 0; i < len - 2; i += 3) {
946         *p++ = basis_64[(string[i] >> 2) & 0x3F];
947         *p++ = basis_64[((string[i] & 0x3) << 4) |
948                         ((int) (string[i + 1] & 0xF0) >> 4)];
949         *p++ = basis_64[((string[i + 1] & 0xF) << 2) |
950                         ((int) (string[i + 2] & 0xC0) >> 6)];
951         *p++ = basis_64[string[i + 2] & 0x3F];
952     }
953     if (i < len) {
954         *p++ = basis_64[(string[i] >> 2) & 0x3F];
955         if (i == (len - 1)) {
956             *p++ = basis_64[((string[i] & 0x3) << 4)];
957             *p++ = '=';
958         }
959         else {
960             *p++ = basis_64[((string[i] & 0x3) << 4) |
961                             ((int) (string[i + 1] & 0xF0) >> 4)];
962             *p++ = basis_64[((string[i + 1] & 0xF) << 2)];
963         }
964         *p++ = '=';
965     }
966
967     *p++ = '\0';
968     return p - encoded;
969 }
970
971 int ap_base64encode(char *encoded, const char *string, int len)
972 {
973     return ap_base64encode_binary(encoded, (const unsigned char *) string, len);
974 }
975
976 char *b64_encode(char *buf, int len)
977 {
978     int elen;
979     char *out;
980
981     if(len == 0)
982         len = strlen(buf);
983
984     elen = ap_base64encode_len(len);
985     out = (char *) malloc(sizeof(char) * (elen + 1));
986
987     ap_base64encode(out, buf, len);
988
989     return out;
990 }
991
992 static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
993 {
994     sout_instance_t   *p_sout = p_stream->p_sout;
995     sout_stream_sys_t *p_sys = p_stream->p_sys;
996     sout_stream_id_t  *id;
997     sout_access_out_t *p_access = NULL;
998     int               i_port;
999     char              *psz_sdp;
1000
1001     if( p_sys->p_mux != NULL )
1002     {
1003         sout_input_t      *p_input  = NULL;
1004         if( ( p_input = sout_MuxAddStream( p_sys->p_mux, p_fmt ) ) == NULL )
1005         {
1006             msg_Err( p_stream, "cannot add this stream to the muxer" );
1007             return NULL;
1008         }
1009
1010         id = malloc( sizeof( sout_stream_id_t ) );
1011         memset( id, 0, sizeof( sout_stream_id_t ) );
1012         id->p_access    = NULL;
1013         id->p_input     = p_input;
1014         id->pf_packetize= NULL;
1015         id->p_rtsp_url  = NULL;
1016         id->i_port      = 0;
1017         return id;
1018     }
1019
1020
1021     /* Choose the port */
1022     i_port = 0;
1023     if( p_fmt->i_cat == AUDIO_ES && p_sys->i_port_audio > 0 )
1024     {
1025         i_port = p_sys->i_port_audio;
1026         p_sys->i_port_audio = 0;
1027     }
1028     else if( p_fmt->i_cat == VIDEO_ES && p_sys->i_port_video > 0 )
1029     {
1030         i_port = p_sys->i_port_video;
1031         p_sys->i_port_video = 0;
1032     }
1033     while( i_port == 0 )
1034     {
1035         if( p_sys->i_port != p_sys->i_port_audio && p_sys->i_port != p_sys->i_port_video )
1036         {
1037             i_port = p_sys->i_port;
1038             p_sys->i_port += 2;
1039             break;
1040         }
1041         p_sys->i_port += 2;
1042     }
1043
1044     if( p_sys->psz_destination )
1045     {
1046         char access[17];
1047         char url[NI_MAXHOST + 8];
1048
1049         /* first try to create the access out */
1050         if( p_sys->i_ttl )
1051         {
1052             snprintf( access, sizeof( access ), "udp{raw,ttl=%d}",
1053                       p_sys->i_ttl );
1054             access[sizeof( access ) - 1] = '\0';
1055         }
1056         else
1057             strcpy( access, "udp{raw}" );
1058
1059         snprintf( url, sizeof( url ), (( p_sys->psz_destination[0] != '[' ) &&
1060                  strchr( p_sys->psz_destination, ':' )) ? "[%s]:%d" : "%s:%d",
1061                  p_sys->psz_destination, i_port );
1062         url[sizeof( url ) - 1] = '\0';
1063
1064         if( ( p_access = sout_AccessOutNew( p_sout, access, url ) ) == NULL )
1065         {
1066             msg_Err( p_stream, "cannot create the access out for %s://%s",
1067                      access, url );
1068             return NULL;
1069         }
1070         msg_Dbg( p_stream, "access out %s:%s", access, url );
1071     }
1072
1073     /* not create the rtp specific stuff */
1074     id = malloc( sizeof( sout_stream_id_t ) );
1075     memset( id, 0, sizeof( sout_stream_id_t ) );
1076     id->p_stream   = p_stream;
1077     id->p_access   = p_access;
1078     id->p_input    = NULL;
1079     id->psz_rtpmap = NULL;
1080     id->psz_fmtp   = NULL;
1081     id->psz_destination = p_sys->psz_destination ? strdup( p_sys->psz_destination ) : NULL;
1082     id->i_port = i_port;
1083     id->p_rtsp_url = NULL;
1084     vlc_mutex_init( p_stream, &id->lock_rtsp );
1085     id->i_rtsp_access = 0;
1086     id->rtsp_access = NULL;
1087
1088     switch( p_fmt->i_codec )
1089     {
1090         case VLC_FOURCC( 's', '1', '6', 'b' ):
1091             if( p_fmt->audio.i_channels == 1 && p_fmt->audio.i_rate == 44100 )
1092             {
1093                 id->i_payload_type = 11;
1094             }
1095             else if( p_fmt->audio.i_channels == 2 &&
1096                      p_fmt->audio.i_rate == 44100 )
1097             {
1098                 id->i_payload_type = 10;
1099             }
1100             else
1101             {
1102                 id->i_payload_type = p_sys->i_payload_type++;
1103             }
1104             id->psz_rtpmap = malloc( strlen( "L16/*/*" ) + 20+1 );
1105             sprintf( id->psz_rtpmap, "L16/%d/%d", p_fmt->audio.i_rate,
1106                      p_fmt->audio.i_channels );
1107             id->i_clock_rate = p_fmt->audio.i_rate;
1108             id->pf_packetize = rtp_packetize_l16;
1109             break;
1110         case VLC_FOURCC( 'u', '8', ' ', ' ' ):
1111             id->i_payload_type = p_sys->i_payload_type++;
1112             id->psz_rtpmap = malloc( strlen( "L8/*/*" ) + 20+1 );
1113             sprintf( id->psz_rtpmap, "L8/%d/%d", p_fmt->audio.i_rate,
1114                      p_fmt->audio.i_channels );
1115             id->i_clock_rate = p_fmt->audio.i_rate;
1116             id->pf_packetize = rtp_packetize_l8;
1117             break;
1118         case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
1119             id->i_payload_type = 14;
1120             id->i_clock_rate = 90000;
1121             id->psz_rtpmap = strdup( "MPA/90000" );
1122             id->pf_packetize = rtp_packetize_mpa;
1123             break;
1124         case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
1125             id->i_payload_type = 32;
1126             id->i_clock_rate = 90000;
1127             id->psz_rtpmap = strdup( "MPV/90000" );
1128             id->pf_packetize = rtp_packetize_mpv;
1129             break;
1130         case VLC_FOURCC( 'a', '5', '2', ' ' ):
1131             id->i_payload_type = p_sys->i_payload_type++;
1132             id->i_clock_rate = 90000;
1133             id->psz_rtpmap = strdup( "ac3/90000" );
1134             id->pf_packetize = rtp_packetize_ac3;
1135             break;
1136         case VLC_FOURCC( 'H', '2', '6', '3' ):
1137             id->i_payload_type = p_sys->i_payload_type++;
1138             id->i_clock_rate = 90000;
1139             id->psz_rtpmap = strdup( "H263-1998/90000" );
1140             id->pf_packetize = rtp_packetize_h263;
1141             break;
1142         case VLC_FOURCC( 'h', '2', '6', '4' ):
1143             id->i_payload_type = p_sys->i_payload_type++;
1144             id->i_clock_rate = 90000;
1145             id->psz_rtpmap = strdup( "H264/90000" );
1146             id->pf_packetize = rtp_packetize_h264;
1147             if( p_fmt->i_extra > 0 )
1148             {
1149                 uint8_t *p_buffer = p_fmt->p_extra;
1150                 int     i_buffer = p_fmt->i_extra;
1151                 char    *p_64_sps;
1152                 char    *p_64_pps;
1153                 char    hexa[6];
1154                 
1155                 while( i_buffer > 4 && 
1156                     p_buffer[0] == 0 && p_buffer[1] == 0 &&
1157                     p_buffer[2] == 0 && p_buffer[3] == 1 )
1158                 {
1159                     const int i_nal_type = p_buffer[4]&0x1f;
1160                     int i_offset    = 1;
1161                     int i_size      = 0;
1162                     int i_startcode = 0;
1163                     int i_encoded   = 0;
1164                     
1165                     msg_Dbg( p_stream, "we found a startcode for NAL with TYPE:%d", i_nal_type );
1166                     
1167                     for( i_offset = 1; i_offset+3 < i_buffer ; i_offset++)
1168                     {
1169                         if( p_buffer[i_offset] == 0 && p_buffer[i_offset+1] == 0 && p_buffer[i_offset+2] == 0 && p_buffer[i_offset+3] == 1 )
1170                         {
1171                             /* we found another startcode */
1172                             i_startcode = i_offset;
1173                             break;
1174                         } 
1175                     }
1176                     i_size = i_startcode ? i_startcode : i_buffer;
1177                     if( i_nal_type == 7 )
1178                     {
1179                         p_64_sps = (char *)malloc( ap_base64encode_len( i_size - 4) );
1180                         i_encoded = ap_base64encode_binary( p_64_sps, &p_buffer[4], i_size - 4 );
1181                         p_64_sps[i_encoded] = '\0';
1182                         sprintf_hexa( hexa, &p_buffer[5], 3 );
1183                         hexa[6] = '\0'; 
1184                     }
1185                     if( i_nal_type == 8 )
1186                     {
1187                         p_64_pps = (char *)malloc( ap_base64encode_len( i_size - 4) );
1188                         i_encoded = ap_base64encode_binary( p_64_pps, &p_buffer[4], i_size - 4 );
1189                         p_64_pps[i_encoded] = '\0';
1190                     }
1191                     i_buffer -= i_size;
1192                     p_buffer += i_size;
1193                 }
1194                 /* FIXME: All this is a bit unsafe */
1195                 asprintf( &id->psz_fmtp, "packetization-mode=1;profile-level-id=%s;sprop-parameter-sets=%s,%s;", hexa, p_64_sps, p_64_pps );
1196                 free( p_64_sps );
1197                 free( p_64_pps );
1198             }
1199             else
1200                 id->psz_fmtp = strdup( "packetization-mode=1" );
1201             break;
1202
1203         case VLC_FOURCC( 'm', 'p', '4', 'v' ):
1204         {
1205             char hexa[2*p_fmt->i_extra +1];
1206
1207             id->i_payload_type = p_sys->i_payload_type++;
1208             id->i_clock_rate = 90000;
1209             id->psz_rtpmap = strdup( "MP4V-ES/90000" );
1210             id->pf_packetize = rtp_packetize_split;
1211             if( p_fmt->i_extra > 0 )
1212             {
1213                 id->psz_fmtp = malloc( 100 + 2 * p_fmt->i_extra );
1214                 sprintf_hexa( hexa, p_fmt->p_extra, p_fmt->i_extra );
1215                 sprintf( id->psz_fmtp,
1216                          "profile-level-id=3; config=%s;", hexa );
1217             }
1218             break;
1219         }
1220         case VLC_FOURCC( 'm', 'p', '4', 'a' ):
1221         {
1222             id->i_payload_type = p_sys->i_payload_type++;
1223             id->i_clock_rate = p_fmt->audio.i_rate;
1224
1225             if(!p_sys->b_latm)
1226             {
1227                 char hexa[2*p_fmt->i_extra +1];
1228
1229                 id->psz_rtpmap = malloc( strlen( "mpeg4-generic/" ) + 12 );
1230                 sprintf( id->psz_rtpmap, "mpeg4-generic/%d", p_fmt->audio.i_rate );
1231                 id->pf_packetize = rtp_packetize_mp4a;
1232                 id->psz_fmtp = malloc( 200 + 2 * p_fmt->i_extra );
1233                 sprintf_hexa( hexa, p_fmt->p_extra, p_fmt->i_extra );
1234                 sprintf( id->psz_fmtp,
1235                         "streamtype=5; profile-level-id=15; mode=AAC-hbr; "
1236                         "config=%s; SizeLength=13;IndexLength=3; "
1237                         "IndexDeltaLength=3; Profile=1;", hexa );
1238             }
1239             else
1240             {
1241                 char hexa[13];
1242                 int i;
1243                 unsigned char config[6];
1244                 unsigned int aacsrates[15] = {
1245                     96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
1246                     16000, 12000, 11025, 8000, 7350, 0, 0 };
1247
1248                 for( i = 0; i < 15; i++ )
1249                     if( p_fmt->audio.i_rate == aacsrates[i] )
1250                         break;
1251
1252                 config[0]=0x40;
1253                 config[1]=0;
1254                 config[2]=0x20|i;
1255                 config[3]=p_fmt->audio.i_channels<<4;
1256                 config[4]=0x3f;
1257                 config[5]=0xc0;
1258
1259                 asprintf( &id->psz_rtpmap, "MP4A-LATM/%d/%d",
1260                           p_fmt->audio.i_rate, p_fmt->audio.i_channels );
1261                 id->pf_packetize = rtp_packetize_mp4a_latm;
1262                 sprintf_hexa( hexa, config, 6 );
1263                 asprintf( &id->psz_fmtp, "profile-level-id=15; "
1264                           "object=2; cpresent=0; config=%s", hexa );
1265             }
1266             break;
1267         }
1268         case VLC_FOURCC( 's', 'a', 'm', 'r' ):
1269             id->i_payload_type = p_sys->i_payload_type++;
1270             id->psz_rtpmap = strdup( p_fmt->audio.i_channels == 2 ?
1271                                      "AMR/8000/2" : "AMR/8000" );
1272             id->psz_fmtp = strdup( "octet-align=1" );
1273             id->i_clock_rate = p_fmt->audio.i_rate;
1274             id->pf_packetize = rtp_packetize_amr;
1275             break; 
1276         case VLC_FOURCC( 's', 'a', 'w', 'b' ):
1277             id->i_payload_type = p_sys->i_payload_type++;
1278             id->psz_rtpmap = strdup( p_fmt->audio.i_channels == 2 ?
1279                                      "AMR-WB/16000/2" : "AMR-WB/16000" );
1280             id->psz_fmtp = strdup( "octet-align=1" );
1281             id->i_clock_rate = p_fmt->audio.i_rate;
1282             id->pf_packetize = rtp_packetize_amr;
1283             break; 
1284
1285         default:
1286             msg_Err( p_stream, "cannot add this stream (unsupported "
1287                      "codec:%4.4s)", (char*)&p_fmt->i_codec );
1288             if( p_access )
1289             {
1290                 sout_AccessOutDelete( p_access );
1291             }
1292             free( id );
1293             return NULL;
1294     }
1295     id->i_cat = p_fmt->i_cat;
1296
1297     id->ssrc[0] = rand()&0xff;
1298     id->ssrc[1] = rand()&0xff;
1299     id->ssrc[2] = rand()&0xff;
1300     id->ssrc[3] = rand()&0xff;
1301     id->i_sequence = rand()&0xffff;
1302     id->i_timestamp_start = rand()&0xffffffff;
1303     id->i_bitrate = p_fmt->i_bitrate/1000; /* Stream bitrate in kbps */
1304
1305     id->i_mtu    = config_GetInt( p_stream, "mtu" );  /* XXX beuk */
1306     if( id->i_mtu <= 16 + MTU_REDUCE )
1307     {
1308         /* better than nothing */
1309         id->i_mtu = 1500;
1310     }
1311     id->i_mtu -= MTU_REDUCE;
1312     msg_Dbg( p_stream, "maximum RTP packet size: %d bytes", id->i_mtu );
1313
1314     if( p_sys->p_rtsp_url )
1315     {
1316         char psz_urlc[strlen( p_sys->psz_rtsp_control ) + 1 + 10];
1317
1318         sprintf( psz_urlc, "%s/trackID=%d", p_sys->psz_rtsp_path, p_sys->i_es );
1319         msg_Dbg( p_stream, "rtsp: adding %s\n", psz_urlc );
1320         id->p_rtsp_url = httpd_UrlNewUnique( p_sys->p_rtsp_host, psz_urlc, NULL, NULL, NULL );
1321
1322         if( id->p_rtsp_url )
1323         {
1324             httpd_UrlCatch( id->p_rtsp_url, HTTPD_MSG_SETUP,    RtspCallbackId, (void*)id );
1325             //httpd_UrlCatch( id->p_rtsp_url, HTTPD_MSG_PLAY,     RtspCallback, (void*)p_stream );
1326             //httpd_UrlCatch( id->p_rtsp_url, HTTPD_MSG_PAUSE,    RtspCallback, (void*)p_stream );
1327         }
1328     }
1329
1330
1331     /* Update p_sys context */
1332     vlc_mutex_lock( &p_sys->lock_es );
1333     TAB_APPEND( p_sys->i_es, p_sys->es, id );
1334     vlc_mutex_unlock( &p_sys->lock_es );
1335
1336     psz_sdp = SDPGenerate( p_stream, p_sys->psz_destination, VLC_FALSE );
1337
1338     vlc_mutex_lock( &p_sys->lock_sdp );
1339     free( p_sys->psz_sdp );
1340     p_sys->psz_sdp = psz_sdp;
1341     vlc_mutex_unlock( &p_sys->lock_sdp );
1342
1343     p_sys->i_sdp_version++;
1344
1345     msg_Dbg( p_stream, "sdp=%s", p_sys->psz_sdp );
1346
1347     /* Update SDP (sap/file) */
1348     if( p_sys->b_export_sap ) SapSetup( p_stream );
1349     if( p_sys->b_export_sdp_file ) FileSetup( p_stream );
1350
1351     return id;
1352 }
1353
1354 static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
1355 {
1356     sout_stream_sys_t *p_sys = p_stream->p_sys;
1357
1358     vlc_mutex_lock( &p_sys->lock_es );
1359     TAB_REMOVE( p_sys->i_es, p_sys->es, id );
1360     vlc_mutex_unlock( &p_sys->lock_es );
1361
1362     /* Release port */
1363     if( id->i_port > 0 )
1364     {
1365         if( id->i_cat == AUDIO_ES && p_sys->i_port_audio == 0 )
1366             p_sys->i_port_audio = id->i_port;
1367         else if( id->i_cat == VIDEO_ES && p_sys->i_port_video == 0 )
1368             p_sys->i_port_video = id->i_port;
1369     }
1370
1371     if( id->p_access )
1372     {
1373         if( id->psz_rtpmap )
1374         {
1375             free( id->psz_rtpmap );
1376         }
1377         if( id->psz_fmtp )
1378         {
1379             free( id->psz_fmtp );
1380         }
1381         if( id->psz_destination )
1382             free( id->psz_destination );
1383         sout_AccessOutDelete( id->p_access );
1384     }
1385     else if( id->p_input )
1386     {
1387         sout_MuxDeleteStream( p_sys->p_mux, id->p_input );
1388     }
1389     if( id->p_rtsp_url )
1390     {
1391         httpd_UrlDelete( id->p_rtsp_url );
1392     }
1393     vlc_mutex_destroy( &id->lock_rtsp );
1394     if( id->rtsp_access ) free( id->rtsp_access );
1395
1396     /* Update SDP (sap/file) */
1397     if( p_sys->b_export_sap && !p_sys->p_mux ) SapSetup( p_stream );
1398     if( p_sys->b_export_sdp_file ) FileSetup( p_stream );
1399
1400     free( id );
1401     return VLC_SUCCESS;
1402 }
1403
1404 static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
1405                  block_t *p_buffer )
1406 {
1407     block_t *p_next;
1408
1409     if( p_stream->p_sys->p_mux )
1410     {
1411         sout_MuxSendBuffer( p_stream->p_sys->p_mux, id->p_input, p_buffer );
1412     }
1413     else
1414     {
1415         while( p_buffer )
1416         {
1417             p_next = p_buffer->p_next;
1418             if( id->pf_packetize( p_stream, id, p_buffer ) )
1419             {
1420                 break;
1421             }
1422             block_Release( p_buffer );
1423             p_buffer = p_next;
1424         }
1425     }
1426     return VLC_SUCCESS;
1427 }
1428
1429
1430 static int AccessOutGrabberWriteBuffer( sout_stream_t *p_stream,
1431                                         block_t *p_buffer )
1432 {
1433     sout_stream_sys_t *p_sys = p_stream->p_sys;
1434
1435     int64_t  i_dts = p_buffer->i_dts;
1436     uint32_t i_timestamp = i_dts * 9 / 100;
1437
1438     uint8_t         *p_data = p_buffer->p_buffer;
1439     unsigned int    i_data  = p_buffer->i_buffer;
1440     unsigned int    i_max   = p_sys->i_mtu - 12;
1441
1442     unsigned i_packet = ( p_buffer->i_buffer + i_max - 1 ) / i_max;
1443
1444     while( i_data > 0 )
1445     {
1446         unsigned int i_size;
1447
1448         /* output complete packet */
1449         if( p_sys->packet &&
1450             p_sys->packet->i_buffer + i_data > i_max )
1451         {
1452             sout_AccessOutWrite( p_sys->p_access, p_sys->packet );
1453             p_sys->packet = NULL;
1454         }
1455
1456         if( p_sys->packet == NULL )
1457         {
1458             /* allocate a new packet */
1459             p_sys->packet = block_New( p_stream, p_sys->i_mtu );
1460             p_sys->packet->p_buffer[ 0] = 0x80;
1461             p_sys->packet->p_buffer[ 1] = 0x80|p_sys->i_payload_type;
1462             p_sys->packet->p_buffer[ 2] = ( p_sys->i_sequence >> 8)&0xff;
1463             p_sys->packet->p_buffer[ 3] = ( p_sys->i_sequence     )&0xff;
1464             p_sys->packet->p_buffer[ 4] = ( i_timestamp >> 24 )&0xff;
1465             p_sys->packet->p_buffer[ 5] = ( i_timestamp >> 16 )&0xff;
1466             p_sys->packet->p_buffer[ 6] = ( i_timestamp >>  8 )&0xff;
1467             p_sys->packet->p_buffer[ 7] = ( i_timestamp       )&0xff;
1468             p_sys->packet->p_buffer[ 8] = p_sys->ssrc[0];
1469             p_sys->packet->p_buffer[ 9] = p_sys->ssrc[1];
1470             p_sys->packet->p_buffer[10] = p_sys->ssrc[2];
1471             p_sys->packet->p_buffer[11] = p_sys->ssrc[3];
1472             p_sys->packet->i_buffer = 12;
1473
1474             p_sys->packet->i_dts = i_dts;
1475             p_sys->packet->i_length = p_buffer->i_length / i_packet;
1476             i_dts += p_sys->packet->i_length;
1477
1478             p_sys->i_sequence++;
1479         }
1480
1481         i_size = __MIN( i_data,
1482                         (unsigned)(p_sys->i_mtu - p_sys->packet->i_buffer) );
1483
1484         memcpy( &p_sys->packet->p_buffer[p_sys->packet->i_buffer],
1485                 p_data, i_size );
1486
1487         p_sys->packet->i_buffer += i_size;
1488         p_data += i_size;
1489         i_data -= i_size;
1490     }
1491
1492     return VLC_SUCCESS;
1493 }
1494
1495 static int AccessOutGrabberWrite( sout_access_out_t *p_access,
1496                                   block_t *p_buffer )
1497 {
1498     sout_stream_t *p_stream = (sout_stream_t*)p_access->p_sys;
1499
1500     //fprintf( stderr, "received buffer size=%d\n", p_buffer->i_buffer );
1501     //
1502     while( p_buffer )
1503     {
1504         block_t *p_next;
1505
1506         AccessOutGrabberWriteBuffer( p_stream, p_buffer );
1507
1508         p_next = p_buffer->p_next;
1509         block_Release( p_buffer );
1510         p_buffer = p_next;
1511     }
1512
1513     return VLC_SUCCESS;
1514 }
1515
1516 /****************************************************************************
1517  * SAP:
1518  ****************************************************************************/
1519 static int SapSetup( sout_stream_t *p_stream )
1520 {
1521     sout_stream_sys_t *p_sys = p_stream->p_sys;
1522     sout_instance_t   *p_sout = p_stream->p_sout;
1523     announce_method_t *p_method = sout_AnnounceMethodCreate( METHOD_TYPE_SAP );
1524
1525     /* Remove the previous session */
1526     if( p_sys->p_session != NULL)
1527     {
1528         sout_AnnounceUnRegister( p_sout, p_sys->p_session);
1529         sout_AnnounceSessionDestroy( p_sys->p_session );
1530         p_sys->p_session = NULL;
1531     }
1532
1533     if( ( p_sys->i_es > 0 || p_sys->p_mux ) && p_sys->psz_sdp && *p_sys->psz_sdp )
1534     {
1535         p_sys->p_session = sout_AnnounceRegisterSDP( p_sout, p_sys->psz_sdp,
1536                                                      p_sys->psz_destination,
1537                                                      p_method );
1538     }
1539
1540     free( p_method );
1541     return VLC_SUCCESS;
1542 }
1543
1544 /****************************************************************************
1545 * File:
1546 ****************************************************************************/
1547 static int FileSetup( sout_stream_t *p_stream )
1548 {
1549     sout_stream_sys_t *p_sys = p_stream->p_sys;
1550     FILE            *f;
1551
1552     if( ( f = utf8_fopen( p_sys->psz_sdp_file, "wt" ) ) == NULL )
1553     {
1554         msg_Err( p_stream, "cannot open file '%s' (%s)",
1555                  p_sys->psz_sdp_file, strerror(errno) );
1556         return VLC_EGENERIC;
1557     }
1558
1559     fprintf( f, "%s", p_sys->psz_sdp );
1560     fclose( f );
1561
1562     return VLC_SUCCESS;
1563 }
1564
1565 /****************************************************************************
1566  * HTTP:
1567  ****************************************************************************/
1568 static int  HttpCallback( httpd_file_sys_t *p_args,
1569                           httpd_file_t *, uint8_t *p_request,
1570                           uint8_t **pp_data, int *pi_data );
1571
1572 static int HttpSetup( sout_stream_t *p_stream, vlc_url_t *url)
1573 {
1574     sout_stream_sys_t *p_sys = p_stream->p_sys;
1575
1576     p_sys->p_httpd_host = httpd_HostNew( VLC_OBJECT(p_stream), url->psz_host, url->i_port > 0 ? url->i_port : 80 );
1577     if( p_sys->p_httpd_host )
1578     {
1579         p_sys->p_httpd_file = httpd_FileNew( p_sys->p_httpd_host,
1580                                              url->psz_path ? url->psz_path : "/",
1581                                              "application/sdp",
1582                                              NULL, NULL, NULL,
1583                                              HttpCallback, (void*)p_sys );
1584     }
1585     if( p_sys->p_httpd_file == NULL )
1586     {
1587         return VLC_EGENERIC;
1588     }
1589     return VLC_SUCCESS;
1590 }
1591
1592 static int  HttpCallback( httpd_file_sys_t *p_args,
1593                           httpd_file_t *f, uint8_t *p_request,
1594                           uint8_t **pp_data, int *pi_data )
1595 {
1596     sout_stream_sys_t *p_sys = (sout_stream_sys_t*)p_args;
1597
1598     vlc_mutex_lock( &p_sys->lock_sdp );
1599     if( p_sys->psz_sdp && *p_sys->psz_sdp )
1600     {
1601         *pi_data = strlen( p_sys->psz_sdp );
1602         *pp_data = malloc( *pi_data );
1603         memcpy( *pp_data, p_sys->psz_sdp, *pi_data );
1604     }
1605     else
1606     {
1607         *pp_data = NULL;
1608         *pi_data = 0;
1609     }
1610     vlc_mutex_unlock( &p_sys->lock_sdp );
1611
1612     return VLC_SUCCESS;
1613 }
1614
1615 /****************************************************************************
1616  * RTSP:
1617  ****************************************************************************/
1618 static rtsp_client_t *RtspClientNew( sout_stream_t *p_stream, char *psz_session )
1619 {
1620     rtsp_client_t *rtsp = malloc( sizeof( rtsp_client_t ));
1621
1622     rtsp->psz_session = psz_session;
1623     rtsp->i_last = 0;
1624     rtsp->b_playing = VLC_FALSE;
1625     rtsp->i_id = 0;
1626     rtsp->id = NULL;
1627     rtsp->i_access = 0;
1628     rtsp->access = NULL;
1629
1630     TAB_APPEND( p_stream->p_sys->i_rtsp, p_stream->p_sys->rtsp, rtsp );
1631
1632     return rtsp;
1633 }
1634 static rtsp_client_t *RtspClientGet( sout_stream_t *p_stream, char *psz_session )
1635 {
1636     int i;
1637
1638     if( psz_session ) return NULL;
1639
1640     for( i = 0; i < p_stream->p_sys->i_rtsp; i++ )
1641     {
1642         if( !strcmp( p_stream->p_sys->rtsp[i]->psz_session, psz_session ) )
1643         {
1644             return p_stream->p_sys->rtsp[i];
1645         }
1646     }
1647     return NULL;
1648 }
1649
1650 static void RtspClientDel( sout_stream_t *p_stream, rtsp_client_t *rtsp )
1651 {
1652     int i;
1653     TAB_REMOVE( p_stream->p_sys->i_rtsp, p_stream->p_sys->rtsp, rtsp );
1654
1655     for( i = 0; i < rtsp->i_access; i++ )
1656     {
1657         sout_AccessOutDelete( rtsp->access[i] );
1658     }
1659     if( rtsp->id )     free( rtsp->id );
1660     if( rtsp->access ) free( rtsp->access );
1661
1662     free( rtsp->psz_session );
1663     free( rtsp );
1664 }
1665
1666 static int RtspSetup( sout_stream_t *p_stream, vlc_url_t *url )
1667 {
1668     sout_stream_sys_t *p_sys = p_stream->p_sys;
1669
1670     msg_Dbg( p_stream, "rtsp setup: %s : %d / %s\n", url->psz_host, url->i_port, url->psz_path );
1671
1672     p_sys->p_rtsp_host = httpd_HostNew( VLC_OBJECT(p_stream), url->psz_host, url->i_port > 0 ? url->i_port : 554 );
1673     if( p_sys->p_rtsp_host == NULL )
1674     {
1675         return VLC_EGENERIC;
1676     }
1677
1678     p_sys->psz_rtsp_path = strdup( url->psz_path ? url->psz_path : "/" );
1679     p_sys->psz_rtsp_control = malloc (strlen( url->psz_host ) + 20 + strlen( p_sys->psz_rtsp_path ) + 1 );
1680     sprintf( p_sys->psz_rtsp_control, "rtsp://%s:%d%s",
1681              url->psz_host,  url->i_port > 0 ? url->i_port : 554, p_sys->psz_rtsp_path );
1682
1683     p_sys->p_rtsp_url = httpd_UrlNewUnique( p_sys->p_rtsp_host, p_sys->psz_rtsp_path, NULL, NULL, NULL );
1684     if( p_sys->p_rtsp_url == 0 )
1685     {
1686         return VLC_EGENERIC;
1687     }
1688     httpd_UrlCatch( p_sys->p_rtsp_url, HTTPD_MSG_DESCRIBE, RtspCallback, (void*)p_stream );
1689     httpd_UrlCatch( p_sys->p_rtsp_url, HTTPD_MSG_PLAY,     RtspCallback, (void*)p_stream );
1690     httpd_UrlCatch( p_sys->p_rtsp_url, HTTPD_MSG_PAUSE,    RtspCallback, (void*)p_stream );
1691     httpd_UrlCatch( p_sys->p_rtsp_url, HTTPD_MSG_TEARDOWN, RtspCallback, (void*)p_stream );
1692
1693     return VLC_SUCCESS;
1694 }
1695
1696 static int  RtspCallback( httpd_callback_sys_t *p_args,
1697                           httpd_client_t *cl,
1698                           httpd_message_t *answer, httpd_message_t *query )
1699 {
1700     sout_stream_t *p_stream = (sout_stream_t*)p_args;
1701     sout_stream_sys_t *p_sys = p_stream->p_sys;
1702     char *psz_destination = p_sys->psz_destination;
1703     char *psz_session = NULL;
1704     char *psz_cseq = NULL;
1705     int i_cseq = 0;
1706
1707     if( answer == NULL || query == NULL )
1708     {
1709         return VLC_SUCCESS;
1710     }
1711     //fprintf( stderr, "RtspCallback query: type=%d\n", query->i_type );
1712
1713     answer->i_proto = HTTPD_PROTO_RTSP;
1714     answer->i_version= query->i_version;
1715     answer->i_type   = HTTPD_MSG_ANSWER;
1716
1717     switch( query->i_type )
1718     {
1719         case HTTPD_MSG_DESCRIBE:
1720         {
1721             char *psz_sdp = SDPGenerate( p_stream, psz_destination ? psz_destination : "0.0.0.0", VLC_TRUE );
1722
1723             answer->i_status = 200;
1724             answer->psz_status = strdup( "OK" );
1725             httpd_MsgAdd( answer, "Content-type",  "%s", "application/sdp" );
1726
1727             answer->p_body = (uint8_t *)psz_sdp;
1728             answer->i_body = strlen( psz_sdp );
1729             break;
1730         }
1731
1732         case HTTPD_MSG_PLAY:
1733         {
1734             rtsp_client_t *rtsp;
1735             /* for now only multicast so easy */
1736             answer->i_status = 200;
1737             answer->psz_status = strdup( "OK" );
1738             answer->i_body = 0;
1739             answer->p_body = NULL;
1740
1741             psz_session = httpd_MsgGet( query, "Session" );
1742             rtsp = RtspClientGet( p_stream, psz_session );
1743             if( rtsp && !rtsp->b_playing )
1744             {
1745                 int i_id;
1746                 /* FIXME */
1747                 rtsp->b_playing = VLC_TRUE;
1748
1749                 vlc_mutex_lock( &p_sys->lock_es );
1750                 for( i_id = 0; i_id < rtsp->i_id; i_id++ )
1751                 {
1752                     sout_stream_id_t *id = rtsp->id[i_id];
1753                     int i;
1754
1755                     for( i = 0; i < p_sys->i_es; i++ )
1756                     {
1757                         if( id == p_sys->es[i] )
1758                             break;
1759                     }
1760                     if( i >= p_sys->i_es ) continue;
1761
1762                     vlc_mutex_lock( &id->lock_rtsp );
1763                     TAB_APPEND( id->i_rtsp_access, id->rtsp_access, rtsp->access[i_id] );
1764                     vlc_mutex_unlock( &id->lock_rtsp );
1765                 }
1766                 vlc_mutex_unlock( &p_sys->lock_es );
1767             }
1768             break;
1769         }
1770         case HTTPD_MSG_PAUSE:
1771             /* FIXME */
1772             return VLC_EGENERIC;
1773         case HTTPD_MSG_TEARDOWN:
1774         {
1775             rtsp_client_t *rtsp;
1776
1777             /* for now only multicast so easy again */
1778             answer->i_status = 200;
1779             answer->psz_status = strdup( "OK" );
1780             answer->i_body = 0;
1781             answer->p_body = NULL;
1782
1783             psz_session = httpd_MsgGet( query, "Session" );
1784             rtsp = RtspClientGet( p_stream, psz_session );
1785             if( rtsp )
1786             {
1787                 int i_id;
1788
1789                 vlc_mutex_lock( &p_sys->lock_es );
1790                 for( i_id = 0; i_id < rtsp->i_id; i_id++ )
1791                 {
1792                     sout_stream_id_t *id = rtsp->id[i_id];
1793                     int i;
1794
1795                     for( i = 0; i < p_sys->i_es; i++ )
1796                     {
1797                         if( id == p_sys->es[i] )
1798                             break;
1799                     }
1800                     if( i >= p_sys->i_es ) continue;
1801
1802                     vlc_mutex_lock( &id->lock_rtsp );
1803                     TAB_REMOVE( id->i_rtsp_access, id->rtsp_access, rtsp->access[i_id] );
1804                     vlc_mutex_unlock( &id->lock_rtsp );
1805                 }
1806                 vlc_mutex_unlock( &p_sys->lock_es );
1807
1808                 RtspClientDel( p_stream, rtsp );
1809             }
1810             break;
1811         }
1812
1813         default:
1814             return VLC_EGENERIC;
1815     }
1816     httpd_MsgAdd( answer, "Server", PACKAGE_STRING );
1817     httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body );
1818     psz_cseq = httpd_MsgGet( query, "Cseq" );
1819     if( psz_cseq )
1820         i_cseq = atoi( psz_cseq );
1821     else
1822         i_cseq = 0;
1823     httpd_MsgAdd( answer, "Cseq", "%d", i_cseq );
1824     httpd_MsgAdd( answer, "Cache-Control", "%s", "no-cache" );
1825
1826     if( psz_session )
1827     {
1828         httpd_MsgAdd( answer, "Session", "%s;timeout=5", psz_session );
1829     }
1830     return VLC_SUCCESS;
1831 }
1832
1833 static int RtspCallbackId( httpd_callback_sys_t *p_args,
1834                           httpd_client_t *cl,
1835                           httpd_message_t *answer, httpd_message_t *query )
1836 {
1837     sout_stream_id_t *id = (sout_stream_id_t*)p_args;
1838     sout_stream_t    *p_stream = id->p_stream;
1839     sout_stream_sys_t *p_sys = p_stream->p_sys;
1840     char *psz_session = NULL;
1841     char *psz_cseq = NULL;
1842     int  i_cseq = 0;
1843
1844
1845     if( answer == NULL || query == NULL )
1846     {
1847         return VLC_SUCCESS;
1848     }
1849     //fprintf( stderr, "RtspCallback query: type=%d\n", query->i_type );
1850
1851     answer->i_proto = HTTPD_PROTO_RTSP;
1852     answer->i_version= query->i_version;
1853     answer->i_type   = HTTPD_MSG_ANSWER;
1854
1855     switch( query->i_type )
1856     {
1857         case HTTPD_MSG_SETUP:
1858         {
1859             char *psz_transport = httpd_MsgGet( query, "Transport" );
1860
1861             //fprintf( stderr, "HTTPD_MSG_SETUP: transport=%s\n", psz_transport );
1862
1863             if( strstr( psz_transport, "multicast" ) && id->psz_destination )
1864             {
1865                 //fprintf( stderr, "HTTPD_MSG_SETUP: multicast\n" );
1866                 answer->i_status = 200;
1867                 answer->psz_status = strdup( "OK" );
1868                 answer->i_body = 0;
1869                 answer->p_body = NULL;
1870                 psz_session = httpd_MsgGet( query, "Session" );
1871                 if( !psz_session )
1872                 {
1873                     psz_session = malloc( 100 );
1874                     sprintf( psz_session, "%d", rand() );
1875                 }
1876                 httpd_MsgAdd( answer, "Transport",
1877                               "RTP/AVP/UDP;destination=%s;port=%d-%d;ttl=%d",
1878                               id->psz_destination, id->i_port,id->i_port+1,
1879                               p_sys->i_ttl );
1880             }
1881             else if( strstr( psz_transport, "unicast" ) && strstr( psz_transport, "client_port=" ) )
1882             {
1883                 int  i_port = atoi( strstr( psz_transport, "client_port=" ) + strlen("client_port=") );
1884                 char ip[NI_MAXNUMERICHOST], psz_access[17], psz_url[NI_MAXNUMERICHOST + 8];
1885
1886                 sout_access_out_t *p_access;
1887
1888                 rtsp_client_t *rtsp = NULL;
1889
1890                 if( httpd_ClientIP( cl, ip ) == NULL )
1891                 {
1892                     answer->i_status = 500;
1893                     answer->psz_status = strdup( "Internal server error" );
1894                     answer->i_body = 0;
1895                     answer->p_body = NULL;
1896                     break;
1897                 }
1898
1899                 //fprintf( stderr, "HTTPD_MSG_SETUP: unicast ip=%s port=%d\n", ip, i_port );
1900
1901                 psz_session = httpd_MsgGet( query, "Session" );
1902                 if( !psz_session )
1903                 {
1904                     psz_session = malloc( 100 );
1905                     sprintf( psz_session, "%d", rand() );
1906
1907                     rtsp = RtspClientNew( p_stream, psz_session );
1908                 }
1909                 else
1910                 {
1911                     rtsp = RtspClientGet( p_stream, psz_session );
1912                     if( rtsp == NULL )
1913                     {
1914                         answer->i_status = 454;
1915                         answer->psz_status = strdup( "Unknown session id" );
1916                         answer->i_body = 0;
1917                         answer->p_body = NULL;
1918                         break;
1919                     }
1920                 }
1921
1922                 /* first try to create the access out */
1923                 if( p_sys->i_ttl )
1924                     snprintf( psz_access, sizeof( psz_access ),
1925                               "udp{raw,ttl=%d}", p_sys->i_ttl );
1926                 else
1927                     strlcpy( psz_access, "udp{raw}", sizeof( psz_access ) );
1928
1929                 snprintf( psz_url, sizeof( psz_url ),
1930                          ( strchr( ip, ':' ) != NULL ) ? "[%s]:%d" : "%s:%d",
1931                          ip, i_port );
1932
1933                 if( ( p_access = sout_AccessOutNew( p_stream->p_sout, psz_access, psz_url ) ) == NULL )
1934                 {
1935                     msg_Err( p_stream, "cannot create the access out for %s://%s",
1936                              psz_access, psz_url );
1937                     answer->i_status = 500;
1938                     answer->psz_status = strdup( "Internal server error" );
1939                     answer->i_body = 0;
1940                     answer->p_body = NULL;
1941                     break;
1942                 }
1943
1944                 TAB_APPEND( rtsp->i_id, rtsp->id, id );
1945                 TAB_APPEND( rtsp->i_access, rtsp->access, p_access );
1946
1947                 answer->i_status = 200;
1948                 answer->psz_status = strdup( "OK" );
1949                 answer->i_body = 0;
1950                 answer->p_body = NULL;
1951
1952                 httpd_MsgAdd( answer, "Transport",
1953                               "RTP/AVP/UDP;client_port=%d-%d", i_port, i_port + 1 );
1954             }
1955             else /* TODO  strstr( psz_transport, "interleaved" ) ) */
1956             {
1957                 answer->i_status = 461;
1958                 answer->psz_status = strdup( "Unsupported Transport" );
1959                 answer->i_body = 0;
1960                 answer->p_body = NULL;
1961             }
1962             break;
1963         }
1964
1965         default:
1966             return VLC_EGENERIC;
1967     }
1968     httpd_MsgAdd( answer, "Server", "VLC Server" );
1969     httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body );
1970     psz_cseq = httpd_MsgGet( query, "Cseq" );
1971     if( psz_cseq )
1972         i_cseq = atoi( psz_cseq );
1973     else
1974         i_cseq = 0;
1975     httpd_MsgAdd( answer, "Cseq", "%d", i_cseq );
1976     httpd_MsgAdd( answer, "Cache-Control", "%s", "no-cache" );
1977
1978     if( psz_session )
1979     {
1980         httpd_MsgAdd( answer, "Session", "%s"/*;timeout=5*/, psz_session );
1981     }
1982     return VLC_SUCCESS;
1983 }
1984
1985 /****************************************************************************
1986  * rtp_packetize_*:
1987  ****************************************************************************/
1988 static void rtp_packetize_common( sout_stream_id_t *id, block_t *out,
1989                                   int b_marker, int64_t i_pts )
1990 {
1991     uint32_t i_timestamp = i_pts * (int64_t)id->i_clock_rate / I64C(1000000);
1992
1993     out->p_buffer[0] = 0x80;
1994     out->p_buffer[1] = (b_marker?0x80:0x00)|id->i_payload_type;
1995     out->p_buffer[2] = ( id->i_sequence >> 8)&0xff;
1996     out->p_buffer[3] = ( id->i_sequence     )&0xff;
1997     out->p_buffer[4] = ( i_timestamp >> 24 )&0xff;
1998     out->p_buffer[5] = ( i_timestamp >> 16 )&0xff;
1999     out->p_buffer[6] = ( i_timestamp >>  8 )&0xff;
2000     out->p_buffer[7] = ( i_timestamp       )&0xff;
2001
2002     out->p_buffer[ 8] = id->ssrc[0];
2003     out->p_buffer[ 9] = id->ssrc[1];
2004     out->p_buffer[10] = id->ssrc[2];
2005     out->p_buffer[11] = id->ssrc[3];
2006
2007     out->i_buffer = 12;
2008     id->i_sequence++;
2009 }
2010
2011 static void rtp_packetize_send( sout_stream_id_t *id, block_t *out )
2012 {
2013     int i;
2014     vlc_mutex_lock( &id->lock_rtsp );
2015     for( i = 0; i < id->i_rtsp_access; i++ )
2016     {
2017         sout_AccessOutWrite( id->rtsp_access[i], block_Duplicate( out ) );
2018     }
2019     vlc_mutex_unlock( &id->lock_rtsp );
2020
2021     if( id->p_access )
2022     {
2023         sout_AccessOutWrite( id->p_access, out );
2024     }
2025     else
2026     {
2027         block_Release( out );
2028     }
2029 }
2030
2031 static int rtp_packetize_mpa( sout_stream_t *p_stream, sout_stream_id_t *id,
2032                               block_t *in )
2033 {
2034     int     i_max   = id->i_mtu - 12 - 4; /* payload max in one packet */
2035     int     i_count = ( in->i_buffer + i_max - 1 ) / i_max;
2036
2037     uint8_t *p_data = in->p_buffer;
2038     int     i_data  = in->i_buffer;
2039     int     i;
2040
2041     for( i = 0; i < i_count; i++ )
2042     {
2043         int           i_payload = __MIN( i_max, i_data );
2044         block_t *out = block_New( p_stream, 16 + i_payload );
2045
2046         /* rtp common header */
2047         rtp_packetize_common( id, out, (i == i_count - 1)?1:0, in->i_pts );
2048         /* mbz set to 0 */
2049         out->p_buffer[12] = 0;
2050         out->p_buffer[13] = 0;
2051         /* fragment offset in the current frame */
2052         out->p_buffer[14] = ( (i*i_max) >> 8 )&0xff;
2053         out->p_buffer[15] = ( (i*i_max)      )&0xff;
2054         memcpy( &out->p_buffer[16], p_data, i_payload );
2055
2056         out->i_buffer   = 16 + i_payload;
2057         out->i_dts    = in->i_dts + i * in->i_length / i_count;
2058         out->i_length = in->i_length / i_count;
2059
2060         rtp_packetize_send( id, out );
2061
2062         p_data += i_payload;
2063         i_data -= i_payload;
2064     }
2065
2066     return VLC_SUCCESS;
2067 }
2068
2069 /* rfc2250 */
2070 static int rtp_packetize_mpv( sout_stream_t *p_stream, sout_stream_id_t *id,
2071                               block_t *in )
2072 {
2073     int     i_max   = id->i_mtu - 12 - 4; /* payload max in one packet */
2074     int     i_count = ( in->i_buffer + i_max - 1 ) / i_max;
2075
2076     uint8_t *p_data = in->p_buffer;
2077     int     i_data  = in->i_buffer;
2078     int     i;
2079     int     b_sequence_start = 0;
2080     int     i_temporal_ref = 0;
2081     int     i_picture_coding_type = 0;
2082     int     i_fbv = 0, i_bfc = 0, i_ffv = 0, i_ffc = 0;
2083     int     b_start_slice = 0;
2084
2085     /* preparse this packet to get some info */
2086     if( in->i_buffer > 4 )
2087     {
2088         uint8_t *p = p_data;
2089         int      i_rest = in->i_buffer;
2090
2091         for( ;; )
2092         {
2093             while( i_rest > 4 &&
2094                    ( p[0] != 0x00 || p[1] != 0x00 || p[2] != 0x01 ) )
2095             {
2096                 p++;
2097                 i_rest--;
2098             }
2099             if( i_rest <= 4 )
2100             {
2101                 break;
2102             }
2103             p += 3;
2104             i_rest -= 4;
2105
2106             if( *p == 0xb3 )
2107             {
2108                 /* sequence start code */
2109                 b_sequence_start = 1;
2110             }
2111             else if( *p == 0x00 && i_rest >= 4 )
2112             {
2113                 /* picture */
2114                 i_temporal_ref = ( p[1] << 2) |((p[2]>>6)&0x03);
2115                 i_picture_coding_type = (p[2] >> 3)&0x07;
2116
2117                 if( i_rest >= 4 && ( i_picture_coding_type == 2 ||
2118                                     i_picture_coding_type == 3 ) )
2119                 {
2120                     i_ffv = (p[3] >> 2)&0x01;
2121                     i_ffc = ((p[3]&0x03) << 1)|((p[4]>>7)&0x01);
2122                     if( i_rest > 4 && i_picture_coding_type == 3 )
2123                     {
2124                         i_fbv = (p[4]>>6)&0x01;
2125                         i_bfc = (p[4]>>3)&0x07;
2126                     }
2127                 }
2128             }
2129             else if( *p <= 0xaf )
2130             {
2131                 b_start_slice = 1;
2132             }
2133         }
2134     }
2135
2136     for( i = 0; i < i_count; i++ )
2137     {
2138         int           i_payload = __MIN( i_max, i_data );
2139         block_t *out = block_New( p_stream,
2140                                              16 + i_payload );
2141         uint32_t      h = ( i_temporal_ref << 16 )|
2142                           ( b_sequence_start << 13 )|
2143                           ( b_start_slice << 12 )|
2144                           ( i == i_count - 1 ? 1 << 11 : 0 )|
2145                           ( i_picture_coding_type << 8 )|
2146                           ( i_fbv << 7 )|( i_bfc << 4 )|( i_ffv << 3 )|i_ffc;
2147
2148         /* rtp common header */
2149         rtp_packetize_common( id, out, (i == i_count - 1)?1:0,
2150                               in->i_pts > 0 ? in->i_pts : in->i_dts );
2151
2152         /* 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 */
2153         out->p_buffer[12] = ( h >> 24 )&0xff;
2154         out->p_buffer[13] = ( h >> 16 )&0xff;
2155         out->p_buffer[14] = ( h >>  8 )&0xff;
2156         out->p_buffer[15] = ( h       )&0xff;
2157
2158         memcpy( &out->p_buffer[16], p_data, i_payload );
2159
2160         out->i_buffer   = 16 + i_payload;
2161         out->i_dts    = in->i_dts + i * in->i_length / i_count;
2162         out->i_length = in->i_length / i_count;
2163
2164         rtp_packetize_send( id, out );
2165
2166         p_data += i_payload;
2167         i_data -= i_payload;
2168     }
2169
2170     return VLC_SUCCESS;
2171 }
2172
2173 static int rtp_packetize_ac3( sout_stream_t *p_stream, sout_stream_id_t *id,
2174                               block_t *in )
2175 {
2176     int     i_max   = id->i_mtu - 12 - 2; /* payload max in one packet */
2177     int     i_count = ( in->i_buffer + i_max - 1 ) / i_max;
2178
2179     uint8_t *p_data = in->p_buffer;
2180     int     i_data  = in->i_buffer;
2181     int     i;
2182
2183     for( i = 0; i < i_count; i++ )
2184     {
2185         int           i_payload = __MIN( i_max, i_data );
2186         block_t *out = block_New( p_stream, 14 + i_payload );
2187
2188         /* rtp common header */
2189         rtp_packetize_common( id, out, (i == i_count - 1)?1:0, in->i_pts );
2190         /* unit count */
2191         out->p_buffer[12] = 1;
2192         /* unit header */
2193         out->p_buffer[13] = 0x00;
2194         /* data */
2195         memcpy( &out->p_buffer[14], p_data, i_payload );
2196
2197         out->i_buffer   = 14 + i_payload;
2198         out->i_dts    = in->i_dts + i * in->i_length / i_count;
2199         out->i_length = in->i_length / i_count;
2200
2201         rtp_packetize_send( id, out );
2202
2203         p_data += i_payload;
2204         i_data -= i_payload;
2205     }
2206
2207     return VLC_SUCCESS;
2208 }
2209
2210 static int rtp_packetize_split( sout_stream_t *p_stream, sout_stream_id_t *id,
2211                                 block_t *in )
2212 {
2213     int     i_max   = id->i_mtu - 12; /* payload max in one packet */
2214     int     i_count = ( in->i_buffer + i_max - 1 ) / i_max;
2215
2216     uint8_t *p_data = in->p_buffer;
2217     int     i_data  = in->i_buffer;
2218     int     i;
2219
2220     for( i = 0; i < i_count; i++ )
2221     {
2222         int           i_payload = __MIN( i_max, i_data );
2223         block_t *out = block_New( p_stream, 12 + i_payload );
2224
2225         /* rtp common header */
2226         rtp_packetize_common( id, out, ((i == i_count - 1)?1:0),
2227                               (in->i_pts > 0 ? in->i_pts : in->i_dts) );
2228         memcpy( &out->p_buffer[12], p_data, i_payload );
2229
2230         out->i_buffer   = 12 + i_payload;
2231         out->i_dts    = in->i_dts + i * in->i_length / i_count;
2232         out->i_length = in->i_length / i_count;
2233
2234         rtp_packetize_send( id, out );
2235
2236         p_data += i_payload;
2237         i_data -= i_payload;
2238     }
2239
2240     return VLC_SUCCESS;
2241 }
2242
2243 /* rfc3016 */
2244 static int rtp_packetize_mp4a_latm( sout_stream_t *p_stream, sout_stream_id_t *id,
2245                                 block_t *in )
2246 {
2247     int     i_max   = id->i_mtu - 14;              /* payload max in one packet */
2248     int     latmhdrsize = in->i_buffer / 0xff + 1;
2249     int     i_count = ( in->i_buffer + i_max - 1 ) / i_max;
2250
2251     uint8_t *p_data = in->p_buffer, *p_header = NULL;
2252     int     i_data  = in->i_buffer;
2253     int     i;
2254
2255     for( i = 0; i < i_count; i++ )
2256     {
2257         int     i_payload = __MIN( i_max, i_data );
2258         block_t *out;
2259
2260         if( i != 0 )
2261             latmhdrsize = 0;
2262         out = block_New( p_stream, 12 + latmhdrsize + i_payload );
2263
2264         /* rtp common header */
2265         rtp_packetize_common( id, out, ((i == i_count - 1) ? 1 : 0),
2266                               (in->i_pts > 0 ? in->i_pts : in->i_dts) );
2267
2268         if( i == 0 )
2269         {
2270             int tmp = in->i_buffer;
2271
2272             p_header=out->p_buffer+12;
2273             while( tmp > 0xfe )
2274             {
2275                 *p_header = 0xff;
2276                 p_header++;
2277                 tmp -= 0xff;
2278             }
2279             *p_header = tmp;
2280         }
2281
2282         memcpy( &out->p_buffer[12+latmhdrsize], p_data, i_payload );
2283
2284         out->i_buffer   = 12 + latmhdrsize + i_payload;
2285         out->i_dts    = in->i_dts + i * in->i_length / i_count;
2286         out->i_length = in->i_length / i_count;
2287
2288         rtp_packetize_send( id, out );
2289
2290         p_data += i_payload;
2291         i_data -= i_payload;
2292     }
2293
2294     return VLC_SUCCESS;
2295 }
2296
2297 static int rtp_packetize_l16( sout_stream_t *p_stream, sout_stream_id_t *id,
2298                               block_t *in )
2299 {
2300     int     i_max   = id->i_mtu - 12; /* payload max in one packet */
2301     int     i_count = ( in->i_buffer + i_max - 1 ) / i_max;
2302
2303     uint8_t *p_data = in->p_buffer;
2304     int     i_data  = in->i_buffer;
2305     int     i_packet = 0;
2306
2307     while( i_data > 0 )
2308     {
2309         int           i_payload = (__MIN( i_max, i_data )/4)*4;
2310         block_t *out = block_New( p_stream, 12 + i_payload );
2311
2312         /* rtp common header */
2313         rtp_packetize_common( id, out, 0,
2314                               (in->i_pts > 0 ? in->i_pts : in->i_dts) );
2315         memcpy( &out->p_buffer[12], p_data, i_payload );
2316
2317         out->i_buffer   = 12 + i_payload;
2318         out->i_dts    = in->i_dts + i_packet * in->i_length / i_count;
2319         out->i_length = in->i_length / i_count;
2320
2321         rtp_packetize_send( id, out );
2322
2323         p_data += i_payload;
2324         i_data -= i_payload;
2325         i_packet++;
2326     }
2327
2328     return VLC_SUCCESS;
2329 }
2330
2331 static int rtp_packetize_l8( sout_stream_t *p_stream, sout_stream_id_t *id,
2332                              block_t *in )
2333 {
2334     int     i_max   = id->i_mtu - 12; /* payload max in one packet */
2335     int     i_count = ( in->i_buffer + i_max - 1 ) / i_max;
2336
2337     uint8_t *p_data = in->p_buffer;
2338     int     i_data  = in->i_buffer;
2339     int     i_packet = 0;
2340
2341     while( i_data > 0 )
2342     {
2343         int           i_payload = (__MIN( i_max, i_data )/2)*2;
2344         block_t *out = block_New( p_stream, 12 + i_payload );
2345
2346         /* rtp common header */
2347         rtp_packetize_common( id, out, 0,
2348                               (in->i_pts > 0 ? in->i_pts : in->i_dts) );
2349         memcpy( &out->p_buffer[12], p_data, i_payload );
2350
2351         out->i_buffer   = 12 + i_payload;
2352         out->i_dts    = in->i_dts + i_packet * in->i_length / i_count;
2353         out->i_length = in->i_length / i_count;
2354
2355         rtp_packetize_send( id, out );
2356
2357         p_data += i_payload;
2358         i_data -= i_payload;
2359         i_packet++;
2360     }
2361
2362     return VLC_SUCCESS;
2363 }
2364 static int rtp_packetize_mp4a( sout_stream_t *p_stream, sout_stream_id_t *id,
2365                                block_t *in )
2366 {
2367     int     i_max   = id->i_mtu - 16; /* payload max in one packet */
2368     int     i_count = ( in->i_buffer + i_max - 1 ) / i_max;
2369
2370     uint8_t *p_data = in->p_buffer;
2371     int     i_data  = in->i_buffer;
2372     int     i;
2373
2374     for( i = 0; i < i_count; i++ )
2375     {
2376         int           i_payload = __MIN( i_max, i_data );
2377         block_t *out = block_New( p_stream, 16 + i_payload );
2378
2379         /* rtp common header */
2380         rtp_packetize_common( id, out, ((i == i_count - 1)?1:0),
2381                               (in->i_pts > 0 ? in->i_pts : in->i_dts) );
2382         /* AU headers */
2383         /* AU headers length (bits) */
2384         out->p_buffer[12] = 0;
2385         out->p_buffer[13] = 2*8;
2386         /* for each AU length 13 bits + idx 3bits, */
2387         out->p_buffer[14] = ( in->i_buffer >> 5 )&0xff;
2388         out->p_buffer[15] = ( (in->i_buffer&0xff)<<3 )|0;
2389
2390         memcpy( &out->p_buffer[16], p_data, i_payload );
2391
2392         out->i_buffer   = 16 + i_payload;
2393         out->i_dts    = in->i_dts + i * in->i_length / i_count;
2394         out->i_length = in->i_length / i_count;
2395
2396         rtp_packetize_send( id, out );
2397
2398         p_data += i_payload;
2399         i_data -= i_payload;
2400     }
2401
2402     return VLC_SUCCESS;
2403 }
2404
2405
2406 /* rfc2429 */
2407 #define RTP_H263_HEADER_SIZE (2)  // plen = 0
2408 #define RTP_H263_PAYLOAD_START (14)  // plen = 0
2409 static int rtp_packetize_h263( sout_stream_t *p_stream, sout_stream_id_t *id,
2410                                block_t *in )
2411 {
2412     uint8_t *p_data = in->p_buffer;
2413     int     i_data  = in->i_buffer;
2414     int     i;
2415     int     i_max   = id->i_mtu - 12 - RTP_H263_HEADER_SIZE; /* payload max in one packet */
2416     int     i_count;
2417     int     b_p_bit;
2418     int     b_v_bit = 0; // no pesky error resilience
2419     int     i_plen = 0; // normally plen=0 for PSC packet
2420     int     i_pebit = 0; // because plen=0
2421     uint16_t h;
2422
2423     if( i_data < 2 )
2424     {
2425         return VLC_EGENERIC;
2426     }
2427     if( p_data[0] || p_data[1] )
2428     {
2429         return VLC_EGENERIC;
2430     }
2431     /* remove 2 leading 0 bytes */
2432     p_data += 2;
2433     i_data -= 2;
2434     i_count = ( i_data + i_max - 1 ) / i_max;
2435
2436     for( i = 0; i < i_count; i++ )
2437     {
2438         int      i_payload = __MIN( i_max, i_data );
2439         block_t *out = block_New( p_stream,
2440                                   RTP_H263_PAYLOAD_START + i_payload );
2441         b_p_bit = (i == 0) ? 1 : 0;
2442         h = ( b_p_bit << 10 )|
2443             ( b_v_bit << 9  )|
2444             ( i_plen  << 3  )|
2445               i_pebit;
2446
2447         /* rtp common header */
2448         //b_m_bit = 1; // always contains end of frame
2449         rtp_packetize_common( id, out, (i == i_count - 1)?1:0,
2450                               in->i_pts > 0 ? in->i_pts : in->i_dts );
2451
2452         /* h263 header */
2453         out->p_buffer[12] = ( h >>  8 )&0xff;
2454         out->p_buffer[13] = ( h       )&0xff;
2455         memcpy( &out->p_buffer[RTP_H263_PAYLOAD_START], p_data, i_payload );
2456
2457         out->i_buffer = RTP_H263_PAYLOAD_START + i_payload;
2458         out->i_dts    = in->i_dts + i * in->i_length / i_count;
2459         out->i_length = in->i_length / i_count;
2460
2461         rtp_packetize_send( id, out );
2462
2463         p_data += i_payload;
2464         i_data -= i_payload;
2465     }
2466
2467     return VLC_SUCCESS;
2468 }
2469
2470 /* rfc3984 */
2471 static int rtp_packetize_h264( sout_stream_t *p_stream, sout_stream_id_t *id,
2472                                block_t *in )
2473 {
2474     int     i_max   = id->i_mtu - 12; /* payload max in one packet */
2475     int     i_count = ( in->i_buffer + i_max - 1 ) / i_max;
2476     uint8_t *p_data = in->p_buffer;
2477     int     i_data  = in->i_buffer;
2478     block_t *out;
2479     int     i_nal_type;
2480     int     i_payload;
2481
2482     while( i_data > 5 &&
2483            ( p_data[0] != 0x00 || p_data[1] != 0x00 || p_data[2] != 0x01 || /* startcode */
2484             (p_data[3]&0x1f) < 1 || (p_data[3]&0x1f) > 23 ) ) /* naltype should be between 1 and 23 */
2485     {
2486         p_data++;
2487         i_data--;
2488     }
2489
2490     if( i_data < 5 )
2491         return VLC_SUCCESS;
2492
2493     p_data+=3;
2494     i_data-=3;
2495     i_nal_type = p_data[0]&0x1f;
2496     
2497     if( i_data <= i_max ) /* The whole pack will fit in one rtp payload */
2498     {
2499         /* single NAL */
2500         i_payload = __MIN( i_max, i_data );
2501         out = block_New( p_stream, 12 + i_payload );
2502
2503         /* rtp common header */
2504         rtp_packetize_common( id, out, 1,
2505                               in->i_pts > 0 ? in->i_pts : in->i_dts );
2506
2507         memcpy( &out->p_buffer[12], p_data, i_payload );
2508
2509         out->i_buffer   = 12 + i_payload;
2510         out->i_dts    = in->i_dts;
2511         out->i_length = in->i_length;
2512
2513         rtp_packetize_send( id, out );
2514
2515         /*msg_Dbg( p_stream, "nal-out plain %d %02x", i_payload, out->p_buffer[16] );*/
2516     }
2517     else
2518     {
2519         /* FU-A */
2520         uint8_t     nalh; /* The nalheader byte */
2521         int i=0, start=1, end=0, first=0;
2522  
2523         nalh = *p_data;
2524         p_data++;
2525         i_data--;
2526
2527         i_max   = id->i_mtu - 14;
2528         i_count = ( i_data + i_max - 1 ) / i_max;
2529
2530         /*msg_Dbg( p_stream, "nal-out fragmented %02x %d", nalh, i_rest);*/
2531
2532         while( end == 0 )
2533         {
2534             i_payload = __MIN( i_max, i_data );
2535             out = block_New( p_stream, 14 + i_payload );
2536
2537             if( i_data == i_payload )
2538                 end = 1;
2539
2540             /* rtp common header */
2541             rtp_packetize_common( id, out, (end)?1:0,
2542                               in->i_pts > 0 ? in->i_pts : in->i_dts );
2543
2544             /* FU indicator */
2545             out->p_buffer[12] = (nalh&0x60)|28;
2546             /* FU header */
2547             out->p_buffer[13] = (start<<7)|(end<<6)|(nalh&0x1f);
2548
2549             memcpy( &out->p_buffer[14], p_data+first, i_payload );
2550  
2551             out->i_buffer   = 14 + i_payload;
2552
2553             // not sure what of these should be used and what it does :)
2554             out->i_pts    = in->i_pts;
2555             out->i_dts    = in->i_dts;
2556             //out->i_dts    = in->i_dts + i * in->i_length / i_count;
2557             //out->i_length = in->i_length / i_count;
2558
2559             rtp_packetize_send( id, out );
2560
2561             /*msg_Dbg( p_stream, "nal-out fragmented: frag %d %d %02x %02x %d", start,end,
2562             out->p_buffer[12], out->p_buffer[13], i_payload );*/
2563
2564             i_data -= i_payload;
2565             first += i_payload;
2566             i++;
2567             start=0;
2568         }
2569     }
2570     return VLC_SUCCESS;
2571 }
2572
2573 static int rtp_packetize_amr( sout_stream_t *p_stream, sout_stream_id_t *id,
2574                               block_t *in )
2575 {
2576     int     i_max   = id->i_mtu - 14; /* payload max in one packet */
2577     int     i_count = ( in->i_buffer + i_max - 1 ) / i_max;
2578
2579     uint8_t *p_data = in->p_buffer;
2580     int     i_data  = in->i_buffer;
2581     int     i;
2582
2583     /* Only supports octet-aligned mode */
2584     for( i = 0; i < i_count; i++ )
2585     {
2586         int           i_payload = __MIN( i_max, i_data );
2587         block_t *out = block_New( p_stream, 14 + i_payload );
2588
2589         /* rtp common header */
2590         rtp_packetize_common( id, out, ((i == i_count - 1)?1:0),
2591                               (in->i_pts > 0 ? in->i_pts : in->i_dts) );
2592         /* Payload header */
2593         out->p_buffer[12] = 0xF0; /* CMR */
2594         out->p_buffer[13] = p_data[0]&0x7C; /* ToC */ /* FIXME: frame type */
2595
2596         /* FIXME: are we fed multiple frames ? */
2597         memcpy( &out->p_buffer[14], p_data+1, i_payload-1 );
2598
2599         out->i_buffer   = 14 + i_payload-1;
2600         out->i_dts    = in->i_dts + i * in->i_length / i_count;
2601         out->i_length = in->i_length / i_count;
2602
2603         rtp_packetize_send( id, out );
2604
2605         p_data += i_payload;
2606         i_data -= i_payload;
2607     }
2608
2609     return VLC_SUCCESS;
2610 }