00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <stdlib.h>
00033
00034 #include <vlc/vlc.h>
00035 #include <vlc/input.h>
00036
00037 #include "network.h"
00038
00039
00040
00041
00042 #define CACHING_TEXT N_("Caching value in ms")
00043 #define CACHING_LONGTEXT N_( \
00044 "Allows you to modify the default caching value for UDP streams. This " \
00045 "value should be set in millisecond units." )
00046
00047 #define AUTO_MTU_TEXT N_("Autodetection of MTU")
00048 #define AUTO_MTU_LONGTEXT N_( \
00049 "Allows growing the MTU if truncated packets are found" )
00050
00051 #define RTP_LATE_TEXT N_("RTP reordering timeout in ms")
00052 #define RTP_LATE_LONGTEXT N_( \
00053 "Allows you to modify the RTP reordering behaviour. " \
00054 "RTP input will wait for late packets upto " \
00055 "the specified timeout in milisecond units." )
00056
00057 static int Open ( vlc_object_t * );
00058 static void Close( vlc_object_t * );
00059
00060 vlc_module_begin();
00061 set_shortname( _("UDP/RTP" ) );
00062 set_description( _("UDP/RTP input") );
00063 set_category( CAT_INPUT );
00064 set_subcategory( SUBCAT_INPUT_ACCESS );
00065
00066 add_integer( "udp-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT,
00067 CACHING_LONGTEXT, VLC_TRUE );
00068 add_integer( "rtp-late", 100, NULL, RTP_LATE_TEXT, RTP_LATE_LONGTEXT, VLC_TRUE );
00069
00070 add_bool( "udp-auto-mtu", 1, NULL,
00071 AUTO_MTU_TEXT, AUTO_MTU_LONGTEXT, VLC_TRUE );
00072
00073 set_capability( "access2", 0 );
00074 add_shortcut( "udp" );
00075 add_shortcut( "udpstream" );
00076 add_shortcut( "udp4" );
00077 add_shortcut( "udp6" );
00078 add_shortcut( "rtp" );
00079 add_shortcut( "rtp4" );
00080 add_shortcut( "rtp6" );
00081 set_callbacks( Open, Close );
00082 vlc_module_end();
00083
00084
00085
00086
00087 #define RTP_HEADER_LEN 12
00088
00089 static block_t *BlockUDP( access_t * );
00090 static block_t *BlockRTP( access_t * );
00091 static block_t *BlockChoose( access_t * );
00092 static int Control( access_t *, int, va_list );
00093
00094 struct access_sys_t
00095 {
00096 int fd;
00097
00098 int i_mtu;
00099 vlc_bool_t b_auto_mtu;
00100
00101
00102 mtime_t i_rtp_late;
00103 uint16_t i_last_seqno;
00104 block_t *p_list;
00105 block_t *p_end;
00106 };
00107
00108
00109
00110
00111 static int Open( vlc_object_t *p_this )
00112 {
00113 access_t *p_access = (access_t*)p_this;
00114 access_sys_t *p_sys;
00115
00116 char *psz_name = strdup( p_access->psz_path );
00117 char *psz_parser, *psz_server_addr, *psz_bind_addr = "";
00118 int i_bind_port, i_server_port = 0;
00119
00120
00121 var_Create( p_access, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
00122 var_Create( p_access, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
00123
00124 if( *p_access->psz_access )
00125 {
00126 vlc_value_t val;
00127
00128 if( !strncmp( p_access->psz_access, "udp4", 6 ) ||
00129 !strncmp( p_access->psz_access, "rtp4", 6 ))
00130 {
00131 val.b_bool = VLC_TRUE;
00132 var_Set( p_access, "ipv4", val );
00133
00134 val.b_bool = VLC_FALSE;
00135 var_Set( p_access, "ipv6", val );
00136 }
00137 else if( !strncmp( p_access->psz_access, "udp6", 6 ) ||
00138 !strncmp( p_access->psz_access, "rtp6", 6 ) )
00139 {
00140 val.b_bool = VLC_TRUE;
00141 var_Set( p_access, "ipv6", val );
00142
00143 val.b_bool = VLC_FALSE;
00144 var_Set( p_access, "ipv4", val );
00145 }
00146 }
00147
00148 i_bind_port = var_CreateGetInteger( p_access, "server-port" );
00149
00150
00151
00152 psz_parser = strchr( psz_name, '@' );
00153 if( psz_parser != NULL )
00154 {
00155
00156 *psz_parser++ = '\0';
00157 psz_bind_addr = psz_parser;
00158
00159 if( *psz_parser == '[' )
00160
00161 psz_parser = strchr( psz_parser, ']' );
00162
00163 if( psz_parser != NULL )
00164 {
00165 psz_parser = strchr( psz_parser, ':' );
00166 if( psz_parser != NULL )
00167 {
00168 *psz_parser++ = '\0';
00169 i_bind_port = atoi( psz_parser );
00170 }
00171 }
00172 }
00173
00174 psz_server_addr = psz_name;
00175 if( *psz_server_addr == '[' )
00176
00177 psz_parser = strchr( psz_name, ']' );
00178
00179 if( psz_parser != NULL )
00180 {
00181 psz_parser = strchr( psz_parser, ':' );
00182 if( psz_parser != NULL )
00183 {
00184 *psz_parser++ = '\0';
00185 i_server_port = atoi( psz_parser );
00186 }
00187 }
00188
00189 msg_Dbg( p_access, "opening server=%s:%d local=%s:%d",
00190 psz_server_addr, i_server_port, psz_bind_addr, i_bind_port );
00191
00192
00193 p_access->pf_read = NULL;
00194 p_access->pf_block = BlockChoose;
00195 p_access->pf_control = Control;
00196 p_access->pf_seek = NULL;
00197 p_access->info.i_update = 0;
00198 p_access->info.i_size = 0;
00199 p_access->info.i_pos = 0;
00200 p_access->info.b_eof = VLC_FALSE;
00201 p_access->info.b_prebuffered = VLC_FALSE;
00202 p_access->info.i_title = 0;
00203 p_access->info.i_seekpoint = 0;
00204
00205 p_access->p_sys = p_sys = malloc( sizeof( access_sys_t ) );
00206 p_sys->fd = net_OpenUDP( p_access, psz_bind_addr, i_bind_port,
00207 psz_server_addr, i_server_port );
00208 if( p_sys->fd < 0 )
00209 {
00210 msg_Err( p_access, "cannot open socket" );
00211 free( psz_name );
00212 free( p_sys );
00213 return VLC_EGENERIC;
00214 }
00215 free( psz_name );
00216
00217 net_StopSend( p_sys->fd );
00218
00219
00220 p_sys->i_mtu = var_CreateGetInteger( p_access, "mtu" );
00221 if( p_sys->i_mtu <= 1 )
00222 p_sys->i_mtu = 1500;
00223
00224 p_sys->b_auto_mtu = var_CreateGetBool( p_access, "udp-auto-mtu" );;
00225
00226
00227 var_Create( p_access, "udp-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
00228
00229
00230
00231 p_sys->i_rtp_late = var_CreateGetInteger( p_access, "rtp-late" ) * 1000;
00232 p_sys->i_last_seqno = 0;
00233 p_sys->p_list = NULL;
00234 p_sys->p_end = NULL;
00235 return VLC_SUCCESS;
00236 }
00237
00238
00239
00240
00241 static void Close( vlc_object_t *p_this )
00242 {
00243 access_t *p_access = (access_t*)p_this;
00244 access_sys_t *p_sys = p_access->p_sys;
00245
00246 block_ChainRelease( p_sys->p_list );
00247 net_Close( p_sys->fd );
00248 free( p_sys );
00249 }
00250
00251
00252
00253
00254 static int Control( access_t *p_access, int i_query, va_list args )
00255 {
00256 access_sys_t *p_sys = p_access->p_sys;
00257 vlc_bool_t *pb_bool;
00258 int *pi_int;
00259 int64_t *pi_64;
00260
00261 switch( i_query )
00262 {
00263
00264 case ACCESS_CAN_SEEK:
00265 case ACCESS_CAN_FASTSEEK:
00266 case ACCESS_CAN_PAUSE:
00267 case ACCESS_CAN_CONTROL_PACE:
00268 pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
00269 *pb_bool = VLC_FALSE;
00270 break;
00271
00272 case ACCESS_GET_MTU:
00273 pi_int = (int*)va_arg( args, int * );
00274 *pi_int = p_sys->i_mtu;
00275 break;
00276
00277 case ACCESS_GET_PTS_DELAY:
00278 pi_64 = (int64_t*)va_arg( args, int64_t * );
00279 *pi_64 = var_GetInteger( p_access, "udp-caching" ) * 1000;
00280 break;
00281
00282
00283 case ACCESS_SET_PAUSE_STATE:
00284 case ACCESS_GET_TITLE_INFO:
00285 case ACCESS_SET_TITLE:
00286 case ACCESS_SET_SEEKPOINT:
00287 case ACCESS_SET_PRIVATE_ID_STATE:
00288 return VLC_EGENERIC;
00289
00290 default:
00291 msg_Warn( p_access, "unimplemented query in control" );
00292 return VLC_EGENERIC;
00293
00294 }
00295 return VLC_SUCCESS;
00296 }
00297
00298
00299
00300
00301 static block_t *BlockUDP( access_t *p_access )
00302 {
00303 access_sys_t *p_sys = p_access->p_sys;
00304 block_t *p_block;
00305
00306
00307 p_block = block_New( p_access, p_sys->i_mtu );
00308 p_block->i_buffer = net_Read( p_access, p_sys->fd, NULL,
00309 p_block->p_buffer, p_sys->i_mtu,
00310 VLC_FALSE );
00311 if( p_block->i_buffer <= 0 )
00312 {
00313 block_Release( p_block );
00314 return NULL;
00315 }
00316
00317 if( (p_block->i_buffer >= p_sys->i_mtu) && p_sys->b_auto_mtu &&
00318 p_sys->i_mtu < 32767 )
00319 {
00320
00321 p_sys->i_mtu *= 2;
00322 msg_Dbg( p_access, "increasing MTU to %d", p_sys->i_mtu );
00323 }
00324
00325 return p_block;
00326 }
00327
00328
00329
00330
00331
00332 static inline vlc_bool_t rtp_ChainInsert( access_t *p_access, block_t *p_block )
00333 {
00334 access_sys_t *p_sys = (access_sys_t *) p_access->p_sys;
00335 block_t *p_prev = NULL;
00336 block_t *p = p_sys->p_end;
00337 uint16_t i_new = (uint16_t) p_block->i_dts;
00338 uint16_t i_tmp = 0;
00339
00340 if( !p_sys->p_list )
00341 {
00342 p_sys->p_list = p_block;
00343 p_sys->p_end = p_block;
00344 return VLC_TRUE;
00345 }
00346
00347
00348
00349 for( ;; )
00350 {
00351 i_tmp = i_new - (uint16_t) p->i_dts;
00352
00353 if( !i_tmp )
00354 break;
00355
00356 if ( i_tmp < 32768 )
00357 {
00358 p_block->p_next = p->p_next;
00359 p->p_next = p_block;
00360 p_block->p_prev = p;
00361 if (p_prev)
00362 {
00363 p_prev->p_prev = p_block;
00364 msg_Dbg(p_access, "RTP reordering: insert after %d, new %d",
00365 (uint16_t) p->i_dts, i_new );
00366 }
00367 else
00368 {
00369 p_sys->p_end = p_block;
00370 }
00371 return VLC_TRUE;
00372 }
00373 if( p == p_sys->p_list )
00374 {
00375 i_tmp = p_sys->i_last_seqno - i_new;
00376 if( !p_access->info.b_prebuffered || (i_tmp > 32767) )
00377 {
00378 msg_Dbg(p_access, "RTP reordering: prepend %d before %d",
00379 i_new, (uint16_t) p->i_dts );
00380 p_block->p_next = p;
00381 p->p_prev = p_block;
00382 p_sys->p_list = p_block;
00383 return VLC_TRUE;
00384 }
00385
00386 if( !i_tmp )
00387 break;
00388
00389
00390 msg_Dbg(p_access, "RTP: sequence changed (or buffer too small) "
00391 "new: %d, buffer %d...%d", i_new, (uint16_t) p->i_dts,
00392 (uint16_t) p_sys->p_end->i_dts);
00393 p_sys->p_end->p_next = p_block;
00394 p_block->p_prev = p_sys->p_end;
00395 p_sys->p_end = p_block;
00396 return VLC_TRUE;
00397 }
00398 p_prev = p;
00399 p = p->p_prev;
00400 }
00401 block_Release( p_block );
00402 return VLC_FALSE;
00403 }
00404
00405
00406
00407
00408 static block_t *BlockParseRTP( access_t *p_access, block_t *p_block )
00409 {
00410 int i_rtp_version;
00411 int i_CSRC_count;
00412 int i_payload_type;
00413 int i_skip = 0;
00414 int i_extension_flag = 0;
00415 int i_extension_length = 0;
00416 uint16_t i_sequence_number = 0;
00417
00418 if( p_block == NULL )
00419 return NULL;
00420
00421 if( p_block->i_buffer < RTP_HEADER_LEN )
00422 goto trash;
00423
00424
00425
00426 i_rtp_version = ( p_block->p_buffer[0] & 0xC0 ) >> 6;
00427 i_CSRC_count = p_block->p_buffer[0] & 0x0F;
00428 i_extension_flag = p_block->p_buffer[0] & 0x10;
00429 i_payload_type = p_block->p_buffer[1] & 0x7F;
00430 i_sequence_number = (p_block->p_buffer[2] << 8 ) + p_block->p_buffer[3];
00431
00432 if( i_rtp_version != 2 )
00433 msg_Dbg( p_access, "RTP version is %u, should be 2", i_rtp_version );
00434
00435 if( i_payload_type == 14 || i_payload_type == 32)
00436 i_skip = 4;
00437 else if( i_payload_type != 33 )
00438 msg_Dbg( p_access, "unsupported RTP payload type (%u)", i_payload_type );
00439 if( i_extension_flag )
00440 i_extension_length = 4 +
00441 4 * ( (p_block->p_buffer[14] << 8) + p_block->p_buffer[15] );
00442
00443
00444 i_skip += RTP_HEADER_LEN + 4*i_CSRC_count + i_extension_length;
00445
00446 if( i_skip >= p_block->i_buffer )
00447 goto trash;
00448
00449
00450 p_block->i_buffer -= i_skip;
00451 p_block->p_buffer += i_skip;
00452 p_block->i_pts = mdate();
00453 p_block->i_dts = (mtime_t) i_sequence_number;
00454
00455 #if 0
00456
00457 if ( (i_sequence_number % 4000) == 0)
00458 {
00459 msg_Warn( p_access, "Emulating packet drop" );
00460 block_Release( p_block );
00461 return NULL;
00462 }
00463 #endif
00464
00465 return p_block;
00466
00467
00468 trash:
00469 msg_Warn( p_access, "received a too short packet for RTP" );
00470 block_Release( p_block );
00471 return NULL;
00472 }
00473
00474 static block_t *BlockPrebufferRTP( access_t *p_access, block_t *p_block )
00475 {
00476 access_sys_t *p_sys = p_access->p_sys;
00477 mtime_t i_first = mdate();
00478 int i_count = 0;
00479 block_t *p = p_block;
00480
00481 for( ;; )
00482 {
00483 mtime_t i_date = mdate();
00484
00485 if( p && rtp_ChainInsert( p_access, p ))
00486 i_count++;
00487
00488
00489 if( i_count > 2 && (i_date - i_first) > p_sys->i_rtp_late )
00490 break;
00491
00492 p = BlockParseRTP( p_access, BlockUDP( p_access ));
00493 if( !p && (i_date - i_first) > p_sys->i_rtp_late )
00494 {
00495 msg_Err( p_access, "Error in RTP prebuffering!" );
00496 break;
00497 }
00498 }
00499
00500 msg_Dbg( p_access, "RTP: prebuffered %d packets", i_count - 1 );
00501 p_access->info.b_prebuffered = VLC_TRUE;
00502 p = p_sys->p_list;
00503 p_sys->p_list = p_sys->p_list->p_next;
00504 p_sys->i_last_seqno = (uint16_t) p->i_dts;
00505 p->p_next = NULL;
00506 return p;
00507 }
00508
00509 static block_t *BlockRTP( access_t *p_access )
00510 {
00511 access_sys_t *p_sys = p_access->p_sys;
00512 block_t *p;
00513
00514 while ( !p_sys->p_list ||
00515 ( mdate() - p_sys->p_list->i_pts ) < p_sys->i_rtp_late )
00516 {
00517 p = BlockParseRTP( p_access, BlockUDP( p_access ));
00518
00519 if ( !p )
00520 return NULL;
00521
00522 rtp_ChainInsert( p_access, p );
00523 }
00524
00525 p = p_sys->p_list;
00526 p_sys->p_list = p_sys->p_list->p_next;
00527 p_sys->i_last_seqno++;
00528 if( p_sys->i_last_seqno != (uint16_t) p->i_dts )
00529 {
00530 msg_Dbg( p_access, "RTP: packet(s) lost, expected %d, got %d",
00531 p_sys->i_last_seqno, (uint16_t) p->i_dts );
00532 p_sys->i_last_seqno = (uint16_t) p->i_dts;
00533 }
00534 p->p_next = NULL;
00535 return p;
00536 }
00537
00538
00539
00540
00541 static block_t *BlockChoose( access_t *p_access )
00542 {
00543 block_t *p_block;
00544 int i_rtp_version;
00545 int i_CSRC_count;
00546 int i_payload_type;
00547
00548 if( ( p_block = BlockUDP( p_access ) ) == NULL )
00549 return NULL;
00550
00551 if( p_block->p_buffer[0] == 0x47 )
00552 {
00553 msg_Dbg( p_access, "detected TS over raw UDP" );
00554 p_access->pf_block = BlockUDP;
00555 p_access->info.b_prebuffered = VLC_TRUE;
00556 return p_block;
00557 }
00558
00559 if( p_block->i_buffer < RTP_HEADER_LEN )
00560 return p_block;
00561
00562
00563
00564
00565 i_rtp_version = ( p_block->p_buffer[0] & 0xC0 ) >> 6;
00566 i_CSRC_count = ( p_block->p_buffer[0] & 0x0F );
00567 i_payload_type = ( p_block->p_buffer[1] & 0x7F );
00568
00569 if( i_rtp_version != 2 )
00570 {
00571 msg_Dbg( p_access, "no supported RTP header detected" );
00572 p_access->pf_block = BlockUDP;
00573 p_access->info.b_prebuffered = VLC_TRUE;
00574 return p_block;
00575 }
00576
00577 switch( i_payload_type )
00578 {
00579 case 33:
00580 msg_Dbg( p_access, "detected TS over RTP" );
00581 p_access->psz_demux = strdup( "ts" );
00582 break;
00583
00584 case 14:
00585 msg_Dbg( p_access, "detected MPEG audio over RTP" );
00586 p_access->psz_demux = strdup( "mpga" );
00587 break;
00588
00589 case 32:
00590 msg_Dbg( p_access, "detected MPEG video over RTP" );
00591 p_access->psz_demux = strdup( "mpgv" );
00592 break;
00593
00594 default:
00595 msg_Dbg( p_access, "no RTP header detected" );
00596 p_access->pf_block = BlockUDP;
00597 p_access->info.b_prebuffered = VLC_TRUE;
00598 return p_block;
00599 }
00600
00601 if( !BlockParseRTP( p_access, p_block )) return NULL;
00602
00603 p_access->pf_block = BlockRTP;
00604
00605 return BlockPrebufferRTP( p_access, p_block );
00606 }