1 /*****************************************************************************
2 * rtp.c: RTP access plug-in
3 *****************************************************************************
4 * Copyright (C) 2001, 2002 VideoLAN
5 * $Id: rtp.c,v 1.2 2002/09/30 11:05:34 sam Exp $
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
28 #include <sys/types.h>
35 #include <vlc/input.h>
39 #elif defined( _MSC_VER ) && defined( _WIN32 )
45 #define RTP_HEADER_LEN 12
46 /*****************************************************************************
48 *****************************************************************************/
49 static int Open ( vlc_object_t * );
50 static int RTPNetworkRead( input_thread_t *, byte_t *, size_t );
51 /*****************************************************************************
53 *****************************************************************************/
55 set_description( _("RTP access module") );
56 set_capability( "access", 0 );
57 add_shortcut( "rtp" );
58 add_shortcut( "rtpstream" );
59 add_shortcut( "rtp4" );
60 add_shortcut( "rtp6" );
61 set_callbacks( Open, __input_FDNetworkClose );
64 /*****************************************************************************
65 * Open: open the socket
66 *****************************************************************************/
67 static int Open( vlc_object_t *p_this )
69 input_thread_t * p_input = (input_thread_t *)p_this;
70 input_socket_t * p_access_data;
72 char * psz_network = "";
73 char * psz_name = strdup(p_input->psz_name);
74 char * psz_parser = psz_name;
75 char * psz_server_addr = "";
76 char * psz_server_port = "";
77 char * psz_bind_addr = "";
78 char * psz_bind_port = "";
79 int i_bind_port = 0, i_server_port = 0;
80 network_socket_t socket_desc;
82 if( config_GetInt( p_input, "ipv4" ) )
86 if( config_GetInt( p_input, "ipv6" ) )
91 if( *p_input->psz_access )
93 /* Find out which shortcut was used */
94 if( !strncmp( p_input->psz_access, "rtp6", 5 ) )
98 else if( !strncmp( p_input->psz_access, "rtp4", 5 ) )
100 psz_network = "ipv4";
104 /* Parse psz_name syntax :
105 * [serveraddr[:serverport]][@[bindaddr]:[bindport]] */
107 if( *psz_parser && *psz_parser != '@' )
110 psz_server_addr = psz_parser;
112 while( *psz_parser && *psz_parser != ':' && *psz_parser != '@' )
114 if( *psz_parser == '[' )
117 while( *psz_parser && *psz_parser != ']' )
125 if( *psz_parser == ':' )
127 /* Found server port */
128 *psz_parser = '\0'; /* Terminate server name */
130 psz_server_port = psz_parser;
132 while( *psz_parser && *psz_parser != '@' )
139 if( *psz_parser == '@' )
141 /* Found bind address or bind port */
142 *psz_parser = '\0'; /* Terminate server port or name if necessary */
145 if( *psz_parser && *psz_parser != ':' )
147 /* Found bind address */
148 psz_bind_addr = psz_parser;
150 while( *psz_parser && *psz_parser != ':' )
152 if( *psz_parser == '[' )
155 while( *psz_parser && *psz_parser != ']' )
164 if( *psz_parser == ':' )
166 /* Found bind port */
167 *psz_parser = '\0'; /* Terminate bind address if necessary */
170 psz_bind_port = psz_parser;
174 /* Convert ports format */
175 if( *psz_server_port )
177 i_server_port = strtol( psz_server_port, &psz_parser, 10 );
180 msg_Err( p_input, "cannot parse server port near %s", psz_parser );
188 i_bind_port = strtol( psz_bind_port, &psz_parser, 10 );
191 msg_Err( p_input, "cannot parse bind port near %s", psz_parser );
197 p_input->pf_read = RTPNetworkRead;
198 p_input->pf_set_program = input_SetProgram;
199 p_input->pf_set_area = NULL;
200 p_input->pf_seek = NULL;
202 vlc_mutex_lock( &p_input->stream.stream_lock );
203 p_input->stream.b_pace_control = 0;
204 p_input->stream.b_seekable = 0;
205 p_input->stream.p_selected_area->i_tell = 0;
206 p_input->stream.i_method = INPUT_METHOD_NETWORK;
207 vlc_mutex_unlock( &p_input->stream.stream_lock );
209 if( *psz_server_addr || i_server_port )
211 msg_Err( p_input, "this RTP syntax is deprecated; the server argument will be");
212 msg_Err( p_input, "ignored (%s:%d). If you wanted to enter a multicast address",
213 psz_server_addr, i_server_port);
214 msg_Err( p_input, "or local port, type : %s:@%s:%d",
215 *p_input->psz_access ? p_input->psz_access : "udp",
216 psz_server_addr, i_server_port );
219 psz_server_addr = "";
222 msg_Dbg( p_input, "opening server=%s:%d local=%s:%d",
223 psz_server_addr, i_server_port, psz_bind_addr, i_bind_port );
225 /* Prepare the network_socket_t structure */
226 socket_desc.i_type = NETWORK_UDP;
227 socket_desc.psz_bind_addr = psz_bind_addr;
228 socket_desc.i_bind_port = i_bind_port;
229 socket_desc.psz_server_addr = psz_server_addr;
230 socket_desc.i_server_port = i_server_port;
232 /* Find an appropriate network module */
233 p_input->p_private = (void*) &socket_desc;
234 p_network = module_Need( p_input, "network", psz_network );
236 if( p_network == NULL )
240 module_Unneed( p_input, p_network );
242 p_access_data = malloc( sizeof(input_socket_t) );
243 p_input->p_access_data = (access_sys_t *)p_access_data;
245 if( p_access_data == NULL )
247 msg_Err( p_input, "out of memory" );
251 p_access_data->i_handle = socket_desc.i_handle;
252 p_input->i_mtu = socket_desc.i_mtu;
254 p_input->psz_demux = "ts";
259 /*****************************************************************************
260 * RTPNetworkRead : Read for the network, and parses the RTP header
261 *****************************************************************************/
262 static int RTPNetworkRead( input_thread_t * p_input, byte_t * p_buffer,
270 byte_t p_tmp_buffer[1500];
272 // Get the Raw data from the socket
273 // We first assume that RTP header size is the classic RTP_HEADER_LEN
274 ssize_t i_ret = input_FDNetworkRead(p_input, p_tmp_buffer,
275 i_len + RTP_HEADER_LEN);
277 if (!i_ret) return 0;
279 // Parse the header and make some verifications
280 // See RFC 1889 & RFC 2250
282 i_rtp_version = ( p_tmp_buffer[0] & 0xC0 ) >> 6;
283 i_CSRC_count = ( p_tmp_buffer[0] & 0x0F );
284 i_payload_type = ( p_tmp_buffer[1] & 0x7F );
286 if ( i_rtp_version != 2 )
287 msg_Dbg( p_input, "RTP version is %u, should be 2", i_rtp_version );
289 if ( i_payload_type != 33 )
290 msg_Dbg( p_input, "RTP payload type is %u, only 33 (Mpeg2-TS) \
291 is supported", i_payload_type );
293 // If both bytes are wrong, maybe a synchro error occurred...
294 if (( i_rtp_version != 2 ) && ( i_payload_type != 0x33 ))
296 msg_Dbg( p_input, "Too many RTP errors, trying to re-synchronize" );
298 //Trying to re-synchronize
299 for ( i=0 ; (i<i_len) ||
300 ((( p_tmp_buffer[0] & 0xC0 ) >> 6 == 2 )
301 && ( p_tmp_buffer[1] & 0x7F ) >> 6 == 0x33 ) ; i++);
305 input_FDNetworkRead(p_input, p_tmp_buffer,i);
312 // if i_CSRC_count != 0, the header is in fact longer than RTP_HEADER_LEN
313 // so we have to read some extra bytes
314 // This case is supposed to be very rare (vls does not handle that),
315 // so in practical this second input_FDNetworkRead is never done...
317 { i_ret += input_FDNetworkRead(p_input,
318 p_tmp_buffer + i_len + RTP_HEADER_LEN,
323 // Return the packet without the RTP header
324 i_ret -= ( RTP_HEADER_LEN + 4 * i_CSRC_count );
326 p_input->p_vlc->pf_memcpy( p_buffer,
327 p_tmp_buffer + RTP_HEADER_LEN + 4 * i_CSRC_count,