]> git.sesse.net Git - vlc/blob - modules/stream_out/rtp.c
Call for help.
[vlc] / modules / stream_out / rtp.c
1 /*****************************************************************************
2  * rtp.c: rtp stream output module
3  *****************************************************************************
4  * Copyright (C) 2003-2004 VideoLAN
5  * $Id: rtp.c,v 1.12 2004/02/02 14:43:50 fenrir Exp $
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>
28
29 #include <vlc/vlc.h>
30 #include <vlc/input.h>
31 #include <vlc/sout.h>
32
33 #include "httpd.h"
34 #include "network.h"
35
36 /*****************************************************************************
37  * Module descriptor
38  *****************************************************************************/
39 static int  Open ( vlc_object_t * );
40 static void Close( vlc_object_t * );
41
42 vlc_module_begin();
43     set_description( _("RTP stream output") );
44     set_capability( "sout stream", 0 );
45     add_shortcut( "rtp" );
46     set_callbacks( Open, Close );
47 vlc_module_end();
48
49 /*****************************************************************************
50  * Exported prototypes
51  *****************************************************************************/
52 static sout_stream_id_t *Add ( sout_stream_t *, es_format_t * );
53 static int               Del ( sout_stream_t *, sout_stream_id_t * );
54 static int               Send( sout_stream_t *, sout_stream_id_t *,
55                                sout_buffer_t* );
56
57 struct sout_stream_sys_t
58 {
59     /* sdp */
60     int64_t i_sdp_id;
61     int     i_sdp_version;
62     char    *psz_sdp;
63
64     vlc_mutex_t  lock_sdp;
65
66     httpd_t      *p_httpd;
67     httpd_host_t *p_httpd_host;
68     httpd_file_t *p_httpd_file;
69
70     /* */
71     char *psz_destination;
72     int  i_port;
73     int  i_ttl;
74
75     /* when need to use a private one or when using muxer */
76     int i_payload_type;
77
78     /* in case we do TS/PS over rtp */
79     sout_mux_t        *p_mux;
80     sout_access_out_t *p_access;
81     int               i_mtu;
82     sout_access_out_t *p_grab;
83     uint16_t          i_sequence;
84     uint32_t          i_timestamp_start;
85     uint8_t           ssrc[4];
86     sout_buffer_t     *packet;
87
88     /* */
89     int              i_es;
90     sout_stream_id_t **es;
91 };
92
93 typedef int (*pf_rtp_packetizer_t)( sout_stream_t *, sout_stream_id_t *,
94                                     sout_buffer_t * );
95
96 struct sout_stream_id_t
97 {
98     /* rtp field */
99     uint8_t     i_payload_type;
100     uint16_t    i_sequence;
101     uint32_t    i_timestamp_start;
102     uint8_t     ssrc[4];
103
104     /* for sdp */
105     int         i_clock_rate;
106     char        *psz_rtpmap;
107     char        *psz_fmtp;
108     char        *psz_destination;
109     int         i_port;
110     int         i_cat;
111
112     /* Packetizer specific fields */
113     pf_rtp_packetizer_t pf_packetize;
114     int           i_mtu;
115
116     /* for sending the packets */
117     sout_access_out_t *p_access;
118     sout_input_t      *p_input;
119 };
120 static int AccessOutGrabberWrite( sout_access_out_t *, sout_buffer_t * );
121
122 static int  HttpCallback( httpd_file_callback_args_t *p_args,
123                           uint8_t *p_request, int i_request,
124                           uint8_t **pp_data, int *pi_data );
125
126 /*****************************************************************************
127  * Open:
128  *****************************************************************************/
129 static int Open( vlc_object_t *p_this )
130 {
131     sout_stream_t       *p_stream = (sout_stream_t*)p_this;
132     sout_instance_t     *p_sout = p_stream->p_sout;
133     sout_stream_sys_t   *p_sys;
134
135     char *val;
136
137     p_sys = malloc( sizeof( sout_stream_sys_t ) );
138     p_sys->psz_destination = sout_cfg_find_value( p_stream->p_cfg, "dst" );
139     if( ( val = sout_cfg_find_value( p_stream->p_cfg, "port" ) ) )
140     {
141         p_sys->i_port = atoi( val );
142     }
143     if( !p_sys->psz_destination || *p_sys->psz_destination == '\0' ||
144         p_sys->i_port <= 0 )
145     {
146         msg_Err( p_stream, "invalid/missing dst or port" );
147         free( p_sys );
148         return VLC_EGENERIC;
149     }
150     if( ( val = sout_cfg_find_value( p_stream->p_cfg, "ttl" ) ) )
151     {
152         p_sys->i_ttl = atoi( val );
153     }
154     else
155     {
156         p_sys->i_ttl = config_GetInt( p_stream, "ttl" );
157     }
158
159     p_sys->i_payload_type = 96;
160     p_sys->i_es = 0;
161     p_sys->es   = NULL;
162     p_sys->psz_sdp = NULL;
163
164     p_sys->i_sdp_id = mdate();
165     p_sys->i_sdp_version = 1;
166     p_sys->psz_sdp = NULL;
167     p_sys->p_httpd = NULL;
168     p_sys->p_httpd_host = NULL;
169     p_sys->p_httpd_file = NULL;
170
171     if( ( val = sout_cfg_find_value( p_stream->p_cfg, "mux" ) ) )
172     {
173         sout_access_out_t *p_grab;
174
175         char *psz_rtpmap;
176         char access[100];
177         char url[strlen( p_sys->psz_destination ) + 1 + 12 + 1];
178
179         /* Check muxer type */
180         if( !strncasecmp( val, "ps", 2 ) || !strncasecmp( val, "mpeg1", 5 ) )
181         {
182             psz_rtpmap = "MP2P/90000";
183         }
184         else if( !strncasecmp( val, "ts", 2 ) )
185         {
186             psz_rtpmap = "MP2T/90000";
187             p_sys->i_payload_type = 33;
188         }
189         else
190         {
191             msg_Err( p_stream, "unsupported muxer type with rtp (only ts/ps)" );
192             return VLC_EGENERIC;
193         }
194
195         /* create the access out */
196         if( p_sys->i_ttl > 0 )
197         {
198             sprintf( access, "udp{raw,ttl=%d}", p_sys->i_ttl );
199         }
200         else
201         {
202             sprintf( access, "udp{raw}" );
203         }
204         sprintf( url, "%s:%d", p_sys->psz_destination, p_sys->i_port );
205         if( !( p_sys->p_access = sout_AccessOutNew( p_sout, access, url ) ) )
206         {
207             msg_Err( p_stream, "cannot create the access out for %s://%s",
208                      access, url );
209             free( p_sys );
210             return VLC_EGENERIC;
211         }
212         p_sys->i_mtu = config_GetInt( p_stream, "mtu" );  /* XXX beurk */
213         if( p_sys->i_mtu <= 16 )
214         {
215             /* better than nothing */
216             p_sys->i_mtu = 1500;
217         }
218
219         /* the access out grabber TODO export it as sout_AccessOutGrabberNew */
220         p_grab = p_sys->p_grab =
221             vlc_object_create( p_sout, sizeof( sout_access_out_t ) );
222         p_grab->p_module    = NULL;
223         p_grab->p_sout      = p_sout;
224         p_grab->psz_access  = strdup( "grab" );
225         p_grab->p_cfg       = NULL;
226         p_grab->psz_name    = strdup( "" );
227         p_grab->p_sys       = (sout_access_out_sys_t*)p_stream;
228         p_grab->pf_seek     = NULL;
229         p_grab->pf_write    = AccessOutGrabberWrite;
230
231         /* the muxer */
232         if( !( p_sys->p_mux = sout_MuxNew( p_sout, val, p_sys->p_grab ) ) )
233         {
234             msg_Err( p_stream, "cannot create the muxer (%s)", val );
235             sout_AccessOutDelete( p_sys->p_grab );
236             sout_AccessOutDelete( p_sys->p_access );
237             free( p_sys );
238             return VLC_EGENERIC;
239         }
240         p_sout->i_preheader = __MAX( p_sout->i_preheader,
241                                      p_sys->p_mux->i_preheader );
242
243         /* create the SDP only once */
244         p_sys->psz_sdp =
245             malloc( 200 + 20 + 10 + strlen( p_sys->psz_destination ) +
246                     10 + 10 + 10 + 10 + strlen( psz_rtpmap ) );
247         sprintf( p_sys->psz_sdp,
248                  "v=0\n"
249                  "o=- "I64Fd" %d IN IP4 127.0.0.1\n"
250                  "s=NONE\n"
251                  "c=IN IP4 %s/%d\n"
252                  "m=video %d RTP/AVP %d\n"
253                  "a=rtpmap:%d %s\n",
254                  p_sys->i_sdp_id, p_sys->i_sdp_version,
255                  p_sys->psz_destination, p_sys->i_ttl,
256                  p_sys->i_port, p_sys->i_payload_type,
257                  p_sys->i_payload_type, psz_rtpmap );
258
259         fprintf( stderr, "sdp=%s", p_sys->psz_sdp );
260
261         /* create the rtp context */
262         p_sys->ssrc[0] = rand()&0xff;
263         p_sys->ssrc[1] = rand()&0xff;
264         p_sys->ssrc[2] = rand()&0xff;
265         p_sys->ssrc[3] = rand()&0xff;
266         p_sys->i_sequence = rand()&0xffff;
267         p_sys->i_timestamp_start = rand()&0xffffffff;
268         p_sys->packet = NULL;
269     }
270     else
271     {
272         p_sys->p_mux    = NULL;
273         p_sys->p_access = NULL;
274         p_sys->p_grab   = NULL;
275     }
276
277     if( ( val = sout_cfg_find_value( p_stream->p_cfg, "sdp" ) ) )
278     {
279         vlc_url_t url;
280
281         vlc_UrlParse( &url, val, 0 );
282         if( url.psz_protocol && !strcmp( url.psz_protocol, "http" ) )
283         {
284             if( ( p_sys->p_httpd =
285                   httpd_Find( VLC_OBJECT(p_stream), VLC_TRUE ) ) )
286             {
287                 p_sys->p_httpd_host =
288                     p_sys->p_httpd->pf_register_host( p_sys->p_httpd,
289                                                       url.psz_host,
290                                                       url.i_port );
291                 if( p_sys->p_httpd_host )
292                 {
293                     p_sys->p_httpd_file =
294                         p_sys->p_httpd->pf_register_file( p_sys->p_httpd,
295                             url.psz_path ? url.psz_path : "/",
296                             "application/sdp", NULL, NULL,
297                             HttpCallback, HttpCallback, (void*)p_sys );
298                 }
299             }
300             if( p_sys->p_httpd_file == NULL )
301             {
302                 msg_Err( p_stream, "cannot export sdp as http" );
303             }
304         }
305         else
306         {
307             msg_Warn( p_stream, "unknow protocol for SDP (%s)",
308                       url.psz_protocol );
309         }
310         vlc_UrlClean( &url );
311     }
312
313     vlc_mutex_init( p_stream, &p_sys->lock_sdp );
314
315     p_stream->pf_add    = Add;
316     p_stream->pf_del    = Del;
317     p_stream->pf_send   = Send;
318
319     p_stream->p_sys     = p_sys;
320
321     return VLC_SUCCESS;
322 }
323
324 /*****************************************************************************
325  * Close:
326  *****************************************************************************/
327 static void Close( vlc_object_t * p_this )
328 {
329     sout_stream_t     *p_stream = (sout_stream_t*)p_this;
330     sout_stream_sys_t *p_sys = p_stream->p_sys;
331
332     if( p_sys->p_mux )
333     {
334         sout_MuxDelete( p_sys->p_mux );
335         sout_AccessOutDelete( p_sys->p_access );
336         sout_AccessOutDelete( p_sys->p_grab );
337         if( p_sys->packet )
338         {
339             sout_BufferDelete( p_stream->p_sout, p_sys->packet );
340         }
341     }
342
343     vlc_mutex_destroy( &p_sys->lock_sdp );
344
345     if( p_sys->p_httpd_file )
346     {
347         p_sys->p_httpd->pf_unregister_file( p_sys->p_httpd,
348                                             p_sys->p_httpd_file );
349     }
350     if( p_sys->p_httpd_host )
351     {
352         p_sys->p_httpd->pf_unregister_host( p_sys->p_httpd,
353                                             p_sys->p_httpd_host );
354     }
355     if( p_sys->p_httpd )
356     {
357         httpd_Release( p_sys->p_httpd );
358     }
359
360     if( p_sys->psz_sdp )
361     {
362         free( p_sys->psz_sdp );
363     }
364     free( p_sys );
365 }
366
367 /*****************************************************************************
368  * SDPGenerate
369  *****************************************************************************/
370 static void SDPGenerate( sout_stream_t *p_stream )
371 {
372     sout_stream_sys_t *p_sys = p_stream->p_sys;
373     int i_size;
374     char *psz_sdp, *p;
375     int i;
376
377     i_size = strlen( "v=0\n" ) +
378              strlen( "o=- * * IN IP4 127.0.0.1\n" ) +
379              strlen( "s=NONE\n" ) +
380              strlen( "c=IN IP4 */*\n" ) +
381              strlen( p_sys->psz_destination ) +
382              20 + 10 + 10 + 1;
383     for( i = 0; i < p_sys->i_es; i++ )
384     {
385         sout_stream_id_t *id = p_sys->es[i];
386
387         i_size += strlen( "m=**d*o * RTP/AVP *\n" ) + 10 + 10;
388
389         if( id->psz_rtpmap )
390         {
391             i_size += strlen( "a=rtpmap:* *\n" ) + strlen( id->psz_rtpmap )+10;
392         }
393         if( id->psz_fmtp )
394         {
395             i_size += strlen( "a=fmtp:* *\n" ) + strlen( id->psz_fmtp ) + 10;
396         }
397     }
398
399     p = psz_sdp = malloc( i_size );
400     p += sprintf( p, "v=0\n" );
401     p += sprintf( p, "o=- "I64Fd" %d IN IP4 127.0.0.1\n",
402                   p_sys->i_sdp_id, p_sys->i_sdp_version );
403     p += sprintf( p, "s=NONE\n" );
404     p += sprintf( p, "c=IN IP4 %s/%d\n", p_sys->psz_destination,
405                   p_sys->i_ttl );
406
407     for( i = 0; i < p_sys->i_es; i++ )
408     {
409         sout_stream_id_t *id = p_sys->es[i];
410
411         if( id->i_cat == AUDIO_ES )
412         {
413             p += sprintf( p, "m=audio %d RTP/AVP %d\n",
414                           id->i_port, id->i_payload_type );
415         }
416         else if( id->i_cat == VIDEO_ES )
417         {
418             p += sprintf( p, "m=video %d RTP/AVP %d\n",
419                           id->i_port, id->i_payload_type );
420         }
421         else
422         {
423             continue;
424         }
425         if( id->psz_rtpmap )
426         {
427             p += sprintf( p, "a=rtpmap:%d %s\n", id->i_payload_type,
428                           id->psz_rtpmap );
429         }
430         if( id->psz_fmtp )
431         {
432             p += sprintf( p, "a=fmtp:%d %s\n", id->i_payload_type,
433                           id->psz_fmtp );
434         }
435     }
436
437     vlc_mutex_lock( &p_sys->lock_sdp );
438     free( p_sys->psz_sdp );
439     p_sys->psz_sdp = psz_sdp;
440     vlc_mutex_unlock( &p_sys->lock_sdp );
441
442     p_sys->i_sdp_version++;
443
444     fprintf( stderr, "sdp=%s", p_sys->psz_sdp );
445 }
446
447 /*****************************************************************************
448  *
449  *****************************************************************************/
450 static int rtp_packetize_l16  ( sout_stream_t *, sout_stream_id_t *, sout_buffer_t * );
451 static int rtp_packetize_l8   ( sout_stream_t *, sout_stream_id_t *, sout_buffer_t * );
452 static int rtp_packetize_mpa  ( sout_stream_t *, sout_stream_id_t *, sout_buffer_t * );
453 static int rtp_packetize_mpv  ( sout_stream_t *, sout_stream_id_t *, sout_buffer_t * );
454 static int rtp_packetize_ac3  ( sout_stream_t *, sout_stream_id_t *, sout_buffer_t * );
455 static int rtp_packetize_split( sout_stream_t *, sout_stream_id_t *, sout_buffer_t * );
456 static int rtp_packetize_mp4a ( sout_stream_t *, sout_stream_id_t *, sout_buffer_t * );
457
458 static void sprintf_hexa( char *s, uint8_t *p_data, int i_data )
459 {
460     static const char hex[16] = "0123456789abcdef";
461     int i;
462
463     for( i = 0; i < i_data; i++ )
464     {
465         s[2*i+0] = hex[(p_data[i]>>4)&0xf];
466         s[2*i+1] = hex[(p_data[i]   )&0xf];
467     }
468     s[2*i_data] = '\0';
469 }
470
471 static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
472 {
473     sout_instance_t   *p_sout = p_stream->p_sout;
474     sout_stream_sys_t *p_sys = p_stream->p_sys;
475     sout_stream_id_t  *id;
476     sout_access_out_t *p_access = NULL;
477
478     char access[100];
479     char url[strlen( p_sys->psz_destination ) + 1 + 12 + 1];
480
481     if( p_sys->p_mux != NULL )
482     {
483         sout_input_t      *p_input  = NULL;
484         if( ( p_input = sout_MuxAddStream( p_sys->p_mux, p_fmt ) ) == NULL )
485         {
486             msg_Err( p_stream, "cannot add this stream to the muxer" );
487             return NULL;
488         }
489
490         id = malloc( sizeof( sout_stream_id_t ) );
491         id->p_access    = NULL;
492         id->p_input     = p_input;
493         id->pf_packetize= NULL;
494
495         return id;
496     }
497
498     /* first try to create the access out */
499     if( p_sys->i_ttl > 0 )
500     {
501         sprintf( access, "udp{raw,ttl=%d}", p_sys->i_ttl );
502     }
503     else
504     {
505         sprintf( access, "udp{raw}" );
506     }
507     sprintf( url, "%s:%d", p_sys->psz_destination, p_sys->i_port );
508     if( ( p_access = sout_AccessOutNew( p_sout, access, url ) ) == NULL )
509     {
510         msg_Err( p_stream, "cannot create the access out for %s://%s",
511                  access, url );
512         return NULL;
513     }
514
515     /* not create the rtp specific stuff */
516     id = malloc( sizeof( sout_stream_id_t ) );
517     id->p_access   = p_access;
518     id->p_input    = NULL;
519     id->psz_rtpmap = NULL;
520     id->psz_fmtp   = NULL;
521     id->psz_destination = strdup( p_sys->psz_destination );
522     id->i_port = p_sys->i_port;
523
524     switch( p_fmt->i_codec )
525     {
526         case VLC_FOURCC( 's', '1', '6', 'b' ):
527             if( p_fmt->audio.i_channels == 1 && p_fmt->audio.i_rate == 44100 )
528             {
529                 id->i_payload_type = 11;
530             }
531             else if( p_fmt->audio.i_channels == 2 &&
532                      p_fmt->audio.i_rate == 44100 )
533             {
534                 id->i_payload_type = 10;
535             }
536             else
537             {
538                 id->i_payload_type = p_sys->i_payload_type++;
539             }
540             id->psz_rtpmap = malloc( strlen( "L16/*/*" ) + 20+1 );
541             sprintf( id->psz_rtpmap, "L16/%d/%d", p_fmt->audio.i_rate,
542                      p_fmt->audio.i_channels );
543             id->i_clock_rate = p_fmt->audio.i_rate;
544             id->pf_packetize = rtp_packetize_l16;
545             break;
546         case VLC_FOURCC( 'u', '8', ' ', ' ' ):
547             id->i_payload_type = p_sys->i_payload_type++;
548             id->psz_rtpmap = malloc( strlen( "L8/*/*" ) + 20+1 );
549             sprintf( id->psz_rtpmap, "L8/%d/%d", p_fmt->audio.i_rate,
550                      p_fmt->audio.i_channels );
551             id->i_clock_rate = p_fmt->audio.i_rate;
552             id->pf_packetize = rtp_packetize_l8;
553             break;
554         case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
555             id->i_payload_type = 14;
556             id->i_clock_rate = 90000;
557             id->psz_rtpmap = strdup( "MPA/90000" );
558             id->pf_packetize = rtp_packetize_mpa;
559             break;
560         case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
561             id->i_payload_type = 32;
562             id->i_clock_rate = 90000;
563             id->psz_rtpmap = strdup( "MPV/90000" );
564             id->pf_packetize = rtp_packetize_mpv;
565             break;
566         case VLC_FOURCC( 'a', '5', '2', ' ' ):
567             id->i_payload_type = p_sys->i_payload_type++;
568             id->i_clock_rate = 90000;
569             id->psz_rtpmap = strdup( "ac3/90000" );
570             id->pf_packetize = rtp_packetize_ac3;
571             break;
572         case VLC_FOURCC( 'm', 'p', '4', 'v' ):
573         {
574             char hexa[2*p_fmt->i_extra +1];
575
576             id->i_payload_type = p_sys->i_payload_type++;
577             id->i_clock_rate = 90000;
578             id->psz_rtpmap = strdup( "MP4V-ES/90000" );
579             id->pf_packetize = rtp_packetize_split;
580             if( p_fmt->i_extra > 0 )
581             {
582                 id->psz_fmtp = malloc( 100 + 2 * p_fmt->i_extra );
583                 sprintf_hexa( hexa, p_fmt->p_extra, p_fmt->i_extra );
584                 sprintf( id->psz_fmtp,
585                          "profile-level-id=3; config=%s;", hexa );
586             }
587             break;
588         }
589         case VLC_FOURCC( 'm', 'p', '4', 'a' ):
590         {
591             char hexa[2*p_fmt->i_extra +1];
592
593             id->i_payload_type = p_sys->i_payload_type++;
594             id->i_clock_rate = p_fmt->audio.i_rate;
595             id->psz_rtpmap = malloc( strlen( "mpeg4-generic/" ) + 12 );
596             sprintf( id->psz_rtpmap, "mpeg4-generic/%d", p_fmt->audio.i_rate );
597             id->pf_packetize = rtp_packetize_mp4a;
598             id->psz_fmtp = malloc( 200 + 2 * p_fmt->i_extra );
599             sprintf_hexa( hexa, p_fmt->p_extra, p_fmt->i_extra );
600             sprintf( id->psz_fmtp,
601                      "streamtype=5; profile-level-id=15; mode=AAC-hbr; "
602                      "config=%s; SizeLength=13;IndexLength=3; "
603                      "IndexDeltaLength=3; Profile=1;", hexa );
604             break;
605         }
606
607         default:
608             msg_Err( p_stream, "cannot add this stream (unsupported "
609                      "codec:%4.4s)", (char*)&p_fmt->i_codec );
610             free( id );
611             return NULL;
612     }
613     id->i_cat = p_fmt->i_cat;
614
615     id->ssrc[0] = rand()&0xff;
616     id->ssrc[1] = rand()&0xff;
617     id->ssrc[2] = rand()&0xff;
618     id->ssrc[3] = rand()&0xff;
619     id->i_sequence = rand()&0xffff;
620     id->i_timestamp_start = rand()&0xffffffff;
621
622     id->i_mtu    = config_GetInt( p_stream, "mtu" );  /* XXX beuk */
623     if( id->i_mtu <= 16 )
624     {
625         /* better than nothing */
626         id->i_mtu = 1500;
627     }
628
629     msg_Dbg( p_stream, "access out %s:%s mtu=%d", access, url, id->i_mtu );
630
631     /* Update p_sys context */
632     /* update port used (2 -> 1 rtp, 1 rtcp )*/
633     TAB_APPEND( p_sys->i_es, p_sys->es, id );
634     if( p_sys->p_mux == NULL )
635     {
636         p_sys->i_port += 2;
637         SDPGenerate( p_stream );
638     }
639
640     return id;
641 }
642
643 static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
644 {
645     sout_stream_sys_t *p_sys = p_stream->p_sys;
646
647     TAB_REMOVE( p_sys->i_es, p_sys->es, id );
648
649     if( id->p_access )
650     {
651         if( id->psz_rtpmap )
652         {
653             free( id->psz_rtpmap );
654         }
655         if( id->psz_fmtp )
656         {
657             free( id->psz_fmtp );
658         }
659         free( id->psz_destination );
660         sout_AccessOutDelete( id->p_access );
661     }
662     else if( id->p_input )
663     {
664         sout_MuxDeleteStream( p_sys->p_mux, id->p_input );
665     }
666     free( id );
667     return VLC_SUCCESS;
668 }
669
670 static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
671                  sout_buffer_t *p_buffer )
672 {
673     sout_buffer_t *p_next;
674
675     if( p_stream->p_sys->p_mux )
676     {
677         sout_MuxSendBuffer( p_stream->p_sys->p_mux, id->p_input, p_buffer );
678     }
679     else
680     {
681         while( p_buffer )
682         {
683             p_next = p_buffer->p_next;
684             if( id->pf_packetize( p_stream, id, p_buffer ) )
685             {
686                 break;
687             }
688             sout_BufferDelete( p_stream->p_sout, p_buffer );
689             p_buffer = p_next;
690         }
691     }
692     return VLC_SUCCESS;
693 }
694
695 static int  HttpCallback( httpd_file_callback_args_t *p_args,
696                           uint8_t *p_request, int i_request,
697                           uint8_t **pp_data, int *pi_data )
698 {
699     sout_stream_sys_t *p_sys = (sout_stream_sys_t*)p_args;
700     vlc_mutex_lock( &p_sys->lock_sdp );
701     if( p_sys->psz_sdp && *p_sys->psz_sdp )
702     {
703         *pi_data = strlen( p_sys->psz_sdp );
704         *pp_data = malloc( *pi_data );
705         memcpy( *pp_data, p_sys->psz_sdp, *pi_data );
706     }
707     else
708     {
709         *pp_data = NULL;
710         *pi_data = 0;
711     }
712     vlc_mutex_unlock( &p_sys->lock_sdp );
713
714     return VLC_SUCCESS;
715 }
716
717 static int AccessOutGrabberWriteBuffer( sout_stream_t *p_stream,
718                                         sout_buffer_t *p_buffer )
719 {
720     sout_stream_sys_t *p_sys = p_stream->p_sys;
721
722     int64_t  i_dts = p_buffer->i_dts;
723     uint32_t i_timestamp = i_dts * 9 / 100;
724
725     uint8_t         *p_data = p_buffer->p_buffer;
726     unsigned int    i_data  = p_buffer->i_size;
727     unsigned int    i_max   = p_sys->i_mtu - 12;
728
729     int i_packet = ( p_buffer->i_size + i_max - 1 ) / i_max;
730
731     while( i_data > 0 )
732     {
733         unsigned int i_size;
734
735         /* output complete packet */
736         if( p_sys->packet &&
737             p_sys->packet->i_size + i_data > i_max )
738         {
739             sout_AccessOutWrite( p_sys->p_access, p_sys->packet );
740             p_sys->packet = NULL;
741         }
742
743         if( p_sys->packet == NULL )
744         {
745             /* allocate a new packet */
746             p_sys->packet = sout_BufferNew( p_stream->p_sout, p_sys->i_mtu );
747             p_sys->packet->p_buffer[ 0] = 0x80;
748             p_sys->packet->p_buffer[ 1] = p_sys->i_payload_type;
749             p_sys->packet->p_buffer[ 2] = ( p_sys->i_sequence >> 8)&0xff;
750             p_sys->packet->p_buffer[ 3] = ( p_sys->i_sequence     )&0xff;
751             p_sys->packet->p_buffer[ 4] = ( i_timestamp >> 24 )&0xff;
752             p_sys->packet->p_buffer[ 5] = ( i_timestamp >> 16 )&0xff;
753             p_sys->packet->p_buffer[ 6] = ( i_timestamp >>  8 )&0xff;
754             p_sys->packet->p_buffer[ 7] = ( i_timestamp       )&0xff;
755             p_sys->packet->p_buffer[ 8] = p_sys->ssrc[0];
756             p_sys->packet->p_buffer[ 9] = p_sys->ssrc[1];
757             p_sys->packet->p_buffer[10] = p_sys->ssrc[2];
758             p_sys->packet->p_buffer[11] = p_sys->ssrc[3];
759             p_sys->packet->i_size = 12;
760
761             p_sys->packet->i_dts = i_dts;
762             p_sys->packet->i_length = p_buffer->i_length / i_packet;
763             i_dts += p_sys->packet->i_length;
764
765             p_sys->i_sequence++;
766         }
767
768         i_size = __MIN( i_data, p_sys->i_mtu - p_sys->packet->i_size );
769
770         memcpy( &p_sys->packet->p_buffer[p_sys->packet->i_size],
771                 p_data,
772                 i_size );
773
774         p_sys->packet->i_size += i_size;
775         p_data += i_size;
776         i_data -= i_size;
777     }
778
779     return VLC_SUCCESS;
780 }
781
782 static int AccessOutGrabberWrite( sout_access_out_t *p_access,
783                                   sout_buffer_t *p_buffer )
784 {
785     sout_stream_t *p_stream = (sout_stream_t*)p_access->p_sys;
786
787     //fprintf( stderr, "received buffer size=%d\n", p_buffer->i_size );
788     //
789     while( p_buffer )
790     {
791         sout_buffer_t *p_next;
792
793         AccessOutGrabberWriteBuffer( p_stream, p_buffer );
794
795         p_next = p_buffer->p_next;
796         sout_BufferDelete( p_access->p_sout, p_buffer );
797         p_buffer = p_next;
798     }
799
800     return VLC_SUCCESS;
801 }
802
803
804 static void rtp_packetize_common( sout_stream_id_t *id, sout_buffer_t *out,
805                                   int b_marker, int64_t i_pts )
806 {
807     uint32_t i_timestamp = i_pts * (int64_t)id->i_clock_rate / I64C(1000000);
808
809     out->p_buffer[0] = 0x80;
810     out->p_buffer[1] = (b_marker?0x80:0x00)|id->i_payload_type;
811     out->p_buffer[2] = ( id->i_sequence >> 8)&0xff;
812     out->p_buffer[3] = ( id->i_sequence     )&0xff;
813     out->p_buffer[4] = ( i_timestamp >> 24 )&0xff;
814     out->p_buffer[5] = ( i_timestamp >> 16 )&0xff;
815     out->p_buffer[6] = ( i_timestamp >>  8 )&0xff;
816     out->p_buffer[7] = ( i_timestamp       )&0xff;
817
818     out->p_buffer[ 8] = id->ssrc[0];
819     out->p_buffer[ 9] = id->ssrc[1];
820     out->p_buffer[10] = id->ssrc[2];
821     out->p_buffer[11] = id->ssrc[3];
822
823     out->i_size = 12;
824     id->i_sequence++;
825 }
826
827 static int rtp_packetize_mpa( sout_stream_t *p_stream, sout_stream_id_t *id,
828                               sout_buffer_t *in )
829 {
830     int     i_max   = id->i_mtu - 12 - 4; /* payload max in one packet */
831     int     i_count = ( in->i_size + i_max - 1 ) / i_max;
832
833     uint8_t *p_data = in->p_buffer;
834     int     i_data  = in->i_size;
835     int     i;
836
837     for( i = 0; i < i_count; i++ )
838     {
839         int           i_payload = __MIN( i_max, i_data );
840         sout_buffer_t *out = sout_BufferNew( p_stream->p_sout, 16 + i_payload );
841
842         /* rtp common header */
843         rtp_packetize_common( id, out, (i == i_count - 1)?1:0, in->i_pts );
844         /* mbz set to 0 */
845         out->p_buffer[12] = 0;
846         out->p_buffer[13] = 0;
847         /* fragment offset in the current frame */
848         out->p_buffer[14] = ( (i*i_max) >> 8 )&0xff;
849         out->p_buffer[15] = ( (i*i_max)      )&0xff;
850         memcpy( &out->p_buffer[16], p_data, i_payload );
851
852         out->i_size   = 16 + i_payload;
853         out->i_dts    = in->i_dts + i * in->i_length / i_count;
854         out->i_length = in->i_length / i_count;
855
856         sout_AccessOutWrite( id->p_access, out );
857
858         p_data += i_payload;
859         i_data -= i_payload;
860     }
861
862     return VLC_SUCCESS;
863 }
864
865 /* rfc2250 */
866 static int rtp_packetize_mpv( sout_stream_t *p_stream, sout_stream_id_t *id,
867                               sout_buffer_t *in )
868 {
869     int     i_max   = id->i_mtu - 12 - 4; /* payload max in one packet */
870     int     i_count = ( in->i_size + i_max - 1 ) / i_max;
871
872     uint8_t *p_data = in->p_buffer;
873     int     i_data  = in->i_size;
874     int     i;
875     int     b_sequence_start = 0;
876     int     i_temporal_ref = 0;
877     int     i_picture_coding_type = 0;
878     int     i_fbv = 0, i_bfc = 0, i_ffv = 0, i_ffc = 0;
879     int     b_start_slice = 0;
880
881     /* preparse this packet to get some info */
882     if( in->i_size > 4 )
883     {
884         uint8_t *p = p_data;
885         int      i_rest = in->i_size;
886
887         for( ;; )
888         {
889             while( i_rest > 4 &&
890                    ( p[0] != 0x00 || p[1] != 0x00 || p[2] != 0x01 ) )
891             {
892                 p++;
893                 i_rest--;
894             }
895             if( i_rest <= 4 )
896             {
897                 break;
898             }
899             p += 3;
900             i_rest -= 4;
901
902             if( *p == 0xb3 )
903             {
904                 /* sequence start code */
905                 b_sequence_start = 1;
906             }
907             else if( *p == 0x00 && i_rest >= 4 )
908             {
909                 /* picture */
910                 i_temporal_ref = ( p[1] << 2) |((p[2]>>6)&0x03);
911                 i_picture_coding_type = (p[2] >> 3)&0x07;
912
913                 if( i_rest >= 4 && ( i_picture_coding_type == 2 ||
914                                     i_picture_coding_type == 3 ) )
915                 {
916                     i_ffv = (p[3] >> 2)&0x01;
917                     i_ffc = ((p[3]&0x03) << 1)|((p[4]>>7)&0x01);
918                     if( i_rest > 4 && i_picture_coding_type == 3 )
919                     {
920                         i_fbv = (p[4]>>6)&0x01;
921                         i_bfc = (p[4]>>3)&0x07;
922                     }
923                 }
924             }
925             else if( *p <= 0xaf )
926             {
927                 b_start_slice = 1;
928             }
929         }
930     }
931
932     for( i = 0; i < i_count; i++ )
933     {
934         int           i_payload = __MIN( i_max, i_data );
935         sout_buffer_t *out = sout_BufferNew( p_stream->p_sout,
936                                              16 + i_payload );
937         uint32_t      h = ( i_temporal_ref << 16 )|
938                           ( b_sequence_start << 13 )|
939                           ( b_start_slice << 12 )|
940                           ( i == i_count - 1 ? 1 << 11 : 0 )|
941                           ( i_picture_coding_type << 8 )|
942                           ( i_fbv << 7 )|( i_bfc << 4 )|( i_ffv << 3 )|i_ffc;
943
944         /* rtp common header */
945         rtp_packetize_common( id, out, (i == i_count - 1)?1:0,
946                               in->i_pts > 0 ? in->i_pts : in->i_dts );
947
948         /* 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 */
949         out->p_buffer[12] = ( h >> 24 )&0xff;
950         out->p_buffer[13] = ( h >> 16 )&0xff;
951         out->p_buffer[14] = ( h >>  8 )&0xff;
952         out->p_buffer[15] = ( h       )&0xff;
953
954         memcpy( &out->p_buffer[16], p_data, i_payload );
955
956         out->i_size   = 16 + i_payload;
957         out->i_dts    = in->i_dts + i * in->i_length / i_count;
958         out->i_length = in->i_length / i_count;
959
960         sout_AccessOutWrite( id->p_access, out );
961
962         p_data += i_payload;
963         i_data -= i_payload;
964     }
965
966     return VLC_SUCCESS;
967 }
968 static int rtp_packetize_ac3( sout_stream_t *p_stream, sout_stream_id_t *id,
969                               sout_buffer_t *in )
970 {
971     int     i_max   = id->i_mtu - 12 - 2; /* payload max in one packet */
972     int     i_count = ( in->i_size + i_max - 1 ) / i_max;
973
974     uint8_t *p_data = in->p_buffer;
975     int     i_data  = in->i_size;
976     int     i;
977
978     for( i = 0; i < i_count; i++ )
979     {
980         int           i_payload = __MIN( i_max, i_data );
981         sout_buffer_t *out = sout_BufferNew( p_stream->p_sout, 14 + i_payload );
982
983         /* rtp common header */
984         rtp_packetize_common( id, out, (i == i_count - 1)?1:0, in->i_pts );
985         /* unit count */
986         out->p_buffer[12] = 1;
987         /* unit header */
988         out->p_buffer[13] = 0x00;
989         /* data */
990         memcpy( &out->p_buffer[14], p_data, i_payload );
991
992         out->i_size   = 14 + i_payload;
993         out->i_dts    = in->i_dts + i * in->i_length / i_count;
994         out->i_length = in->i_length / i_count;
995
996         sout_AccessOutWrite( id->p_access, out );
997
998         p_data += i_payload;
999         i_data -= i_payload;
1000     }
1001
1002     return VLC_SUCCESS;
1003 }
1004
1005 static int rtp_packetize_split( sout_stream_t *p_stream, sout_stream_id_t *id,
1006                                 sout_buffer_t *in )
1007 {
1008     int     i_max   = id->i_mtu - 12; /* payload max in one packet */
1009     int     i_count = ( in->i_size + i_max - 1 ) / i_max;
1010
1011     uint8_t *p_data = in->p_buffer;
1012     int     i_data  = in->i_size;
1013     int     i;
1014
1015     for( i = 0; i < i_count; i++ )
1016     {
1017         int           i_payload = __MIN( i_max, i_data );
1018         sout_buffer_t *out = sout_BufferNew( p_stream->p_sout, 12 + i_payload );
1019
1020         /* rtp common header */
1021         rtp_packetize_common( id, out, ((i == i_count - 1)?1:0),
1022                               (in->i_pts > 0 ? in->i_pts : in->i_dts) );
1023         memcpy( &out->p_buffer[12], p_data, i_payload );
1024
1025         out->i_size   = 12 + i_payload;
1026         out->i_dts    = in->i_dts + i * in->i_length / i_count;
1027         out->i_length = in->i_length / i_count;
1028
1029         sout_AccessOutWrite( id->p_access, out );
1030
1031         p_data += i_payload;
1032         i_data -= i_payload;
1033     }
1034
1035     return VLC_SUCCESS;
1036 }
1037
1038 static int rtp_packetize_l16( sout_stream_t *p_stream, sout_stream_id_t *id,
1039                               sout_buffer_t *in )
1040 {
1041     int     i_max   = id->i_mtu - 12; /* payload max in one packet */
1042     int     i_count = ( in->i_size + i_max - 1 ) / i_max;
1043
1044     uint8_t *p_data = in->p_buffer;
1045     int     i_data  = in->i_size;
1046     int     i_packet = 0;
1047
1048     while( i_data > 0 )
1049     {
1050         int           i_payload = (__MIN( i_max, i_data )/4)*4;
1051         sout_buffer_t *out = sout_BufferNew( p_stream->p_sout, 12 + i_payload );
1052
1053         /* rtp common header */
1054         rtp_packetize_common( id, out, 0,
1055                               (in->i_pts > 0 ? in->i_pts : in->i_dts) );
1056         memcpy( &out->p_buffer[12], p_data, i_payload );
1057
1058         out->i_size   = 12 + i_payload;
1059         out->i_dts    = in->i_dts + i_packet * in->i_length / i_count;
1060         out->i_length = in->i_length / i_count;
1061
1062         sout_AccessOutWrite( id->p_access, out );
1063
1064         p_data += i_payload;
1065         i_data -= i_payload;
1066         i_packet++;
1067     }
1068
1069     return VLC_SUCCESS;
1070 }
1071
1072 static int rtp_packetize_l8( sout_stream_t *p_stream, sout_stream_id_t *id,
1073                              sout_buffer_t *in )
1074 {
1075     int     i_max   = id->i_mtu - 12; /* payload max in one packet */
1076     int     i_count = ( in->i_size + i_max - 1 ) / i_max;
1077
1078     uint8_t *p_data = in->p_buffer;
1079     int     i_data  = in->i_size;
1080     int     i_packet = 0;
1081
1082     while( i_data > 0 )
1083     {
1084         int           i_payload = (__MIN( i_max, i_data )/2)*2;
1085         sout_buffer_t *out = sout_BufferNew( p_stream->p_sout, 12 + i_payload );
1086
1087         /* rtp common header */
1088         rtp_packetize_common( id, out, 0,
1089                               (in->i_pts > 0 ? in->i_pts : in->i_dts) );
1090         memcpy( &out->p_buffer[12], p_data, i_payload );
1091
1092         out->i_size   = 12 + i_payload;
1093         out->i_dts    = in->i_dts + i_packet * in->i_length / i_count;
1094         out->i_length = in->i_length / i_count;
1095
1096         sout_AccessOutWrite( id->p_access, out );
1097
1098         p_data += i_payload;
1099         i_data -= i_payload;
1100         i_packet++;
1101     }
1102
1103     return VLC_SUCCESS;
1104 }
1105 static int rtp_packetize_mp4a( sout_stream_t *p_stream, sout_stream_id_t *id,
1106                                sout_buffer_t *in )
1107 {
1108     int     i_max   = id->i_mtu - 16; /* payload max in one packet */
1109     int     i_count = ( in->i_size + i_max - 1 ) / i_max;
1110
1111     uint8_t *p_data = in->p_buffer;
1112     int     i_data  = in->i_size;
1113     int     i;
1114
1115     for( i = 0; i < i_count; i++ )
1116     {
1117         int           i_payload = __MIN( i_max, i_data );
1118         sout_buffer_t *out = sout_BufferNew( p_stream->p_sout, 16 + i_payload );
1119
1120         /* rtp common header */
1121         rtp_packetize_common( id, out, ((i == i_count - 1)?1:0),
1122                               (in->i_pts > 0 ? in->i_pts : in->i_dts) );
1123         /* AU headers */
1124         /* AU headers length (bits) */
1125         out->p_buffer[12] = 0;
1126         out->p_buffer[13] = 2*8;
1127         /* for each AU length 13 bits + idx 3bits, */
1128         out->p_buffer[14] = ( in->i_size >> 5 )&0xff;
1129         out->p_buffer[15] = ( (in->i_size&0xff)<<3 )|0;
1130
1131         memcpy( &out->p_buffer[16], p_data, i_payload );
1132
1133         out->i_size   = 16 + i_payload;
1134         out->i_dts    = in->i_dts + i * in->i_length / i_count;
1135         out->i_length = in->i_length / i_count;
1136
1137         sout_AccessOutWrite( id->p_access, out );
1138
1139         p_data += i_payload;
1140         i_data -= i_payload;
1141     }
1142
1143     return VLC_SUCCESS;
1144 }