1 /*****************************************************************************
2 * udp.c: raw UDP access plug-in
3 *****************************************************************************
4 * Copyright (C) 2001, 2002 VideoLAN
5 * $Id: rtp.c,v 1.1 2002/08/14 08:50:33 tooney 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( "rtpstream" );
58 add_shortcut( "rtp4" );
59 add_shortcut( "rtp6" );
60 set_callbacks( Open, __input_FDNetworkClose );
63 /*****************************************************************************
64 * Open: open the socket
65 *****************************************************************************/
66 static int Open( vlc_object_t *p_this )
68 input_thread_t * p_input = (input_thread_t *)p_this;
69 input_socket_t * p_access_data;
71 char * psz_network = "";
72 char * psz_name = strdup(p_input->psz_name);
73 char * psz_parser = psz_name;
74 char * psz_server_addr = "";
75 char * psz_server_port = "";
76 char * psz_bind_addr = "";
77 char * psz_bind_port = "";
78 int i_bind_port = 0, i_server_port = 0;
79 network_socket_t socket_desc;
81 if( config_GetInt( p_input, "ipv4" ) )
85 if( config_GetInt( p_input, "ipv6" ) )
90 if( *p_input->psz_access )
92 /* Find out which shortcut was used */
93 if( !strncmp( p_input->psz_access, "rtp6", 5 ) )
97 else if( !strncmp( p_input->psz_access, "rtp4", 5 ) )
103 /* Parse psz_name syntax :
104 * [serveraddr[:serverport]][@[bindaddr]:[bindport]] */
106 if( *psz_parser && *psz_parser != '@' )
109 psz_server_addr = psz_parser;
111 while( *psz_parser && *psz_parser != ':' && *psz_parser != '@' )
113 if( *psz_parser == '[' )
116 while( *psz_parser && *psz_parser != ']' )
124 if( *psz_parser == ':' )
126 /* Found server port */
127 *psz_parser = '\0'; /* Terminate server name */
129 psz_server_port = psz_parser;
131 while( *psz_parser && *psz_parser != '@' )
138 if( *psz_parser == '@' )
140 /* Found bind address or bind port */
141 *psz_parser = '\0'; /* Terminate server port or name if necessary */
144 if( *psz_parser && *psz_parser != ':' )
146 /* Found bind address */
147 psz_bind_addr = psz_parser;
149 while( *psz_parser && *psz_parser != ':' )
151 if( *psz_parser == '[' )
154 while( *psz_parser && *psz_parser != ']' )
163 if( *psz_parser == ':' )
165 /* Found bind port */
166 *psz_parser = '\0'; /* Terminate bind address if necessary */
169 psz_bind_port = psz_parser;
173 /* Convert ports format */
174 if( *psz_server_port )
176 i_server_port = strtol( psz_server_port, &psz_parser, 10 );
179 msg_Err( p_input, "cannot parse server port near %s", psz_parser );
187 i_bind_port = strtol( psz_bind_port, &psz_parser, 10 );
190 msg_Err( p_input, "cannot parse bind port near %s", psz_parser );
196 p_input->pf_read = RTPNetworkRead;
197 p_input->pf_set_program = input_SetProgram;
198 p_input->pf_set_area = NULL;
199 p_input->pf_seek = NULL;
201 vlc_mutex_lock( &p_input->stream.stream_lock );
202 p_input->stream.b_pace_control = 0;
203 p_input->stream.b_seekable = 0;
204 p_input->stream.p_selected_area->i_tell = 0;
205 p_input->stream.i_method = INPUT_METHOD_NETWORK;
206 vlc_mutex_unlock( &p_input->stream.stream_lock );
208 if( *psz_server_addr || i_server_port )
210 msg_Err( p_input, "this RTP syntax is deprecated; the server argument will be");
211 msg_Err( p_input, "ignored (%s:%d). If you wanted to enter a multicast address",
212 psz_server_addr, i_server_port);
213 msg_Err( p_input, "or local port, type : %s:@%s:%d",
214 *p_input->psz_access ? p_input->psz_access : "udp",
215 psz_server_addr, i_server_port );
218 psz_server_addr = "";
221 msg_Dbg( p_input, "opening server=%s:%d local=%s:%d",
222 psz_server_addr, i_server_port, psz_bind_addr, i_bind_port );
224 /* Prepare the network_socket_t structure */
225 socket_desc.i_type = NETWORK_UDP;
226 socket_desc.psz_bind_addr = psz_bind_addr;
227 socket_desc.i_bind_port = i_bind_port;
228 socket_desc.psz_server_addr = psz_server_addr;
229 socket_desc.i_server_port = i_server_port;
231 /* Find an appropriate network module */
232 p_input->p_private = (void*) &socket_desc;
233 p_network = module_Need( p_input, "network", psz_network );
235 if( p_network == NULL )
239 module_Unneed( p_input, p_network );
241 p_access_data = malloc( sizeof(input_socket_t) );
242 p_input->p_access_data = (access_sys_t *)p_access_data;
244 if( p_access_data == NULL )
246 msg_Err( p_input, "out of memory" );
250 p_access_data->i_handle = socket_desc.i_handle;
251 p_input->i_mtu = socket_desc.i_mtu;
253 p_input->psz_demux = "ts";
258 /*****************************************************************************
259 * RTPNetworkRead : Read for the network, and parses the RTP header
260 *****************************************************************************/
261 static int RTPNetworkRead( input_thread_t * p_input, byte_t * p_buffer,
269 byte_t p_tmp_buffer[1500];
271 // Get the Raw data from the socket
272 // We first assume that RTP header size is the classic RTP_HEADER_LEN
273 ssize_t i_ret = input_FDNetworkRead(p_input, p_tmp_buffer,
274 i_len + RTP_HEADER_LEN);
276 if (!i_ret) return 0;
278 // Parse the header and make some verifications
279 // See RFC 1889 & RFC 2250
281 i_rtp_version = ( p_tmp_buffer[0] & 0xC0 ) >> 6;
282 i_CSRC_count = ( p_tmp_buffer[0] & 0x0F );
283 i_payload_type = ( p_tmp_buffer[1] & 0x7F );
285 if ( i_rtp_version != 2 )
286 msg_Dbg( p_input, "RTP version is %u, should be 2", i_rtp_version );
288 if ( i_payload_type != 33 )
289 msg_Dbg( p_input, "RTP payload type is %u, only 33 (Mpeg2-TS) \
290 is supported", i_payload_type );
292 // If both bytes are wrong, maybe a synchro error occurred...
293 if (( i_rtp_version != 2 ) && ( i_payload_type != 0x33 ))
295 msg_Dbg( p_input, "Too many RTP errors, trying to re-synchronize" );
297 //Trying to re-synchronize
298 for ( i=0 ; (i<i_len) ||
299 ((( p_tmp_buffer[0] & 0xC0 ) >> 6 == 2 )
300 && ( p_tmp_buffer[1] & 0x7F ) >> 6 == 0x33 ) ; i++);
304 input_FDNetworkRead(p_input, p_tmp_buffer,i);
311 // if i_CSRC_count != 0, the header is in fact longer than RTP_HEADER_LEN
312 // so we have to read some extra bytes
313 // This case is supposed to be very rare (vls does not handle that),
314 // so in practical this second input_FDNetworkRead is never done...
316 { i_ret += input_FDNetworkRead(p_input,
317 p_tmp_buffer + i_len + RTP_HEADER_LEN,
322 // Return the packet without the RTP header
323 i_ret -= ( RTP_HEADER_LEN + 4 * i_CSRC_count );
325 p_input->p_vlc->pf_memcpy( p_buffer,
326 p_tmp_buffer + RTP_HEADER_LEN + 4 * i_CSRC_count,