]> git.sesse.net Git - vlc/blob - modules/stream_out/rtp.c
rtp sout: adjust scope of variable
[vlc] / modules / stream_out / rtp.c
1 /*****************************************************************************
2  * rtp.c: rtp stream output module
3  *****************************************************************************
4  * Copyright (C) 2003-2004 the VideoLAN team
5  * Copyright © 2007-2008 Rémi Denis-Courmont
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
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_sout.h>
35 #include <vlc_block.h>
36
37 #include <vlc_httpd.h>
38 #include <vlc_url.h>
39 #include <vlc_network.h>
40 #include <vlc_charset.h>
41 #include <vlc_strings.h>
42 #include <vlc_rand.h>
43 #ifdef HAVE_SRTP
44 # include <srtp.h>
45 #endif
46
47 #include "rtp.h"
48
49 #ifdef HAVE_UNISTD_H
50 #   include <sys/types.h>
51 #   include <unistd.h>
52 #   include <fcntl.h>
53 #   include <sys/stat.h>
54 #endif
55 #ifdef HAVE_ARPA_INET_H
56 #   include <arpa/inet.h>
57 #endif
58 #ifdef HAVE_LINUX_DCCP_H
59 #   include <linux/dccp.h>
60 #endif
61 #ifndef IPPROTO_DCCP
62 # define IPPROTO_DCCP 33
63 #endif
64 #ifndef IPPROTO_UDPLITE
65 # define IPPROTO_UDPLITE 136
66 #endif
67
68 #include <errno.h>
69
70 #include <assert.h>
71
72 /*****************************************************************************
73  * Module descriptor
74  *****************************************************************************/
75
76 #define DEST_TEXT N_("Destination")
77 #define DEST_LONGTEXT N_( \
78     "This is the output URL that will be used." )
79 #define SDP_TEXT N_("SDP")
80 #define SDP_LONGTEXT N_( \
81     "This allows you to specify how the SDP (Session Descriptor) for this RTP "\
82     "session will be made available. You must use an url: http://location to " \
83     "access the SDP via HTTP, rtsp://location for RTSP access, and sap:// " \
84     "for the SDP to be announced via SAP." )
85 #define SAP_TEXT N_("SAP announcing")
86 #define SAP_LONGTEXT N_("Announce this session with SAP.")
87 #define MUX_TEXT N_("Muxer")
88 #define MUX_LONGTEXT N_( \
89     "This allows you to specify the muxer used for the streaming output. " \
90     "Default is to use no muxer (standard RTP stream)." )
91
92 #define NAME_TEXT N_("Session name")
93 #define NAME_LONGTEXT N_( \
94     "This is the name of the session that will be announced in the SDP " \
95     "(Session Descriptor)." )
96 #define DESC_TEXT N_("Session description")
97 #define DESC_LONGTEXT N_( \
98     "This allows you to give a short description with details about the stream, " \
99     "that will be announced in the SDP (Session Descriptor)." )
100 #define URL_TEXT N_("Session URL")
101 #define URL_LONGTEXT N_( \
102     "This allows you to give an URL with more details about the stream " \
103     "(often the website of the streaming organization), that will " \
104     "be announced in the SDP (Session Descriptor)." )
105 #define EMAIL_TEXT N_("Session email")
106 #define EMAIL_LONGTEXT N_( \
107     "This allows you to give a contact mail address for the stream, that will " \
108     "be announced in the SDP (Session Descriptor)." )
109 #define PHONE_TEXT N_("Session phone number")
110 #define PHONE_LONGTEXT N_( \
111     "This allows you to give a contact telephone number for the stream, that will " \
112     "be announced in the SDP (Session Descriptor)." )
113
114 #define PORT_TEXT N_("Port")
115 #define PORT_LONGTEXT N_( \
116     "This allows you to specify the base port for the RTP streaming." )
117 #define PORT_AUDIO_TEXT N_("Audio port")
118 #define PORT_AUDIO_LONGTEXT N_( \
119     "This allows you to specify the default audio port for the RTP streaming." )
120 #define PORT_VIDEO_TEXT N_("Video port")
121 #define PORT_VIDEO_LONGTEXT N_( \
122     "This allows you to specify the default video port for the RTP streaming." )
123
124 #define TTL_TEXT N_("Hop limit (TTL)")
125 #define TTL_LONGTEXT N_( \
126     "This is the hop limit (also known as \"Time-To-Live\" or TTL) of " \
127     "the multicast packets sent by the stream output (-1 = use operating " \
128     "system built-in default).")
129
130 #define RTCP_MUX_TEXT N_("RTP/RTCP multiplexing")
131 #define RTCP_MUX_LONGTEXT N_( \
132     "This sends and receives RTCP packet multiplexed over the same port " \
133     "as RTP packets." )
134
135 #define CACHING_TEXT N_("Caching value (ms)")
136 #define CACHING_LONGTEXT N_( \
137     "Default caching value for outbound RTP streams. This " \
138     "value should be set in milliseconds." )
139
140 #define PROTO_TEXT N_("Transport protocol")
141 #define PROTO_LONGTEXT N_( \
142     "This selects which transport protocol to use for RTP." )
143
144 #define SRTP_KEY_TEXT N_("SRTP key (hexadecimal)")
145 #define SRTP_KEY_LONGTEXT N_( \
146     "RTP packets will be integrity-protected and ciphered "\
147     "with this Secure RTP master shared secret key.")
148
149 #define SRTP_SALT_TEXT N_("SRTP salt (hexadecimal)")
150 #define SRTP_SALT_LONGTEXT N_( \
151     "Secure RTP requires a (non-secret) master salt value.")
152
153 static const char *const ppsz_protos[] = {
154     "dccp", "sctp", "tcp", "udp", "udplite",
155 };
156
157 static const char *const ppsz_protocols[] = {
158     "DCCP", "SCTP", "TCP", "UDP", "UDP-Lite",
159 };
160
161 #define RFC3016_TEXT N_("MP4A LATM")
162 #define RFC3016_LONGTEXT N_( \
163     "This allows you to stream MPEG4 LATM audio streams (see RFC3016)." )
164
165 static int  Open ( vlc_object_t * );
166 static void Close( vlc_object_t * );
167
168 #define SOUT_CFG_PREFIX "sout-rtp-"
169 #define MAX_EMPTY_BLOCKS 200
170
171 vlc_module_begin ()
172     set_shortname( N_("RTP"))
173     set_description( N_("RTP stream output") )
174     set_capability( "sout stream", 0 )
175     add_shortcut( "rtp" )
176     set_category( CAT_SOUT )
177     set_subcategory( SUBCAT_SOUT_STREAM )
178
179     add_string( SOUT_CFG_PREFIX "dst", "", NULL, DEST_TEXT,
180                 DEST_LONGTEXT, true )
181     add_string( SOUT_CFG_PREFIX "sdp", "", NULL, SDP_TEXT,
182                 SDP_LONGTEXT, true )
183     add_string( SOUT_CFG_PREFIX "mux", "", NULL, MUX_TEXT,
184                 MUX_LONGTEXT, true )
185     add_bool( SOUT_CFG_PREFIX "sap", false, NULL, SAP_TEXT, SAP_LONGTEXT,
186               true )
187
188     add_string( SOUT_CFG_PREFIX "name", "", NULL, NAME_TEXT,
189                 NAME_LONGTEXT, true )
190     add_string( SOUT_CFG_PREFIX "description", "", NULL, DESC_TEXT,
191                 DESC_LONGTEXT, true )
192     add_string( SOUT_CFG_PREFIX "url", "", NULL, URL_TEXT,
193                 URL_LONGTEXT, true )
194     add_string( SOUT_CFG_PREFIX "email", "", NULL, EMAIL_TEXT,
195                 EMAIL_LONGTEXT, true )
196     add_string( SOUT_CFG_PREFIX "phone", "", NULL, PHONE_TEXT,
197                 PHONE_LONGTEXT, true )
198
199     add_string( SOUT_CFG_PREFIX "proto", "udp", NULL, PROTO_TEXT,
200                 PROTO_LONGTEXT, false )
201         change_string_list( ppsz_protos, ppsz_protocols, NULL )
202     add_integer( SOUT_CFG_PREFIX "port", 5004, NULL, PORT_TEXT,
203                  PORT_LONGTEXT, true )
204     add_integer( SOUT_CFG_PREFIX "port-audio", 0, NULL, PORT_AUDIO_TEXT,
205                  PORT_AUDIO_LONGTEXT, true )
206     add_integer( SOUT_CFG_PREFIX "port-video", 0, NULL, PORT_VIDEO_TEXT,
207                  PORT_VIDEO_LONGTEXT, true )
208
209     add_integer( SOUT_CFG_PREFIX "ttl", -1, NULL, TTL_TEXT,
210                  TTL_LONGTEXT, true )
211     add_bool( SOUT_CFG_PREFIX "rtcp-mux", false, NULL,
212               RTCP_MUX_TEXT, RTCP_MUX_LONGTEXT, false )
213     add_integer( SOUT_CFG_PREFIX "caching", DEFAULT_PTS_DELAY / 1000, NULL,
214                  CACHING_TEXT, CACHING_LONGTEXT, true )
215
216 #ifdef HAVE_SRTP
217     add_string( SOUT_CFG_PREFIX "key", "", NULL,
218                 SRTP_KEY_TEXT, SRTP_KEY_LONGTEXT, false )
219     add_string( SOUT_CFG_PREFIX "salt", "", NULL,
220                 SRTP_SALT_TEXT, SRTP_SALT_LONGTEXT, false )
221 #endif
222
223     add_bool( SOUT_CFG_PREFIX "mp4a-latm", false, NULL, RFC3016_TEXT,
224                  RFC3016_LONGTEXT, false )
225
226     set_callbacks( Open, Close )
227 vlc_module_end ()
228
229 /*****************************************************************************
230  * Exported prototypes
231  *****************************************************************************/
232 static const char *const ppsz_sout_options[] = {
233     "dst", "name", "port", "port-audio", "port-video", "*sdp", "ttl", "mux",
234     "sap", "description", "url", "email", "phone",
235     "proto", "rtcp-mux", "caching", "key", "salt",
236     "mp4a-latm", NULL
237 };
238
239 static sout_stream_id_t *Add ( sout_stream_t *, es_format_t * );
240 static int               Del ( sout_stream_t *, sout_stream_id_t * );
241 static int               Send( sout_stream_t *, sout_stream_id_t *,
242                                block_t* );
243 static sout_stream_id_t *MuxAdd ( sout_stream_t *, es_format_t * );
244 static int               MuxDel ( sout_stream_t *, sout_stream_id_t * );
245 static int               MuxSend( sout_stream_t *, sout_stream_id_t *,
246                                   block_t* );
247
248 static sout_access_out_t *GrabberCreate( sout_stream_t *p_sout );
249 static void* ThreadSend( vlc_object_t *p_this );
250 static void *rtp_listen_thread( void * );
251
252 static void SDPHandleUrl( sout_stream_t *, const char * );
253
254 static int SapSetup( sout_stream_t *p_stream );
255 static int FileSetup( sout_stream_t *p_stream );
256 static int HttpSetup( sout_stream_t *p_stream, const vlc_url_t * );
257
258 struct sout_stream_sys_t
259 {
260     /* SDP */
261     char    *psz_sdp;
262     vlc_mutex_t  lock_sdp;
263
264     /* SDP to disk */
265     char *psz_sdp_file;
266
267     /* SDP via SAP */
268     bool b_export_sap;
269     session_descriptor_t *p_session;
270
271     /* SDP via HTTP */
272     httpd_host_t *p_httpd_host;
273     httpd_file_t *p_httpd_file;
274
275     /* RTSP */
276     rtsp_stream_t *rtsp;
277
278     /* RTSP NPT and timestamp computations */
279     mtime_t      i_npt_zero;    /* when NPT=0 packet is sent */
280     int64_t      i_pts_zero;    /* predicts PTS of NPT=0 packet */
281     int64_t      i_pts_offset;  /* matches actual PTS to prediction */
282     vlc_mutex_t  lock_ts;
283
284     /* */
285     char     *psz_destination;
286     uint32_t  payload_bitmap;
287     uint16_t  i_port;
288     uint16_t  i_port_audio;
289     uint16_t  i_port_video;
290     uint8_t   proto;
291     bool      rtcp_mux;
292     int       i_ttl:9;
293     bool      b_latm;
294
295     /* in case we do TS/PS over rtp */
296     sout_mux_t        *p_mux;
297     sout_access_out_t *p_grab;
298     block_t           *packet;
299
300     /* */
301     vlc_mutex_t      lock_es;
302     int              i_es;
303     sout_stream_id_t **es;
304 };
305
306 typedef int (*pf_rtp_packetizer_t)( sout_stream_id_t *, block_t * );
307
308 typedef struct rtp_sink_t
309 {
310     int rtp_fd;
311     rtcp_sender_t *rtcp;
312 } rtp_sink_t;
313
314 struct sout_stream_id_t
315 {
316     VLC_COMMON_MEMBERS
317
318     sout_stream_t *p_stream;
319     /* rtp field */
320     uint16_t    i_sequence;
321     uint8_t     i_payload_type;
322     bool        b_ts_init;
323     uint32_t    i_ts_offset;
324     uint8_t     ssrc[4];
325
326     /* for rtsp */
327     uint16_t    i_seq_sent_next;
328
329     /* for sdp */
330     const char  *psz_enc;
331     char        *psz_fmtp;
332     int          i_clock_rate;
333     int          i_port;
334     int          i_cat;
335     int          i_channels;
336     int          i_bitrate;
337
338     /* Packetizer specific fields */
339     int                 i_mtu;
340 #ifdef HAVE_SRTP
341     srtp_session_t     *srtp;
342 #endif
343     pf_rtp_packetizer_t pf_packetize;
344
345     /* Packets sinks */
346     vlc_mutex_t       lock_sink;
347     int               sinkc;
348     rtp_sink_t       *sinkv;
349     rtsp_stream_id_t *rtsp_id;
350     struct {
351         int          *fd;
352         vlc_thread_t  thread;
353     } listen;
354
355     block_fifo_t     *p_fifo;
356     int64_t           i_caching;
357 };
358
359 /*****************************************************************************
360  * Open:
361  *****************************************************************************/
362 static int Open( vlc_object_t *p_this )
363 {
364     sout_stream_t       *p_stream = (sout_stream_t*)p_this;
365     sout_instance_t     *p_sout = p_stream->p_sout;
366     sout_stream_sys_t   *p_sys = NULL;
367     config_chain_t      *p_cfg = NULL;
368     char                *psz;
369     bool          b_rtsp = false;
370
371     config_ChainParse( p_stream, SOUT_CFG_PREFIX,
372                        ppsz_sout_options, p_stream->p_cfg );
373
374     p_sys = malloc( sizeof( sout_stream_sys_t ) );
375     if( p_sys == NULL )
376         return VLC_ENOMEM;
377
378     p_sys->psz_destination = var_GetNonEmptyString( p_stream, SOUT_CFG_PREFIX "dst" );
379
380     p_sys->i_port       = var_GetInteger( p_stream, SOUT_CFG_PREFIX "port" );
381     p_sys->i_port_audio = var_GetInteger( p_stream, SOUT_CFG_PREFIX "port-audio" );
382     p_sys->i_port_video = var_GetInteger( p_stream, SOUT_CFG_PREFIX "port-video" );
383     p_sys->rtcp_mux     = var_GetBool( p_stream, SOUT_CFG_PREFIX "rtcp-mux" );
384
385     if( p_sys->i_port_audio && p_sys->i_port_video == p_sys->i_port_audio )
386     {
387         msg_Err( p_stream, "audio and video RTP port must be distinct" );
388         free( p_sys->psz_destination );
389         free( p_sys );
390         return VLC_EGENERIC;
391     }
392
393     for( p_cfg = p_stream->p_cfg; p_cfg != NULL; p_cfg = p_cfg->p_next )
394     {
395         if( !strcmp( p_cfg->psz_name, "sdp" )
396          && ( p_cfg->psz_value != NULL )
397          && !strncasecmp( p_cfg->psz_value, "rtsp:", 5 ) )
398         {
399             b_rtsp = true;
400             break;
401         }
402     }
403     if( !b_rtsp )
404     {
405         psz = var_GetNonEmptyString( p_stream, SOUT_CFG_PREFIX "sdp" );
406         if( psz != NULL )
407         {
408             if( !strncasecmp( psz, "rtsp:", 5 ) )
409                 b_rtsp = true;
410             free( psz );
411         }
412     }
413
414     /* Transport protocol */
415     p_sys->proto = IPPROTO_UDP;
416     psz = var_GetNonEmptyString (p_stream, SOUT_CFG_PREFIX"proto");
417
418     if ((psz == NULL) || !strcasecmp (psz, "udp"))
419         (void)0; /* default */
420     else
421     if (!strcasecmp (psz, "dccp"))
422     {
423         p_sys->proto = IPPROTO_DCCP;
424         p_sys->rtcp_mux = true; /* Force RTP/RTCP mux */
425     }
426 #if 0
427     else
428     if (!strcasecmp (psz, "sctp"))
429     {
430         p_sys->proto = IPPROTO_TCP;
431         p_sys->rtcp_mux = true; /* Force RTP/RTCP mux */
432     }
433 #endif
434 #if 0
435     else
436     if (!strcasecmp (psz, "tcp"))
437     {
438         p_sys->proto = IPPROTO_TCP;
439         p_sys->rtcp_mux = true; /* Force RTP/RTCP mux */
440     }
441 #endif
442     else
443     if (!strcasecmp (psz, "udplite") || !strcasecmp (psz, "udp-lite"))
444         p_sys->proto = IPPROTO_UDPLITE;
445     else
446         msg_Warn (p_this, "unknown or unsupported transport protocol \"%s\"",
447                   psz);
448     free (psz);
449     var_Create (p_this, "dccp-service", VLC_VAR_STRING);
450
451     if( ( p_sys->psz_destination == NULL ) && !b_rtsp )
452     {
453         msg_Err( p_stream, "missing destination and not in RTSP mode" );
454         free( p_sys );
455         return VLC_EGENERIC;
456     }
457
458     p_sys->i_ttl = var_GetInteger( p_stream, SOUT_CFG_PREFIX "ttl" );
459     if( p_sys->i_ttl == -1 )
460     {
461         /* Normally, we should let the default hop limit up to the core,
462          * but we have to know it to build our SDP properly, which is why
463          * we ask the core. FIXME: broken when neither sout-rtp-ttl nor
464          * ttl are set. */
465         p_sys->i_ttl = config_GetInt( p_stream, "ttl" );
466     }
467
468     p_sys->b_latm = var_GetBool( p_stream, SOUT_CFG_PREFIX "mp4a-latm" );
469
470     /* NPT=0 time will be determined when we packetize the first packet
471      * (of any ES). But we want to be able to report rtptime in RTSP
472      * without waiting. So until then, we use an arbitrary reference
473      * PTS for timestamp computations, and then actual PTS will catch
474      * up using offsets. */
475     p_sys->i_npt_zero = VLC_TS_INVALID;
476     p_sys->i_pts_zero = mdate(); /* arbitrary value, could probably be
477                                   * random */
478     p_sys->payload_bitmap = 0;
479     p_sys->i_es = 0;
480     p_sys->es   = NULL;
481     p_sys->rtsp = NULL;
482     p_sys->psz_sdp = NULL;
483
484     p_sys->b_export_sap = false;
485     p_sys->p_session = NULL;
486     p_sys->psz_sdp_file = NULL;
487
488     p_sys->p_httpd_host = NULL;
489     p_sys->p_httpd_file = NULL;
490
491     p_stream->p_sys     = p_sys;
492
493     vlc_mutex_init( &p_sys->lock_sdp );
494     vlc_mutex_init( &p_sys->lock_ts );
495     vlc_mutex_init( &p_sys->lock_es );
496
497     psz = var_GetNonEmptyString( p_stream, SOUT_CFG_PREFIX "mux" );
498     if( psz != NULL )
499     {
500         sout_stream_id_t *id;
501
502         /* Check muxer type */
503         if( strncasecmp( psz, "ps", 2 )
504          && strncasecmp( psz, "mpeg1", 5 )
505          && strncasecmp( psz, "ts", 2 ) )
506         {
507             msg_Err( p_stream, "unsupported muxer type for RTP (only TS/PS)" );
508             free( psz );
509             vlc_mutex_destroy( &p_sys->lock_sdp );
510             vlc_mutex_destroy( &p_sys->lock_es );
511             free( p_sys->psz_destination );
512             free( p_sys );
513             return VLC_EGENERIC;
514         }
515
516         p_sys->p_grab = GrabberCreate( p_stream );
517         p_sys->p_mux = sout_MuxNew( p_sout, psz, p_sys->p_grab );
518         free( psz );
519
520         if( p_sys->p_mux == NULL )
521         {
522             msg_Err( p_stream, "cannot create muxer" );
523             sout_AccessOutDelete( p_sys->p_grab );
524             vlc_mutex_destroy( &p_sys->lock_sdp );
525             vlc_mutex_destroy( &p_sys->lock_es );
526             free( p_sys->psz_destination );
527             free( p_sys );
528             return VLC_EGENERIC;
529         }
530
531         id = Add( p_stream, NULL );
532         if( id == NULL )
533         {
534             sout_MuxDelete( p_sys->p_mux );
535             sout_AccessOutDelete( p_sys->p_grab );
536             vlc_mutex_destroy( &p_sys->lock_sdp );
537             vlc_mutex_destroy( &p_sys->lock_es );
538             free( p_sys->psz_destination );
539             free( p_sys );
540             return VLC_EGENERIC;
541         }
542
543         p_sys->packet = NULL;
544
545         p_stream->pf_add  = MuxAdd;
546         p_stream->pf_del  = MuxDel;
547         p_stream->pf_send = MuxSend;
548     }
549     else
550     {
551         p_sys->p_mux    = NULL;
552         p_sys->p_grab   = NULL;
553
554         p_stream->pf_add    = Add;
555         p_stream->pf_del    = Del;
556         p_stream->pf_send   = Send;
557     }
558
559     if( var_GetBool( p_stream, SOUT_CFG_PREFIX"sap" ) )
560         SDPHandleUrl( p_stream, "sap" );
561
562     psz = var_GetNonEmptyString( p_stream, SOUT_CFG_PREFIX "sdp" );
563     if( psz != NULL )
564     {
565         config_chain_t *p_cfg;
566
567         SDPHandleUrl( p_stream, psz );
568
569         for( p_cfg = p_stream->p_cfg; p_cfg != NULL; p_cfg = p_cfg->p_next )
570         {
571             if( !strcmp( p_cfg->psz_name, "sdp" ) )
572             {
573                 if( p_cfg->psz_value == NULL || *p_cfg->psz_value == '\0' )
574                     continue;
575
576                 /* needed both :sout-rtp-sdp= and rtp{sdp=} can be used */
577                 if( !strcmp( p_cfg->psz_value, psz ) )
578                     continue;
579
580                 SDPHandleUrl( p_stream, p_cfg->psz_value );
581             }
582         }
583         free( psz );
584     }
585
586     /* update p_sout->i_out_pace_nocontrol */
587     p_stream->p_sout->i_out_pace_nocontrol++;
588
589     return VLC_SUCCESS;
590 }
591
592 /*****************************************************************************
593  * Close:
594  *****************************************************************************/
595 static void Close( vlc_object_t * p_this )
596 {
597     sout_stream_t     *p_stream = (sout_stream_t*)p_this;
598     sout_stream_sys_t *p_sys = p_stream->p_sys;
599
600     /* update p_sout->i_out_pace_nocontrol */
601     p_stream->p_sout->i_out_pace_nocontrol--;
602
603     if( p_sys->p_mux )
604     {
605         assert( p_sys->i_es == 1 );
606
607         sout_MuxDelete( p_sys->p_mux );
608         Del( p_stream, p_sys->es[0] );
609         sout_AccessOutDelete( p_sys->p_grab );
610
611         if( p_sys->packet )
612         {
613             block_Release( p_sys->packet );
614         }
615         if( p_sys->b_export_sap )
616         {
617             p_sys->p_mux = NULL;
618             SapSetup( p_stream );
619         }
620     }
621
622     if( p_sys->rtsp != NULL )
623         RtspUnsetup( p_sys->rtsp );
624
625     vlc_mutex_destroy( &p_sys->lock_sdp );
626     vlc_mutex_destroy( &p_sys->lock_ts );
627     vlc_mutex_destroy( &p_sys->lock_es );
628
629     if( p_sys->p_httpd_file )
630         httpd_FileDelete( p_sys->p_httpd_file );
631
632     if( p_sys->p_httpd_host )
633         httpd_HostDelete( p_sys->p_httpd_host );
634
635     free( p_sys->psz_sdp );
636
637     if( p_sys->psz_sdp_file != NULL )
638     {
639 #ifdef HAVE_UNISTD_H
640         unlink( p_sys->psz_sdp_file );
641 #endif
642         free( p_sys->psz_sdp_file );
643     }
644     free( p_sys->psz_destination );
645     free( p_sys );
646 }
647
648 /*****************************************************************************
649  * SDPHandleUrl:
650  *****************************************************************************/
651 static void SDPHandleUrl( sout_stream_t *p_stream, const char *psz_url )
652 {
653     sout_stream_sys_t *p_sys = p_stream->p_sys;
654     vlc_url_t url;
655
656     vlc_UrlParse( &url, psz_url, 0 );
657     if( url.psz_protocol && !strcasecmp( url.psz_protocol, "http" ) )
658     {
659         if( p_sys->p_httpd_file )
660         {
661             msg_Err( p_stream, "you can use sdp=http:// only once" );
662             goto out;
663         }
664
665         if( HttpSetup( p_stream, &url ) )
666         {
667             msg_Err( p_stream, "cannot export SDP as HTTP" );
668         }
669     }
670     else if( url.psz_protocol && !strcasecmp( url.psz_protocol, "rtsp" ) )
671     {
672         if( p_sys->rtsp != NULL )
673         {
674             msg_Err( p_stream, "you can use sdp=rtsp:// only once" );
675             goto out;
676         }
677
678         /* FIXME test if destination is multicast or no destination at all */
679         p_sys->rtsp = RtspSetup( p_stream, &url );
680         if( p_sys->rtsp == NULL )
681             msg_Err( p_stream, "cannot export SDP as RTSP" );
682         else
683         if( p_sys->p_mux != NULL )
684         {
685             sout_stream_id_t *id = p_sys->es[0];
686             id->rtsp_id = RtspAddId( p_sys->rtsp, id, GetDWBE( id->ssrc ),
687                                      p_sys->psz_destination, p_sys->i_ttl,
688                                      id->i_port, id->i_port + 1 );
689         }
690     }
691     else if( ( url.psz_protocol && !strcasecmp( url.psz_protocol, "sap" ) ) ||
692              ( url.psz_host && !strcasecmp( url.psz_host, "sap" ) ) )
693     {
694         p_sys->b_export_sap = true;
695         SapSetup( p_stream );
696     }
697     else if( url.psz_protocol && !strcasecmp( url.psz_protocol, "file" ) )
698     {
699         if( p_sys->psz_sdp_file != NULL )
700         {
701             msg_Err( p_stream, "you can use sdp=file:// only once" );
702             goto out;
703         }
704         psz_url = &psz_url[5];
705         if( psz_url[0] == '/' && psz_url[1] == '/' )
706             psz_url += 2;
707         p_sys->psz_sdp_file = strdup( psz_url );
708         if( p_sys->psz_sdp_file == NULL )
709             goto out;
710         decode_URI( p_sys->psz_sdp_file ); /* FIXME? */
711         FileSetup( p_stream );
712     }
713     else
714     {
715         msg_Warn( p_stream, "unknown protocol for SDP (%s)",
716                   url.psz_protocol );
717     }
718
719 out:
720     vlc_UrlClean( &url );
721 }
722
723 /*****************************************************************************
724  * SDPGenerate
725  *****************************************************************************/
726 /*static*/
727 char *SDPGenerate( const sout_stream_t *p_stream, const char *rtsp_url )
728 {
729     const sout_stream_sys_t *p_sys = p_stream->p_sys;
730     char *psz_sdp;
731     struct sockaddr_storage dst;
732     socklen_t dstlen;
733     int i;
734     /*
735      * When we have a fixed destination (typically when we do multicast),
736      * we need to put the actual port numbers in the SDP.
737      * When there is no fixed destination, we only support RTSP unicast
738      * on-demand setup, so we should rather let the clients decide which ports
739      * to use.
740      * When there is both a fixed destination and RTSP unicast, we need to
741      * put port numbers used by the fixed destination, otherwise the SDP would
742      * become totally incorrect for multicast use. It should be noted that
743      * port numbers from SDP with RTSP are only "recommendation" from the
744      * server to the clients (per RFC2326), so only broken clients will fail
745      * to handle this properly. There is no solution but to use two differents
746      * output chain with two different RTSP URLs if you need to handle this
747      * scenario.
748      */
749     int inclport;
750
751     if( p_sys->psz_destination != NULL )
752     {
753         inclport = 1;
754
755         /* Oh boy, this is really ugly! (+ race condition on lock_es) */
756         dstlen = sizeof( dst );
757         if( p_sys->es[0]->listen.fd != NULL )
758             getsockname( p_sys->es[0]->listen.fd[0],
759                          (struct sockaddr *)&dst, &dstlen );
760         else
761             getpeername( p_sys->es[0]->sinkv[0].rtp_fd,
762                          (struct sockaddr *)&dst, &dstlen );
763     }
764     else
765     {
766         inclport = 0;
767
768         /* Dummy destination address for RTSP */
769         memset (&dst, 0, sizeof( struct sockaddr_in ) );
770         dst.ss_family = AF_INET;
771 #ifdef HAVE_SA_LEN
772         dst.ss_len =
773 #endif
774         dstlen = sizeof( struct sockaddr_in );
775     }
776
777     psz_sdp = vlc_sdp_Start( VLC_OBJECT( p_stream ), SOUT_CFG_PREFIX,
778                              NULL, 0, (struct sockaddr *)&dst, dstlen );
779     if( psz_sdp == NULL )
780         return NULL;
781
782     /* TODO: a=source-filter */
783     if( p_sys->rtcp_mux )
784         sdp_AddAttribute( &psz_sdp, "rtcp-mux", NULL );
785
786     if( rtsp_url != NULL )
787         sdp_AddAttribute ( &psz_sdp, "control", "%s", rtsp_url );
788
789     /* FIXME: locking?! */
790     for( i = 0; i < p_sys->i_es; i++ )
791     {
792         sout_stream_id_t *id = p_sys->es[i];
793         const char *mime_major; /* major MIME type */
794         const char *proto = "RTP/AVP"; /* protocol */
795
796         switch( id->i_cat )
797         {
798             case VIDEO_ES:
799                 mime_major = "video";
800                 break;
801             case AUDIO_ES:
802                 mime_major = "audio";
803                 break;
804             case SPU_ES:
805                 mime_major = "text";
806                 break;
807             default:
808                 continue;
809         }
810
811         if( rtsp_url == NULL )
812         {
813             switch( p_sys->proto )
814             {
815                 case IPPROTO_UDP:
816                     break;
817                 case IPPROTO_TCP:
818                     proto = "TCP/RTP/AVP";
819                     break;
820                 case IPPROTO_DCCP:
821                     proto = "DCCP/RTP/AVP";
822                     break;
823                 case IPPROTO_UDPLITE:
824                     continue;
825             }
826         }
827
828         sdp_AddMedia( &psz_sdp, mime_major, proto, inclport * id->i_port,
829                       id->i_payload_type, false, id->i_bitrate,
830                       id->psz_enc, id->i_clock_rate, id->i_channels,
831                       id->psz_fmtp);
832
833         if( !p_sys->rtcp_mux && (id->i_port & 1) ) /* cf RFC4566 §5.14 */
834             sdp_AddAttribute ( &psz_sdp, "rtcp", "%u", id->i_port + 1 );
835
836         if( rtsp_url != NULL )
837         {
838             assert( strlen( rtsp_url ) > 0 );
839             bool addslash = ( rtsp_url[strlen( rtsp_url ) - 1] != '/' );
840             sdp_AddAttribute ( &psz_sdp, "control",
841                                addslash ? "%s/trackID=%u" : "%strackID=%u",
842                                rtsp_url, i );
843         }
844         else
845         {
846             if( id->listen.fd != NULL )
847                 sdp_AddAttribute( &psz_sdp, "setup", "passive" );
848             if( p_sys->proto == IPPROTO_DCCP )
849                 sdp_AddAttribute( &psz_sdp, "dccp-service-code",
850                                   "SC:RTP%c", toupper( mime_major[0] ) );
851         }
852     }
853
854     return psz_sdp;
855 }
856
857 /*****************************************************************************
858  * RTP mux
859  *****************************************************************************/
860
861 static void sprintf_hexa( char *s, uint8_t *p_data, int i_data )
862 {
863     static const char hex[16] = "0123456789abcdef";
864     int i;
865
866     for( i = 0; i < i_data; i++ )
867     {
868         s[2*i+0] = hex[(p_data[i]>>4)&0xf];
869         s[2*i+1] = hex[(p_data[i]   )&0xf];
870     }
871     s[2*i_data] = '\0';
872 }
873
874 /**
875  * Shrink the MTU down to a fixed packetization time (for audio).
876  */
877 static void
878 rtp_set_ptime (sout_stream_id_t *id, unsigned ptime_ms, size_t bytes)
879 {
880     /* Samples per second */
881     size_t spl = (id->i_clock_rate - 1) * ptime_ms / 1000 + 1;
882     bytes *= id->i_channels;
883     spl *= bytes;
884
885     if (spl < rtp_mtu (id)) /* MTU is big enough for ptime */
886         id->i_mtu = 12 + spl;
887     else /* MTU is too small for ptime, align to a sample boundary */
888         id->i_mtu = 12 + (((id->i_mtu - 12) / bytes) * bytes);
889 }
890
891 uint32_t rtp_compute_ts( const sout_stream_id_t *id, int64_t i_pts )
892 {
893     /* NOTE: this plays nice with offsets because the calculations are
894      * linear. */
895     return i_pts * (int64_t)id->i_clock_rate / CLOCK_FREQ;
896 }
897
898 /** Add an ES as a new RTP stream */
899 static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
900 {
901     /* NOTE: As a special case, if we use a non-RTP
902      * mux (TS/PS), then p_fmt is NULL. */
903     sout_stream_sys_t *p_sys = p_stream->p_sys;
904     sout_stream_id_t  *id;
905     char              *psz_sdp;
906
907     if (0xffffffff == p_sys->payload_bitmap)
908     {
909         msg_Err (p_stream, "too many RTP elementary streams");
910         return NULL;
911     }
912
913     /* Choose the port */
914     uint16_t i_port = 0;
915     if( p_fmt == NULL )
916         ;
917     else
918     if( p_fmt->i_cat == AUDIO_ES && p_sys->i_port_audio > 0 )
919         i_port = p_sys->i_port_audio;
920     else
921     if( p_fmt->i_cat == VIDEO_ES && p_sys->i_port_video > 0 )
922         i_port = p_sys->i_port_video;
923
924     /* We do not need the ES lock (p_sys->lock_es) here, because this is the
925      * only one thread that can *modify* the ES table. The ES lock protects
926      * the other threads from our modifications (TAB_APPEND, TAB_REMOVE). */
927     for (int i = 0; i_port && (i < p_sys->i_es); i++)
928          if (i_port == p_sys->es[i]->i_port)
929              i_port = 0; /* Port already in use! */
930     for (uint16_t p = p_sys->i_port; i_port == 0; p += 2)
931     {
932         if (p == 0)
933         {
934             msg_Err (p_stream, "too many RTP elementary streams");
935             return NULL;
936         }
937         i_port = p;
938         for (int i = 0; i_port && (i < p_sys->i_es); i++)
939              if (p == p_sys->es[i]->i_port)
940                  i_port = 0;
941     }
942
943     id = vlc_object_create( p_stream, sizeof( sout_stream_id_t ) );
944     if( id == NULL )
945         return NULL;
946     vlc_object_attach( id, p_stream );
947
948     id->p_stream   = p_stream;
949
950     /* Look for free dymanic payload type */
951     id->i_payload_type = 96;
952     while (p_sys->payload_bitmap & (1 << (id->i_payload_type - 96)))
953         id->i_payload_type++;
954     assert (id->i_payload_type < 128);
955
956     vlc_rand_bytes (&id->i_sequence, sizeof (id->i_sequence));
957     vlc_rand_bytes (id->ssrc, sizeof (id->ssrc));
958
959     id->i_seq_sent_next = id->i_sequence;
960
961     id->psz_enc    = NULL;
962     id->psz_fmtp   = NULL;
963     id->i_clock_rate = 90000; /* most common case for video */
964     id->i_channels = 0;
965     id->i_port     = i_port;
966     if( p_fmt != NULL )
967     {
968         id->i_cat  = p_fmt->i_cat;
969         if( p_fmt->i_cat == AUDIO_ES )
970         {
971             id->i_clock_rate = p_fmt->audio.i_rate;
972             id->i_channels = p_fmt->audio.i_channels;
973         }
974         id->i_bitrate = p_fmt->i_bitrate/1000; /* Stream bitrate in kbps */
975     }
976     else
977     {
978         id->i_cat  = VIDEO_ES;
979         id->i_bitrate = 0;
980     }
981
982     id->i_mtu = config_GetInt( p_stream, "mtu" );
983     if( id->i_mtu <= 12 + 16 )
984         id->i_mtu = 576 - 20 - 8; /* pessimistic */
985     msg_Dbg( p_stream, "maximum RTP packet size: %d bytes", id->i_mtu );
986
987     id->pf_packetize = NULL;
988
989 #ifdef HAVE_SRTP
990     id->srtp = NULL;
991
992     char *key = var_CreateGetNonEmptyString (p_stream, SOUT_CFG_PREFIX"key");
993     if (key)
994     {
995         id->srtp = srtp_create (SRTP_ENCR_AES_CM, SRTP_AUTH_HMAC_SHA1, 10,
996                                    SRTP_PRF_AES_CM, SRTP_RCC_MODE1);
997         if (id->srtp == NULL)
998         {
999             free (key);
1000             goto error;
1001         }
1002
1003         char *salt = var_CreateGetNonEmptyString (p_stream, SOUT_CFG_PREFIX"salt");
1004         errno = srtp_setkeystring (id->srtp, key, salt ? salt : "");
1005         free (salt);
1006         free (key);
1007         if (errno)
1008         {
1009             msg_Err (p_stream, "bad SRTP key/salt combination (%m)");
1010             goto error;
1011         }
1012         id->i_sequence = 0; /* FIXME: awful hack for libvlc_srtp */
1013     }
1014 #endif
1015
1016     vlc_mutex_init( &id->lock_sink );
1017     id->sinkc = 0;
1018     id->sinkv = NULL;
1019     id->rtsp_id = NULL;
1020     id->p_fifo = NULL;
1021     id->listen.fd = NULL;
1022
1023     id->i_caching =
1024         (int64_t)1000 * var_GetInteger( p_stream, SOUT_CFG_PREFIX "caching");
1025
1026     if( p_sys->psz_destination != NULL )
1027         switch( p_sys->proto )
1028         {
1029             case IPPROTO_DCCP:
1030             {
1031                 const char *code;
1032                 switch (id->i_cat)
1033                 {
1034                     case VIDEO_ES: code = "RTPV";     break;
1035                     case AUDIO_ES: code = "RTPARTPV"; break;
1036                     case SPU_ES:   code = "RTPTRTPV"; break;
1037                     default:       code = "RTPORTPV"; break;
1038                 }
1039                 var_SetString (p_stream, "dccp-service", code);
1040             }   /* fall through */
1041             case IPPROTO_TCP:
1042                 id->listen.fd = net_Listen( VLC_OBJECT(p_stream),
1043                                             p_sys->psz_destination, i_port,
1044                                             p_sys->proto );
1045                 if( id->listen.fd == NULL )
1046                 {
1047                     msg_Err( p_stream, "passive COMEDIA RTP socket failed" );
1048                     goto error;
1049                 }
1050                 if( vlc_clone( &id->listen.thread, rtp_listen_thread, id,
1051                                VLC_THREAD_PRIORITY_LOW ) )
1052                 {
1053                     net_ListenClose( id->listen.fd );
1054                     id->listen.fd = NULL;
1055                     goto error;
1056                 }
1057                 break;
1058
1059             default:
1060             {
1061                 int ttl = (p_sys->i_ttl >= 0) ? p_sys->i_ttl : -1;
1062                 int fd = net_ConnectDgram( p_stream, p_sys->psz_destination,
1063                                            i_port, ttl, p_sys->proto );
1064                 if( fd == -1 )
1065                 {
1066                     msg_Err( p_stream, "cannot create RTP socket" );
1067                     goto error;
1068                 }
1069                 /* Ignore any unexpected incoming packet (including RTCP-RR
1070                  * packets in case of rtcp-mux) */
1071                 setsockopt (fd, SOL_SOCKET, SO_RCVBUF, &(int){ 0 },
1072                             sizeof (int));
1073                 rtp_add_sink( id, fd, p_sys->rtcp_mux, NULL );
1074             }
1075         }
1076
1077     if( p_fmt == NULL )
1078     {
1079         char *psz = var_GetNonEmptyString( p_stream, SOUT_CFG_PREFIX "mux" );
1080
1081         if( psz == NULL ) /* Uho! */
1082             ;
1083         else
1084         if( strncmp( psz, "ts", 2 ) == 0 )
1085         {
1086             id->i_payload_type = 33;
1087             id->psz_enc = "MP2T";
1088         }
1089         else
1090         {
1091             id->psz_enc = "MP2P";
1092         }
1093         free( psz );
1094     }
1095     else
1096     switch( p_fmt->i_codec )
1097     {
1098         case VLC_CODEC_MULAW:
1099             if( p_fmt->audio.i_channels == 1 && p_fmt->audio.i_rate == 8000 )
1100                 id->i_payload_type = 0;
1101             id->psz_enc = "PCMU";
1102             id->pf_packetize = rtp_packetize_split;
1103             rtp_set_ptime (id, 20, 1);
1104             break;
1105         case VLC_CODEC_ALAW:
1106             if( p_fmt->audio.i_channels == 1 && p_fmt->audio.i_rate == 8000 )
1107                 id->i_payload_type = 8;
1108             id->psz_enc = "PCMA";
1109             id->pf_packetize = rtp_packetize_split;
1110             rtp_set_ptime (id, 20, 1);
1111             break;
1112         case VLC_CODEC_S16B:
1113         case VLC_CODEC_S16L:
1114             if( p_fmt->audio.i_channels == 1 && p_fmt->audio.i_rate == 44100 )
1115             {
1116                 id->i_payload_type = 11;
1117             }
1118             else if( p_fmt->audio.i_channels == 2 &&
1119                      p_fmt->audio.i_rate == 44100 )
1120             {
1121                 id->i_payload_type = 10;
1122             }
1123             id->psz_enc = "L16";
1124             if( p_fmt->i_codec == VLC_CODEC_S16B )
1125                 id->pf_packetize = rtp_packetize_split;
1126             else
1127                 id->pf_packetize = rtp_packetize_swab;
1128             rtp_set_ptime (id, 20, 2);
1129             break;
1130         case VLC_CODEC_U8:
1131             id->psz_enc = "L8";
1132             id->pf_packetize = rtp_packetize_split;
1133             rtp_set_ptime (id, 20, 1);
1134             break;
1135         case VLC_CODEC_MPGA:
1136             id->i_payload_type = 14;
1137             id->psz_enc = "MPA";
1138             id->i_clock_rate = 90000; /* not 44100 */
1139             id->pf_packetize = rtp_packetize_mpa;
1140             break;
1141         case VLC_CODEC_MPGV:
1142             id->i_payload_type = 32;
1143             id->psz_enc = "MPV";
1144             id->pf_packetize = rtp_packetize_mpv;
1145             break;
1146         case VLC_CODEC_ADPCM_G726:
1147             switch( p_fmt->i_bitrate / 1000 )
1148             {
1149             case 16:
1150                 id->psz_enc = "G726-16";
1151                 id->pf_packetize = rtp_packetize_g726_16;
1152                 break;
1153             case 24:
1154                 id->psz_enc = "G726-24";
1155                 id->pf_packetize = rtp_packetize_g726_24;
1156                 break;
1157             case 32:
1158                 id->psz_enc = "G726-32";
1159                 id->pf_packetize = rtp_packetize_g726_32;
1160                 break;
1161             case 40:
1162                 id->psz_enc = "G726-40";
1163                 id->pf_packetize = rtp_packetize_g726_40;
1164                 break;
1165             default:
1166                 msg_Err( p_stream, "cannot add this stream (unsupported "
1167                          "G.726 bit rate: %u)", p_fmt->i_bitrate );
1168                 goto error;
1169             }
1170             break;
1171         case VLC_CODEC_A52:
1172             id->psz_enc = "ac3";
1173             id->pf_packetize = rtp_packetize_ac3;
1174             break;
1175         case VLC_CODEC_H263:
1176             id->psz_enc = "H263-1998";
1177             id->pf_packetize = rtp_packetize_h263;
1178             break;
1179         case VLC_CODEC_H264:
1180             id->psz_enc = "H264";
1181             id->pf_packetize = rtp_packetize_h264;
1182             id->psz_fmtp = NULL;
1183
1184             if( p_fmt->i_extra > 0 )
1185             {
1186                 uint8_t *p_buffer = p_fmt->p_extra;
1187                 int     i_buffer = p_fmt->i_extra;
1188                 char    *p_64_sps = NULL;
1189                 char    *p_64_pps = NULL;
1190                 char    hexa[6+1];
1191
1192                 while( i_buffer > 4 &&
1193                        p_buffer[0] == 0 && p_buffer[1] == 0 &&
1194                        p_buffer[2] == 0 && p_buffer[3] == 1 )
1195                 {
1196                     const int i_nal_type = p_buffer[4]&0x1f;
1197                     int i_offset;
1198                     int i_size      = 0;
1199
1200                     msg_Dbg( p_stream, "we found a startcode for NAL with TYPE:%d", i_nal_type );
1201
1202                     i_size = i_buffer;
1203                     for( i_offset = 4; i_offset+3 < i_buffer ; i_offset++)
1204                     {
1205                         if( !memcmp (p_buffer + i_offset, "\x00\x00\x00\x01", 4 ) )
1206                         {
1207                             /* we found another startcode */
1208                             i_size = i_offset;
1209                             break;
1210                         }
1211                     }
1212                     if( i_nal_type == 7 )
1213                     {
1214                         p_64_sps = vlc_b64_encode_binary( &p_buffer[4], i_size - 4 );
1215                         sprintf_hexa( hexa, &p_buffer[5], 3 );
1216                     }
1217                     else if( i_nal_type == 8 )
1218                     {
1219                         p_64_pps = vlc_b64_encode_binary( &p_buffer[4], i_size - 4 );
1220                     }
1221                     i_buffer -= i_size;
1222                     p_buffer += i_size;
1223                 }
1224                 /* */
1225                 if( p_64_sps && p_64_pps &&
1226                     ( asprintf( &id->psz_fmtp,
1227                                 "packetization-mode=1;profile-level-id=%s;"
1228                                 "sprop-parameter-sets=%s,%s;", hexa, p_64_sps,
1229                                 p_64_pps ) == -1 ) )
1230                     id->psz_fmtp = NULL;
1231                 free( p_64_sps );
1232                 free( p_64_pps );
1233             }
1234             if( !id->psz_fmtp )
1235                 id->psz_fmtp = strdup( "packetization-mode=1" );
1236             break;
1237
1238         case VLC_CODEC_MP4V:
1239         {
1240             id->psz_enc = "MP4V-ES";
1241             id->pf_packetize = rtp_packetize_split;
1242             if( p_fmt->i_extra > 0 )
1243             {
1244                 char hexa[2*p_fmt->i_extra +1];
1245                 sprintf_hexa( hexa, p_fmt->p_extra, p_fmt->i_extra );
1246                 if( asprintf( &id->psz_fmtp,
1247                               "profile-level-id=3; config=%s;", hexa ) == -1 )
1248                     id->psz_fmtp = NULL;
1249             }
1250             break;
1251         }
1252         case VLC_CODEC_MP4A:
1253         {
1254             if(!p_sys->b_latm)
1255             {
1256                 char hexa[2*p_fmt->i_extra +1];
1257
1258                 id->psz_enc = "mpeg4-generic";
1259                 id->pf_packetize = rtp_packetize_mp4a;
1260                 sprintf_hexa( hexa, p_fmt->p_extra, p_fmt->i_extra );
1261                 if( asprintf( &id->psz_fmtp,
1262                               "streamtype=5; profile-level-id=15; "
1263                               "mode=AAC-hbr; config=%s; SizeLength=13; "
1264                               "IndexLength=3; IndexDeltaLength=3; Profile=1;",
1265                               hexa ) == -1 )
1266                     id->psz_fmtp = NULL;
1267             }
1268             else
1269             {
1270                 char hexa[13];
1271                 int i;
1272                 unsigned char config[6];
1273                 unsigned int aacsrates[15] = {
1274                     96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
1275                     16000, 12000, 11025, 8000, 7350, 0, 0 };
1276
1277                 for( i = 0; i < 15; i++ )
1278                     if( p_fmt->audio.i_rate == aacsrates[i] )
1279                         break;
1280
1281                 config[0]=0x40;
1282                 config[1]=0;
1283                 config[2]=0x20|i;
1284                 config[3]=p_fmt->audio.i_channels<<4;
1285                 config[4]=0x3f;
1286                 config[5]=0xc0;
1287
1288                 id->psz_enc = "MP4A-LATM";
1289                 id->pf_packetize = rtp_packetize_mp4a_latm;
1290                 sprintf_hexa( hexa, config, 6 );
1291                 if( asprintf( &id->psz_fmtp, "profile-level-id=15; "
1292                               "object=2; cpresent=0; config=%s", hexa ) == -1 )
1293                     id->psz_fmtp = NULL;
1294             }
1295             break;
1296         }
1297         case VLC_CODEC_AMR_NB:
1298             id->psz_enc = "AMR";
1299             id->psz_fmtp = strdup( "octet-align=1" );
1300             id->pf_packetize = rtp_packetize_amr;
1301             break;
1302         case VLC_CODEC_AMR_WB:
1303             id->psz_enc = "AMR-WB";
1304             id->psz_fmtp = strdup( "octet-align=1" );
1305             id->pf_packetize = rtp_packetize_amr;
1306             break;
1307         case VLC_CODEC_SPEEX:
1308             id->psz_enc = "SPEEX";
1309             id->pf_packetize = rtp_packetize_spx;
1310             break;
1311         case VLC_CODEC_ITU_T140:
1312             id->psz_enc = "t140" ;
1313             id->i_clock_rate = 1000;
1314             id->pf_packetize = rtp_packetize_t140;
1315             break;
1316
1317         default:
1318             msg_Err( p_stream, "cannot add this stream (unsupported "
1319                      "codec: %4.4s)", (char*)&p_fmt->i_codec );
1320             goto error;
1321     }
1322     if (id->i_payload_type >= 96)
1323         /* Mark dynamic payload type in use */
1324         p_sys->payload_bitmap |= 1 << (id->i_payload_type - 96);
1325
1326 #if 0 /* No payload formats sets this at the moment */
1327     int cscov = -1;
1328     if( cscov != -1 )
1329         cscov += 8 /* UDP */ + 12 /* RTP */;
1330     if( id->sinkc > 0 )
1331         net_SetCSCov( id->sinkv[0].rtp_fd, cscov, -1 );
1332 #endif
1333
1334     vlc_mutex_lock( &p_sys->lock_ts );
1335     id->b_ts_init = ( p_sys->i_npt_zero != VLC_TS_INVALID );
1336     vlc_mutex_unlock( &p_sys->lock_ts );
1337     if( id->b_ts_init )
1338         id->i_ts_offset = rtp_compute_ts( id, p_sys->i_pts_offset );
1339
1340     if( p_sys->rtsp != NULL )
1341         id->rtsp_id = RtspAddId( p_sys->rtsp, id,
1342                                  GetDWBE( id->ssrc ),
1343                                  p_sys->psz_destination,
1344                                  p_sys->i_ttl, id->i_port, id->i_port + 1 );
1345
1346     id->p_fifo = block_FifoNew();
1347     if( vlc_thread_create( id, "RTP send thread", ThreadSend,
1348                            VLC_THREAD_PRIORITY_HIGHEST ) )
1349         goto error;
1350
1351     /* Update p_sys context */
1352     vlc_mutex_lock( &p_sys->lock_es );
1353     TAB_APPEND( p_sys->i_es, p_sys->es, id );
1354     vlc_mutex_unlock( &p_sys->lock_es );
1355
1356     psz_sdp = SDPGenerate( p_stream, NULL );
1357
1358     vlc_mutex_lock( &p_sys->lock_sdp );
1359     free( p_sys->psz_sdp );
1360     p_sys->psz_sdp = psz_sdp;
1361     vlc_mutex_unlock( &p_sys->lock_sdp );
1362
1363     msg_Dbg( p_stream, "sdp=\n%s", p_sys->psz_sdp );
1364
1365     /* Update SDP (sap/file) */
1366     if( p_sys->b_export_sap ) SapSetup( p_stream );
1367     if( p_sys->psz_sdp_file != NULL ) FileSetup( p_stream );
1368
1369     return id;
1370
1371 error:
1372     Del( p_stream, id );
1373     return NULL;
1374 }
1375
1376 static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
1377 {
1378     sout_stream_sys_t *p_sys = p_stream->p_sys;
1379
1380     if( id->p_fifo != NULL )
1381     {
1382         vlc_object_kill( id );
1383         vlc_thread_join( id );
1384         block_FifoRelease( id->p_fifo );
1385     }
1386
1387     vlc_mutex_lock( &p_sys->lock_es );
1388     TAB_REMOVE( p_sys->i_es, p_sys->es, id );
1389     vlc_mutex_unlock( &p_sys->lock_es );
1390
1391     /* Release dynamic payload type */
1392     if (id->i_payload_type >= 96)
1393         p_sys->payload_bitmap &= ~(1 << (id->i_payload_type - 96));
1394
1395     free( id->psz_fmtp );
1396
1397     if( id->rtsp_id )
1398         RtspDelId( p_sys->rtsp, id->rtsp_id );
1399     if( id->sinkc > 0 )
1400         rtp_del_sink( id, id->sinkv[0].rtp_fd ); /* sink for explicit dst= */
1401     if( id->listen.fd != NULL )
1402     {
1403         vlc_cancel( id->listen.thread );
1404         vlc_join( id->listen.thread, NULL );
1405         net_ListenClose( id->listen.fd );
1406     }
1407 #ifdef HAVE_SRTP
1408     if( id->srtp != NULL )
1409         srtp_destroy( id->srtp );
1410 #endif
1411
1412     vlc_mutex_destroy( &id->lock_sink );
1413
1414     /* Update SDP (sap/file) */
1415     if( p_sys->b_export_sap && !p_sys->p_mux ) SapSetup( p_stream );
1416     if( p_sys->psz_sdp_file != NULL ) FileSetup( p_stream );
1417
1418     vlc_object_detach( id );
1419     vlc_object_release( id );
1420     return VLC_SUCCESS;
1421 }
1422
1423 static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
1424                  block_t *p_buffer )
1425 {
1426     block_t *p_next;
1427
1428     assert( p_stream->p_sys->p_mux == NULL );
1429     (void)p_stream;
1430
1431     while( p_buffer != NULL )
1432     {
1433         p_next = p_buffer->p_next;
1434         if( id->pf_packetize( id, p_buffer ) )
1435             break;
1436
1437         block_Release( p_buffer );
1438         p_buffer = p_next;
1439     }
1440     return VLC_SUCCESS;
1441 }
1442
1443 /****************************************************************************
1444  * SAP:
1445  ****************************************************************************/
1446 static int SapSetup( sout_stream_t *p_stream )
1447 {
1448     sout_stream_sys_t *p_sys = p_stream->p_sys;
1449     sout_instance_t   *p_sout = p_stream->p_sout;
1450
1451     /* Remove the previous session */
1452     if( p_sys->p_session != NULL)
1453     {
1454         sout_AnnounceUnRegister( p_sout, p_sys->p_session);
1455         p_sys->p_session = NULL;
1456     }
1457
1458     if( ( p_sys->i_es > 0 || p_sys->p_mux ) && p_sys->psz_sdp && *p_sys->psz_sdp )
1459     {
1460         announce_method_t *p_method = sout_SAPMethod();
1461         p_sys->p_session = sout_AnnounceRegisterSDP( p_sout,
1462                                                      p_sys->psz_sdp,
1463                                                      p_sys->psz_destination,
1464                                                      p_method );
1465         sout_MethodRelease( p_method );
1466     }
1467
1468     return VLC_SUCCESS;
1469 }
1470
1471 /****************************************************************************
1472 * File:
1473 ****************************************************************************/
1474 static int FileSetup( sout_stream_t *p_stream )
1475 {
1476     sout_stream_sys_t *p_sys = p_stream->p_sys;
1477     FILE            *f;
1478
1479     if( p_sys->psz_sdp == NULL )
1480         return VLC_EGENERIC; /* too early */
1481
1482     if( ( f = utf8_fopen( p_sys->psz_sdp_file, "wt" ) ) == NULL )
1483     {
1484         msg_Err( p_stream, "cannot open file '%s' (%m)",
1485                  p_sys->psz_sdp_file );
1486         return VLC_EGENERIC;
1487     }
1488
1489     fputs( p_sys->psz_sdp, f );
1490     fclose( f );
1491
1492     return VLC_SUCCESS;
1493 }
1494
1495 /****************************************************************************
1496  * HTTP:
1497  ****************************************************************************/
1498 static int  HttpCallback( httpd_file_sys_t *p_args,
1499                           httpd_file_t *, uint8_t *p_request,
1500                           uint8_t **pp_data, int *pi_data );
1501
1502 static int HttpSetup( sout_stream_t *p_stream, const vlc_url_t *url)
1503 {
1504     sout_stream_sys_t *p_sys = p_stream->p_sys;
1505
1506     p_sys->p_httpd_host = httpd_HostNew( VLC_OBJECT(p_stream), url->psz_host,
1507                                          url->i_port > 0 ? url->i_port : 80 );
1508     if( p_sys->p_httpd_host )
1509     {
1510         p_sys->p_httpd_file = httpd_FileNew( p_sys->p_httpd_host,
1511                                              url->psz_path ? url->psz_path : "/",
1512                                              "application/sdp",
1513                                              NULL, NULL, NULL,
1514                                              HttpCallback, (void*)p_sys );
1515     }
1516     if( p_sys->p_httpd_file == NULL )
1517     {
1518         return VLC_EGENERIC;
1519     }
1520     return VLC_SUCCESS;
1521 }
1522
1523 static int  HttpCallback( httpd_file_sys_t *p_args,
1524                           httpd_file_t *f, uint8_t *p_request,
1525                           uint8_t **pp_data, int *pi_data )
1526 {
1527     VLC_UNUSED(f); VLC_UNUSED(p_request);
1528     sout_stream_sys_t *p_sys = (sout_stream_sys_t*)p_args;
1529
1530     vlc_mutex_lock( &p_sys->lock_sdp );
1531     if( p_sys->psz_sdp && *p_sys->psz_sdp )
1532     {
1533         *pi_data = strlen( p_sys->psz_sdp );
1534         *pp_data = malloc( *pi_data );
1535         memcpy( *pp_data, p_sys->psz_sdp, *pi_data );
1536     }
1537     else
1538     {
1539         *pp_data = NULL;
1540         *pi_data = 0;
1541     }
1542     vlc_mutex_unlock( &p_sys->lock_sdp );
1543
1544     return VLC_SUCCESS;
1545 }
1546
1547 /****************************************************************************
1548  * RTP send
1549  ****************************************************************************/
1550 static void* ThreadSend( vlc_object_t *p_this )
1551 {
1552 #ifdef WIN32
1553 # define ECONNREFUSED WSAECONNREFUSED
1554 # define ENOPROTOOPT  WSAENOPROTOOPT
1555 # define EHOSTUNREACH WSAEHOSTUNREACH
1556 # define ENETUNREACH  WSAENETUNREACH
1557 # define ENETDOWN     WSAENETDOWN
1558 # define ENOBUFS      WSAENOBUFS
1559 # define EAGAIN       WSAEWOULDBLOCK
1560 # define EWOULDBLOCK  WSAEWOULDBLOCK
1561 #endif
1562     sout_stream_id_t *id = (sout_stream_id_t *)p_this;
1563     unsigned i_caching = id->i_caching;
1564
1565     for (;;)
1566     {
1567         block_t *out = block_FifoGet( id->p_fifo );
1568         block_cleanup_push (out);
1569
1570 #ifdef HAVE_SRTP
1571         if( id->srtp )
1572         {   /* FIXME: this is awfully inefficient */
1573             size_t len = out->i_buffer;
1574             out = block_Realloc( out, 0, len + 10 );
1575             out->i_buffer = len;
1576
1577             int canc = vlc_savecancel ();
1578             int val = srtp_send( id->srtp, out->p_buffer, &len, len + 10 );
1579             vlc_restorecancel (canc);
1580             if( val )
1581             {
1582                 errno = val;
1583                 msg_Dbg( id, "SRTP sending error: %m" );
1584                 block_Release( out );
1585                 out = NULL;
1586             }
1587             else
1588                 out->i_buffer = len;
1589         }
1590         if (out)
1591 #endif
1592             mwait (out->i_dts + i_caching);
1593         vlc_cleanup_pop ();
1594         if (out == NULL)
1595             continue;
1596
1597         ssize_t len = out->i_buffer;
1598         int canc = vlc_savecancel ();
1599
1600         vlc_mutex_lock( &id->lock_sink );
1601         unsigned deadc = 0; /* How many dead sockets? */
1602         int deadv[id->sinkc]; /* Dead sockets list */
1603
1604         for( int i = 0; i < id->sinkc; i++ )
1605         {
1606 #ifdef HAVE_SRTP
1607             if( !id->srtp ) /* FIXME: SRTCP support */
1608 #endif
1609                 SendRTCP( id->sinkv[i].rtcp, out );
1610
1611             if( send( id->sinkv[i].rtp_fd, out->p_buffer, len, 0 ) >= 0 )
1612                 continue;
1613             switch( net_errno )
1614             {
1615                 /* Soft errors (e.g. ICMP): */
1616                 case ECONNREFUSED: /* Port unreachable */
1617                 case ENOPROTOOPT:
1618 #ifdef EPROTO
1619                 case EPROTO:       /* Protocol unreachable */
1620 #endif
1621                 case EHOSTUNREACH: /* Host unreachable */
1622                 case ENETUNREACH:  /* Network unreachable */
1623                 case ENETDOWN:     /* Entire network down */
1624                     send( id->sinkv[i].rtp_fd, out->p_buffer, len, 0 );
1625                 /* Transient congestion: */
1626                 case ENOMEM: /* out of socket buffers */
1627                 case ENOBUFS:
1628                 case EAGAIN:
1629 #if (EAGAIN != EWOULDBLOCK)
1630                 case EWOULDBLOCK:
1631 #endif
1632                     continue;
1633             }
1634
1635             deadv[deadc++] = id->sinkv[i].rtp_fd;
1636         }
1637         id->i_seq_sent_next = ntohs(((uint16_t *) out->p_buffer)[1]) + 1;
1638         vlc_mutex_unlock( &id->lock_sink );
1639         block_Release( out );
1640
1641         for( unsigned i = 0; i < deadc; i++ )
1642         {
1643             msg_Dbg( id, "removing socket %d", deadv[i] );
1644             rtp_del_sink( id, deadv[i] );
1645         }
1646         vlc_restorecancel (canc);
1647     }
1648     return NULL;
1649 }
1650
1651
1652 /* This thread dequeues incoming connections (DCCP streaming) */
1653 static void *rtp_listen_thread( void *data )
1654 {
1655     sout_stream_id_t *id = data;
1656
1657     assert( id->listen.fd != NULL );
1658
1659     for( ;; )
1660     {
1661         int fd = net_Accept( id, id->listen.fd );
1662         if( fd == -1 )
1663             continue;
1664         int canc = vlc_savecancel( );
1665         rtp_add_sink( id, fd, true, NULL );
1666         vlc_restorecancel( canc );
1667     }
1668
1669     assert( 0 );
1670 }
1671
1672
1673 int rtp_add_sink( sout_stream_id_t *id, int fd, bool rtcp_mux, uint16_t *seq )
1674 {
1675     rtp_sink_t sink = { fd, NULL };
1676     sink.rtcp = OpenRTCP( VLC_OBJECT( id->p_stream ), fd, IPPROTO_UDP,
1677                           rtcp_mux );
1678     if( sink.rtcp == NULL )
1679         msg_Err( id, "RTCP failed!" );
1680
1681     vlc_mutex_lock( &id->lock_sink );
1682     INSERT_ELEM( id->sinkv, id->sinkc, id->sinkc, sink );
1683     if( seq != NULL )
1684         *seq = id->i_seq_sent_next;
1685     vlc_mutex_unlock( &id->lock_sink );
1686     return VLC_SUCCESS;
1687 }
1688
1689 void rtp_del_sink( sout_stream_id_t *id, int fd )
1690 {
1691     rtp_sink_t sink = { fd, NULL };
1692
1693     /* NOTE: must be safe to use if fd is not included */
1694     vlc_mutex_lock( &id->lock_sink );
1695     for( int i = 0; i < id->sinkc; i++ )
1696     {
1697         if (id->sinkv[i].rtp_fd == fd)
1698         {
1699             sink = id->sinkv[i];
1700             REMOVE_ELEM( id->sinkv, id->sinkc, i );
1701             break;
1702         }
1703     }
1704     vlc_mutex_unlock( &id->lock_sink );
1705
1706     CloseRTCP( sink.rtcp );
1707     net_Close( sink.rtp_fd );
1708 }
1709
1710 uint16_t rtp_get_seq( sout_stream_id_t *id )
1711 {
1712     /* This will return values for the next packet. */
1713     uint16_t seq;
1714
1715     vlc_mutex_lock( &id->lock_sink );
1716     seq = id->i_seq_sent_next;
1717     vlc_mutex_unlock( &id->lock_sink );
1718
1719     return seq;
1720 }
1721
1722 /* Return a timestamp corresponding to packets being sent now, and that
1723  * can be passed to rtp_compute_ts() to get rtptime values for each ES. */
1724 int64_t rtp_get_ts( const sout_stream_t *p_stream )
1725 {
1726     sout_stream_sys_t *p_sys = p_stream->p_sys;
1727     mtime_t i_npt_zero;
1728     vlc_mutex_lock( &p_sys->lock_ts );
1729     i_npt_zero = p_sys->i_npt_zero;
1730     vlc_mutex_unlock( &p_sys->lock_ts );
1731
1732     if( i_npt_zero == VLC_TS_INVALID )
1733         return p_sys->i_pts_zero;
1734
1735     mtime_t now = mdate();
1736     if( now < i_npt_zero )
1737         return p_sys->i_pts_zero;
1738
1739     return p_sys->i_pts_zero + (now - i_npt_zero); 
1740 }
1741
1742 void rtp_packetize_common( sout_stream_id_t *id, block_t *out,
1743                            int b_marker, int64_t i_pts )
1744 {
1745     if( !id->b_ts_init )
1746     {
1747         sout_stream_sys_t *p_sys = id->p_stream->p_sys;
1748         vlc_mutex_lock( &p_sys->lock_ts );
1749         if( p_sys->i_npt_zero == VLC_TS_INVALID )
1750         {
1751             /* This is the first packet of any ES. We initialize the
1752              * NPT=0 time reference, and the offset to match the
1753              * arbitrary PTS reference. */
1754             p_sys->i_npt_zero = i_pts + id->i_caching;
1755             p_sys->i_pts_offset = p_sys->i_pts_zero - i_pts;
1756         }
1757         vlc_mutex_unlock( &p_sys->lock_ts );
1758
1759         /* And in any case this is the first packet of this ES, so we
1760          * initialize the offset for this ES. */
1761         id->i_ts_offset = rtp_compute_ts( id, p_sys->i_pts_offset );
1762         id->b_ts_init = true;
1763     }
1764
1765     uint32_t i_timestamp = rtp_compute_ts( id, i_pts ) + id->i_ts_offset;
1766
1767     out->p_buffer[0] = 0x80;
1768     out->p_buffer[1] = (b_marker?0x80:0x00)|id->i_payload_type;
1769     out->p_buffer[2] = ( id->i_sequence >> 8)&0xff;
1770     out->p_buffer[3] = ( id->i_sequence     )&0xff;
1771     out->p_buffer[4] = ( i_timestamp >> 24 )&0xff;
1772     out->p_buffer[5] = ( i_timestamp >> 16 )&0xff;
1773     out->p_buffer[6] = ( i_timestamp >>  8 )&0xff;
1774     out->p_buffer[7] = ( i_timestamp       )&0xff;
1775
1776     memcpy( out->p_buffer + 8, id->ssrc, 4 );
1777
1778     out->i_buffer = 12;
1779     id->i_sequence++;
1780 }
1781
1782 void rtp_packetize_send( sout_stream_id_t *id, block_t *out )
1783 {
1784     block_FifoPut( id->p_fifo, out );
1785 }
1786
1787 /**
1788  * @return configured max RTP payload size (including payload type-specific
1789  * headers, excluding RTP and transport headers)
1790  */
1791 size_t rtp_mtu (const sout_stream_id_t *id)
1792 {
1793     return id->i_mtu - 12;
1794 }
1795
1796 /*****************************************************************************
1797  * Non-RTP mux
1798  *****************************************************************************/
1799
1800 /** Add an ES to a non-RTP muxed stream */
1801 static sout_stream_id_t *MuxAdd( sout_stream_t *p_stream, es_format_t *p_fmt )
1802 {
1803     sout_input_t      *p_input;
1804     sout_mux_t *p_mux = p_stream->p_sys->p_mux;
1805     assert( p_mux != NULL );
1806
1807     p_input = sout_MuxAddStream( p_mux, p_fmt );
1808     if( p_input == NULL )
1809     {
1810         msg_Err( p_stream, "cannot add this stream to the muxer" );
1811         return NULL;
1812     }
1813
1814     return (sout_stream_id_t *)p_input;
1815 }
1816
1817
1818 static int MuxSend( sout_stream_t *p_stream, sout_stream_id_t *id,
1819                     block_t *p_buffer )
1820 {
1821     sout_mux_t *p_mux = p_stream->p_sys->p_mux;
1822     assert( p_mux != NULL );
1823
1824     sout_MuxSendBuffer( p_mux, (sout_input_t *)id, p_buffer );
1825     return VLC_SUCCESS;
1826 }
1827
1828
1829 /** Remove an ES from a non-RTP muxed stream */
1830 static int MuxDel( sout_stream_t *p_stream, sout_stream_id_t *id )
1831 {
1832     sout_mux_t *p_mux = p_stream->p_sys->p_mux;
1833     assert( p_mux != NULL );
1834
1835     sout_MuxDeleteStream( p_mux, (sout_input_t *)id );
1836     return VLC_SUCCESS;
1837 }
1838
1839
1840 static ssize_t AccessOutGrabberWriteBuffer( sout_stream_t *p_stream,
1841                                             const block_t *p_buffer )
1842 {
1843     sout_stream_sys_t *p_sys = p_stream->p_sys;
1844     sout_stream_id_t *id = p_sys->es[0];
1845
1846     int64_t  i_dts = p_buffer->i_dts;
1847
1848     uint8_t         *p_data = p_buffer->p_buffer;
1849     size_t          i_data  = p_buffer->i_buffer;
1850     size_t          i_max   = id->i_mtu - 12;
1851
1852     size_t i_packet = ( p_buffer->i_buffer + i_max - 1 ) / i_max;
1853
1854     while( i_data > 0 )
1855     {
1856         size_t i_size;
1857
1858         /* output complete packet */
1859         if( p_sys->packet &&
1860             p_sys->packet->i_buffer + i_data > i_max )
1861         {
1862             rtp_packetize_send( id, p_sys->packet );
1863             p_sys->packet = NULL;
1864         }
1865
1866         if( p_sys->packet == NULL )
1867         {
1868             /* allocate a new packet */
1869             p_sys->packet = block_New( p_stream, id->i_mtu );
1870             rtp_packetize_common( id, p_sys->packet, 1, i_dts );
1871             p_sys->packet->i_dts = i_dts;
1872             p_sys->packet->i_length = p_buffer->i_length / i_packet;
1873             i_dts += p_sys->packet->i_length;
1874         }
1875
1876         i_size = __MIN( i_data,
1877                         (unsigned)(id->i_mtu - p_sys->packet->i_buffer) );
1878
1879         memcpy( &p_sys->packet->p_buffer[p_sys->packet->i_buffer],
1880                 p_data, i_size );
1881
1882         p_sys->packet->i_buffer += i_size;
1883         p_data += i_size;
1884         i_data -= i_size;
1885     }
1886
1887     return VLC_SUCCESS;
1888 }
1889
1890
1891 static ssize_t AccessOutGrabberWrite( sout_access_out_t *p_access,
1892                                       block_t *p_buffer )
1893 {
1894     sout_stream_t *p_stream = (sout_stream_t*)p_access->p_sys;
1895
1896     while( p_buffer )
1897     {
1898         block_t *p_next;
1899
1900         AccessOutGrabberWriteBuffer( p_stream, p_buffer );
1901
1902         p_next = p_buffer->p_next;
1903         block_Release( p_buffer );
1904         p_buffer = p_next;
1905     }
1906
1907     return VLC_SUCCESS;
1908 }
1909
1910
1911 static sout_access_out_t *GrabberCreate( sout_stream_t *p_stream )
1912 {
1913     sout_access_out_t *p_grab;
1914
1915     p_grab = vlc_object_create( p_stream->p_sout, sizeof( *p_grab ) );
1916     if( p_grab == NULL )
1917         return NULL;
1918
1919     p_grab->p_module    = NULL;
1920     p_grab->psz_access  = strdup( "grab" );
1921     p_grab->p_cfg       = NULL;
1922     p_grab->psz_path    = strdup( "" );
1923     p_grab->p_sys       = (sout_access_out_sys_t *)p_stream;
1924     p_grab->pf_seek     = NULL;
1925     p_grab->pf_write    = AccessOutGrabberWrite;
1926     vlc_object_attach( p_grab, p_stream );
1927     return p_grab;
1928 }