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,
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 p_sys->psz_destination,
1147 p_sys->i_ttl, id->i_port, id->i_port + 1 );
1149 id->p_fifo = block_FifoNew( p_stream );
1150 if( vlc_thread_create( id, "RTP send thread", ThreadSend,
1151 VLC_THREAD_PRIORITY_HIGHEST, VLC_FALSE ) )
1154 /* Update p_sys context */
1155 vlc_mutex_lock( &p_sys->lock_es );
1156 TAB_APPEND( p_sys->i_es, p_sys->es, id );
1157 vlc_mutex_unlock( &p_sys->lock_es );
1159 psz_sdp = SDPGenerate( p_stream, NULL );
1161 vlc_mutex_lock( &p_sys->lock_sdp );
1162 free( p_sys->psz_sdp );
1163 p_sys->psz_sdp = psz_sdp;
1164 vlc_mutex_unlock( &p_sys->lock_sdp );
1166 msg_Dbg( p_stream, "sdp=\n%s", p_sys->psz_sdp );
1168 /* Update SDP (sap/file) */
1169 if( p_sys->b_export_sap ) SapSetup( p_stream );
1170 if( p_sys->b_export_sdp_file ) FileSetup( p_stream );
1175 Del( p_stream, id );
1179 static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
1181 sout_stream_sys_t *p_sys = p_stream->p_sys;
1183 if( id->p_fifo != NULL )
1185 vlc_object_kill( id );
1186 block_FifoWake( id->p_fifo );
1187 vlc_thread_join( id );
1188 block_FifoRelease( id->p_fifo );
1191 vlc_mutex_lock( &p_sys->lock_es );
1192 TAB_REMOVE( p_sys->i_es, p_sys->es, id );
1193 vlc_mutex_unlock( &p_sys->lock_es );
1196 if( id->i_port > 0 )
1198 if( id->i_cat == AUDIO_ES && p_sys->i_port_audio == 0 )
1199 p_sys->i_port_audio = id->i_port;
1200 else if( id->i_cat == VIDEO_ES && p_sys->i_port_video == 0 )
1201 p_sys->i_port_video = id->i_port;
1204 free( id->psz_rtpmap );
1205 free( id->psz_fmtp );
1208 RtspDelId( p_sys->rtsp, id->rtsp_id );
1210 rtp_del_sink( id, id->sinkv[0].rtp_fd ); /* sink for explicit dst= */
1211 if( id->listen_fd != NULL )
1212 net_ListenClose( id->listen_fd );
1214 vlc_mutex_destroy( &id->lock_sink );
1216 /* Update SDP (sap/file) */
1217 if( p_sys->b_export_sap && !p_sys->p_mux ) SapSetup( p_stream );
1218 if( p_sys->b_export_sdp_file ) FileSetup( p_stream );
1220 vlc_object_detach( id );
1221 vlc_object_destroy( id );
1225 static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
1230 assert( p_stream->p_sys->p_mux == NULL );
1232 while( p_buffer != NULL )
1234 p_next = p_buffer->p_next;
1235 if( id->pf_packetize( p_stream, id, p_buffer ) )
1238 block_Release( p_buffer );
1244 /****************************************************************************
1246 ****************************************************************************/
1247 static int SapSetup( sout_stream_t *p_stream )
1249 sout_stream_sys_t *p_sys = p_stream->p_sys;
1250 sout_instance_t *p_sout = p_stream->p_sout;
1252 /* Remove the previous session */
1253 if( p_sys->p_session != NULL)
1255 sout_AnnounceUnRegister( p_sout, p_sys->p_session);
1256 p_sys->p_session = NULL;
1259 if( ( p_sys->i_es > 0 || p_sys->p_mux ) && p_sys->psz_sdp && *p_sys->psz_sdp )
1261 announce_method_t *p_method = sout_SAPMethod();
1262 p_sys->p_session = sout_AnnounceRegisterSDP( p_sout, SOUT_CFG_PREFIX,
1264 p_sys->psz_destination,
1266 sout_MethodRelease( p_method );
1272 /****************************************************************************
1274 ****************************************************************************/
1275 static int FileSetup( sout_stream_t *p_stream )
1277 sout_stream_sys_t *p_sys = p_stream->p_sys;
1280 if( ( f = utf8_fopen( p_sys->psz_sdp_file, "wt" ) ) == NULL )
1282 msg_Err( p_stream, "cannot open file '%s' (%m)",
1283 p_sys->psz_sdp_file );
1284 return VLC_EGENERIC;
1287 fputs( p_sys->psz_sdp, f );
1293 /****************************************************************************
1295 ****************************************************************************/
1296 static int HttpCallback( httpd_file_sys_t *p_args,
1297 httpd_file_t *, uint8_t *p_request,
1298 uint8_t **pp_data, int *pi_data );
1300 static int HttpSetup( sout_stream_t *p_stream, vlc_url_t *url)
1302 sout_stream_sys_t *p_sys = p_stream->p_sys;
1304 p_sys->p_httpd_host = httpd_HostNew( VLC_OBJECT(p_stream), url->psz_host,
1305 url->i_port > 0 ? url->i_port : 80 );
1306 if( p_sys->p_httpd_host )
1308 p_sys->p_httpd_file = httpd_FileNew( p_sys->p_httpd_host,
1309 url->psz_path ? url->psz_path : "/",
1312 HttpCallback, (void*)p_sys );
1314 if( p_sys->p_httpd_file == NULL )
1316 return VLC_EGENERIC;
1321 static int HttpCallback( httpd_file_sys_t *p_args,
1322 httpd_file_t *f, uint8_t *p_request,
1323 uint8_t **pp_data, int *pi_data )
1325 sout_stream_sys_t *p_sys = (sout_stream_sys_t*)p_args;
1327 vlc_mutex_lock( &p_sys->lock_sdp );
1328 if( p_sys->psz_sdp && *p_sys->psz_sdp )
1330 *pi_data = strlen( p_sys->psz_sdp );
1331 *pp_data = malloc( *pi_data );
1332 memcpy( *pp_data, p_sys->psz_sdp, *pi_data );
1339 vlc_mutex_unlock( &p_sys->lock_sdp );
1344 /****************************************************************************
1346 ****************************************************************************/
1347 static void ThreadSend( vlc_object_t *p_this )
1349 sout_stream_id_t *id = (sout_stream_id_t *)p_this;
1350 unsigned i_caching = id->i_caching;
1352 int fd[5] = { -1, -1, -1, -1, -1 };
1360 fd[4] = open( "/dev/null", O_WRONLY );
1365 block_t *out = block_FifoGet( id->p_fifo );
1367 continue; /* Forced wakeup */
1369 mtime_t i_date = out->i_dts + i_caching;
1370 ssize_t len = out->i_buffer;
1374 len = write( fd[1], out->p_buffer, len);
1376 continue; /* Uho - should not happen */
1380 vlc_mutex_lock( &id->lock_sink );
1381 unsigned deadc = 0; /* How many dead sockets? */
1382 int deadv[id->sinkc]; /* Dead sockets list */
1384 for( int i = 0; i < id->sinkc; i++ )
1386 SendRTCP( id->sinkv[i].rtcp, out );
1389 tee( fd[0], fd[3], len, 0 );
1390 if( splice( fd[2], NULL, id->sinkv[i].rtp_fd, NULL, len,
1391 SPLICE_F_NONBLOCK ) >= 0 )
1393 if( errno == EAGAIN )
1397 splice( fd[2], NULL, fd[4], NULL, len, 0 );
1399 if( send( id->sinkv[i].rtp_fd, out->p_buffer, len, 0 ) >= 0 )
1402 /* Retry sending to root out soft-errors */
1403 if( send( id->sinkv[i].rtp_fd, out->p_buffer, len, 0 ) >= 0 )
1406 deadv[deadc++] = id->sinkv[i].rtp_fd;
1408 vlc_mutex_unlock( &id->lock_sink );
1410 block_Release( out );
1412 splice( fd[0], NULL, fd[4], NULL, len, 0 );
1415 for( unsigned i = 0; i < deadc; i++ )
1417 msg_Dbg( id, "removing socket %d", deadv[i] );
1418 rtp_del_sink( id, deadv[i] );
1421 /* Hopefully we won't overflow the SO_MAXCONN accept queue */
1422 while( id->listen_fd != NULL )
1424 int fd = net_Accept( id, id->listen_fd, 0 );
1427 msg_Dbg( id, "adding socket %d", fd );
1428 rtp_add_sink( id, fd, VLC_TRUE );
1433 for( unsigned i = 0; i < 5; i++ )
1438 static inline void rtp_packetize_send( sout_stream_id_t *id, block_t *out )
1440 block_FifoPut( id->p_fifo, out );
1443 int rtp_add_sink( sout_stream_id_t *id, int fd, vlc_bool_t rtcp_mux )
1445 rtp_sink_t sink = { fd, NULL };
1446 sink.rtcp = OpenRTCP( VLC_OBJECT( id->p_stream ), fd, IPPROTO_UDP,
1448 if( sink.rtcp == NULL )
1449 msg_Err( id, "RTCP failed!" );
1451 vlc_mutex_lock( &id->lock_sink );
1452 INSERT_ELEM( id->sinkv, id->sinkc, id->sinkc, sink );
1453 vlc_mutex_unlock( &id->lock_sink );
1457 void rtp_del_sink( sout_stream_id_t *id, int fd )
1459 rtp_sink_t sink = { fd, NULL };
1461 /* NOTE: must be safe to use if fd is not included */
1462 vlc_mutex_lock( &id->lock_sink );
1463 for( int i = 0; i < id->sinkc; i++ )
1465 if (id->sinkv[i].rtp_fd == fd)
1467 sink = id->sinkv[i];
1468 REMOVE_ELEM( id->sinkv, id->sinkc, i );
1472 vlc_mutex_unlock( &id->lock_sink );
1474 CloseRTCP( sink.rtcp );
1475 net_Close( sink.rtp_fd );
1478 uint16_t rtp_get_seq( const sout_stream_id_t *id )
1480 /* This will return values for the next packet.
1481 * Accounting for caching would not be totally trivial. */
1482 return id->i_sequence;
1485 /* FIXME: this is pretty bad - if we remove and then insert an ES
1486 * the number will get unsynched from inside RTSP */
1487 unsigned rtp_get_num( const sout_stream_id_t *id )
1489 sout_stream_sys_t *p_sys = id->p_stream->p_sys;
1492 vlc_mutex_lock( &p_sys->lock_es );
1493 for( i = 0; i < p_sys->i_es; i++ )
1495 if( id == p_sys->es[i] )
1498 vlc_mutex_unlock( &p_sys->lock_es );
1504 /****************************************************************************
1506 ****************************************************************************/
1507 static void rtp_packetize_common( sout_stream_id_t *id, block_t *out,
1508 int b_marker, int64_t i_pts )
1510 uint32_t i_timestamp = i_pts * (int64_t)id->i_clock_rate / I64C(1000000);
1512 out->p_buffer[0] = 0x80;
1513 out->p_buffer[1] = (b_marker?0x80:0x00)|id->i_payload_type;
1514 out->p_buffer[2] = ( id->i_sequence >> 8)&0xff;
1515 out->p_buffer[3] = ( id->i_sequence )&0xff;
1516 out->p_buffer[4] = ( i_timestamp >> 24 )&0xff;
1517 out->p_buffer[5] = ( i_timestamp >> 16 )&0xff;
1518 out->p_buffer[6] = ( i_timestamp >> 8 )&0xff;
1519 out->p_buffer[7] = ( i_timestamp )&0xff;
1521 memcpy( out->p_buffer + 8, id->ssrc, 4 );
1527 static int rtp_packetize_mpa( sout_stream_t *p_stream, sout_stream_id_t *id,
1530 int i_max = id->i_mtu - 12 - 4; /* payload max in one packet */
1531 int i_count = ( in->i_buffer + i_max - 1 ) / i_max;
1533 uint8_t *p_data = in->p_buffer;
1534 int i_data = in->i_buffer;
1537 for( i = 0; i < i_count; i++ )
1539 int i_payload = __MIN( i_max, i_data );
1540 block_t *out = block_New( p_stream, 16 + i_payload );
1542 /* rtp common header */
1543 rtp_packetize_common( id, out, (i == i_count - 1)?1:0, in->i_pts );
1545 out->p_buffer[12] = 0;
1546 out->p_buffer[13] = 0;
1547 /* fragment offset in the current frame */
1548 out->p_buffer[14] = ( (i*i_max) >> 8 )&0xff;
1549 out->p_buffer[15] = ( (i*i_max) )&0xff;
1550 memcpy( &out->p_buffer[16], p_data, i_payload );
1552 out->i_buffer = 16 + i_payload;
1553 out->i_dts = in->i_dts + i * in->i_length / i_count;
1554 out->i_length = in->i_length / i_count;
1556 rtp_packetize_send( id, out );
1558 p_data += i_payload;
1559 i_data -= i_payload;
1566 static int rtp_packetize_mpv( sout_stream_t *p_stream, sout_stream_id_t *id,
1569 int i_max = id->i_mtu - 12 - 4; /* payload max in one packet */
1570 int i_count = ( in->i_buffer + i_max - 1 ) / i_max;
1572 uint8_t *p_data = in->p_buffer;
1573 int i_data = in->i_buffer;
1575 int b_sequence_start = 0;
1576 int i_temporal_ref = 0;
1577 int i_picture_coding_type = 0;
1578 int i_fbv = 0, i_bfc = 0, i_ffv = 0, i_ffc = 0;
1579 int b_start_slice = 0;
1581 /* preparse this packet to get some info */
1582 if( in->i_buffer > 4 )
1584 uint8_t *p = p_data;
1585 int i_rest = in->i_buffer;
1589 while( i_rest > 4 &&
1590 ( p[0] != 0x00 || p[1] != 0x00 || p[2] != 0x01 ) )
1604 /* sequence start code */
1605 b_sequence_start = 1;
1607 else if( *p == 0x00 && i_rest >= 4 )
1610 i_temporal_ref = ( p[1] << 2) |((p[2]>>6)&0x03);
1611 i_picture_coding_type = (p[2] >> 3)&0x07;
1613 if( i_rest >= 4 && ( i_picture_coding_type == 2 ||
1614 i_picture_coding_type == 3 ) )
1616 i_ffv = (p[3] >> 2)&0x01;
1617 i_ffc = ((p[3]&0x03) << 1)|((p[4]>>7)&0x01);
1618 if( i_rest > 4 && i_picture_coding_type == 3 )
1620 i_fbv = (p[4]>>6)&0x01;
1621 i_bfc = (p[4]>>3)&0x07;
1625 else if( *p <= 0xaf )
1632 for( i = 0; i < i_count; i++ )
1634 int i_payload = __MIN( i_max, i_data );
1635 block_t *out = block_New( p_stream,
1637 uint32_t h = ( i_temporal_ref << 16 )|
1638 ( b_sequence_start << 13 )|
1639 ( b_start_slice << 12 )|
1640 ( i == i_count - 1 ? 1 << 11 : 0 )|
1641 ( i_picture_coding_type << 8 )|
1642 ( i_fbv << 7 )|( i_bfc << 4 )|( i_ffv << 3 )|i_ffc;
1644 /* rtp common header */
1645 rtp_packetize_common( id, out, (i == i_count - 1)?1:0,
1646 in->i_pts > 0 ? in->i_pts : in->i_dts );
1648 /* 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 */
1649 out->p_buffer[12] = ( h >> 24 )&0xff;
1650 out->p_buffer[13] = ( h >> 16 )&0xff;
1651 out->p_buffer[14] = ( h >> 8 )&0xff;
1652 out->p_buffer[15] = ( h )&0xff;
1654 memcpy( &out->p_buffer[16], p_data, i_payload );
1656 out->i_buffer = 16 + i_payload;
1657 out->i_dts = in->i_dts + i * in->i_length / i_count;
1658 out->i_length = in->i_length / i_count;
1660 rtp_packetize_send( id, out );
1662 p_data += i_payload;
1663 i_data -= i_payload;
1669 static int rtp_packetize_ac3( sout_stream_t *p_stream, sout_stream_id_t *id,
1672 int i_max = id->i_mtu - 12 - 2; /* payload max in one packet */
1673 int i_count = ( in->i_buffer + i_max - 1 ) / i_max;
1675 uint8_t *p_data = in->p_buffer;
1676 int i_data = in->i_buffer;
1679 for( i = 0; i < i_count; i++ )
1681 int i_payload = __MIN( i_max, i_data );
1682 block_t *out = block_New( p_stream, 14 + i_payload );
1684 /* rtp common header */
1685 rtp_packetize_common( id, out, (i == i_count - 1)?1:0, in->i_pts );
1687 out->p_buffer[12] = 1;
1689 out->p_buffer[13] = 0x00;
1691 memcpy( &out->p_buffer[14], p_data, i_payload );
1693 out->i_buffer = 14 + i_payload;
1694 out->i_dts = in->i_dts + i * in->i_length / i_count;
1695 out->i_length = in->i_length / i_count;
1697 rtp_packetize_send( id, out );
1699 p_data += i_payload;
1700 i_data -= i_payload;
1706 static int rtp_packetize_split( sout_stream_t *p_stream, sout_stream_id_t *id,
1709 int i_max = id->i_mtu - 12; /* payload max in one packet */
1710 int i_count = ( in->i_buffer + i_max - 1 ) / i_max;
1712 uint8_t *p_data = in->p_buffer;
1713 int i_data = in->i_buffer;
1716 for( i = 0; i < i_count; i++ )
1718 int i_payload = __MIN( i_max, i_data );
1719 block_t *out = block_New( p_stream, 12 + i_payload );
1721 /* rtp common header */
1722 rtp_packetize_common( id, out, ((i == i_count - 1)?1:0),
1723 (in->i_pts > 0 ? in->i_pts : in->i_dts) );
1724 memcpy( &out->p_buffer[12], p_data, i_payload );
1726 out->i_buffer = 12 + i_payload;
1727 out->i_dts = in->i_dts + i * in->i_length / i_count;
1728 out->i_length = in->i_length / i_count;
1730 rtp_packetize_send( id, out );
1732 p_data += i_payload;
1733 i_data -= i_payload;
1740 static int rtp_packetize_mp4a_latm( sout_stream_t *p_stream, sout_stream_id_t *id,
1743 int i_max = id->i_mtu - 14; /* payload max in one packet */
1744 int latmhdrsize = in->i_buffer / 0xff + 1;
1745 int i_count = ( in->i_buffer + i_max - 1 ) / i_max;
1747 uint8_t *p_data = in->p_buffer, *p_header = NULL;
1748 int i_data = in->i_buffer;
1751 for( i = 0; i < i_count; i++ )
1753 int i_payload = __MIN( i_max, i_data );
1758 out = block_New( p_stream, 12 + latmhdrsize + i_payload );
1760 /* rtp common header */
1761 rtp_packetize_common( id, out, ((i == i_count - 1) ? 1 : 0),
1762 (in->i_pts > 0 ? in->i_pts : in->i_dts) );
1766 int tmp = in->i_buffer;
1768 p_header=out->p_buffer+12;
1778 memcpy( &out->p_buffer[12+latmhdrsize], p_data, i_payload );
1780 out->i_buffer = 12 + latmhdrsize + i_payload;
1781 out->i_dts = in->i_dts + i * in->i_length / i_count;
1782 out->i_length = in->i_length / i_count;
1784 rtp_packetize_send( id, out );
1786 p_data += i_payload;
1787 i_data -= i_payload;
1793 static int rtp_packetize_l16( sout_stream_t *p_stream, sout_stream_id_t *id,
1796 int i_max = id->i_mtu - 12; /* payload max in one packet */
1797 int i_count = ( in->i_buffer + i_max - 1 ) / i_max;
1799 uint8_t *p_data = in->p_buffer;
1800 int i_data = in->i_buffer;
1805 int i_payload = (__MIN( i_max, i_data )/4)*4;
1806 block_t *out = block_New( p_stream, 12 + i_payload );
1808 /* rtp common header */
1809 rtp_packetize_common( id, out, 0,
1810 (in->i_pts > 0 ? in->i_pts : in->i_dts) );
1811 memcpy( &out->p_buffer[12], p_data, i_payload );
1813 out->i_buffer = 12 + i_payload;
1814 out->i_dts = in->i_dts + i_packet * in->i_length / i_count;
1815 out->i_length = in->i_length / i_count;
1817 rtp_packetize_send( id, out );
1819 p_data += i_payload;
1820 i_data -= i_payload;
1827 static int rtp_packetize_l8( sout_stream_t *p_stream, sout_stream_id_t *id,
1830 int i_max = id->i_mtu - 12; /* payload max in one packet */
1831 int i_count = ( in->i_buffer + i_max - 1 ) / i_max;
1833 uint8_t *p_data = in->p_buffer;
1834 int i_data = in->i_buffer;
1839 int i_payload = (__MIN( i_max, i_data )/2)*2;
1840 block_t *out = block_New( p_stream, 12 + i_payload );
1842 /* rtp common header */
1843 rtp_packetize_common( id, out, 0,
1844 (in->i_pts > 0 ? in->i_pts : in->i_dts) );
1845 memcpy( &out->p_buffer[12], p_data, i_payload );
1847 out->i_buffer = 12 + i_payload;
1848 out->i_dts = in->i_dts + i_packet * in->i_length / i_count;
1849 out->i_length = in->i_length / i_count;
1851 rtp_packetize_send( id, out );
1853 p_data += i_payload;
1854 i_data -= i_payload;
1861 static int rtp_packetize_mp4a( sout_stream_t *p_stream, sout_stream_id_t *id,
1864 int i_max = id->i_mtu - 16; /* payload max in one packet */
1865 int i_count = ( in->i_buffer + i_max - 1 ) / i_max;
1867 uint8_t *p_data = in->p_buffer;
1868 int i_data = in->i_buffer;
1871 for( i = 0; i < i_count; i++ )
1873 int i_payload = __MIN( i_max, i_data );
1874 block_t *out = block_New( p_stream, 16 + i_payload );
1876 /* rtp common header */
1877 rtp_packetize_common( id, out, ((i == i_count - 1)?1:0),
1878 (in->i_pts > 0 ? in->i_pts : in->i_dts) );
1880 /* AU headers length (bits) */
1881 out->p_buffer[12] = 0;
1882 out->p_buffer[13] = 2*8;
1883 /* for each AU length 13 bits + idx 3bits, */
1884 out->p_buffer[14] = ( in->i_buffer >> 5 )&0xff;
1885 out->p_buffer[15] = ( (in->i_buffer&0xff)<<3 )|0;
1887 memcpy( &out->p_buffer[16], p_data, i_payload );
1889 out->i_buffer = 16 + i_payload;
1890 out->i_dts = in->i_dts + i * in->i_length / i_count;
1891 out->i_length = in->i_length / i_count;
1893 rtp_packetize_send( id, out );
1895 p_data += i_payload;
1896 i_data -= i_payload;
1904 #define RTP_H263_HEADER_SIZE (2) // plen = 0
1905 #define RTP_H263_PAYLOAD_START (14) // plen = 0
1906 static int rtp_packetize_h263( sout_stream_t *p_stream, sout_stream_id_t *id,
1909 uint8_t *p_data = in->p_buffer;
1910 int i_data = in->i_buffer;
1912 int i_max = id->i_mtu - 12 - RTP_H263_HEADER_SIZE; /* payload max in one packet */
1915 int b_v_bit = 0; // no pesky error resilience
1916 int i_plen = 0; // normally plen=0 for PSC packet
1917 int i_pebit = 0; // because plen=0
1922 return VLC_EGENERIC;
1924 if( p_data[0] || p_data[1] )
1926 return VLC_EGENERIC;
1928 /* remove 2 leading 0 bytes */
1931 i_count = ( i_data + i_max - 1 ) / i_max;
1933 for( i = 0; i < i_count; i++ )
1935 int i_payload = __MIN( i_max, i_data );
1936 block_t *out = block_New( p_stream,
1937 RTP_H263_PAYLOAD_START + i_payload );
1938 b_p_bit = (i == 0) ? 1 : 0;
1939 h = ( b_p_bit << 10 )|
1944 /* rtp common header */
1945 //b_m_bit = 1; // always contains end of frame
1946 rtp_packetize_common( id, out, (i == i_count - 1)?1:0,
1947 in->i_pts > 0 ? in->i_pts : in->i_dts );
1950 out->p_buffer[12] = ( h >> 8 )&0xff;
1951 out->p_buffer[13] = ( h )&0xff;
1952 memcpy( &out->p_buffer[RTP_H263_PAYLOAD_START], p_data, i_payload );
1954 out->i_buffer = RTP_H263_PAYLOAD_START + i_payload;
1955 out->i_dts = in->i_dts + i * in->i_length / i_count;
1956 out->i_length = in->i_length / i_count;
1958 rtp_packetize_send( id, out );
1960 p_data += i_payload;
1961 i_data -= i_payload;
1969 rtp_packetize_h264_nal( sout_stream_t *p_stream, sout_stream_id_t *id,
1970 const uint8_t *p_data, int i_data, int64_t i_pts,
1971 int64_t i_dts, vlc_bool_t b_last, int64_t i_length )
1973 const int i_max = id->i_mtu - 12; /* payload max in one packet */
1980 i_nal_hdr = p_data[3];
1981 i_nal_type = i_nal_hdr&0x1f;
1983 /* Skip start code */
1988 if( i_data <= i_max )
1990 /* Single NAL unit packet */
1991 block_t *out = block_New( p_stream, 12 + i_data );
1993 out->i_length = i_length;
1996 rtp_packetize_common( id, out, b_last, i_pts );
1997 out->i_buffer = 12 + i_data;
1999 memcpy( &out->p_buffer[12], p_data, i_data );
2001 rtp_packetize_send( id, out );
2005 /* FU-A Fragmentation Unit without interleaving */
2006 const int i_count = ( i_data-1 + i_max-2 - 1 ) / (i_max-2);
2012 for( i = 0; i < i_count; i++ )
2014 const int i_payload = __MIN( i_data, i_max-2 );
2015 block_t *out = block_New( p_stream, 12 + 2 + i_payload );
2016 out->i_dts = i_dts + i * i_length / i_count;
2017 out->i_length = i_length / i_count;
2020 rtp_packetize_common( id, out, (b_last && i_payload == i_data), i_pts );
2021 out->i_buffer = 14 + i_payload;
2024 out->p_buffer[12] = 0x00 | (i_nal_hdr & 0x60) | 28;
2026 out->p_buffer[13] = ( i == 0 ? 0x80 : 0x00 ) | ( (i == i_count-1) ? 0x40 : 0x00 ) | i_nal_type;
2027 memcpy( &out->p_buffer[14], p_data, i_payload );
2029 rtp_packetize_send( id, out );
2031 i_data -= i_payload;
2032 p_data += i_payload;
2038 static int rtp_packetize_h264( sout_stream_t *p_stream, sout_stream_id_t *id,
2041 const uint8_t *p_buffer = in->p_buffer;
2042 int i_buffer = in->i_buffer;
2044 while( i_buffer > 4 && ( p_buffer[0] != 0 || p_buffer[1] != 0 || p_buffer[2] != 1 ) )
2050 /* Split nal units */
2051 while( i_buffer > 4 )
2054 int i_size = i_buffer;
2055 int i_skip = i_buffer;
2057 /* search nal end */
2058 for( i_offset = 4; i_offset+2 < i_buffer ; i_offset++)
2060 if( p_buffer[i_offset] == 0 && p_buffer[i_offset+1] == 0 && p_buffer[i_offset+2] == 1 )
2062 /* we found another startcode */
2063 i_size = i_offset - ( p_buffer[i_offset-1] == 0 ? 1 : 0);
2068 /* TODO add STAP-A to remove a lot of overhead with small slice/sei/... */
2069 rtp_packetize_h264_nal( p_stream, id, p_buffer, i_size,
2070 (in->i_pts > 0 ? in->i_pts : in->i_dts), in->i_dts,
2071 (i_size >= i_buffer), in->i_length * i_size / in->i_buffer );
2079 static int rtp_packetize_amr( sout_stream_t *p_stream, sout_stream_id_t *id,
2082 int i_max = id->i_mtu - 14; /* payload max in one packet */
2083 int i_count = ( in->i_buffer + i_max - 1 ) / i_max;
2085 uint8_t *p_data = in->p_buffer;
2086 int i_data = in->i_buffer;
2089 /* Only supports octet-aligned mode */
2090 for( i = 0; i < i_count; i++ )
2092 int i_payload = __MIN( i_max, i_data );
2093 block_t *out = block_New( p_stream, 14 + i_payload );
2095 /* rtp common header */
2096 rtp_packetize_common( id, out, ((i == i_count - 1)?1:0),
2097 (in->i_pts > 0 ? in->i_pts : in->i_dts) );
2098 /* Payload header */
2099 out->p_buffer[12] = 0xF0; /* CMR */
2100 out->p_buffer[13] = p_data[0]&0x7C; /* ToC */ /* FIXME: frame type */
2102 /* FIXME: are we fed multiple frames ? */
2103 memcpy( &out->p_buffer[14], p_data+1, i_payload-1 );
2105 out->i_buffer = 14 + i_payload-1;
2106 out->i_dts = in->i_dts + i * in->i_length / i_count;
2107 out->i_length = in->i_length / i_count;
2109 rtp_packetize_send( id, out );
2111 p_data += i_payload;
2112 i_data -= i_payload;
2118 static int rtp_packetize_t140( sout_stream_t *p_stream, sout_stream_id_t *id,
2121 const size_t i_max = id->i_mtu - 12;
2122 const uint8_t *p_data = in->p_buffer;
2123 size_t i_data = in->i_buffer;
2125 for( unsigned i_packet = 0; i_data > 0; i_packet++ )
2127 size_t i_payload = i_data;
2129 /* Make sure we stop on an UTF-8 character boundary
2130 * (assuming the input is valid UTF-8) */
2131 if( i_data > i_max )
2135 while( ( p_data[i_payload] & 0xC0 ) == 0x80 )
2137 if( i_payload == 0 )
2138 return VLC_SUCCESS; /* fishy input! */
2144 block_t *out = block_New( p_stream, 12 + i_payload );
2148 rtp_packetize_common( id, out, 0, in->i_pts + i_packet );
2149 memcpy( out->p_buffer + 12, p_data, i_payload );
2151 out->i_buffer = 12 + i_payload;
2152 out->i_dts = out->i_pts;
2155 rtp_packetize_send( id, out );
2157 p_data += i_payload;
2158 i_data -= i_payload;
2164 /*****************************************************************************
2166 *****************************************************************************/
2168 /** Add an ES to a non-RTP muxed stream */
2169 static sout_stream_id_t *MuxAdd( sout_stream_t *p_stream, es_format_t *p_fmt )
2171 sout_input_t *p_input;
2172 sout_mux_t *p_mux = p_stream->p_sys->p_mux;
2173 assert( p_mux != NULL );
2175 p_input = sout_MuxAddStream( p_mux, p_fmt );
2176 if( p_input == NULL )
2178 msg_Err( p_stream, "cannot add this stream to the muxer" );
2182 return (sout_stream_id_t *)p_input;
2186 static int MuxSend( sout_stream_t *p_stream, sout_stream_id_t *id,
2189 sout_mux_t *p_mux = p_stream->p_sys->p_mux;
2190 assert( p_mux != NULL );
2192 sout_MuxSendBuffer( p_mux, (sout_input_t *)id, p_buffer );
2197 /** Remove an ES from a non-RTP muxed stream */
2198 static int MuxDel( sout_stream_t *p_stream, sout_stream_id_t *id )
2200 sout_mux_t *p_mux = p_stream->p_sys->p_mux;
2201 assert( p_mux != NULL );
2203 sout_MuxDeleteStream( p_mux, (sout_input_t *)id );
2208 static int AccessOutGrabberWriteBuffer( sout_stream_t *p_stream,
2209 const block_t *p_buffer )
2211 sout_stream_sys_t *p_sys = p_stream->p_sys;
2212 sout_stream_id_t *id = p_sys->es[0];
2214 int64_t i_dts = p_buffer->i_dts;
2216 uint8_t *p_data = p_buffer->p_buffer;
2217 unsigned int i_data = p_buffer->i_buffer;
2218 unsigned int i_max = id->i_mtu - 12;
2220 unsigned i_packet = ( p_buffer->i_buffer + i_max - 1 ) / i_max;
2224 unsigned int i_size;
2226 /* output complete packet */
2227 if( p_sys->packet &&
2228 p_sys->packet->i_buffer + i_data > i_max )
2230 rtp_packetize_send( id, p_sys->packet );
2231 p_sys->packet = NULL;
2234 if( p_sys->packet == NULL )
2236 /* allocate a new packet */
2237 p_sys->packet = block_New( p_stream, id->i_mtu );
2238 rtp_packetize_common( id, p_sys->packet, 1, i_dts );
2239 p_sys->packet->i_dts = i_dts;
2240 p_sys->packet->i_length = p_buffer->i_length / i_packet;
2241 i_dts += p_sys->packet->i_length;
2244 i_size = __MIN( i_data,
2245 (unsigned)(id->i_mtu - p_sys->packet->i_buffer) );
2247 memcpy( &p_sys->packet->p_buffer[p_sys->packet->i_buffer],
2250 p_sys->packet->i_buffer += i_size;
2259 static int AccessOutGrabberWrite( sout_access_out_t *p_access,
2262 sout_stream_t *p_stream = (sout_stream_t*)p_access->p_sys;
2268 AccessOutGrabberWriteBuffer( p_stream, p_buffer );
2270 p_next = p_buffer->p_next;
2271 block_Release( p_buffer );
2279 static sout_access_out_t *GrabberCreate( sout_stream_t *p_stream )
2281 sout_access_out_t *p_grab;
2283 p_grab = vlc_object_create( p_stream->p_sout, sizeof( *p_grab ) );
2284 if( p_grab == NULL )
2287 p_grab->p_module = NULL;
2288 p_grab->p_sout = p_stream->p_sout;
2289 p_grab->psz_access = strdup( "grab" );
2290 p_grab->p_cfg = NULL;
2291 p_grab->psz_path = strdup( "" );
2292 p_grab->p_sys = (sout_access_out_sys_t *)p_stream;
2293 p_grab->pf_seek = NULL;
2294 p_grab->pf_write = AccessOutGrabberWrite;
2298 static int rtp_packetize_spx( sout_stream_t *p_stream, sout_stream_id_t *id,
2301 uint8_t *p_buffer = in->p_buffer;
2302 int i_data_size, i_payload_size, i_payload_padding;
2303 i_data_size = i_payload_size = in->i_buffer;
2304 i_payload_padding = 0;
2307 if ( in->i_buffer + 12 > id->i_mtu )
2309 msg_Warn( p_stream, "Cannot send packet larger than output MTU" );
2314 RFC for Speex in RTP says that each packet must end on an octet
2315 boundary. So, we check to see if the number of bytes % 4 is zero.
2316 If not, we have to add some padding.
2318 This MAY be overkill since packetization is handled elsewhere and
2319 appears to ensure the octet boundary. However, better safe than
2322 if ( i_payload_size % 4 )
2324 i_payload_padding = 4 - ( i_payload_size % 4 );
2325 i_payload_size += i_payload_padding;
2329 Allocate a new RTP p_output block of the appropriate size.
2330 Allow for 12 extra bytes of RTP header.
2332 p_out = block_New( p_stream, 12 + i_payload_size );
2334 if ( i_payload_padding )
2337 The padding is required to be a zero followed by all 1s.
2339 char c_first_pad, c_remaining_pad;
2341 c_remaining_pad = 0xFF;
2344 Allow for 12 bytes before the i_data_size because
2345 of the expected RTP header added during
2346 rtp_packetize_common.
2348 p_out->p_buffer[12 + i_data_size] = c_first_pad;
2349 switch (i_payload_padding)
2352 p_out->p_buffer[12 + i_data_size + 1] = c_remaining_pad;
2355 p_out->p_buffer[12 + i_data_size + 1] = c_remaining_pad;
2356 p_out->p_buffer[12 + i_data_size + 2] = c_remaining_pad;
2361 /* Add the RTP header to our p_output buffer. */
2362 rtp_packetize_common( id, p_out, 0, (in->i_pts > 0 ? in->i_pts : in->i_dts) );
2363 /* Copy the Speex payload to the p_output buffer */
2364 memcpy( &p_out->p_buffer[12], p_buffer, i_data_size );
2366 p_out->i_buffer = 12 + i_payload_size;
2367 p_out->i_dts = in->i_dts;
2368 p_out->i_length = in->i_length;
2370 /* Queue the buffer for actual transmission. */
2371 rtp_packetize_send( id, p_out );