1 /*****************************************************************************
2 * rtp.c: rtp stream output module
3 *****************************************************************************
4 * Copyright (C) 2003-2004 the VideoLAN team
5 * Copyright © 2007 Rémi Denis-Courmont
8 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
31 #include <vlc_block.h>
33 #include <vlc_httpd.h>
35 #include <vlc_network.h>
36 #include <vlc_charset.h>
37 #include <vlc_strings.h>
42 # include <sys/types.h>
45 # include <sys/stat.h>
47 #ifdef HAVE_LINUX_DCCP_H
48 # include <linux/dccp.h>
51 # define IPPROTO_DCCP 33
53 #ifndef IPPROTO_UDPLITE
54 # define IPPROTO_UDPLITE 136
59 /*****************************************************************************
61 *****************************************************************************/
63 #define DST_TEXT N_("Destination")
64 #define DST_LONGTEXT N_( \
65 "This is the output URL that will be used." )
66 #define SDP_TEXT N_("SDP")
67 #define SDP_LONGTEXT N_( \
68 "This allows you to specify how the SDP (Session Descriptor) for this RTP "\
69 "session will be made available. You must use an url: http://location to " \
70 "access the SDP via HTTP, rtsp://location for RTSP access, and sap:// " \
71 "for the SDP to be announced via SAP." )
72 #define MUX_TEXT N_("Muxer")
73 #define MUX_LONGTEXT N_( \
74 "This allows you to specify the muxer used for the streaming output. " \
75 "Default is to use no muxer (standard RTP stream)." )
77 #define NAME_TEXT N_("Session name")
78 #define NAME_LONGTEXT N_( \
79 "This is the name of the session that will be announced in the SDP " \
80 "(Session Descriptor)." )
81 #define DESC_TEXT N_("Session descriptipn")
82 #define DESC_LONGTEXT N_( \
83 "This allows you to give a short description with details about the stream, " \
84 "that will be announced in the SDP (Session Descriptor)." )
85 #define URL_TEXT N_("Session URL")
86 #define URL_LONGTEXT N_( \
87 "This allows you to give an URL with more details about the stream " \
88 "(often the website of the streaming organization), that will " \
89 "be announced in the SDP (Session Descriptor)." )
90 #define EMAIL_TEXT N_("Session email")
91 #define EMAIL_LONGTEXT N_( \
92 "This allows you to give a contact mail address for the stream, that will " \
93 "be announced in the SDP (Session Descriptor)." )
94 #define PHONE_TEXT N_("Session phone number")
95 #define PHONE_LONGTEXT N_( \
96 "This allows you to give a contact telephone number for the stream, that will " \
97 "be announced in the SDP (Session Descriptor)." )
99 #define PORT_TEXT N_("Port")
100 #define PORT_LONGTEXT N_( \
101 "This allows you to specify the base port for the RTP streaming." )
102 #define PORT_AUDIO_TEXT N_("Audio port")
103 #define PORT_AUDIO_LONGTEXT N_( \
104 "This allows you to specify the default audio port for the RTP streaming." )
105 #define PORT_VIDEO_TEXT N_("Video port")
106 #define PORT_VIDEO_LONGTEXT N_( \
107 "This allows you to specify the default video port for the RTP streaming." )
109 #define TTL_TEXT N_("Hop limit (TTL)")
110 #define TTL_LONGTEXT N_( \
111 "This is the hop limit (also known as \"Time-To-Live\" or TTL) of " \
112 "the multicast packets sent by the stream output (0 = use operating " \
113 "system built-in default).")
115 #define RTCP_MUX_TEXT N_("RTP/RTCP multiplexing")
116 #define RTCP_MUX_LONGTEXT N_( \
117 "This sends and receives RTCP packet multiplexed over the same port " \
120 #define DCCP_TEXT N_("DCCP transport")
121 #define DCCP_LONGTEXT N_( \
122 "This enables DCCP instead of UDP as a transport for RTP." )
123 #define TCP_TEXT N_("TCP transport")
124 #define TCP_LONGTEXT N_( \
125 "This enables TCP instead of UDP as a transport for RTP." )
126 #define UDP_LITE_TEXT N_("UDP-Lite transport")
127 #define UDP_LITE_LONGTEXT N_( \
128 "This enables UDP-Lite instead of UDP as a transport for RTP." )
130 #define RFC3016_TEXT N_("MP4A LATM")
131 #define RFC3016_LONGTEXT N_( \
132 "This allows you to stream MPEG4 LATM audio streams (see RFC3016)." )
134 static int Open ( vlc_object_t * );
135 static void Close( vlc_object_t * );
137 #define SOUT_CFG_PREFIX "sout-rtp-"
138 #define MAX_EMPTY_BLOCKS 200
141 set_shortname( _("RTP"));
142 set_description( _("RTP stream output") );
143 set_capability( "sout stream", 0 );
144 add_shortcut( "rtp" );
145 set_category( CAT_SOUT );
146 set_subcategory( SUBCAT_SOUT_STREAM );
148 add_string( SOUT_CFG_PREFIX "dst", "", NULL, DST_TEXT,
149 DST_LONGTEXT, VLC_TRUE );
150 add_string( SOUT_CFG_PREFIX "sdp", "", NULL, SDP_TEXT,
151 SDP_LONGTEXT, VLC_TRUE );
152 add_string( SOUT_CFG_PREFIX "mux", "", NULL, MUX_TEXT,
153 MUX_LONGTEXT, VLC_TRUE );
155 add_string( SOUT_CFG_PREFIX "name", "", NULL, NAME_TEXT,
156 NAME_LONGTEXT, VLC_TRUE );
157 add_string( SOUT_CFG_PREFIX "description", "", NULL, DESC_TEXT,
158 DESC_LONGTEXT, VLC_TRUE );
159 add_string( SOUT_CFG_PREFIX "url", "", NULL, URL_TEXT,
160 URL_LONGTEXT, VLC_TRUE );
161 add_string( SOUT_CFG_PREFIX "email", "", NULL, EMAIL_TEXT,
162 EMAIL_LONGTEXT, VLC_TRUE );
163 add_string( SOUT_CFG_PREFIX "phone", "", NULL, PHONE_TEXT,
164 PHONE_LONGTEXT, VLC_TRUE );
166 add_integer( SOUT_CFG_PREFIX "port", 1234, NULL, PORT_TEXT,
167 PORT_LONGTEXT, VLC_TRUE );
168 add_integer( SOUT_CFG_PREFIX "port-audio", 1230, NULL, PORT_AUDIO_TEXT,
169 PORT_AUDIO_LONGTEXT, VLC_TRUE );
170 add_integer( SOUT_CFG_PREFIX "port-video", 1232, NULL, PORT_VIDEO_TEXT,
171 PORT_VIDEO_LONGTEXT, VLC_TRUE );
173 add_integer( SOUT_CFG_PREFIX "ttl", 0, NULL, TTL_TEXT,
174 TTL_LONGTEXT, VLC_TRUE );
176 add_bool( SOUT_CFG_PREFIX "rtcp-mux", VLC_FALSE, NULL,
177 RTCP_MUX_TEXT, RTCP_MUX_LONGTEXT, VLC_FALSE );
179 add_bool( SOUT_CFG_PREFIX "dccp", VLC_FALSE, NULL,
180 DCCP_TEXT, DCCP_LONGTEXT, VLC_FALSE );
181 add_bool( SOUT_CFG_PREFIX "tcp", VLC_FALSE, NULL,
182 TCP_TEXT, TCP_LONGTEXT, VLC_FALSE );
183 add_bool( SOUT_CFG_PREFIX "udplite", VLC_FALSE, NULL,
184 UDP_LITE_TEXT, UDP_LITE_LONGTEXT, VLC_FALSE );
186 add_bool( SOUT_CFG_PREFIX "mp4a-latm", 0, NULL, RFC3016_TEXT,
187 RFC3016_LONGTEXT, VLC_FALSE );
189 set_callbacks( Open, Close );
192 /*****************************************************************************
193 * Exported prototypes
194 *****************************************************************************/
195 static const char *ppsz_sout_options[] = {
196 "dst", "name", "port", "port-audio", "port-video", "*sdp", "ttl", "mux",
197 "description", "url", "email", "phone",
198 "rtcp-mux", "dccp", "tcp", "udplite",
202 static sout_stream_id_t *Add ( sout_stream_t *, es_format_t * );
203 static int Del ( sout_stream_t *, sout_stream_id_t * );
204 static int Send( sout_stream_t *, sout_stream_id_t *,
206 static sout_stream_id_t *MuxAdd ( sout_stream_t *, es_format_t * );
207 static int MuxDel ( sout_stream_t *, sout_stream_id_t * );
208 static int MuxSend( sout_stream_t *, sout_stream_id_t *,
211 static sout_access_out_t *GrabberCreate( sout_stream_t *p_sout );
212 static void ThreadSend( vlc_object_t *p_this );
214 static void SDPHandleUrl( sout_stream_t *, char * );
216 static int SapSetup( sout_stream_t *p_stream );
217 static int FileSetup( sout_stream_t *p_stream );
218 static int HttpSetup( sout_stream_t *p_stream, vlc_url_t * );
220 struct sout_stream_sys_t
224 vlc_mutex_t lock_sdp;
227 vlc_bool_t b_export_sdp_file;
231 vlc_bool_t b_export_sap;
232 session_descriptor_t *p_session;
235 httpd_host_t *p_httpd_host;
236 httpd_file_t *p_httpd_file;
242 char *psz_destination;
246 uint16_t i_port_audio;
247 uint16_t i_port_video;
251 /* when need to use a private one or when using muxer */
254 /* in case we do TS/PS over rtp */
256 sout_access_out_t *p_grab;
262 sout_stream_id_t **es;
265 typedef int (*pf_rtp_packetizer_t)( sout_stream_t *, sout_stream_id_t *,
268 typedef struct rtp_sink_t
274 struct sout_stream_id_t
278 sout_stream_t *p_stream;
281 uint8_t i_payload_type;
292 /* Packetizer specific fields */
293 pf_rtp_packetizer_t pf_packetize;
297 vlc_mutex_t lock_sink;
300 rtsp_stream_id_t *rtsp_id;
303 block_fifo_t *p_fifo;
308 /*****************************************************************************
310 *****************************************************************************/
311 static int Open( vlc_object_t *p_this )
313 sout_stream_t *p_stream = (sout_stream_t*)p_this;
314 sout_instance_t *p_sout = p_stream->p_sout;
315 sout_stream_sys_t *p_sys = NULL;
316 config_chain_t *p_cfg = NULL;
318 vlc_bool_t b_rtsp = VLC_FALSE;
320 config_ChainParse( p_stream, SOUT_CFG_PREFIX,
321 ppsz_sout_options, p_stream->p_cfg );
323 p_sys = malloc( sizeof( sout_stream_sys_t ) );
327 p_sys->psz_destination = var_GetNonEmptyString( p_stream, SOUT_CFG_PREFIX "dst" );
329 p_sys->i_port = var_GetInteger( p_stream, SOUT_CFG_PREFIX "port" );
330 p_sys->i_port_audio = var_GetInteger( p_stream, SOUT_CFG_PREFIX "port-audio" );
331 p_sys->i_port_video = var_GetInteger( p_stream, SOUT_CFG_PREFIX "port-video" );
332 p_sys->rtcp_mux = var_GetBool( p_stream, SOUT_CFG_PREFIX "rtcp-mux" );
334 p_sys->psz_sdp_file = NULL;
336 if( p_sys->i_port_audio == p_sys->i_port_video )
338 msg_Err( p_stream, "audio and video port cannot be the same" );
339 p_sys->i_port_audio = 0;
340 p_sys->i_port_video = 0;
343 for( p_cfg = p_stream->p_cfg; p_cfg != NULL; p_cfg = p_cfg->p_next )
345 if( !strcmp( p_cfg->psz_name, "sdp" )
346 && ( p_cfg->psz_value != NULL )
347 && !strncasecmp( p_cfg->psz_value, "rtsp:", 5 ) )
355 psz = var_GetNonEmptyString( p_stream, SOUT_CFG_PREFIX "sdp" );
358 if( !strncasecmp( psz, "rtsp:", 5 ) )
364 /* Transport protocol */
365 p_sys->proto = IPPROTO_UDP;
367 if( var_GetBool( p_stream, SOUT_CFG_PREFIX "dccp" ) )
369 p_sys->proto = IPPROTO_DCCP;
370 p_sys->rtcp_mux = VLC_TRUE; /* Force RTP/RTCP mux */
374 if( var_GetBool( p_stream, SOUT_CFG_PREFIX "tcp" ) )
376 p_sys->proto = IPPROTO_TCP;
377 p_sys->rtcp_mux = VLC_TRUE; /* Force RTP/RTCP mux */
381 if( var_GetBool( p_stream, SOUT_CFG_PREFIX "udplite" ) )
382 p_sys->proto = IPPROTO_UDPLITE;
384 if( ( p_sys->psz_destination == NULL ) && !b_rtsp )
386 msg_Err( p_stream, "missing destination and not in RTSP mode" );
391 p_sys->i_ttl = var_GetInteger( p_stream, SOUT_CFG_PREFIX "ttl" );
392 if( p_sys->i_ttl == 0 )
394 /* Normally, we should let the default hop limit up to the core,
395 * but we have to know it to build our SDP properly, which is why
396 * we ask the core. FIXME: broken when neither sout-rtp-ttl nor
398 p_sys->i_ttl = config_GetInt( p_stream, "ttl" );
401 p_sys->b_latm = var_GetBool( p_stream, SOUT_CFG_PREFIX "mp4a-latm" );
403 p_sys->i_payload_type = 96;
407 p_sys->psz_sdp = NULL;
409 p_sys->b_export_sap = VLC_FALSE;
410 p_sys->b_export_sdp_file = VLC_FALSE;
411 p_sys->p_session = NULL;
413 p_sys->p_httpd_host = NULL;
414 p_sys->p_httpd_file = NULL;
416 p_stream->p_sys = p_sys;
418 vlc_mutex_init( p_stream, &p_sys->lock_sdp );
419 vlc_mutex_init( p_stream, &p_sys->lock_es );
421 psz = var_GetNonEmptyString( p_stream, SOUT_CFG_PREFIX "mux" );
424 sout_stream_id_t *id;
426 /* Check muxer type */
427 if( strncasecmp( psz, "ps", 2 )
428 && strncasecmp( psz, "mpeg1", 5 )
429 && strncasecmp( psz, "ts", 2 ) )
431 msg_Err( p_stream, "unsupported muxer type for RTP (only TS/PS)" );
433 vlc_mutex_destroy( &p_sys->lock_sdp );
434 vlc_mutex_destroy( &p_sys->lock_es );
439 p_sys->p_grab = GrabberCreate( p_stream );
440 p_sys->p_mux = sout_MuxNew( p_sout, psz, p_sys->p_grab );
443 if( p_sys->p_mux == NULL )
445 msg_Err( p_stream, "cannot create muxer" );
446 sout_AccessOutDelete( p_sys->p_grab );
447 vlc_mutex_destroy( &p_sys->lock_sdp );
448 vlc_mutex_destroy( &p_sys->lock_es );
453 id = Add( p_stream, NULL );
456 sout_MuxDelete( p_sys->p_mux );
457 sout_AccessOutDelete( p_sys->p_grab );
458 vlc_mutex_destroy( &p_sys->lock_sdp );
459 vlc_mutex_destroy( &p_sys->lock_es );
464 p_sys->packet = NULL;
466 p_stream->pf_add = MuxAdd;
467 p_stream->pf_del = MuxDel;
468 p_stream->pf_send = MuxSend;
473 p_sys->p_grab = NULL;
475 p_stream->pf_add = Add;
476 p_stream->pf_del = Del;
477 p_stream->pf_send = Send;
480 psz = var_GetNonEmptyString( p_stream, SOUT_CFG_PREFIX "sdp" );
483 config_chain_t *p_cfg;
485 SDPHandleUrl( p_stream, psz );
487 for( p_cfg = p_stream->p_cfg; p_cfg != NULL; p_cfg = p_cfg->p_next )
489 if( !strcmp( p_cfg->psz_name, "sdp" ) )
491 if( p_cfg->psz_value == NULL || *p_cfg->psz_value == '\0' )
494 /* needed both :sout-rtp-sdp= and rtp{sdp=} can be used */
495 if( !strcmp( p_cfg->psz_value, psz ) )
498 SDPHandleUrl( p_stream, p_cfg->psz_value );
504 /* update p_sout->i_out_pace_nocontrol */
505 p_stream->p_sout->i_out_pace_nocontrol++;
510 /*****************************************************************************
512 *****************************************************************************/
513 static void Close( vlc_object_t * p_this )
515 sout_stream_t *p_stream = (sout_stream_t*)p_this;
516 sout_stream_sys_t *p_sys = p_stream->p_sys;
518 /* update p_sout->i_out_pace_nocontrol */
519 p_stream->p_sout->i_out_pace_nocontrol--;
523 assert( p_sys->i_es == 1 );
524 Del( p_stream, p_sys->es[0] );
526 sout_MuxDelete( p_sys->p_mux );
527 sout_AccessOutDelete( p_sys->p_grab );
530 block_Release( p_sys->packet );
532 if( p_sys->b_export_sap )
535 SapSetup( p_stream );
539 if( p_sys->rtsp != NULL )
540 RtspUnsetup( p_sys->rtsp );
542 vlc_mutex_destroy( &p_sys->lock_sdp );
543 vlc_mutex_destroy( &p_sys->lock_es );
545 if( p_sys->p_httpd_file )
546 httpd_FileDelete( p_sys->p_httpd_file );
548 if( p_sys->p_httpd_host )
549 httpd_HostDelete( p_sys->p_httpd_host );
551 free( p_sys->psz_sdp );
553 if( p_sys->b_export_sdp_file )
556 unlink( p_sys->psz_sdp_file );
558 free( p_sys->psz_sdp_file );
560 free( p_sys->psz_destination );
564 /*****************************************************************************
566 *****************************************************************************/
567 static void SDPHandleUrl( sout_stream_t *p_stream, char *psz_url )
569 sout_stream_sys_t *p_sys = p_stream->p_sys;
572 vlc_UrlParse( &url, psz_url, 0 );
573 if( url.psz_protocol && !strcasecmp( url.psz_protocol, "http" ) )
575 if( p_sys->p_httpd_file )
577 msg_Err( p_stream, "you can use sdp=http:// only once" );
581 if( HttpSetup( p_stream, &url ) )
583 msg_Err( p_stream, "cannot export SDP as HTTP" );
586 else if( url.psz_protocol && !strcasecmp( url.psz_protocol, "rtsp" ) )
588 if( p_sys->rtsp != NULL )
590 msg_Err( p_stream, "you can use sdp=rtsp:// only once" );
594 /* FIXME test if destination is multicast or no destination at all */
595 p_sys->rtsp = RtspSetup( p_stream, &url );
596 if( p_sys->rtsp == NULL )
598 msg_Err( p_stream, "cannot export SDP as RTSP" );
601 if( p_sys->p_mux != NULL )
603 sout_stream_id_t *id = p_sys->es[0];
604 id->rtsp_id = RtspAddId( p_sys->rtsp, id, 0, GetDWBE( id->ssrc ),
605 p_sys->psz_destination, p_sys->i_ttl,
606 id->i_port, id->i_port + 1 );
609 else if( ( url.psz_protocol && !strcasecmp( url.psz_protocol, "sap" ) ) ||
610 ( url.psz_host && !strcasecmp( url.psz_host, "sap" ) ) )
612 p_sys->b_export_sap = VLC_TRUE;
613 SapSetup( p_stream );
615 else if( url.psz_protocol && !strcasecmp( url.psz_protocol, "file" ) )
617 if( p_sys->b_export_sdp_file )
619 msg_Err( p_stream, "you can use sdp=file:// only once" );
622 p_sys->b_export_sdp_file = VLC_TRUE;
623 psz_url = &psz_url[5];
624 if( psz_url[0] == '/' && psz_url[1] == '/' )
626 p_sys->psz_sdp_file = strdup( psz_url );
630 msg_Warn( p_stream, "unknown protocol for SDP (%s)",
635 vlc_UrlClean( &url );
638 /*****************************************************************************
640 *****************************************************************************/
642 char *SDPGenerate( const sout_stream_t *p_stream, const char *rtsp_url )
644 const sout_stream_sys_t *p_sys = p_stream->p_sys;
646 struct sockaddr_storage dst;
650 * When we have a fixed destination (typically when we do multicast),
651 * we need to put the actual port numbers in the SDP.
652 * When there is no fixed destination, we only support RTSP unicast
653 * on-demand setup, so we should rather let the clients decide which ports
655 * When there is both a fixed destination and RTSP unicast, we need to
656 * put port numbers used by the fixed destination, otherwise the SDP would
657 * become totally incorrect for multicast use. It should be noted that
658 * port numbers from SDP with RTSP are only "recommendation" from the
659 * server to the clients (per RFC2326), so only broken clients will fail
660 * to handle this properly. There is no solution but to use two differents
661 * output chain with two different RTSP URLs if you need to handle this
666 if( p_sys->psz_destination != NULL )
670 /* Oh boy, this is really ugly! (+ race condition on lock_es) */
671 dstlen = sizeof( dst );
672 if( p_sys->es[0]->listen_fd != NULL )
673 getsockname( p_sys->es[0]->listen_fd[0],
674 (struct sockaddr *)&dst, &dstlen );
676 getpeername( p_sys->es[0]->sinkv[0].rtp_fd,
677 (struct sockaddr *)&dst, &dstlen );
683 /* Dummy destination address for RTSP */
684 memset (&dst, 0, sizeof( struct sockaddr_in ) );
685 dst.ss_family = AF_INET;
689 dstlen = sizeof( struct sockaddr_in );
692 psz_sdp = vlc_sdp_Start( VLC_OBJECT( p_stream ), SOUT_CFG_PREFIX,
693 NULL, 0, (struct sockaddr *)&dst, dstlen );
694 if( psz_sdp == NULL )
697 /* TODO: a=source-filter */
698 if( p_sys->rtcp_mux )
699 sdp_AddAttribute( &psz_sdp, "rtcp-mux", NULL );
701 if( rtsp_url != NULL )
702 sdp_AddAttribute ( &psz_sdp, "control", "%s", rtsp_url );
704 /* FIXME: locking?! */
705 for( i = 0; i < p_sys->i_es; i++ )
707 sout_stream_id_t *id = p_sys->es[i];
708 const char *mime_major; /* major MIME type */
709 const char *proto = "RTP/AVP"; /* protocol */
714 mime_major = "video";
717 mime_major = "audio";
726 if( rtsp_url == NULL )
728 switch( p_sys->proto )
733 proto = "TCP/RTP/AVP";
736 proto = "DCCP/RTP/AVP";
738 case IPPROTO_UDPLITE:
743 sdp_AddMedia( &psz_sdp, mime_major, proto, inclport * id->i_port,
744 id->i_payload_type, VLC_FALSE, id->i_bitrate,
745 id->psz_rtpmap, id->psz_fmtp);
747 if( rtsp_url != NULL )
749 assert( strlen( rtsp_url ) > 0 );
750 vlc_bool_t addslash = ( rtsp_url[strlen( rtsp_url ) - 1] != '/' );
751 sdp_AddAttribute ( &psz_sdp, "control",
752 addslash ? "%s/trackID=%u" : "%strackID=%u",
757 if( id->listen_fd != NULL )
758 sdp_AddAttribute( &psz_sdp, "setup", "passive" );
760 if( p_sys->proto == IPPROTO_DCCP )
761 sdp_AddAttribute( &psz_sdp, "dccp-service-code",
762 "SC:RTP%c", toupper( mime_major[0] ) );
770 /*****************************************************************************
772 *****************************************************************************/
773 static int rtp_packetize_l16 ( sout_stream_t *, sout_stream_id_t *, block_t * );
774 static int rtp_packetize_l8 ( sout_stream_t *, sout_stream_id_t *, block_t * );
775 static int rtp_packetize_mpa ( sout_stream_t *, sout_stream_id_t *, block_t * );
776 static int rtp_packetize_mpv ( sout_stream_t *, sout_stream_id_t *, block_t * );
777 static int rtp_packetize_ac3 ( sout_stream_t *, sout_stream_id_t *, block_t * );
778 static int rtp_packetize_split( sout_stream_t *, sout_stream_id_t *, block_t * );
779 static int rtp_packetize_mp4a ( sout_stream_t *, sout_stream_id_t *, block_t * );
780 static int rtp_packetize_mp4a_latm ( sout_stream_t *, sout_stream_id_t *, block_t * );
781 static int rtp_packetize_h263 ( sout_stream_t *, sout_stream_id_t *, block_t * );
782 static int rtp_packetize_h264 ( sout_stream_t *, sout_stream_id_t *, block_t * );
783 static int rtp_packetize_amr ( sout_stream_t *, sout_stream_id_t *, block_t * );
784 static int rtp_packetize_spx ( sout_stream_t *, sout_stream_id_t *, block_t * );
785 static int rtp_packetize_t140 ( sout_stream_t *, sout_stream_id_t *, block_t * );
787 static void sprintf_hexa( char *s, uint8_t *p_data, int i_data )
789 static const char hex[16] = "0123456789abcdef";
792 for( i = 0; i < i_data; i++ )
794 s[2*i+0] = hex[(p_data[i]>>4)&0xf];
795 s[2*i+1] = hex[(p_data[i] )&0xf];
801 /** Add an ES as a new RTP stream */
802 static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
804 /* NOTE: As a special case, if we use a non-RTP
805 * mux (TS/PS), then p_fmt is NULL. */
806 sout_stream_sys_t *p_sys = p_stream->p_sys;
807 sout_stream_id_t *id;
808 int i_port, cscov = -1;
811 id = vlc_object_create( p_stream, sizeof( sout_stream_id_t ) );
814 vlc_object_attach( id, p_stream );
816 /* Choose the port */
821 if( p_fmt->i_cat == AUDIO_ES && p_sys->i_port_audio > 0 )
823 i_port = p_sys->i_port_audio;
824 p_sys->i_port_audio = 0;
827 if( p_fmt->i_cat == VIDEO_ES && p_sys->i_port_video > 0 )
829 i_port = p_sys->i_port_video;
830 p_sys->i_port_video = 0;
835 if( p_sys->i_port != p_sys->i_port_audio
836 && p_sys->i_port != p_sys->i_port_video )
838 i_port = p_sys->i_port;
845 id->p_stream = p_stream;
847 id->i_sequence = rand()&0xffff;
848 id->i_payload_type = p_sys->i_payload_type;
849 id->ssrc[0] = rand()&0xff;
850 id->ssrc[1] = rand()&0xff;
851 id->ssrc[2] = rand()&0xff;
852 id->ssrc[3] = rand()&0xff;
854 id->psz_rtpmap = NULL;
856 id->i_clock_rate = 90000; /* most common case */
860 id->i_cat = p_fmt->i_cat;
861 id->i_bitrate = p_fmt->i_bitrate/1000; /* Stream bitrate in kbps */
865 id->i_cat = VIDEO_ES;
869 id->pf_packetize = NULL;
870 id->i_mtu = config_GetInt( p_stream, "mtu" );
871 if( id->i_mtu <= 12 + 16 )
872 id->i_mtu = 576 - 20 - 8; /* pessimistic */
874 msg_Dbg( p_stream, "maximum RTP packet size: %d bytes", id->i_mtu );
876 vlc_mutex_init( p_stream, &id->lock_sink );
881 id->listen_fd = NULL;
884 (int64_t)1000 * var_GetInteger( p_stream, SOUT_CFG_PREFIX "caching");
886 if( p_sys->psz_destination != NULL )
887 switch( p_sys->proto )
891 id->listen_fd = net_Listen( VLC_OBJECT(p_stream),
892 p_sys->psz_destination, i_port,
894 if( id->listen_fd == NULL )
896 msg_Err( p_stream, "passive COMEDIA RTP socket failed" );
903 int ttl = (p_sys->i_ttl > 0) ? p_sys->i_ttl : -1;
904 int fd = net_ConnectDgram( p_stream, p_sys->psz_destination,
905 i_port, ttl, p_sys->proto );
908 msg_Err( p_stream, "cannot create RTP socket" );
911 rtp_add_sink( id, fd, p_sys->rtcp_mux );
917 char *psz = var_GetNonEmptyString( p_stream, SOUT_CFG_PREFIX "mux" );
919 if( psz == NULL ) /* Uho! */
922 if( strncmp( psz, "ts", 2 ) == 0 )
924 id->i_payload_type = 33;
925 id->psz_rtpmap = strdup( "MP2T/90000" );
929 id->psz_rtpmap = strdup( "MP2P/90000" );
933 switch( p_fmt->i_codec )
935 case VLC_FOURCC( 's', '1', '6', 'b' ):
936 if( p_fmt->audio.i_channels == 1 && p_fmt->audio.i_rate == 44100 )
938 id->i_payload_type = 11;
940 else if( p_fmt->audio.i_channels == 2 &&
941 p_fmt->audio.i_rate == 44100 )
943 id->i_payload_type = 10;
945 if( asprintf( &id->psz_rtpmap, "L16/%d/%d", p_fmt->audio.i_rate,
946 p_fmt->audio.i_channels ) == -1 )
947 id->psz_rtpmap = NULL;
948 id->i_clock_rate = p_fmt->audio.i_rate;
949 id->pf_packetize = rtp_packetize_l16;
951 case VLC_FOURCC( 'u', '8', ' ', ' ' ):
952 if( asprintf( &id->psz_rtpmap, "L8/%d/%d", p_fmt->audio.i_rate,
953 p_fmt->audio.i_channels ) == -1 )
954 id->psz_rtpmap = NULL;
955 id->i_clock_rate = p_fmt->audio.i_rate;
956 id->pf_packetize = rtp_packetize_l8;
958 case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
959 id->i_payload_type = 14;
960 id->psz_rtpmap = strdup( "MPA/90000" );
961 id->pf_packetize = rtp_packetize_mpa;
963 case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
964 id->i_payload_type = 32;
965 id->psz_rtpmap = strdup( "MPV/90000" );
966 id->pf_packetize = rtp_packetize_mpv;
968 case VLC_FOURCC( 'a', '5', '2', ' ' ):
969 id->psz_rtpmap = strdup( "ac3/90000" );
970 id->pf_packetize = rtp_packetize_ac3;
972 case VLC_FOURCC( 'H', '2', '6', '3' ):
973 id->psz_rtpmap = strdup( "H263-1998/90000" );
974 id->pf_packetize = rtp_packetize_h263;
976 case VLC_FOURCC( 'h', '2', '6', '4' ):
977 id->psz_rtpmap = strdup( "H264/90000" );
978 id->pf_packetize = rtp_packetize_h264;
981 if( p_fmt->i_extra > 0 )
983 uint8_t *p_buffer = p_fmt->p_extra;
984 int i_buffer = p_fmt->i_extra;
985 char *p_64_sps = NULL;
986 char *p_64_pps = NULL;
989 while( i_buffer > 4 &&
990 p_buffer[0] == 0 && p_buffer[1] == 0 &&
991 p_buffer[2] == 0 && p_buffer[3] == 1 )
993 const int i_nal_type = p_buffer[4]&0x1f;
997 msg_Dbg( p_stream, "we found a startcode for NAL with TYPE:%d", i_nal_type );
1000 for( i_offset = 4; i_offset+3 < i_buffer ; i_offset++)
1002 if( !memcmp (p_buffer + i_offset, "\x00\x00\x00\x01", 4 ) )
1004 /* we found another startcode */
1009 if( i_nal_type == 7 )
1011 p_64_sps = vlc_b64_encode_binary( &p_buffer[4], i_size - 4 );
1012 sprintf_hexa( hexa, &p_buffer[5], 3 );
1014 else if( i_nal_type == 8 )
1016 p_64_pps = vlc_b64_encode_binary( &p_buffer[4], i_size - 4 );
1022 if( p_64_sps && p_64_pps &&
1023 ( asprintf( &id->psz_fmtp,
1024 "packetization-mode=1;profile-level-id=%s;"
1025 "sprop-parameter-sets=%s,%s;", hexa, p_64_sps,
1026 p_64_pps ) == -1 ) )
1027 id->psz_fmtp = NULL;
1032 id->psz_fmtp = strdup( "packetization-mode=1" );
1035 case VLC_FOURCC( 'm', 'p', '4', 'v' ):
1037 char hexa[2*p_fmt->i_extra +1];
1039 id->psz_rtpmap = strdup( "MP4V-ES/90000" );
1040 id->pf_packetize = rtp_packetize_split;
1041 if( p_fmt->i_extra > 0 )
1043 sprintf_hexa( hexa, p_fmt->p_extra, p_fmt->i_extra );
1044 if( asprintf( &id->psz_fmtp,
1045 "profile-level-id=3; config=%s;", hexa ) == -1 )
1046 id->psz_fmtp = NULL;
1050 case VLC_FOURCC( 'm', 'p', '4', 'a' ):
1052 id->i_clock_rate = p_fmt->audio.i_rate;
1056 char hexa[2*p_fmt->i_extra +1];
1058 if( asprintf( &id->psz_rtpmap, "mpeg4-generic/%d",
1059 p_fmt->audio.i_rate ) == -1 )
1060 id->psz_rtpmap = NULL;
1061 id->pf_packetize = rtp_packetize_mp4a;
1062 sprintf_hexa( hexa, p_fmt->p_extra, p_fmt->i_extra );
1063 if( asprintf( &id->psz_fmtp,
1064 "streamtype=5; profile-level-id=15; "
1065 "mode=AAC-hbr; config=%s; SizeLength=13; "
1066 "IndexLength=3; IndexDeltaLength=3; Profile=1;",
1068 id->psz_fmtp = NULL;
1074 unsigned char config[6];
1075 unsigned int aacsrates[15] = {
1076 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
1077 16000, 12000, 11025, 8000, 7350, 0, 0 };
1079 for( i = 0; i < 15; i++ )
1080 if( p_fmt->audio.i_rate == aacsrates[i] )
1086 config[3]=p_fmt->audio.i_channels<<4;
1090 if( asprintf( &id->psz_rtpmap, "MP4A-LATM/%d/%d",
1091 p_fmt->audio.i_rate,
1092 p_fmt->audio.i_channels ) == -1)
1093 id->psz_rtpmap = NULL;
1094 id->pf_packetize = rtp_packetize_mp4a_latm;
1095 sprintf_hexa( hexa, config, 6 );
1096 if( asprintf( &id->psz_fmtp, "profile-level-id=15; "
1097 "object=2; cpresent=0; config=%s", hexa ) == -1 )
1098 id->psz_fmtp = NULL;
1102 case VLC_FOURCC( 's', 'a', 'm', 'r' ):
1103 id->psz_rtpmap = strdup( p_fmt->audio.i_channels == 2 ?
1104 "AMR/8000/2" : "AMR/8000" );
1105 id->psz_fmtp = strdup( "octet-align=1" );
1106 id->i_clock_rate = p_fmt->audio.i_rate;
1107 id->pf_packetize = rtp_packetize_amr;
1109 case VLC_FOURCC( 's', 'a', 'w', 'b' ):
1110 id->psz_rtpmap = strdup( p_fmt->audio.i_channels == 2 ?
1111 "AMR-WB/16000/2" : "AMR-WB/16000" );
1112 id->psz_fmtp = strdup( "octet-align=1" );
1113 id->i_clock_rate = p_fmt->audio.i_rate;
1114 id->pf_packetize = rtp_packetize_amr;
1116 case VLC_FOURCC( 's', 'p', 'x', ' ' ):
1117 id->i_payload_type = p_sys->i_payload_type++;
1118 if( asprintf( &id->psz_rtpmap, "SPEEX/%d",
1119 p_fmt->audio.i_rate ) == -1)
1120 id->psz_rtpmap = NULL;
1121 id->i_clock_rate = p_fmt->audio.i_rate;
1122 id->pf_packetize = rtp_packetize_spx;
1124 case VLC_FOURCC( 't', '1', '4', '0' ):
1125 id->psz_rtpmap = strdup( "t140/1000" );
1126 id->i_clock_rate = 1000;
1127 id->pf_packetize = rtp_packetize_t140;
1131 msg_Err( p_stream, "cannot add this stream (unsupported "
1132 "codec:%4.4s)", (char*)&p_fmt->i_codec );
1137 cscov += 8 /* UDP */ + 12 /* RTP */;
1139 net_SetCSCov( id->sinkv[0].rtp_fd, cscov, -1 );
1141 if( id->i_payload_type == p_sys->i_payload_type )
1142 p_sys->i_payload_type++;
1144 if( p_sys->rtsp != NULL )
1145 id->rtsp_id = RtspAddId( p_sys->rtsp, id, p_sys->i_es,
1146 GetDWBE( id->ssrc ),
1147 p_sys->psz_destination,
1148 p_sys->i_ttl, id->i_port, id->i_port + 1 );
1150 id->p_fifo = block_FifoNew( p_stream );
1151 if( vlc_thread_create( id, "RTP send thread", ThreadSend,
1152 VLC_THREAD_PRIORITY_HIGHEST, VLC_FALSE ) )
1155 /* Update p_sys context */
1156 vlc_mutex_lock( &p_sys->lock_es );
1157 TAB_APPEND( p_sys->i_es, p_sys->es, id );
1158 vlc_mutex_unlock( &p_sys->lock_es );
1160 psz_sdp = SDPGenerate( p_stream, NULL );
1162 vlc_mutex_lock( &p_sys->lock_sdp );
1163 free( p_sys->psz_sdp );
1164 p_sys->psz_sdp = psz_sdp;
1165 vlc_mutex_unlock( &p_sys->lock_sdp );
1167 msg_Dbg( p_stream, "sdp=\n%s", p_sys->psz_sdp );
1169 /* Update SDP (sap/file) */
1170 if( p_sys->b_export_sap ) SapSetup( p_stream );
1171 if( p_sys->b_export_sdp_file ) FileSetup( p_stream );
1176 Del( p_stream, id );
1180 static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
1182 sout_stream_sys_t *p_sys = p_stream->p_sys;
1184 if( id->p_fifo != NULL )
1186 vlc_object_kill( id );
1187 block_FifoWake( id->p_fifo );
1188 vlc_thread_join( id );
1189 block_FifoRelease( id->p_fifo );
1192 vlc_mutex_lock( &p_sys->lock_es );
1193 TAB_REMOVE( p_sys->i_es, p_sys->es, id );
1194 vlc_mutex_unlock( &p_sys->lock_es );
1197 if( id->i_port > 0 )
1199 if( id->i_cat == AUDIO_ES && p_sys->i_port_audio == 0 )
1200 p_sys->i_port_audio = id->i_port;
1201 else if( id->i_cat == VIDEO_ES && p_sys->i_port_video == 0 )
1202 p_sys->i_port_video = id->i_port;
1205 free( id->psz_rtpmap );
1206 free( id->psz_fmtp );
1209 RtspDelId( p_sys->rtsp, id->rtsp_id );
1211 rtp_del_sink( id, id->sinkv[0].rtp_fd ); /* sink for explicit dst= */
1212 if( id->listen_fd != NULL )
1213 net_ListenClose( id->listen_fd );
1215 vlc_mutex_destroy( &id->lock_sink );
1217 /* Update SDP (sap/file) */
1218 if( p_sys->b_export_sap && !p_sys->p_mux ) SapSetup( p_stream );
1219 if( p_sys->b_export_sdp_file ) FileSetup( p_stream );
1221 vlc_object_detach( id );
1222 vlc_object_destroy( id );
1226 static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
1231 assert( p_stream->p_sys->p_mux == NULL );
1233 while( p_buffer != NULL )
1235 p_next = p_buffer->p_next;
1236 if( id->pf_packetize( p_stream, id, p_buffer ) )
1239 block_Release( p_buffer );
1245 /****************************************************************************
1247 ****************************************************************************/
1248 static int SapSetup( sout_stream_t *p_stream )
1250 sout_stream_sys_t *p_sys = p_stream->p_sys;
1251 sout_instance_t *p_sout = p_stream->p_sout;
1253 /* Remove the previous session */
1254 if( p_sys->p_session != NULL)
1256 sout_AnnounceUnRegister( p_sout, p_sys->p_session);
1257 p_sys->p_session = NULL;
1260 if( ( p_sys->i_es > 0 || p_sys->p_mux ) && p_sys->psz_sdp && *p_sys->psz_sdp )
1262 announce_method_t *p_method = sout_SAPMethod();
1263 p_sys->p_session = sout_AnnounceRegisterSDP( p_sout, SOUT_CFG_PREFIX,
1265 p_sys->psz_destination,
1267 sout_MethodRelease( p_method );
1273 /****************************************************************************
1275 ****************************************************************************/
1276 static int FileSetup( sout_stream_t *p_stream )
1278 sout_stream_sys_t *p_sys = p_stream->p_sys;
1281 if( ( f = utf8_fopen( p_sys->psz_sdp_file, "wt" ) ) == NULL )
1283 msg_Err( p_stream, "cannot open file '%s' (%m)",
1284 p_sys->psz_sdp_file );
1285 return VLC_EGENERIC;
1288 fputs( p_sys->psz_sdp, f );
1294 /****************************************************************************
1296 ****************************************************************************/
1297 static int HttpCallback( httpd_file_sys_t *p_args,
1298 httpd_file_t *, uint8_t *p_request,
1299 uint8_t **pp_data, int *pi_data );
1301 static int HttpSetup( sout_stream_t *p_stream, vlc_url_t *url)
1303 sout_stream_sys_t *p_sys = p_stream->p_sys;
1305 p_sys->p_httpd_host = httpd_HostNew( VLC_OBJECT(p_stream), url->psz_host,
1306 url->i_port > 0 ? url->i_port : 80 );
1307 if( p_sys->p_httpd_host )
1309 p_sys->p_httpd_file = httpd_FileNew( p_sys->p_httpd_host,
1310 url->psz_path ? url->psz_path : "/",
1313 HttpCallback, (void*)p_sys );
1315 if( p_sys->p_httpd_file == NULL )
1317 return VLC_EGENERIC;
1322 static int HttpCallback( httpd_file_sys_t *p_args,
1323 httpd_file_t *f, uint8_t *p_request,
1324 uint8_t **pp_data, int *pi_data )
1326 sout_stream_sys_t *p_sys = (sout_stream_sys_t*)p_args;
1328 vlc_mutex_lock( &p_sys->lock_sdp );
1329 if( p_sys->psz_sdp && *p_sys->psz_sdp )
1331 *pi_data = strlen( p_sys->psz_sdp );
1332 *pp_data = malloc( *pi_data );
1333 memcpy( *pp_data, p_sys->psz_sdp, *pi_data );
1340 vlc_mutex_unlock( &p_sys->lock_sdp );
1345 /****************************************************************************
1347 ****************************************************************************/
1348 static void ThreadSend( vlc_object_t *p_this )
1350 sout_stream_id_t *id = (sout_stream_id_t *)p_this;
1351 unsigned i_caching = id->i_caching;
1353 int fd[5] = { -1, -1, -1, -1, -1 };
1361 fd[4] = open( "/dev/null", O_WRONLY );
1366 block_t *out = block_FifoGet( id->p_fifo );
1368 continue; /* Forced wakeup */
1370 mtime_t i_date = out->i_dts + i_caching;
1371 ssize_t len = out->i_buffer;
1375 len = write( fd[1], out->p_buffer, len);
1377 continue; /* Uho - should not happen */
1381 vlc_mutex_lock( &id->lock_sink );
1382 unsigned deadc = 0; /* How many dead sockets? */
1383 int deadv[id->sinkc]; /* Dead sockets list */
1385 for( int i = 0; i < id->sinkc; i++ )
1387 SendRTCP( id->sinkv[i].rtcp, out );
1390 tee( fd[0], fd[3], len, 0 );
1391 if( splice( fd[2], NULL, id->sinkv[i].rtp_fd, NULL, len,
1392 SPLICE_F_NONBLOCK ) >= 0 )
1394 if( errno == EAGAIN )
1398 splice( fd[2], NULL, fd[4], NULL, len, 0 );
1400 if( send( id->sinkv[i].rtp_fd, out->p_buffer, len, 0 ) >= 0 )
1403 /* Retry sending to root out soft-errors */
1404 if( send( id->sinkv[i].rtp_fd, out->p_buffer, len, 0 ) >= 0 )
1407 deadv[deadc++] = id->sinkv[i].rtp_fd;
1409 vlc_mutex_unlock( &id->lock_sink );
1411 block_Release( out );
1413 splice( fd[0], NULL, fd[4], NULL, len, 0 );
1416 for( unsigned i = 0; i < deadc; i++ )
1418 msg_Dbg( id, "removing socket %d", deadv[i] );
1419 rtp_del_sink( id, deadv[i] );
1422 /* Hopefully we won't overflow the SO_MAXCONN accept queue */
1423 while( id->listen_fd != NULL )
1425 int fd = net_Accept( id, id->listen_fd, 0 );
1428 msg_Dbg( id, "adding socket %d", fd );
1429 rtp_add_sink( id, fd, VLC_TRUE );
1434 for( unsigned i = 0; i < 5; i++ )
1439 static inline void rtp_packetize_send( sout_stream_id_t *id, block_t *out )
1441 block_FifoPut( id->p_fifo, out );
1444 int rtp_add_sink( sout_stream_id_t *id, int fd, vlc_bool_t rtcp_mux )
1446 rtp_sink_t sink = { fd, NULL };
1447 sink.rtcp = OpenRTCP( VLC_OBJECT( id->p_stream ), fd, IPPROTO_UDP,
1449 if( sink.rtcp == NULL )
1450 msg_Err( id, "RTCP failed!" );
1452 vlc_mutex_lock( &id->lock_sink );
1453 INSERT_ELEM( id->sinkv, id->sinkc, id->sinkc, sink );
1454 vlc_mutex_unlock( &id->lock_sink );
1458 void rtp_del_sink( sout_stream_id_t *id, int fd )
1460 rtp_sink_t sink = { fd, NULL };
1462 /* NOTE: must be safe to use if fd is not included */
1463 vlc_mutex_lock( &id->lock_sink );
1464 for( int i = 0; i < id->sinkc; i++ )
1466 if (id->sinkv[i].rtp_fd == fd)
1468 sink = id->sinkv[i];
1469 REMOVE_ELEM( id->sinkv, id->sinkc, i );
1473 vlc_mutex_unlock( &id->lock_sink );
1475 CloseRTCP( sink.rtcp );
1476 net_Close( sink.rtp_fd );
1479 uint16_t rtp_get_seq( const sout_stream_id_t *id )
1481 /* This will return values for the next packet.
1482 * Accounting for caching would not be totally trivial. */
1483 return id->i_sequence;
1486 /* FIXME: this is pretty bad - if we remove and then insert an ES
1487 * the number will get unsynched from inside RTSP */
1488 unsigned rtp_get_num( const sout_stream_id_t *id )
1490 sout_stream_sys_t *p_sys = id->p_stream->p_sys;
1493 vlc_mutex_lock( &p_sys->lock_es );
1494 for( i = 0; i < p_sys->i_es; i++ )
1496 if( id == p_sys->es[i] )
1499 vlc_mutex_unlock( &p_sys->lock_es );
1505 /****************************************************************************
1507 ****************************************************************************/
1508 static void rtp_packetize_common( sout_stream_id_t *id, block_t *out,
1509 int b_marker, int64_t i_pts )
1511 uint32_t i_timestamp = i_pts * (int64_t)id->i_clock_rate / I64C(1000000);
1513 out->p_buffer[0] = 0x80;
1514 out->p_buffer[1] = (b_marker?0x80:0x00)|id->i_payload_type;
1515 out->p_buffer[2] = ( id->i_sequence >> 8)&0xff;
1516 out->p_buffer[3] = ( id->i_sequence )&0xff;
1517 out->p_buffer[4] = ( i_timestamp >> 24 )&0xff;
1518 out->p_buffer[5] = ( i_timestamp >> 16 )&0xff;
1519 out->p_buffer[6] = ( i_timestamp >> 8 )&0xff;
1520 out->p_buffer[7] = ( i_timestamp )&0xff;
1522 memcpy( out->p_buffer + 8, id->ssrc, 4 );
1528 static int rtp_packetize_mpa( sout_stream_t *p_stream, sout_stream_id_t *id,
1531 int i_max = id->i_mtu - 12 - 4; /* payload max in one packet */
1532 int i_count = ( in->i_buffer + i_max - 1 ) / i_max;
1534 uint8_t *p_data = in->p_buffer;
1535 int i_data = in->i_buffer;
1538 for( i = 0; i < i_count; i++ )
1540 int i_payload = __MIN( i_max, i_data );
1541 block_t *out = block_New( p_stream, 16 + i_payload );
1543 /* rtp common header */
1544 rtp_packetize_common( id, out, (i == i_count - 1)?1:0, in->i_pts );
1546 out->p_buffer[12] = 0;
1547 out->p_buffer[13] = 0;
1548 /* fragment offset in the current frame */
1549 out->p_buffer[14] = ( (i*i_max) >> 8 )&0xff;
1550 out->p_buffer[15] = ( (i*i_max) )&0xff;
1551 memcpy( &out->p_buffer[16], p_data, i_payload );
1553 out->i_buffer = 16 + i_payload;
1554 out->i_dts = in->i_dts + i * in->i_length / i_count;
1555 out->i_length = in->i_length / i_count;
1557 rtp_packetize_send( id, out );
1559 p_data += i_payload;
1560 i_data -= i_payload;
1567 static int rtp_packetize_mpv( sout_stream_t *p_stream, sout_stream_id_t *id,
1570 int i_max = id->i_mtu - 12 - 4; /* payload max in one packet */
1571 int i_count = ( in->i_buffer + i_max - 1 ) / i_max;
1573 uint8_t *p_data = in->p_buffer;
1574 int i_data = in->i_buffer;
1576 int b_sequence_start = 0;
1577 int i_temporal_ref = 0;
1578 int i_picture_coding_type = 0;
1579 int i_fbv = 0, i_bfc = 0, i_ffv = 0, i_ffc = 0;
1580 int b_start_slice = 0;
1582 /* preparse this packet to get some info */
1583 if( in->i_buffer > 4 )
1585 uint8_t *p = p_data;
1586 int i_rest = in->i_buffer;
1590 while( i_rest > 4 &&
1591 ( p[0] != 0x00 || p[1] != 0x00 || p[2] != 0x01 ) )
1605 /* sequence start code */
1606 b_sequence_start = 1;
1608 else if( *p == 0x00 && i_rest >= 4 )
1611 i_temporal_ref = ( p[1] << 2) |((p[2]>>6)&0x03);
1612 i_picture_coding_type = (p[2] >> 3)&0x07;
1614 if( i_rest >= 4 && ( i_picture_coding_type == 2 ||
1615 i_picture_coding_type == 3 ) )
1617 i_ffv = (p[3] >> 2)&0x01;
1618 i_ffc = ((p[3]&0x03) << 1)|((p[4]>>7)&0x01);
1619 if( i_rest > 4 && i_picture_coding_type == 3 )
1621 i_fbv = (p[4]>>6)&0x01;
1622 i_bfc = (p[4]>>3)&0x07;
1626 else if( *p <= 0xaf )
1633 for( i = 0; i < i_count; i++ )
1635 int i_payload = __MIN( i_max, i_data );
1636 block_t *out = block_New( p_stream,
1638 uint32_t h = ( i_temporal_ref << 16 )|
1639 ( b_sequence_start << 13 )|
1640 ( b_start_slice << 12 )|
1641 ( i == i_count - 1 ? 1 << 11 : 0 )|
1642 ( i_picture_coding_type << 8 )|
1643 ( i_fbv << 7 )|( i_bfc << 4 )|( i_ffv << 3 )|i_ffc;
1645 /* rtp common header */
1646 rtp_packetize_common( id, out, (i == i_count - 1)?1:0,
1647 in->i_pts > 0 ? in->i_pts : in->i_dts );
1649 /* 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 */
1650 out->p_buffer[12] = ( h >> 24 )&0xff;
1651 out->p_buffer[13] = ( h >> 16 )&0xff;
1652 out->p_buffer[14] = ( h >> 8 )&0xff;
1653 out->p_buffer[15] = ( h )&0xff;
1655 memcpy( &out->p_buffer[16], p_data, i_payload );
1657 out->i_buffer = 16 + i_payload;
1658 out->i_dts = in->i_dts + i * in->i_length / i_count;
1659 out->i_length = in->i_length / i_count;
1661 rtp_packetize_send( id, out );
1663 p_data += i_payload;
1664 i_data -= i_payload;
1670 static int rtp_packetize_ac3( sout_stream_t *p_stream, sout_stream_id_t *id,
1673 int i_max = id->i_mtu - 12 - 2; /* payload max in one packet */
1674 int i_count = ( in->i_buffer + i_max - 1 ) / i_max;
1676 uint8_t *p_data = in->p_buffer;
1677 int i_data = in->i_buffer;
1680 for( i = 0; i < i_count; i++ )
1682 int i_payload = __MIN( i_max, i_data );
1683 block_t *out = block_New( p_stream, 14 + i_payload );
1685 /* rtp common header */
1686 rtp_packetize_common( id, out, (i == i_count - 1)?1:0, in->i_pts );
1688 out->p_buffer[12] = 1;
1690 out->p_buffer[13] = 0x00;
1692 memcpy( &out->p_buffer[14], p_data, i_payload );
1694 out->i_buffer = 14 + i_payload;
1695 out->i_dts = in->i_dts + i * in->i_length / i_count;
1696 out->i_length = in->i_length / i_count;
1698 rtp_packetize_send( id, out );
1700 p_data += i_payload;
1701 i_data -= i_payload;
1707 static int rtp_packetize_split( sout_stream_t *p_stream, sout_stream_id_t *id,
1710 int i_max = id->i_mtu - 12; /* payload max in one packet */
1711 int i_count = ( in->i_buffer + i_max - 1 ) / i_max;
1713 uint8_t *p_data = in->p_buffer;
1714 int i_data = in->i_buffer;
1717 for( i = 0; i < i_count; i++ )
1719 int i_payload = __MIN( i_max, i_data );
1720 block_t *out = block_New( p_stream, 12 + i_payload );
1722 /* rtp common header */
1723 rtp_packetize_common( id, out, ((i == i_count - 1)?1:0),
1724 (in->i_pts > 0 ? in->i_pts : in->i_dts) );
1725 memcpy( &out->p_buffer[12], p_data, i_payload );
1727 out->i_buffer = 12 + i_payload;
1728 out->i_dts = in->i_dts + i * in->i_length / i_count;
1729 out->i_length = in->i_length / i_count;
1731 rtp_packetize_send( id, out );
1733 p_data += i_payload;
1734 i_data -= i_payload;
1741 static int rtp_packetize_mp4a_latm( sout_stream_t *p_stream, sout_stream_id_t *id,
1744 int i_max = id->i_mtu - 14; /* payload max in one packet */
1745 int latmhdrsize = in->i_buffer / 0xff + 1;
1746 int i_count = ( in->i_buffer + i_max - 1 ) / i_max;
1748 uint8_t *p_data = in->p_buffer, *p_header = NULL;
1749 int i_data = in->i_buffer;
1752 for( i = 0; i < i_count; i++ )
1754 int i_payload = __MIN( i_max, i_data );
1759 out = block_New( p_stream, 12 + latmhdrsize + i_payload );
1761 /* rtp common header */
1762 rtp_packetize_common( id, out, ((i == i_count - 1) ? 1 : 0),
1763 (in->i_pts > 0 ? in->i_pts : in->i_dts) );
1767 int tmp = in->i_buffer;
1769 p_header=out->p_buffer+12;
1779 memcpy( &out->p_buffer[12+latmhdrsize], p_data, i_payload );
1781 out->i_buffer = 12 + latmhdrsize + i_payload;
1782 out->i_dts = in->i_dts + i * in->i_length / i_count;
1783 out->i_length = in->i_length / i_count;
1785 rtp_packetize_send( id, out );
1787 p_data += i_payload;
1788 i_data -= i_payload;
1794 static int rtp_packetize_l16( sout_stream_t *p_stream, sout_stream_id_t *id,
1797 int i_max = id->i_mtu - 12; /* payload max in one packet */
1798 int i_count = ( in->i_buffer + i_max - 1 ) / i_max;
1800 uint8_t *p_data = in->p_buffer;
1801 int i_data = in->i_buffer;
1806 int i_payload = (__MIN( i_max, i_data )/4)*4;
1807 block_t *out = block_New( p_stream, 12 + i_payload );
1809 /* rtp common header */
1810 rtp_packetize_common( id, out, 0,
1811 (in->i_pts > 0 ? in->i_pts : in->i_dts) );
1812 memcpy( &out->p_buffer[12], p_data, i_payload );
1814 out->i_buffer = 12 + i_payload;
1815 out->i_dts = in->i_dts + i_packet * in->i_length / i_count;
1816 out->i_length = in->i_length / i_count;
1818 rtp_packetize_send( id, out );
1820 p_data += i_payload;
1821 i_data -= i_payload;
1828 static int rtp_packetize_l8( sout_stream_t *p_stream, sout_stream_id_t *id,
1831 int i_max = id->i_mtu - 12; /* payload max in one packet */
1832 int i_count = ( in->i_buffer + i_max - 1 ) / i_max;
1834 uint8_t *p_data = in->p_buffer;
1835 int i_data = in->i_buffer;
1840 int i_payload = (__MIN( i_max, i_data )/2)*2;
1841 block_t *out = block_New( p_stream, 12 + i_payload );
1843 /* rtp common header */
1844 rtp_packetize_common( id, out, 0,
1845 (in->i_pts > 0 ? in->i_pts : in->i_dts) );
1846 memcpy( &out->p_buffer[12], p_data, i_payload );
1848 out->i_buffer = 12 + i_payload;
1849 out->i_dts = in->i_dts + i_packet * in->i_length / i_count;
1850 out->i_length = in->i_length / i_count;
1852 rtp_packetize_send( id, out );
1854 p_data += i_payload;
1855 i_data -= i_payload;
1862 static int rtp_packetize_mp4a( sout_stream_t *p_stream, sout_stream_id_t *id,
1865 int i_max = id->i_mtu - 16; /* payload max in one packet */
1866 int i_count = ( in->i_buffer + i_max - 1 ) / i_max;
1868 uint8_t *p_data = in->p_buffer;
1869 int i_data = in->i_buffer;
1872 for( i = 0; i < i_count; i++ )
1874 int i_payload = __MIN( i_max, i_data );
1875 block_t *out = block_New( p_stream, 16 + i_payload );
1877 /* rtp common header */
1878 rtp_packetize_common( id, out, ((i == i_count - 1)?1:0),
1879 (in->i_pts > 0 ? in->i_pts : in->i_dts) );
1881 /* AU headers length (bits) */
1882 out->p_buffer[12] = 0;
1883 out->p_buffer[13] = 2*8;
1884 /* for each AU length 13 bits + idx 3bits, */
1885 out->p_buffer[14] = ( in->i_buffer >> 5 )&0xff;
1886 out->p_buffer[15] = ( (in->i_buffer&0xff)<<3 )|0;
1888 memcpy( &out->p_buffer[16], p_data, i_payload );
1890 out->i_buffer = 16 + i_payload;
1891 out->i_dts = in->i_dts + i * in->i_length / i_count;
1892 out->i_length = in->i_length / i_count;
1894 rtp_packetize_send( id, out );
1896 p_data += i_payload;
1897 i_data -= i_payload;
1905 #define RTP_H263_HEADER_SIZE (2) // plen = 0
1906 #define RTP_H263_PAYLOAD_START (14) // plen = 0
1907 static int rtp_packetize_h263( sout_stream_t *p_stream, sout_stream_id_t *id,
1910 uint8_t *p_data = in->p_buffer;
1911 int i_data = in->i_buffer;
1913 int i_max = id->i_mtu - 12 - RTP_H263_HEADER_SIZE; /* payload max in one packet */
1916 int b_v_bit = 0; // no pesky error resilience
1917 int i_plen = 0; // normally plen=0 for PSC packet
1918 int i_pebit = 0; // because plen=0
1923 return VLC_EGENERIC;
1925 if( p_data[0] || p_data[1] )
1927 return VLC_EGENERIC;
1929 /* remove 2 leading 0 bytes */
1932 i_count = ( i_data + i_max - 1 ) / i_max;
1934 for( i = 0; i < i_count; i++ )
1936 int i_payload = __MIN( i_max, i_data );
1937 block_t *out = block_New( p_stream,
1938 RTP_H263_PAYLOAD_START + i_payload );
1939 b_p_bit = (i == 0) ? 1 : 0;
1940 h = ( b_p_bit << 10 )|
1945 /* rtp common header */
1946 //b_m_bit = 1; // always contains end of frame
1947 rtp_packetize_common( id, out, (i == i_count - 1)?1:0,
1948 in->i_pts > 0 ? in->i_pts : in->i_dts );
1951 out->p_buffer[12] = ( h >> 8 )&0xff;
1952 out->p_buffer[13] = ( h )&0xff;
1953 memcpy( &out->p_buffer[RTP_H263_PAYLOAD_START], p_data, i_payload );
1955 out->i_buffer = RTP_H263_PAYLOAD_START + i_payload;
1956 out->i_dts = in->i_dts + i * in->i_length / i_count;
1957 out->i_length = in->i_length / i_count;
1959 rtp_packetize_send( id, out );
1961 p_data += i_payload;
1962 i_data -= i_payload;
1970 rtp_packetize_h264_nal( sout_stream_t *p_stream, sout_stream_id_t *id,
1971 const uint8_t *p_data, int i_data, int64_t i_pts,
1972 int64_t i_dts, vlc_bool_t b_last, int64_t i_length )
1974 const int i_max = id->i_mtu - 12; /* payload max in one packet */
1981 i_nal_hdr = p_data[3];
1982 i_nal_type = i_nal_hdr&0x1f;
1984 /* Skip start code */
1989 if( i_data <= i_max )
1991 /* Single NAL unit packet */
1992 block_t *out = block_New( p_stream, 12 + i_data );
1994 out->i_length = i_length;
1997 rtp_packetize_common( id, out, b_last, i_pts );
1998 out->i_buffer = 12 + i_data;
2000 memcpy( &out->p_buffer[12], p_data, i_data );
2002 rtp_packetize_send( id, out );
2006 /* FU-A Fragmentation Unit without interleaving */
2007 const int i_count = ( i_data-1 + i_max-2 - 1 ) / (i_max-2);
2013 for( i = 0; i < i_count; i++ )
2015 const int i_payload = __MIN( i_data, i_max-2 );
2016 block_t *out = block_New( p_stream, 12 + 2 + i_payload );
2017 out->i_dts = i_dts + i * i_length / i_count;
2018 out->i_length = i_length / i_count;
2021 rtp_packetize_common( id, out, (b_last && i_payload == i_data), i_pts );
2022 out->i_buffer = 14 + i_payload;
2025 out->p_buffer[12] = 0x00 | (i_nal_hdr & 0x60) | 28;
2027 out->p_buffer[13] = ( i == 0 ? 0x80 : 0x00 ) | ( (i == i_count-1) ? 0x40 : 0x00 ) | i_nal_type;
2028 memcpy( &out->p_buffer[14], p_data, i_payload );
2030 rtp_packetize_send( id, out );
2032 i_data -= i_payload;
2033 p_data += i_payload;
2039 static int rtp_packetize_h264( sout_stream_t *p_stream, sout_stream_id_t *id,
2042 const uint8_t *p_buffer = in->p_buffer;
2043 int i_buffer = in->i_buffer;
2045 while( i_buffer > 4 && ( p_buffer[0] != 0 || p_buffer[1] != 0 || p_buffer[2] != 1 ) )
2051 /* Split nal units */
2052 while( i_buffer > 4 )
2055 int i_size = i_buffer;
2056 int i_skip = i_buffer;
2058 /* search nal end */
2059 for( i_offset = 4; i_offset+2 < i_buffer ; i_offset++)
2061 if( p_buffer[i_offset] == 0 && p_buffer[i_offset+1] == 0 && p_buffer[i_offset+2] == 1 )
2063 /* we found another startcode */
2064 i_size = i_offset - ( p_buffer[i_offset-1] == 0 ? 1 : 0);
2069 /* TODO add STAP-A to remove a lot of overhead with small slice/sei/... */
2070 rtp_packetize_h264_nal( p_stream, id, p_buffer, i_size,
2071 (in->i_pts > 0 ? in->i_pts : in->i_dts), in->i_dts,
2072 (i_size >= i_buffer), in->i_length * i_size / in->i_buffer );
2080 static int rtp_packetize_amr( sout_stream_t *p_stream, sout_stream_id_t *id,
2083 int i_max = id->i_mtu - 14; /* payload max in one packet */
2084 int i_count = ( in->i_buffer + i_max - 1 ) / i_max;
2086 uint8_t *p_data = in->p_buffer;
2087 int i_data = in->i_buffer;
2090 /* Only supports octet-aligned mode */
2091 for( i = 0; i < i_count; i++ )
2093 int i_payload = __MIN( i_max, i_data );
2094 block_t *out = block_New( p_stream, 14 + i_payload );
2096 /* rtp common header */
2097 rtp_packetize_common( id, out, ((i == i_count - 1)?1:0),
2098 (in->i_pts > 0 ? in->i_pts : in->i_dts) );
2099 /* Payload header */
2100 out->p_buffer[12] = 0xF0; /* CMR */
2101 out->p_buffer[13] = p_data[0]&0x7C; /* ToC */ /* FIXME: frame type */
2103 /* FIXME: are we fed multiple frames ? */
2104 memcpy( &out->p_buffer[14], p_data+1, i_payload-1 );
2106 out->i_buffer = 14 + i_payload-1;
2107 out->i_dts = in->i_dts + i * in->i_length / i_count;
2108 out->i_length = in->i_length / i_count;
2110 rtp_packetize_send( id, out );
2112 p_data += i_payload;
2113 i_data -= i_payload;
2119 static int rtp_packetize_t140( sout_stream_t *p_stream, sout_stream_id_t *id,
2122 const size_t i_max = id->i_mtu - 12;
2123 const uint8_t *p_data = in->p_buffer;
2124 size_t i_data = in->i_buffer;
2126 for( unsigned i_packet = 0; i_data > 0; i_packet++ )
2128 size_t i_payload = i_data;
2130 /* Make sure we stop on an UTF-8 character boundary
2131 * (assuming the input is valid UTF-8) */
2132 if( i_data > i_max )
2136 while( ( p_data[i_payload] & 0xC0 ) == 0x80 )
2138 if( i_payload == 0 )
2139 return VLC_SUCCESS; /* fishy input! */
2145 block_t *out = block_New( p_stream, 12 + i_payload );
2149 rtp_packetize_common( id, out, 0, in->i_pts + i_packet );
2150 memcpy( out->p_buffer + 12, p_data, i_payload );
2152 out->i_buffer = 12 + i_payload;
2153 out->i_dts = out->i_pts;
2156 rtp_packetize_send( id, out );
2158 p_data += i_payload;
2159 i_data -= i_payload;
2165 /*****************************************************************************
2167 *****************************************************************************/
2169 /** Add an ES to a non-RTP muxed stream */
2170 static sout_stream_id_t *MuxAdd( sout_stream_t *p_stream, es_format_t *p_fmt )
2172 sout_input_t *p_input;
2173 sout_mux_t *p_mux = p_stream->p_sys->p_mux;
2174 assert( p_mux != NULL );
2176 p_input = sout_MuxAddStream( p_mux, p_fmt );
2177 if( p_input == NULL )
2179 msg_Err( p_stream, "cannot add this stream to the muxer" );
2183 return (sout_stream_id_t *)p_input;
2187 static int MuxSend( sout_stream_t *p_stream, sout_stream_id_t *id,
2190 sout_mux_t *p_mux = p_stream->p_sys->p_mux;
2191 assert( p_mux != NULL );
2193 sout_MuxSendBuffer( p_mux, (sout_input_t *)id, p_buffer );
2198 /** Remove an ES from a non-RTP muxed stream */
2199 static int MuxDel( sout_stream_t *p_stream, sout_stream_id_t *id )
2201 sout_mux_t *p_mux = p_stream->p_sys->p_mux;
2202 assert( p_mux != NULL );
2204 sout_MuxDeleteStream( p_mux, (sout_input_t *)id );
2209 static int AccessOutGrabberWriteBuffer( sout_stream_t *p_stream,
2210 const block_t *p_buffer )
2212 sout_stream_sys_t *p_sys = p_stream->p_sys;
2213 sout_stream_id_t *id = p_sys->es[0];
2215 int64_t i_dts = p_buffer->i_dts;
2217 uint8_t *p_data = p_buffer->p_buffer;
2218 unsigned int i_data = p_buffer->i_buffer;
2219 unsigned int i_max = id->i_mtu - 12;
2221 unsigned i_packet = ( p_buffer->i_buffer + i_max - 1 ) / i_max;
2225 unsigned int i_size;
2227 /* output complete packet */
2228 if( p_sys->packet &&
2229 p_sys->packet->i_buffer + i_data > i_max )
2231 rtp_packetize_send( id, p_sys->packet );
2232 p_sys->packet = NULL;
2235 if( p_sys->packet == NULL )
2237 /* allocate a new packet */
2238 p_sys->packet = block_New( p_stream, id->i_mtu );
2239 rtp_packetize_common( id, p_sys->packet, 1, i_dts );
2240 p_sys->packet->i_dts = i_dts;
2241 p_sys->packet->i_length = p_buffer->i_length / i_packet;
2242 i_dts += p_sys->packet->i_length;
2245 i_size = __MIN( i_data,
2246 (unsigned)(id->i_mtu - p_sys->packet->i_buffer) );
2248 memcpy( &p_sys->packet->p_buffer[p_sys->packet->i_buffer],
2251 p_sys->packet->i_buffer += i_size;
2260 static int AccessOutGrabberWrite( sout_access_out_t *p_access,
2263 sout_stream_t *p_stream = (sout_stream_t*)p_access->p_sys;
2269 AccessOutGrabberWriteBuffer( p_stream, p_buffer );
2271 p_next = p_buffer->p_next;
2272 block_Release( p_buffer );
2280 static sout_access_out_t *GrabberCreate( sout_stream_t *p_stream )
2282 sout_access_out_t *p_grab;
2284 p_grab = vlc_object_create( p_stream->p_sout, sizeof( *p_grab ) );
2285 if( p_grab == NULL )
2288 p_grab->p_module = NULL;
2289 p_grab->p_sout = p_stream->p_sout;
2290 p_grab->psz_access = strdup( "grab" );
2291 p_grab->p_cfg = NULL;
2292 p_grab->psz_path = strdup( "" );
2293 p_grab->p_sys = (sout_access_out_sys_t *)p_stream;
2294 p_grab->pf_seek = NULL;
2295 p_grab->pf_write = AccessOutGrabberWrite;
2299 static int rtp_packetize_spx( sout_stream_t *p_stream, sout_stream_id_t *id,
2302 uint8_t *p_buffer = in->p_buffer;
2303 int i_data_size, i_payload_size, i_payload_padding;
2304 i_data_size = i_payload_size = in->i_buffer;
2305 i_payload_padding = 0;
2308 if ( in->i_buffer + 12 > id->i_mtu )
2310 msg_Warn( p_stream, "Cannot send packet larger than output MTU" );
2315 RFC for Speex in RTP says that each packet must end on an octet
2316 boundary. So, we check to see if the number of bytes % 4 is zero.
2317 If not, we have to add some padding.
2319 This MAY be overkill since packetization is handled elsewhere and
2320 appears to ensure the octet boundary. However, better safe than
2323 if ( i_payload_size % 4 )
2325 i_payload_padding = 4 - ( i_payload_size % 4 );
2326 i_payload_size += i_payload_padding;
2330 Allocate a new RTP p_output block of the appropriate size.
2331 Allow for 12 extra bytes of RTP header.
2333 p_out = block_New( p_stream, 12 + i_payload_size );
2335 if ( i_payload_padding )
2338 The padding is required to be a zero followed by all 1s.
2340 char c_first_pad, c_remaining_pad;
2342 c_remaining_pad = 0xFF;
2345 Allow for 12 bytes before the i_data_size because
2346 of the expected RTP header added during
2347 rtp_packetize_common.
2349 p_out->p_buffer[12 + i_data_size] = c_first_pad;
2350 switch (i_payload_padding)
2353 p_out->p_buffer[12 + i_data_size + 1] = c_remaining_pad;
2356 p_out->p_buffer[12 + i_data_size + 1] = c_remaining_pad;
2357 p_out->p_buffer[12 + i_data_size + 2] = c_remaining_pad;
2362 /* Add the RTP header to our p_output buffer. */
2363 rtp_packetize_common( id, p_out, 0, (in->i_pts > 0 ? in->i_pts : in->i_dts) );
2364 /* Copy the Speex payload to the p_output buffer */
2365 memcpy( &p_out->p_buffer[12], p_buffer, i_data_size );
2367 p_out->i_buffer = 12 + i_payload_size;
2368 p_out->i_dts = in->i_dts;
2369 p_out->i_length = in->i_length;
2371 /* Queue the buffer for actual transmission. */
2372 rtp_packetize_send( id, p_out );