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 #include <stdlib.h>
00029 #include <ctype.h>
00030
00031 #include <vlc/vlc.h>
00032 #include <vlc/input.h>
00033 #include <vlc/decoder.h>
00034 #include <vlc/vout.h>
00035
00036 #include "input_internal.h"
00037
00038 #include "stream_output.h"
00039 #include "vlc_playlist.h"
00040 #include "vlc_interface.h"
00041
00042
00043
00044
00045 static int Run ( input_thread_t *p_input );
00046
00047 static int Init ( input_thread_t *p_input, vlc_bool_t b_quick );
00048 static void Error( input_thread_t *p_input );
00049 static void End ( input_thread_t *p_input );
00050
00051 static inline int ControlPopNoLock( input_thread_t *, int *, vlc_value_t * );
00052 static void ControlReduce( input_thread_t * );
00053 static vlc_bool_t Control( input_thread_t *, int, vlc_value_t );
00054
00055
00056 static int UpdateFromAccess( input_thread_t * );
00057 static int UpdateFromDemux( input_thread_t * );
00058 static int UpdateMeta( input_thread_t *, vlc_bool_t );
00059
00060 static void UpdateItemLength( input_thread_t *, int64_t i_length, vlc_bool_t );
00061
00062 static void ParseOption( input_thread_t *p_input, const char *psz_option );
00063
00064 static void DecodeUrl( char * );
00065 static void MRLSections( input_thread_t *, char *, int *, int *, int *, int *);
00066
00067 static input_source_t *InputSourceNew( input_thread_t *);
00068 static int InputSourceInit( input_thread_t *, input_source_t *,
00069 char *, char *psz_forced_demux,
00070 vlc_bool_t b_quick );
00071 static void InputSourceClean( input_thread_t *, input_source_t * );
00072
00073 static void SlaveDemux( input_thread_t *p_input );
00074 static void SlaveSeek( input_thread_t *p_input );
00075
00076 static vlc_meta_t *InputMetaUser( input_thread_t *p_input );
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104 input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
00105 input_item_t *p_item )
00106
00107 {
00108 input_thread_t *p_input;
00109 vlc_value_t val;
00110 int i;
00111
00112
00113 p_input = vlc_object_create( p_parent, VLC_OBJECT_INPUT );
00114 if( p_input == NULL )
00115 {
00116 msg_Err( p_parent, "out of memory" );
00117 return NULL;
00118 }
00119
00120
00121 p_input->b_eof = VLC_FALSE;
00122 p_input->b_can_pace_control = VLC_TRUE;
00123 p_input->i_start = 0;
00124 p_input->i_time = 0;
00125 p_input->i_stop = 0;
00126 p_input->i_title = 0;
00127 p_input->title = NULL;
00128 p_input->i_title_offset = p_input->i_seekpoint_offset = 0;
00129 p_input->i_state = INIT_S;
00130 p_input->i_rate = INPUT_RATE_DEFAULT;
00131 p_input->i_bookmark = 0;
00132 p_input->bookmark = NULL;
00133 p_input->p_meta = NULL;
00134 p_input->p_es_out = NULL;
00135 p_input->p_sout = NULL;
00136 p_input->b_out_pace_control = VLC_FALSE;
00137 p_input->i_pts_delay = 0;
00138
00139
00140 p_input->input.p_item = p_item;
00141 p_input->input.p_access = NULL;
00142 p_input->input.p_stream = NULL;
00143 p_input->input.p_demux = NULL;
00144 p_input->input.b_title_demux = VLC_FALSE;
00145 p_input->input.i_title = 0;
00146 p_input->input.title = NULL;
00147 p_input->input.i_title_offset = p_input->input.i_seekpoint_offset = 0;
00148 p_input->input.b_can_pace_control = VLC_TRUE;
00149 p_input->input.b_eof = VLC_FALSE;
00150 p_input->input.i_cr_average = 0;
00151
00152
00153 p_input->i_slave = 0;
00154 p_input->slave = NULL;
00155
00156
00157 vlc_mutex_init( p_input, &p_input->lock_control );
00158 p_input->i_control = 0;
00159
00160
00161 vlc_mutex_lock( &p_item->lock );
00162 for( i = 0; i < p_item->i_options; i++ )
00163 {
00164 ParseOption( p_input, p_item->ppsz_options[i] );
00165 }
00166 vlc_mutex_unlock( &p_item->lock );
00167
00168
00169 input_ConfigVarInit( p_input );
00170
00171
00172 input_ControlVarInit( p_input );
00173 p_input->input.i_cr_average = var_GetInteger( p_input, "cr-average" );
00174
00175
00176 var_Get( p_input, "bookmarks", &val );
00177 if( val.psz_string )
00178 {
00179
00180 char *psz_parser, *psz_start, *psz_end;
00181 psz_parser = val.psz_string;
00182 while( (psz_start = strchr( psz_parser, '{' ) ) )
00183 {
00184 seekpoint_t *p_seekpoint = vlc_seekpoint_New();
00185 char backup;
00186 psz_start++;
00187 psz_end = strchr( psz_start, '}' );
00188 if( !psz_end ) break;
00189 psz_parser = psz_end + 1;
00190 backup = *psz_parser;
00191 *psz_parser = 0;
00192 *psz_end = ',';
00193
00194 while( (psz_end = strchr( psz_start, ',' ) ) )
00195 {
00196 *psz_end = 0;
00197 if( !strncmp( psz_start, "name=", 5 ) )
00198 {
00199 p_seekpoint->psz_name = psz_start + 5;
00200 }
00201 else if( !strncmp( psz_start, "bytes=", 6 ) )
00202 {
00203 p_seekpoint->i_byte_offset = atoll(psz_start + 6);
00204 }
00205 else if( !strncmp( psz_start, "time=", 5 ) )
00206 {
00207 p_seekpoint->i_time_offset = atoll(psz_start + 5) * 1000000;
00208 }
00209 psz_start = psz_end + 1;
00210 }
00211 msg_Dbg( p_input, "adding bookmark: %s, bytes="I64Fd", time="I64Fd,
00212 p_seekpoint->psz_name, p_seekpoint->i_byte_offset,
00213 p_seekpoint->i_time_offset );
00214 input_Control( p_input, INPUT_ADD_BOOKMARK, p_seekpoint );
00215 vlc_seekpoint_Delete( p_seekpoint );
00216 *psz_parser = backup;
00217 }
00218 free( val.psz_string );
00219 }
00220
00221
00222 input_Control( p_input, INPUT_DEL_INFO, _("Meta-information"),
00223 VLC_META_NOW_PLAYING );
00224
00225
00226 vlc_object_attach( p_input, p_parent );
00227
00228
00229 if( vlc_thread_create( p_input, "input", Run,
00230 VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) )
00231 {
00232 msg_Err( p_input, "cannot create input thread" );
00233 vlc_object_detach( p_input );
00234 vlc_object_destroy( p_input );
00235 return NULL;
00236 }
00237
00238 return p_input;
00239 }
00240
00241
00242
00243
00244 int __input_Preparse( vlc_object_t *p_parent, input_item_t *p_item )
00245 {
00246 input_thread_t *p_input;
00247 int i;
00248
00249
00250 p_input = vlc_object_create( p_parent, VLC_OBJECT_INPUT );
00251 if( p_input == NULL )
00252 {
00253 msg_Err( p_parent, "out of memory" );
00254 return VLC_EGENERIC;
00255 }
00256
00257
00258 p_input->b_eof = VLC_FALSE;
00259 p_input->b_can_pace_control = VLC_TRUE;
00260 p_input->i_start = 0;
00261 p_input->i_time = 0;
00262 p_input->i_stop = 0;
00263 p_input->i_title = 0;
00264 p_input->title = NULL;
00265 p_input->i_title_offset = p_input->i_seekpoint_offset = 0;
00266 p_input->i_state = INIT_S;
00267 p_input->i_rate = INPUT_RATE_DEFAULT;
00268 p_input->i_bookmark = 0;
00269 p_input->bookmark = NULL;
00270 p_input->p_meta = NULL;
00271 p_input->p_es_out = NULL;
00272 p_input->p_sout = NULL;
00273 p_input->b_out_pace_control = VLC_FALSE;
00274 p_input->i_pts_delay = 0;
00275
00276
00277 p_input->input.p_item = p_item;
00278 p_input->input.p_access = NULL;
00279 p_input->input.p_stream = NULL;
00280 p_input->input.p_demux = NULL;
00281 p_input->input.b_title_demux = VLC_FALSE;
00282 p_input->input.i_title = 0;
00283 p_input->input.title = NULL;
00284 p_input->input.i_title_offset = p_input->input.i_seekpoint_offset = 0;
00285 p_input->input.b_can_pace_control = VLC_TRUE;
00286 p_input->input.b_eof = VLC_FALSE;
00287 p_input->input.i_cr_average = 0;
00288
00289
00290 p_input->i_slave = 0;
00291 p_input->slave = NULL;
00292
00293
00294 vlc_mutex_init( p_input, &p_input->lock_control );
00295 p_input->i_control = 0;
00296
00297
00298 vlc_mutex_lock( &p_item->lock );
00299 for( i = 0; i < p_item->i_options; i++ )
00300 {
00301 ParseOption( p_input, p_item->ppsz_options[i] );
00302 }
00303 vlc_mutex_unlock( &p_item->lock );
00304
00305
00306 input_ConfigVarInit( p_input );
00307 input_ControlVarInit( p_input );
00308
00309 p_input->input.i_cr_average = var_GetInteger( p_input, "cr-average" );
00310
00311
00312 vlc_object_attach( p_input, p_parent );
00313
00314 Init( p_input, VLC_TRUE );
00315
00316
00317 InputSourceClean( p_input, &p_input->input );
00318
00319
00320 if( p_input->input.p_access ) p_input->input.p_access->b_die = VLC_TRUE;
00321 if( p_input->input.p_demux ) p_input->input.p_access->b_die = VLC_TRUE;
00322
00323
00324 if( p_input->p_es_out ) input_EsOutDelete( p_input->p_es_out );
00325
00326
00327 if( p_input->p_meta ) vlc_meta_Delete( p_input->p_meta );
00328
00329 vlc_object_detach( p_input );
00330 vlc_object_destroy( p_input );
00331
00332 return VLC_SUCCESS;
00333 }
00334
00335
00336
00337
00338
00339
00340 void input_StopThread( input_thread_t *p_input )
00341 {
00342 vlc_list_t *p_list;
00343 int i;
00344
00345
00346 p_input->b_die = VLC_TRUE;
00347
00348
00349
00350
00351
00352 p_list = vlc_list_find( p_input, VLC_OBJECT_ACCESS, FIND_CHILD );
00353 for( i = 0; i < p_list->i_count; i++ )
00354 {
00355 p_list->p_values[i].p_object->b_die = VLC_TRUE;
00356 }
00357 vlc_list_release( p_list );
00358
00359
00360 p_list = vlc_list_find( p_input, VLC_OBJECT_STREAM, FIND_CHILD );
00361 for( i = 0; i < p_list->i_count; i++ )
00362 {
00363 p_list->p_values[i].p_object->b_die = VLC_TRUE;
00364 }
00365 vlc_list_release( p_list );
00366
00367
00368 p_list = vlc_list_find( p_input, VLC_OBJECT_DEMUX, FIND_CHILD );
00369 for( i = 0; i < p_list->i_count; i++ )
00370 {
00371 p_list->p_values[i].p_object->b_die = VLC_TRUE;
00372 }
00373 vlc_list_release( p_list );
00374
00375 input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
00376 }
00377
00378
00379
00380
00381
00382
00383 void input_DestroyThread( input_thread_t *p_input )
00384 {
00385
00386 vlc_thread_join( p_input );
00387
00388
00389 vlc_mutex_destroy( &p_input->lock_control );
00390
00391
00392
00393 }
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404 static int Run( input_thread_t *p_input )
00405 {
00406 int64_t i_intf_update = 0;
00407
00408
00409 vlc_thread_ready( p_input );
00410
00411 if( Init( p_input, VLC_FALSE ) )
00412 {
00413
00414 p_input->b_error = VLC_TRUE;
00415
00416 Error( p_input );
00417
00418
00419 p_input->b_dead = VLC_TRUE;
00420
00421 return 0;
00422 }
00423
00424
00425 while( !p_input->b_die && !p_input->b_error && !p_input->input.b_eof )
00426 {
00427 vlc_bool_t b_force_update = VLC_FALSE;
00428 int i_ret;
00429 int i_type;
00430 vlc_value_t val;
00431
00432
00433 if( p_input->i_state != PAUSE_S )
00434 {
00435 if( p_input->i_stop <= 0 || p_input->i_time < p_input->i_stop )
00436 i_ret=p_input->input.p_demux->pf_demux(p_input->input.p_demux);
00437 else
00438 i_ret = 0;
00439
00440 if( i_ret > 0 )
00441 {
00442
00443 if( p_input->input.b_title_demux &&
00444 p_input->input.p_demux->info.i_update )
00445 {
00446 i_ret = UpdateFromDemux( p_input );
00447 b_force_update = VLC_TRUE;
00448 }
00449 else if( !p_input->input.b_title_demux &&
00450 p_input->input.p_access &&
00451 p_input->input.p_access->info.i_update )
00452 {
00453 i_ret = UpdateFromAccess( p_input );
00454 b_force_update = VLC_TRUE;
00455 }
00456 }
00457
00458 if( i_ret == 0 )
00459 {
00460 vlc_value_t repeat;
00461
00462 var_Get( p_input, "input-repeat", &repeat );
00463 if( repeat.i_int == 0 )
00464 {
00465
00466
00467 msg_Dbg( p_input, "EOF reached" );
00468 p_input->input.b_eof = VLC_TRUE;
00469 }
00470 else
00471 {
00472 msg_Dbg( p_input, "repeating the same input (%d)",
00473 repeat.i_int );
00474 if( repeat.i_int > 0 )
00475 {
00476 repeat.i_int--;
00477 var_Set( p_input, "input-repeat", repeat );
00478 }
00479
00480
00481 val.i_int = p_input->input.i_title_start -
00482 p_input->input.i_title_offset;
00483 if( val.i_int < 0 || val.i_int >= p_input->input.i_title )
00484 val.i_int = 0;
00485 input_ControlPush( p_input,
00486 INPUT_CONTROL_SET_TITLE, &val );
00487
00488 val.i_int = p_input->input.i_seekpoint_start -
00489 p_input->input.i_seekpoint_offset;
00490 if( val.i_int > 0 )
00491 input_ControlPush( p_input,
00492 INPUT_CONTROL_SET_SEEKPOINT, &val );
00493
00494
00495 if( p_input->i_start > 0 )
00496 {
00497 val.i_time = p_input->i_start;
00498 input_ControlPush( p_input, INPUT_CONTROL_SET_TIME,
00499 &val );
00500 }
00501 else
00502 {
00503 val.f_float = 0.0;
00504 input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION,
00505 &val );
00506 }
00507 }
00508 }
00509 else if( i_ret < 0 )
00510 {
00511 p_input->b_error = VLC_TRUE;
00512 }
00513
00514 if( i_ret > 0 && p_input->i_slave > 0 )
00515 {
00516 SlaveDemux( p_input );
00517 }
00518 }
00519 else
00520 {
00521
00522 msleep( 10*1000 );
00523 }
00524
00525
00526 vlc_mutex_lock( &p_input->lock_control );
00527 ControlReduce( p_input );
00528 while( !ControlPopNoLock( p_input, &i_type, &val ) )
00529 {
00530 msg_Dbg( p_input, "control type=%d", i_type );
00531 if( Control( p_input, i_type, val ) )
00532 b_force_update = VLC_TRUE;
00533 }
00534 vlc_mutex_unlock( &p_input->lock_control );
00535
00536 if( b_force_update || i_intf_update < mdate() )
00537 {
00538 vlc_value_t val;
00539 double f_pos;
00540 int64_t i_time, i_length;
00541
00542 if( !demux2_Control( p_input->input.p_demux,
00543 DEMUX_GET_POSITION, &f_pos ) )
00544 {
00545 val.f_float = (float)f_pos;
00546 var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
00547 }
00548 if( !demux2_Control( p_input->input.p_demux,
00549 DEMUX_GET_TIME, &i_time ) )
00550 {
00551 p_input->i_time = i_time;
00552 val.i_time = i_time;
00553 var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
00554 }
00555 if( !demux2_Control( p_input->input.p_demux,
00556 DEMUX_GET_LENGTH, &i_length ) )
00557 {
00558 vlc_value_t old_val;
00559 var_Get( p_input, "length", &old_val );
00560 val.i_time = i_length;
00561 var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
00562
00563 if( old_val.i_time != val.i_time )
00564 {
00565 UpdateItemLength( p_input, i_length, VLC_TRUE );
00566 }
00567 }
00568
00569 var_SetBool( p_input, "intf-change", VLC_TRUE );
00570 i_intf_update = mdate() + I64C(150000);
00571 }
00572 }
00573
00574 if( !p_input->b_eof && !p_input->b_error && p_input->input.b_eof )
00575 {
00576
00577 while( !p_input->b_die )
00578 {
00579 if( input_EsOutDecodersEmpty( p_input->p_es_out ) )
00580 break;
00581
00582 msg_Dbg( p_input, "waiting decoder fifos to empty" );
00583
00584 msleep( INPUT_IDLE_SLEEP );
00585 }
00586
00587
00588 p_input->b_eof = VLC_TRUE;
00589 }
00590
00591
00592 if( !p_input->b_die )
00593 {
00594 Error( p_input );
00595 }
00596
00597
00598 End( p_input );
00599
00600 return 0;
00601 }
00602
00603
00604 static int Init( input_thread_t * p_input, vlc_bool_t b_quick )
00605 {
00606 char *psz;
00607 char *psz_subtitle;
00608 vlc_value_t val;
00609 double f_fps;
00610 vlc_meta_t *p_meta, *p_meta_tmp;
00611 int i_es_out_mode;
00612 int i, i_delay;
00613
00614
00615
00616
00617
00618
00619
00620
00621 if( !b_quick )
00622 {
00623 psz = var_GetString( p_input, "sout" );
00624 if( *psz && strncasecmp( p_input->input.p_item->psz_uri, "vlc:", 4 ) )
00625 {
00626 p_input->p_sout = sout_NewInstance( p_input, psz );
00627 if( p_input->p_sout == NULL )
00628 {
00629 msg_Err( p_input, "cannot start stream output instance, " \
00630 "aborting" );
00631 free( psz );
00632 return VLC_EGENERIC;
00633 }
00634 }
00635 free( psz );
00636 }
00637
00638
00639 p_input->p_es_out = input_EsOutNew( p_input );
00640 es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_FALSE );
00641 es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE, ES_OUT_MODE_NONE );
00642
00643 if( InputSourceInit( p_input, &p_input->input,
00644 p_input->input.p_item->psz_uri, NULL, b_quick ) )
00645 {
00646 goto error;
00647 }
00648
00649
00650 if( !b_quick )
00651 {
00652 p_input->i_title = p_input->input.i_title;
00653 p_input->title = p_input->input.title;
00654 p_input->i_title_offset = p_input->input.i_title_offset;
00655 p_input->i_seekpoint_offset = p_input->input.i_seekpoint_offset;
00656 if( p_input->i_title > 0 )
00657 {
00658
00659 input_ControlVarNavigation( p_input );
00660 input_ControlVarTitle( p_input, 0 );
00661 }
00662
00663
00664 p_input->b_can_pace_control = p_input->input.b_can_pace_control;
00665 p_input->b_can_pause = p_input->input.b_can_pause;
00666
00667
00668 if( p_input->i_pts_delay < 0 )
00669 p_input->i_pts_delay = 0;
00670
00671
00672
00673 var_Get( p_input, "audio-desync", &val );
00674 if( val.i_int < 0 ) p_input->i_pts_delay -= (val.i_int * 1000);
00675
00676
00677 p_input->input.i_cr_average *= (10 * p_input->i_pts_delay / 200000);
00678 p_input->input.i_cr_average /= 10;
00679 if( p_input->input.i_cr_average < 10 ) p_input->input.i_cr_average = 10;
00680 }
00681
00682
00683
00684 if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_LENGTH,
00685 &val.i_time ) && val.i_time > 0 )
00686 {
00687 var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
00688 UpdateItemLength( p_input, val.i_time, b_quick );
00689 p_input->input.p_item->i_duration = val.i_time;
00690 }
00691
00692
00693 if( !b_quick )
00694 {
00695 val.i_int = p_input->input.i_title_start -
00696 p_input->input.i_title_offset;
00697 if( val.i_int > 0 && val.i_int < p_input->input.i_title )
00698 input_ControlPush( p_input, INPUT_CONTROL_SET_TITLE, &val );
00699 val.i_int = p_input->input.i_seekpoint_start -
00700 p_input->input.i_seekpoint_offset;
00701 if( val.i_int > 0 )
00702 input_ControlPush( p_input, INPUT_CONTROL_SET_SEEKPOINT, &val );
00703
00704
00705
00706 p_input->i_start = (int64_t)var_GetInteger( p_input, "start-time" ) *
00707 I64C(1000000);
00708 p_input->i_stop = (int64_t)var_GetInteger( p_input, "stop-time" ) *
00709 I64C(1000000);
00710
00711 if( p_input->i_start > 0 )
00712 {
00713 if( p_input->i_start >= val.i_time )
00714 {
00715 msg_Warn( p_input, "invalid start-time ignored" );
00716 }
00717 else
00718 {
00719 vlc_value_t s;
00720
00721 msg_Dbg( p_input, "starting at time: %ds",
00722 (int)( p_input->i_start / I64C(1000000) ) );
00723
00724 s.i_time = p_input->i_start;
00725 input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &s );
00726 }
00727 }
00728 if( p_input->i_stop > 0 && p_input->i_stop <= p_input->i_start )
00729 {
00730 msg_Warn( p_input, "invalid stop-time ignored" );
00731 p_input->i_stop = 0;
00732 }
00733
00734
00735
00736
00737 if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_FPS, &f_fps ) &&
00738 f_fps > 1.0 )
00739 {
00740 float f_requested_fps;
00741
00742 var_Create( p_input, "sub-original-fps", VLC_VAR_FLOAT );
00743 var_SetFloat( p_input, "sub-original-fps", f_fps );
00744
00745 f_requested_fps = var_CreateGetFloat( p_input, "sub-fps" );
00746 if( f_requested_fps != f_fps )
00747 {
00748 var_Create( p_input, "sub-fps", VLC_VAR_FLOAT|
00749 VLC_VAR_DOINHERIT );
00750 var_SetFloat( p_input, "sub-fps", f_requested_fps );
00751 }
00752 }
00753
00754 i_delay = var_CreateGetInteger( p_input, "sub-delay" );
00755 if( i_delay != 0 )
00756 {
00757 var_SetTime( p_input, "spu-delay", (mtime_t)i_delay * 100000 );
00758 }
00759
00760
00761
00762 psz_subtitle = var_GetString( p_input, "sub-file" );
00763 if( *psz_subtitle )
00764 {
00765 input_source_t *sub;
00766 vlc_value_t count;
00767 vlc_value_t list;
00768
00769 msg_Dbg( p_input, "forced subtitle: %s", psz_subtitle );
00770
00771 var_Change( p_input, "spu-es", VLC_VAR_CHOICESCOUNT, &count, NULL );
00772
00773
00774 sub = InputSourceNew( p_input );
00775 if( !InputSourceInit( p_input, sub, psz_subtitle, "subtitle",
00776 VLC_FALSE ) )
00777 {
00778 TAB_APPEND( p_input->i_slave, p_input->slave, sub );
00779
00780
00781 if( !var_Change( p_input, "spu-es", VLC_VAR_GETLIST, &list,
00782 NULL ) )
00783 {
00784 if( count.i_int == 0 )
00785 count.i_int++;
00786
00787
00788 if( count.i_int < list.p_list->i_count )
00789 {
00790 input_ControlPush( p_input, INPUT_CONTROL_SET_ES,
00791 &list.p_list->p_values[count.i_int] );
00792 }
00793 var_Change( p_input, "spu-es", VLC_VAR_FREELIST, &list,
00794 NULL );
00795 }
00796 }
00797 }
00798
00799 var_Get( p_input, "sub-autodetect-file", &val );
00800 if( val.b_bool )
00801 {
00802 char *psz_autopath = var_GetString( p_input, "sub-autodetect-path" );
00803 char **subs = subtitles_Detect( p_input, psz_autopath,
00804 p_input->input.p_item->psz_uri );
00805 input_source_t *sub;
00806
00807 for( i = 0; subs && subs[i]; i++ )
00808 {
00809 if( strcmp( psz_subtitle, subs[i] ) )
00810 {
00811 sub = InputSourceNew( p_input );
00812 if( !InputSourceInit( p_input, sub, subs[i], "subtitle",
00813 VLC_FALSE ) )
00814 {
00815 TAB_APPEND( p_input->i_slave, p_input->slave, sub );
00816 }
00817 }
00818 free( subs[i] );
00819 }
00820 if( subs ) free( subs );
00821 if( psz_autopath ) free( psz_autopath );
00822 }
00823 free( psz_subtitle );
00824
00825
00826 psz = var_GetString( p_input, "input-slave" );
00827 if( *psz )
00828 {
00829 char *psz_delim;
00830 input_source_t *slave;
00831 while( psz && *psz )
00832 {
00833 while( *psz == ' ' || *psz == '#' )
00834 {
00835 psz++;
00836 }
00837 if( ( psz_delim = strchr( psz, '#' ) ) )
00838 {
00839 *psz_delim++ = '\0';
00840 }
00841 if( *psz == 0 )
00842 {
00843 break;
00844 }
00845
00846 msg_Dbg( p_input, "adding slave input '%s'", psz );
00847 slave = InputSourceNew( p_input );
00848 if( !InputSourceInit( p_input, slave, psz, NULL, VLC_FALSE ) )
00849 {
00850 TAB_APPEND( p_input->i_slave, p_input->slave, slave );
00851 }
00852 psz = psz_delim;
00853 }
00854 }
00855 if( psz ) free( psz );
00856 }
00857 else
00858 {
00859 p_input->i_start = 0;
00860 p_input->i_start = 0;
00861 }
00862
00863
00864 if( !b_quick )
00865 {
00866 es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_TRUE );
00867 i_es_out_mode = ES_OUT_MODE_AUTO;
00868 val.p_list = NULL;
00869 if( p_input->p_sout )
00870 {
00871 var_Get( p_input, "sout-all", &val );
00872 if ( val.b_bool )
00873 {
00874 i_es_out_mode = ES_OUT_MODE_ALL;
00875 val.p_list = NULL;
00876 }
00877 else
00878 {
00879 var_Get( p_input, "programs", &val );
00880 if ( val.p_list && val.p_list->i_count )
00881 {
00882 i_es_out_mode = ES_OUT_MODE_PARTIAL;
00883
00884 }
00885 else
00886 var_Change( p_input, "programs", VLC_VAR_FREELIST, &val,
00887 NULL );
00888 }
00889 }
00890 es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE, i_es_out_mode );
00891
00892
00893 if( i_es_out_mode == ES_OUT_MODE_ALL )
00894 {
00895 demux2_Control( p_input->input.p_demux, DEMUX_SET_GROUP, -1, NULL );
00896 }
00897 else if( i_es_out_mode == ES_OUT_MODE_PARTIAL )
00898 {
00899 demux2_Control( p_input->input.p_demux, DEMUX_SET_GROUP, -1,
00900 val.p_list );
00901 }
00902 else
00903 {
00904 demux2_Control( p_input->input.p_demux, DEMUX_SET_GROUP,
00905 (int) var_GetInteger( p_input, "program" ), NULL );
00906 }
00907
00908 if( p_input->p_sout )
00909 {
00910 if( p_input->p_sout->i_out_pace_nocontrol > 0 )
00911 {
00912 p_input->b_out_pace_control = VLC_FALSE;
00913 }
00914 else
00915 {
00916 p_input->b_out_pace_control = VLC_TRUE;
00917 }
00918
00919 if( p_input->b_can_pace_control && p_input->b_out_pace_control )
00920 {
00921
00922
00923 vlc_thread_set_priority( p_input, VLC_THREAD_PRIORITY_LOW );
00924 }
00925
00926 msg_Dbg( p_input, "starting in %s mode",
00927 p_input->b_out_pace_control ? "asynch" : "synch" );
00928 }
00929 }
00930
00931
00932 p_meta_tmp = InputMetaUser( p_input );
00933
00934
00935 if( demux2_Control( p_input->input.p_demux, DEMUX_GET_META, &p_meta ) )
00936 p_meta = NULL;
00937
00938
00939 if( p_meta == NULL )
00940 {
00941 p_meta = p_meta_tmp;
00942 }
00943 else if( p_meta_tmp )
00944 {
00945 vlc_meta_Merge( p_meta, p_meta_tmp );
00946 vlc_meta_Delete( p_meta_tmp );
00947 }
00948
00949
00950 if( !b_quick )
00951 {
00952 if( !p_input->input.p_access ||
00953 access2_Control( p_input->input.p_access, ACCESS_GET_META,
00954 &p_meta_tmp))
00955 p_meta_tmp = NULL;
00956
00957 if( p_meta == NULL )
00958 {
00959 p_meta = p_meta_tmp;
00960 }
00961 else if( p_meta_tmp )
00962 {
00963 vlc_meta_Merge( p_meta, p_meta_tmp );
00964 vlc_meta_Delete( p_meta_tmp );
00965 }
00966
00967
00968 for( i = 0; i < p_input->i_slave; i++ )
00969 {
00970 vlc_meta_t *p_meta_slave;
00971
00972 if( !demux2_Control( p_input->slave[i]->p_demux,
00973 DEMUX_GET_META, &p_meta_slave ) )
00974 {
00975 if( p_meta == NULL )
00976 {
00977 p_meta = p_meta_slave;
00978 }
00979 else if( p_meta_slave )
00980 {
00981 vlc_meta_Merge( p_meta, p_meta_slave );
00982 vlc_meta_Delete( p_meta_slave );
00983 }
00984 }
00985
00986 if( p_input->slave[i]->p_access &&
00987 !access2_Control( p_input->slave[i]->p_access,
00988 ACCESS_GET_META, &p_meta_slave ) )
00989 {
00990 if( p_meta == NULL )
00991 {
00992 p_meta = p_meta_slave;
00993 }
00994 else if( p_meta_slave )
00995 {
00996 vlc_meta_Merge( p_meta, p_meta_slave );
00997 vlc_meta_Delete( p_meta_slave );
00998 }
00999 }
01000 }
01001 }
01002
01003 p_input->p_meta = p_meta;
01004 UpdateMeta( p_input, b_quick );
01005
01006 if( !b_quick )
01007 {
01008 msg_Dbg( p_input, "`%s' successfully opened",
01009 p_input->input.p_item->psz_uri );
01010
01011 }
01012
01013
01014
01015
01016 var_SetInteger( p_input, "item-change", p_input->input.p_item->i_id );
01017
01018
01019 p_input->i_state = PLAYING_S;
01020
01021 val.i_int = PLAYING_S;
01022 var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
01023
01024 return VLC_SUCCESS;
01025
01026 error:
01027 if( p_input->p_es_out )
01028 input_EsOutDelete( p_input->p_es_out );
01029
01030 if( p_input->p_sout )
01031 sout_DeleteInstance( p_input->p_sout );
01032
01033
01034 p_input->input.p_demux = NULL;
01035 p_input->input.p_stream = NULL;
01036 p_input->input.p_access = NULL;
01037 p_input->p_es_out = NULL;
01038 p_input->p_sout = NULL;
01039
01040 return VLC_EGENERIC;
01041 }
01042
01043
01044
01045
01046
01047
01048 static void Error( input_thread_t *p_input )
01049 {
01050 while( !p_input->b_die )
01051 {
01052
01053 msleep( INPUT_IDLE_SLEEP );
01054 }
01055 }
01056
01057
01058
01059
01060 static void End( input_thread_t * p_input )
01061 {
01062 vlc_value_t val;
01063 int i;
01064
01065 msg_Dbg( p_input, "closing input" );
01066
01067
01068 p_input->i_state = END_S;
01069
01070 val.i_int = END_S;
01071 var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
01072
01073
01074 input_ControlVarClean( p_input );
01075
01076
01077 InputSourceClean( p_input, &p_input->input );
01078
01079
01080 for( i = 0; i < p_input->i_slave; i++ )
01081 {
01082 InputSourceClean( p_input, p_input->slave[i] );
01083 free( p_input->slave[i] );
01084 }
01085 if( p_input->slave ) free( p_input->slave );
01086
01087
01088 if( p_input->p_es_out )
01089 input_EsOutDelete( p_input->p_es_out );
01090
01091
01092 if( p_input->p_sout )
01093 {
01094 vlc_object_t *p_pl =
01095 vlc_object_find( p_input, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
01096 vlc_value_t keep;
01097
01098 if( var_Get( p_input, "sout-keep", &keep ) >= 0 && keep.b_bool && p_pl )
01099 {
01100
01101 msg_Dbg( p_input, "keeping sout" );
01102 vlc_object_detach( p_input->p_sout );
01103 vlc_object_attach( p_input->p_sout, p_pl );
01104 }
01105 else
01106 {
01107 msg_Dbg( p_input, "destroying sout" );
01108 sout_DeleteInstance( p_input->p_sout );
01109 }
01110 if( p_pl )
01111 vlc_object_release( p_pl );
01112 }
01113
01114
01115 if( p_input->p_meta )
01116 vlc_meta_Delete( p_input->p_meta );
01117
01118
01119 p_input->b_dead = VLC_TRUE;
01120 }
01121
01122
01123
01124
01125 static inline int ControlPopNoLock( input_thread_t *p_input,
01126 int *pi_type, vlc_value_t *p_val )
01127 {
01128 if( p_input->i_control <= 0 )
01129 {
01130 return VLC_EGENERIC;
01131 }
01132
01133 *pi_type = p_input->control[0].i_type;
01134 *p_val = p_input->control[0].val;
01135
01136 p_input->i_control--;
01137 if( p_input->i_control > 0 )
01138 {
01139 int i;
01140
01141 for( i = 0; i < p_input->i_control; i++ )
01142 {
01143 p_input->control[i].i_type = p_input->control[i+1].i_type;
01144 p_input->control[i].val = p_input->control[i+1].val;
01145 }
01146 }
01147
01148 return VLC_SUCCESS;
01149 }
01150
01151 static void ControlReduce( input_thread_t *p_input )
01152 {
01153 int i;
01154 for( i = 1; i < p_input->i_control; i++ )
01155 {
01156 const int i_lt = p_input->control[i-1].i_type;
01157 const int i_ct = p_input->control[i].i_type;
01158
01159
01160
01161
01162
01163 if( i_lt == i_ct &&
01164 ( i_ct == INPUT_CONTROL_SET_STATE ||
01165 i_ct == INPUT_CONTROL_SET_RATE ||
01166 i_ct == INPUT_CONTROL_SET_POSITION ||
01167 i_ct == INPUT_CONTROL_SET_TIME ||
01168 i_ct == INPUT_CONTROL_SET_PROGRAM ||
01169 i_ct == INPUT_CONTROL_SET_TITLE ||
01170 i_ct == INPUT_CONTROL_SET_SEEKPOINT ||
01171 i_ct == INPUT_CONTROL_SET_BOOKMARK ) )
01172 {
01173 int j;
01174
01175
01176 for( j = i; j < p_input->i_control; j++ )
01177 p_input->control[j-1] = p_input->control[j];
01178 p_input->i_control--;
01179 }
01180 else
01181 {
01182
01183
01184
01185
01186
01187
01188 }
01189 }
01190 }
01191
01192 static vlc_bool_t Control( input_thread_t *p_input, int i_type,
01193 vlc_value_t val )
01194 {
01195 vlc_bool_t b_force_update = VLC_FALSE;
01196
01197 if( !p_input ) return b_force_update;
01198
01199 switch( i_type )
01200 {
01201 case INPUT_CONTROL_SET_DIE:
01202 msg_Dbg( p_input, "control: stopping input" );
01203
01204 if( p_input->input.p_access )
01205 p_input->input.p_access->b_die = VLC_TRUE;
01206 if( p_input->input.p_stream )
01207 p_input->input.p_stream->b_die = VLC_TRUE;
01208 p_input->input.p_demux->b_die = VLC_TRUE;
01209
01210 p_input->b_die = VLC_TRUE;
01211 break;
01212
01213 case INPUT_CONTROL_SET_POSITION:
01214 case INPUT_CONTROL_SET_POSITION_OFFSET:
01215 {
01216 double f_pos;
01217 if( i_type == INPUT_CONTROL_SET_POSITION )
01218 {
01219 f_pos = val.f_float;
01220 }
01221 else
01222 {
01223
01224 demux2_Control( p_input->input.p_demux,
01225 DEMUX_GET_POSITION, &f_pos );
01226 f_pos += val.f_float;
01227 }
01228 if( f_pos < 0.0 ) f_pos = 0.0;
01229 if( f_pos > 1.0 ) f_pos = 1.0;
01230
01231 es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
01232 input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
01233 if( demux2_Control( p_input->input.p_demux, DEMUX_SET_POSITION,
01234 f_pos ) )
01235 {
01236 msg_Err( p_input, "INPUT_CONTROL_SET_POSITION(_OFFSET) "
01237 "%2.1f%% failed", f_pos * 100 );
01238 }
01239 else
01240 {
01241 if( p_input->i_slave > 0 )
01242 SlaveSeek( p_input );
01243
01244 b_force_update = VLC_TRUE;
01245 }
01246 break;
01247 }
01248
01249 case INPUT_CONTROL_SET_TIME:
01250 case INPUT_CONTROL_SET_TIME_OFFSET:
01251 {
01252 int64_t i_time;
01253 int i_ret;
01254
01255 if( i_type == INPUT_CONTROL_SET_TIME )
01256 {
01257 i_time = val.i_time;
01258 }
01259 else
01260 {
01261
01262 demux2_Control( p_input->input.p_demux,
01263 DEMUX_GET_TIME, &i_time );
01264 i_time += val.i_time;
01265 }
01266 if( i_time < 0 ) i_time = 0;
01267
01268
01269 es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
01270 input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
01271
01272 i_ret = demux2_Control( p_input->input.p_demux,
01273 DEMUX_SET_TIME, i_time );
01274 if( i_ret )
01275 {
01276 int64_t i_length;
01277
01278
01279 demux2_Control( p_input->input.p_demux,
01280 DEMUX_GET_LENGTH, &i_length );
01281 if( i_length > 0 )
01282 {
01283 double f_pos = (double)i_time / (double)i_length;
01284 i_ret = demux2_Control( p_input->input.p_demux,
01285 DEMUX_SET_POSITION, f_pos );
01286 }
01287 }
01288 if( i_ret )
01289 {
01290 msg_Warn( p_input, "INPUT_CONTROL_SET_TIME(_OFFSET) "I64Fd
01291 " failed or not possible", i_time );
01292 }
01293 else
01294 {
01295 if( p_input->i_slave > 0 )
01296 SlaveSeek( p_input );
01297
01298 b_force_update = VLC_TRUE;
01299 }
01300 break;
01301 }
01302
01303 case INPUT_CONTROL_SET_STATE:
01304 if( ( val.i_int == PLAYING_S && p_input->i_state == PAUSE_S ) ||
01305 ( val.i_int == PAUSE_S && p_input->i_state == PAUSE_S ) )
01306 {
01307 int i_ret;
01308 if( p_input->input.p_access )
01309 i_ret = access2_Control( p_input->input.p_access,
01310 ACCESS_SET_PAUSE_STATE, VLC_FALSE );
01311 else
01312 i_ret = demux2_Control( p_input->input.p_demux,
01313 DEMUX_SET_PAUSE_STATE, VLC_FALSE );
01314
01315 if( i_ret )
01316 {
01317
01318 msg_Warn( p_input, "cannot unset pause -> EOF" );
01319 vlc_mutex_unlock( &p_input->lock_control );
01320 input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
01321 vlc_mutex_lock( &p_input->lock_control );
01322 }
01323
01324 b_force_update = VLC_TRUE;
01325
01326
01327 p_input->i_state = PLAYING_S;
01328 val.i_int = PLAYING_S;
01329 var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
01330
01331
01332 es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
01333 input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
01334 }
01335 else if( val.i_int == PAUSE_S && p_input->i_state == PLAYING_S &&
01336 p_input->b_can_pause )
01337 {
01338 int i_ret;
01339 if( p_input->input.p_access )
01340 i_ret = access2_Control( p_input->input.p_access,
01341 ACCESS_SET_PAUSE_STATE, VLC_TRUE );
01342 else
01343 i_ret = demux2_Control( p_input->input.p_demux,
01344 DEMUX_SET_PAUSE_STATE, VLC_TRUE );
01345
01346 b_force_update = VLC_TRUE;
01347
01348 if( i_ret )
01349 {
01350 msg_Warn( p_input, "cannot set pause state" );
01351 val.i_int = p_input->i_state;
01352 }
01353 else
01354 {
01355 val.i_int = PAUSE_S;
01356 }
01357
01358
01359 p_input->i_state = val.i_int;
01360 var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
01361 }
01362 else if( val.i_int == PAUSE_S && !p_input->b_can_pause )
01363 {
01364 b_force_update = VLC_TRUE;
01365
01366
01367 val.i_int = p_input->i_state;
01368 var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
01369 }
01370 else if( val.i_int != PLAYING_S && val.i_int != PAUSE_S )
01371 {
01372 msg_Err( p_input, "invalid state in INPUT_CONTROL_SET_STATE" );
01373 }
01374 break;
01375
01376 case INPUT_CONTROL_SET_RATE:
01377 case INPUT_CONTROL_SET_RATE_SLOWER:
01378 case INPUT_CONTROL_SET_RATE_FASTER:
01379 {
01380 int i_rate;
01381
01382 if( i_type == INPUT_CONTROL_SET_RATE_SLOWER )
01383 i_rate = p_input->i_rate * 2;
01384 else if( i_type == INPUT_CONTROL_SET_RATE_FASTER )
01385 i_rate = p_input->i_rate / 2;
01386 else
01387 i_rate = val.i_int;
01388
01389 if( i_rate < INPUT_RATE_MIN )
01390 {
01391 msg_Dbg( p_input, "cannot set rate faster" );
01392 i_rate = INPUT_RATE_MIN;
01393 }
01394 else if( i_rate > INPUT_RATE_MAX )
01395 {
01396 msg_Dbg( p_input, "cannot set rate slower" );
01397 i_rate = INPUT_RATE_MAX;
01398 }
01399 if( i_rate != INPUT_RATE_DEFAULT &&
01400 ( !p_input->b_can_pace_control ||
01401 ( p_input->p_sout && !p_input->b_out_pace_control ) ) )
01402 {
01403 msg_Dbg( p_input, "cannot change rate" );
01404 i_rate = INPUT_RATE_DEFAULT;
01405 }
01406 if( i_rate != p_input->i_rate )
01407 {
01408 p_input->i_rate = i_rate;
01409 val.i_int = i_rate;
01410 var_Change( p_input, "rate", VLC_VAR_SETVALUE, &val, NULL );
01411
01412
01413 if( i_rate == INPUT_RATE_DEFAULT )
01414 input_EsOutDiscontinuity( p_input->p_es_out, VLC_TRUE );
01415
01416
01417 es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
01418
01419 b_force_update = VLC_TRUE;
01420 }
01421 break;
01422 }
01423
01424 case INPUT_CONTROL_SET_PROGRAM:
01425
01426 es_out_Control( p_input->p_es_out,
01427 ES_OUT_SET_GROUP, val.i_int );
01428
01429 demux2_Control( p_input->input.p_demux, DEMUX_SET_GROUP, val.i_int,
01430 NULL );
01431 break;
01432
01433 case INPUT_CONTROL_SET_ES:
01434
01435 es_out_Control( p_input->p_es_out, ES_OUT_SET_ES,
01436 input_EsOutGetFromID( p_input->p_es_out,
01437 val.i_int ) );
01438 break;
01439
01440 case INPUT_CONTROL_SET_AUDIO_DELAY:
01441 input_EsOutSetDelay( p_input->p_es_out,
01442 AUDIO_ES, val.i_time );
01443 var_Change( p_input, "audio-delay", VLC_VAR_SETVALUE, &val, NULL );
01444 break;
01445
01446 case INPUT_CONTROL_SET_SPU_DELAY:
01447 input_EsOutSetDelay( p_input->p_es_out,
01448 SPU_ES, val.i_time );
01449 var_Change( p_input, "spu-delay", VLC_VAR_SETVALUE, &val, NULL );
01450 break;
01451
01452 case INPUT_CONTROL_SET_TITLE:
01453 case INPUT_CONTROL_SET_TITLE_NEXT:
01454 case INPUT_CONTROL_SET_TITLE_PREV:
01455 if( p_input->input.b_title_demux &&
01456 p_input->input.i_title > 0 )
01457 {
01458
01459
01460 demux_t *p_demux = p_input->input.p_demux;
01461 int i_title;
01462
01463 if( i_type == INPUT_CONTROL_SET_TITLE_PREV )
01464 i_title = p_demux->info.i_title - 1;
01465 else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
01466 i_title = p_demux->info.i_title + 1;
01467 else
01468 i_title = val.i_int;
01469
01470 if( i_title >= 0 && i_title < p_input->input.i_title )
01471 {
01472 input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
01473 es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
01474
01475 demux2_Control( p_demux, DEMUX_SET_TITLE, i_title );
01476 input_ControlVarTitle( p_input, i_title );
01477 }
01478 }
01479 else if( p_input->input.i_title > 0 )
01480 {
01481 access_t *p_access = p_input->input.p_access;
01482 int i_title;
01483
01484 if( i_type == INPUT_CONTROL_SET_TITLE_PREV )
01485 i_title = p_access->info.i_title - 1;
01486 else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
01487 i_title = p_access->info.i_title + 1;
01488 else
01489 i_title = val.i_int;
01490
01491 if( i_title >= 0 && i_title < p_input->input.i_title )
01492 {
01493 input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
01494 es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
01495
01496 access2_Control( p_access, ACCESS_SET_TITLE, i_title );
01497 stream_AccessReset( p_input->input.p_stream );
01498 }
01499 }
01500 break;
01501 case INPUT_CONTROL_SET_SEEKPOINT:
01502 case INPUT_CONTROL_SET_SEEKPOINT_NEXT:
01503 case INPUT_CONTROL_SET_SEEKPOINT_PREV:
01504 if( p_input->input.b_title_demux &&
01505 p_input->input.i_title > 0 )
01506 {
01507 demux_t *p_demux = p_input->input.p_demux;
01508 int i_seekpoint;
01509 int64_t i_input_time;
01510 int64_t i_seekpoint_time;
01511
01512 if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV )
01513 {
01514 i_seekpoint = p_demux->info.i_seekpoint;
01515 i_seekpoint_time = p_input->input.title[p_demux->info.i_title]->seekpoint[i_seekpoint]->i_time_offset;
01516 if( i_seekpoint_time >= 0 &&
01517 !demux2_Control( p_demux,
01518 DEMUX_GET_TIME, &i_input_time ) )
01519 {
01520 if ( i_input_time < i_seekpoint_time + 3000000 )
01521 i_seekpoint--;
01522 }
01523 else
01524 i_seekpoint--;
01525 }
01526 else if( i_type == INPUT_CONTROL_SET_SEEKPOINT_NEXT )
01527 i_seekpoint = p_demux->info.i_seekpoint + 1;
01528 else
01529 i_seekpoint = val.i_int;
01530
01531 if( i_seekpoint >= 0 && i_seekpoint <
01532 p_input->input.title[p_demux->info.i_title]->i_seekpoint )
01533 {
01534 input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
01535 es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
01536
01537 demux2_Control( p_demux, DEMUX_SET_SEEKPOINT, i_seekpoint );
01538 }
01539 }
01540 else if( p_input->input.i_title > 0 )
01541 {
01542 demux_t *p_demux = p_input->input.p_demux;
01543 access_t *p_access = p_input->input.p_access;
01544 int i_seekpoint;
01545 int64_t i_input_time;
01546 int64_t i_seekpoint_time;
01547
01548 if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV )
01549 {
01550 i_seekpoint = p_access->info.i_seekpoint;
01551 i_seekpoint_time = p_input->input.title[p_access->info.i_title]->seekpoint[i_seekpoint]->i_time_offset;
01552 if( i_seekpoint_time >= 0 &&
01553 demux2_Control( p_demux,
01554 DEMUX_GET_TIME, &i_input_time ) )
01555 {
01556 if ( i_input_time < i_seekpoint_time + 3000000 )
01557 i_seekpoint--;
01558 }
01559 else
01560 i_seekpoint--;
01561 }
01562 else if( i_type == INPUT_CONTROL_SET_SEEKPOINT_NEXT )
01563 i_seekpoint = p_access->info.i_seekpoint + 1;
01564 else
01565 i_seekpoint = val.i_int;
01566
01567 if( i_seekpoint >= 0 && i_seekpoint <
01568 p_input->input.title[p_access->info.i_title]->i_seekpoint )
01569 {
01570 input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
01571 es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
01572
01573 access2_Control( p_access, ACCESS_SET_SEEKPOINT, i_seekpoint );
01574 stream_AccessReset( p_input->input.p_stream );
01575 }
01576 }
01577 break;
01578
01579 case INPUT_CONTROL_ADD_SLAVE:
01580 if( val.psz_string )
01581 {
01582 input_source_t *slave = InputSourceNew( p_input );
01583
01584 if( !InputSourceInit( p_input, slave, val.psz_string, NULL,
01585 VLC_FALSE ) )
01586 {
01587 vlc_meta_t *p_meta_new = NULL;
01588 vlc_meta_t *p_meta;
01589 int64_t i_time;
01590
01591
01592 msg_Dbg( p_input, "adding %s as slave on the fly",
01593 val.psz_string );
01594
01595
01596 if( demux2_Control( p_input->input.p_demux,
01597 DEMUX_GET_TIME, &i_time ) )
01598 {
01599 msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
01600 InputSourceClean( p_input, slave );
01601 free( slave );
01602 break;
01603 }
01604 if( demux2_Control( slave->p_demux,
01605 DEMUX_SET_TIME, i_time ) )
01606 {
01607 msg_Err( p_input, "seek failed for new slave" );
01608 InputSourceClean( p_input, slave );
01609 free( slave );
01610 break;
01611 }
01612
01613
01614
01615 if( access2_Control( slave->p_access,
01616 ACCESS_GET_META, &p_meta_new ) )
01617 p_meta_new = NULL;
01618 if( !demux2_Control( slave->p_demux,
01619 DEMUX_GET_META, &p_meta ) )
01620 {
01621 if( p_meta_new )
01622 {
01623 vlc_meta_Merge( p_meta_new, p_meta );
01624 vlc_meta_Delete( p_meta );
01625 }
01626 else
01627 {
01628 p_meta_new = p_meta;
01629 }
01630 }
01631
01632 if( p_meta_new )
01633 {
01634 if( p_input->p_meta )
01635 {
01636 vlc_meta_Merge( p_input->p_meta, p_meta_new );
01637 vlc_meta_Delete( p_meta_new );
01638 }
01639 else
01640 {
01641 p_input->p_meta = p_meta_new;
01642 }
01643 UpdateMeta( p_input, VLC_FALSE );
01644 }
01645
01646 TAB_APPEND( p_input->i_slave, p_input->slave, slave );
01647 }
01648 else
01649 {
01650 msg_Warn( p_input, "failed to add %s as slave",
01651 val.psz_string );
01652 }
01653
01654 free( val.psz_string );
01655 }
01656 break;
01657
01658 case INPUT_CONTROL_SET_BOOKMARK:
01659 default:
01660 msg_Err( p_input, "not yet implemented" );
01661 break;
01662 }
01663
01664 return b_force_update;
01665 }
01666
01667
01668
01669
01670 static int UpdateFromDemux( input_thread_t *p_input )
01671 {
01672 demux_t *p_demux = p_input->input.p_demux;
01673 vlc_value_t v;
01674
01675 if( p_demux->info.i_update & INPUT_UPDATE_TITLE )
01676 {
01677 v.i_int = p_demux->info.i_title;
01678 var_Change( p_input, "title", VLC_VAR_SETVALUE, &v, NULL );
01679
01680 input_ControlVarTitle( p_input, p_demux->info.i_title );
01681
01682 p_demux->info.i_update &= ~INPUT_UPDATE_TITLE;
01683 }
01684 if( p_demux->info.i_update & INPUT_UPDATE_SEEKPOINT )
01685 {
01686 v.i_int = p_demux->info.i_seekpoint;
01687 var_Change( p_input, "chapter", VLC_VAR_SETVALUE, &v, NULL);
01688
01689 p_demux->info.i_update &= ~INPUT_UPDATE_SEEKPOINT;
01690 }
01691 p_demux->info.i_update &= ~INPUT_UPDATE_SIZE;
01692
01693
01694 if( p_input->input.p_demux == p_demux )
01695 {
01696 int i_title_end = p_input->input.i_title_end -
01697 p_input->input.i_title_offset;
01698 int i_seekpoint_end = p_input->input.i_seekpoint_end -
01699 p_input->input.i_seekpoint_offset;
01700
01701 if( i_title_end >= 0 && i_seekpoint_end >= 0 )
01702 {
01703 if( p_demux->info.i_title > i_title_end ||
01704 ( p_demux->info.i_title == i_title_end &&
01705 p_demux->info.i_seekpoint > i_seekpoint_end ) ) return 0;
01706 }
01707 else if( i_seekpoint_end >=0 )
01708 {
01709 if( p_demux->info.i_seekpoint > i_seekpoint_end ) return 0;
01710 }
01711 else if( i_title_end >= 0 )
01712 {
01713 if( p_demux->info.i_title > i_title_end ) return 0;
01714 }
01715 }
01716
01717 return 1;
01718 }
01719
01720
01721
01722
01723 static int UpdateFromAccess( input_thread_t *p_input )
01724 {
01725 access_t *p_access = p_input->input.p_access;
01726 vlc_value_t v;
01727
01728 if( p_access->info.i_update & INPUT_UPDATE_TITLE )
01729 {
01730 v.i_int = p_access->info.i_title;
01731 var_Change( p_input, "title", VLC_VAR_SETVALUE, &v, NULL );
01732
01733 input_ControlVarTitle( p_input, p_access->info.i_title );
01734
01735 stream_AccessUpdate( p_input->input.p_stream );
01736
01737 p_access->info.i_update &= ~INPUT_UPDATE_TITLE;
01738 }
01739 if( p_access->info.i_update & INPUT_UPDATE_SEEKPOINT )
01740 {
01741 v.i_int = p_access->info.i_seekpoint;
01742 var_Change( p_input, "chapter", VLC_VAR_SETVALUE, &v, NULL);
01743
01744 p_access->info.i_update &= ~INPUT_UPDATE_SEEKPOINT;
01745 }
01746 if( p_access->info.i_update & INPUT_UPDATE_META )
01747 {
01748
01749 vlc_meta_t *p_meta;
01750 if( !access2_Control( p_input->input.p_access,ACCESS_GET_META,&p_meta))
01751 {
01752 if( p_input->p_meta )
01753 {
01754 vlc_meta_Merge( p_input->p_meta, p_meta );
01755 vlc_meta_Delete( p_meta );
01756 }
01757 else
01758 {
01759 p_input->p_meta = p_meta;
01760 }
01761
01762 UpdateMeta( p_input, VLC_FALSE );
01763 var_SetBool( p_input, "item-change", p_input->input.p_item->i_id );
01764 }
01765 p_access->info.i_update &= ~INPUT_UPDATE_META;
01766 }
01767
01768 p_access->info.i_update &= ~INPUT_UPDATE_SIZE;
01769
01770
01771 if( p_input->input.p_access == p_access )
01772 {
01773 int i_title_end = p_input->input.i_title_end -
01774 p_input->input.i_title_offset;
01775 int i_seekpoint_end = p_input->input.i_seekpoint_end -
01776 p_input->input.i_seekpoint_offset;
01777
01778 if( i_title_end >= 0 && i_seekpoint_end >=0 )
01779 {
01780 if( p_access->info.i_title > i_title_end ||
01781 ( p_access->info.i_title == i_title_end &&
01782 p_access->info.i_seekpoint > i_seekpoint_end ) ) return 0;
01783 }
01784 else if( i_seekpoint_end >=0 )
01785 {
01786 if( p_access->info.i_seekpoint > i_seekpoint_end ) return 0;
01787 }
01788 else if( i_title_end >= 0 )
01789 {
01790 if( p_access->info.i_title > i_title_end ) return 0;
01791 }
01792 }
01793
01794 return 1;
01795 }
01796
01797
01798
01799
01800 static int UpdateMeta( input_thread_t *p_input, vlc_bool_t b_quick )
01801 {
01802 vlc_meta_t *p_meta = p_input->p_meta;
01803 int i;
01804
01805 if( !p_meta || p_meta->i_meta == 0 )
01806 return VLC_SUCCESS;
01807
01808 if( !b_quick ) msg_Dbg( p_input, "meta information:" );
01809 for( i = 0; i < p_meta->i_meta; i++ )
01810 {
01811 if( !b_quick )
01812 msg_Dbg( p_input, " - '%s' = '%s'",
01813 _(p_meta->name[i]), p_meta->value[i] );
01814
01815 if( !strcmp(p_meta->name[i], VLC_META_TITLE) && p_meta->value[i] &&
01816 !p_input->input.p_item->b_fixed_name )
01817 input_Control( p_input, INPUT_SET_NAME, p_meta->value[i] );
01818
01819 if( !strcmp( p_meta->name[i], VLC_META_AUTHOR ) )
01820 input_Control( p_input, INPUT_ADD_INFO, _("General"),
01821 _("Author"), p_meta->value[i] );
01822
01823 input_Control( p_input, INPUT_ADD_INFO, _("Meta-information"),
01824 _(p_meta->name[i]), "%s", p_meta->value[i] );
01825 }
01826
01827 for( i = 0; i < p_meta->i_track; i++ )
01828 {
01829 vlc_meta_t *tk = p_meta->track[i];
01830 int j;
01831
01832 if( tk->i_meta > 0 )
01833 {
01834 char *psz_cat = malloc( strlen(_("Stream")) + 10 );
01835
01836 msg_Dbg( p_input, " - track[%d]:", i );
01837
01838 sprintf( psz_cat, "%s %d", _("Stream"), i );
01839 for( j = 0; j < tk->i_meta; j++ )
01840 {
01841 msg_Dbg( p_input, " - '%s' = '%s'", _(tk->name[j]),
01842 tk->value[j] );
01843
01844 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
01845 _(tk->name[j]), "%s", tk->value[j] );
01846 }
01847 }
01848 }
01849
01850 if( p_input->p_sout && p_input->p_sout->p_meta == NULL )
01851 {
01852 p_input->p_sout->p_meta = vlc_meta_Duplicate( p_meta );
01853 }
01854
01855 return VLC_SUCCESS;
01856 }
01857
01858
01859
01860
01861 static void UpdateItemLength( input_thread_t *p_input, int64_t i_length,
01862 vlc_bool_t b_quick )
01863 {
01864 playlist_t *p_playlist;
01865 char psz_buffer[MSTRTIME_MAX_SIZE];
01866
01867 vlc_mutex_lock( &p_input->input.p_item->lock );
01868 p_input->input.p_item->i_duration = i_length;
01869 vlc_mutex_unlock( &p_input->input.p_item->lock );
01870
01871 p_playlist = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
01872 FIND_PARENT);
01873 if( p_playlist )
01874 {
01875 var_SetInteger( p_playlist, "item-change",
01876 p_input->input.p_item->i_id );
01877 vlc_object_release( p_playlist );
01878 }
01879
01880 input_Control( p_input, INPUT_ADD_INFO, _("General"), _("Duration"),
01881 msecstotimestr( psz_buffer, i_length / 1000 ) );
01882 }
01883
01884
01885
01886
01887 static input_source_t *InputSourceNew( input_thread_t *p_input )
01888 {
01889 input_source_t *in = (input_source_t*) malloc( sizeof( input_source_t ) );
01890
01891 if( !in )
01892 {
01893 msg_Err( p_input, "out of memory for new input source" );
01894 return NULL;
01895 }
01896
01897 in->p_item = NULL;
01898 in->p_access = NULL;
01899 in->p_stream = NULL;
01900 in->p_demux = NULL;
01901 in->b_title_demux = VLC_FALSE;
01902 in->i_title = 0;
01903 in->title = NULL;
01904 in->b_can_pace_control = VLC_TRUE;
01905 in->b_eof = VLC_FALSE;
01906 in->i_cr_average = 0;
01907
01908 return in;
01909 }
01910
01911
01912
01913
01914 static int InputSourceInit( input_thread_t *p_input,
01915 input_source_t *in, char *psz_mrl,
01916 char *psz_forced_demux, vlc_bool_t b_quick )
01917 {
01918 char *psz_dup = strdup( psz_mrl );
01919 char *psz_access;
01920 char *psz_demux;
01921 char *psz_path;
01922 char *psz_tmp;
01923 char *psz;
01924 vlc_value_t val;
01925
01926 if( !in ) return VLC_EGENERIC;
01927
01928
01929 if( !b_quick )
01930 {
01931 MRLSplit( VLC_OBJECT(p_input), psz_dup,
01932 &psz_access, &psz_demux, &psz_path );
01933
01934 msg_Dbg( p_input, "`%s' gives access `%s' demux `%s' path `%s'",
01935 psz_mrl, psz_access, psz_demux, psz_path );
01936
01937
01938 if( !psz_access ||
01939 (strncmp( psz_access, "udp", 3 ) &&
01940 strncmp( psz_access, "rtp", 3 )) )
01941
01942
01943 MRLSections( p_input, psz_path, &in->i_title_start, &in->i_title_end,
01944 &in->i_seekpoint_start, &in->i_seekpoint_end );
01945
01946 if( psz_forced_demux && *psz_forced_demux )
01947 {
01948 psz_demux = psz_forced_demux;
01949 }
01950 else if( !psz_demux || *psz_demux == '\0' )
01951 {
01952
01953
01954 char *psz_var_demux = var_GetString( p_input, "demux" );
01955
01956 if( *psz_var_demux != '\0' &&
01957 !strchr(psz_var_demux, ',' ) &&
01958 !strchr(psz_var_demux, ':' ) )
01959 {
01960 psz_demux = psz_var_demux;
01961
01962 msg_Dbg( p_input, "Enforce demux ` %s'", psz_demux );
01963 }
01964 else if( psz_var_demux )
01965 {
01966 free( psz_var_demux );
01967 }
01968 }
01969
01970
01971 if( *psz_demux == '\0' )
01972 {
01973 in->p_demux = demux2_New( p_input, psz_access, psz_demux, psz_path,
01974 NULL, p_input->p_es_out, VLC_FALSE );
01975 }
01976 }
01977 else
01978 {
01979 psz_path = psz_mrl;
01980 msg_Dbg( p_input, "trying to preparse %s", psz_path );
01981 psz_demux = strdup( "" );
01982 psz_access = strdup( "file" );
01983 }
01984
01985 if( in->p_demux )
01986 {
01987 int64_t i_pts_delay;
01988
01989
01990 demux2_Control( in->p_demux,
01991 DEMUX_GET_PTS_DELAY, &i_pts_delay );
01992 p_input->i_pts_delay = __MAX( p_input->i_pts_delay, i_pts_delay );
01993
01994 in->b_title_demux = VLC_TRUE;
01995 if( demux2_Control( in->p_demux, DEMUX_GET_TITLE_INFO,
01996 &in->title, &in->i_title,
01997 &in->i_title_offset, &in->i_seekpoint_offset ) )
01998 {
01999 in->i_title = 0;
02000 in->title = NULL;
02001 }
02002 demux2_Control( in->p_demux, DEMUX_CAN_CONTROL_PACE,
02003 &in->b_can_pace_control );
02004 demux2_Control( in->p_demux, DEMUX_CAN_PAUSE,
02005 &in->b_can_pause );
02006
02007
02008
02009
02010
02011 }
02012 else
02013 {
02014 int64_t i_pts_delay;
02015
02016
02017 in->p_access = access2_New( p_input, psz_access, psz_demux, psz_path,
02018 b_quick );
02019
02020
02021 if( in->p_access == NULL && strchr( psz_path, '%' ) )
02022 {
02023 DecodeUrl( psz_path );
02024
02025 msg_Dbg( p_input, "retrying with access `%s' demux `%s' path `%s'",
02026 psz_access, psz_demux, psz_path );
02027
02028 in->p_access = access2_New( p_input,
02029 psz_access, psz_demux, psz_path,
02030 b_quick );
02031 }
02032 #ifndef WIN32
02033
02034
02035
02036 if( in->p_access == NULL &&
02037 *psz_access == '\0' && ( *psz_demux || *psz_path ) )
02038 {
02039 if( psz_dup ) free( psz_dup );
02040 psz_dup = strdup( psz_mrl );
02041 psz_access = "";
02042 psz_demux = "";
02043 psz_path = psz_dup;
02044
02045 in->p_access = access2_New( p_input,
02046 psz_access, psz_demux, psz_path,
02047 b_quick );
02048 }
02049 #endif
02050
02051 if( in->p_access == NULL )
02052 {
02053 msg_Err( p_input, "no suitable access module for `%s'", psz_mrl );
02054 goto error;
02055 }
02056
02057
02058 psz_tmp = psz = var_GetString( p_input, "access-filter" );
02059 while( psz && *psz )
02060 {
02061 access_t *p_access = in->p_access;
02062 char *end = strchr( psz, ':' );
02063
02064 if( end )
02065 *end++ = '\0';
02066
02067 in->p_access = access2_FilterNew( in->p_access, psz );
02068 if( in->p_access == NULL )
02069 {
02070 in->p_access = p_access;
02071 msg_Warn( p_input, "failed to insert access filter %s",
02072 psz );
02073 }
02074
02075 psz = end;
02076 }
02077 if( psz_tmp ) free( psz_tmp );
02078
02079
02080 if( !b_quick )
02081 {
02082 access2_Control( in->p_access,
02083 ACCESS_GET_PTS_DELAY, &i_pts_delay );
02084 p_input->i_pts_delay = __MAX( p_input->i_pts_delay, i_pts_delay );
02085
02086 in->b_title_demux = VLC_FALSE;
02087 if( access2_Control( in->p_access, ACCESS_GET_TITLE_INFO,
02088 &in->title, &in->i_title,
02089 &in->i_title_offset, &in->i_seekpoint_offset ) )
02090
02091 {
02092 in->i_title = 0;
02093 in->title = NULL;
02094 }
02095 access2_Control( in->p_access, ACCESS_CAN_CONTROL_PACE,
02096 &in->b_can_pace_control );
02097 access2_Control( in->p_access, ACCESS_CAN_PAUSE,
02098 &in->b_can_pause );
02099 access2_Control( in->p_access, ACCESS_CAN_SEEK,
02100 &val.b_bool );
02101 var_Set( p_input, "seekable", val );
02102 }
02103
02104
02105 in->p_stream = stream_AccessNew( in->p_access, b_quick );
02106 if( in->p_stream == NULL )
02107 {
02108 msg_Warn( p_input, "cannot create a stream_t from access" );
02109 goto error;
02110 }
02111
02112
02113 if( *psz_demux == '\0' && *in->p_access->psz_demux )
02114 {
02115 psz_demux = in->p_access->psz_demux;
02116 }
02117 in->p_demux = demux2_New( p_input, psz_access, psz_demux, psz_path,
02118 in->p_stream, p_input->p_es_out, b_quick );
02119 if( in->p_demux == NULL )
02120 {
02121 msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
02122 psz_access, psz_demux, psz_path );
02123 goto error;
02124 }
02125
02126
02127 if( !b_quick && in->i_title <= 0 )
02128 {
02129 if( demux2_Control( in->p_demux, DEMUX_GET_TITLE_INFO,
02130 &in->title, &in->i_title,
02131 &in->i_title_offset, &in->i_seekpoint_offset ))
02132 {
02133 in->i_title = 0;
02134 in->title = NULL;
02135 }
02136 else
02137 {
02138 in->b_title_demux = VLC_TRUE;
02139 }
02140 }
02141 }
02142
02143 if( var_GetInteger( p_input, "clock-synchro" ) != -1 )
02144 in->b_can_pace_control = !var_GetInteger( p_input, "clock-synchro" );
02145
02146 if( psz_dup ) free( psz_dup );
02147 return VLC_SUCCESS;
02148
02149 error:
02150 if( in->p_demux )
02151 demux2_Delete( in->p_demux );
02152
02153 if( in->p_stream )
02154 stream_Delete( in->p_stream );
02155
02156 if( in->p_access )
02157 access2_Delete( in->p_access );
02158 if( psz_dup ) free( psz_dup );
02159
02160 return VLC_EGENERIC;
02161 }
02162
02163
02164
02165
02166 static void InputSourceClean( input_thread_t *p_input, input_source_t *in )
02167 {
02168 if( in->p_demux )
02169 demux2_Delete( in->p_demux );
02170
02171 if( in->p_stream )
02172 stream_Delete( in->p_stream );
02173
02174 if( in->p_access )
02175 access2_Delete( in->p_access );
02176
02177 if( in->i_title > 0 )
02178 {
02179 int i;
02180 for( i = 0; i < in->i_title; i++ )
02181 {
02182 vlc_input_title_Delete( in->title[i] );
02183 }
02184 free( in->title );
02185 }
02186 }
02187
02188 static void SlaveDemux( input_thread_t *p_input )
02189 {
02190 int64_t i_time;
02191 int i;
02192
02193 if( demux2_Control( p_input->input.p_demux, DEMUX_GET_TIME, &i_time ) )
02194 {
02195 msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
02196 return;
02197 }
02198
02199 for( i = 0; i < p_input->i_slave; i++ )
02200 {
02201 input_source_t *in = p_input->slave[i];
02202 int i_ret = 1;
02203
02204 if( in->b_eof )
02205 continue;
02206
02207 if( demux2_Control( in->p_demux, DEMUX_SET_NEXT_DEMUX_TIME, i_time ) )
02208 {
02209 for( ;; )
02210 {
02211 int64_t i_stime;
02212 if( demux2_Control( in->p_demux, DEMUX_GET_TIME, &i_stime ) )
02213 {
02214 msg_Err( p_input, "slave[%d] doesn't like "
02215 "DEMUX_GET_TIME -> EOF", i );
02216 i_ret = 0;
02217 break;
02218 }
02219
02220 if( i_stime >= i_time )
02221 break;
02222
02223 if( ( i_ret = in->p_demux->pf_demux( in->p_demux ) ) <= 0 )
02224 break;
02225 }
02226 }
02227 else
02228 {
02229 i_ret = in->p_demux->pf_demux( in->p_demux );
02230 }
02231
02232 if( i_ret <= 0 )
02233 {
02234 msg_Dbg( p_input, "slave %d EOF", i );
02235 in->b_eof = VLC_TRUE;
02236 }
02237 }
02238 }
02239
02240 static void SlaveSeek( input_thread_t *p_input )
02241 {
02242 int64_t i_time;
02243 int i;
02244
02245 if( demux2_Control( p_input->input.p_demux, DEMUX_GET_TIME, &i_time ) )
02246 {
02247 msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
02248 return;
02249 }
02250
02251 for( i = 0; i < p_input->i_slave; i++ )
02252 {
02253 input_source_t *in = p_input->slave[i];
02254
02255 if( demux2_Control( in->p_demux, DEMUX_SET_TIME, i_time ) )
02256 {
02257 msg_Err( p_input, "seek failed for slave %d -> EOF", i );
02258 in->b_eof = VLC_TRUE;
02259 }
02260 }
02261 }
02262
02263
02264
02265 static vlc_meta_t *InputMetaUser( input_thread_t *p_input )
02266 {
02267 vlc_meta_t *p_meta;
02268 vlc_value_t val;
02269
02270 if( ( p_meta = vlc_meta_New() ) == NULL )
02271 return NULL;
02272
02273
02274 #define GET_META( c, s ) \
02275 var_Get( p_input, (s), &val ); \
02276 if( *val.psz_string ) \
02277 vlc_meta_Add( p_meta, c, val.psz_string ); \
02278 free( val.psz_string )
02279
02280 GET_META( VLC_META_TITLE, "meta-title" );
02281 GET_META( VLC_META_AUTHOR, "meta-author" );
02282 GET_META( VLC_META_ARTIST, "meta-artist" );
02283 GET_META( VLC_META_GENRE, "meta-genre" );
02284 GET_META( VLC_META_COPYRIGHT, "meta-copyright" );
02285 GET_META( VLC_META_DESCRIPTION, "meta-description" );
02286 GET_META( VLC_META_DATE, "meta-date" );
02287 GET_META( VLC_META_URL, "meta-url" );
02288 #undef GET_META
02289
02290 return p_meta;
02291 }
02292
02293
02294
02295
02296 static void DecodeUrl( char *psz )
02297 {
02298 char *dup = strdup( psz );
02299 char *p = dup;
02300
02301 while( *p )
02302 {
02303 if( *p == '%' )
02304 {
02305 char val[3];
02306 p++;
02307 if( !*p )
02308 {
02309 break;
02310 }
02311
02312 val[0] = *p++;
02313 val[1] = *p++;
02314 val[2] = '\0';
02315
02316 *psz++ = strtol( val, NULL, 16 );
02317 }
02318 else if( *p == '+' )
02319 {
02320 *psz++ = ' ';
02321 p++;
02322 }
02323 else
02324 {
02325 *psz++ = *p++;
02326 }
02327 }
02328 if( psz ) *psz++ ='\0';
02329 if( dup ) free( dup );
02330 }
02331
02332
02333
02334
02335
02336
02337
02338
02339
02340 static void ParseOption( input_thread_t *p_input, const char *psz_option )
02341 {
02342 char *psz_name = (char *)psz_option;
02343 char *psz_value = strchr( psz_option, '=' );
02344 int i_name_len, i_type;
02345 vlc_bool_t b_isno = VLC_FALSE;
02346 vlc_value_t val;
02347
02348 if( psz_value ) i_name_len = psz_value - psz_option;
02349 else i_name_len = strlen( psz_option );
02350
02351
02352
02353 if( i_name_len && *psz_name == ':' )
02354 {
02355 psz_name++;
02356 i_name_len--;
02357 }
02358
02359 if( i_name_len == 0 ) return;
02360
02361 psz_name = strndup( psz_name, i_name_len );
02362 if( psz_value ) psz_value++;
02363
02364
02365 if( !strcmp( psz_name, "programs" ) )
02366 i_type = VLC_VAR_LIST;
02367 else
02368 i_type = config_GetType( p_input, psz_name );
02369
02370 if( !i_type && !psz_value )
02371 {
02372
02373 if( !strncmp( psz_name, "no-", 3 ) )
02374 {
02375 memmove( psz_name, psz_name + 3, strlen(psz_name) + 1 - 3 );
02376 }
02377 else if( !strncmp( psz_name, "no", 2 ) )
02378 {
02379 memmove( psz_name, psz_name + 2, strlen(psz_name) + 1 - 2 );
02380 }
02381 else goto cleanup;
02382
02383 b_isno = VLC_TRUE;
02384 i_type = config_GetType( p_input, psz_name );
02385
02386 if( !i_type ) goto cleanup;
02387 }
02388 else if( !i_type ) goto cleanup;
02389
02390 if( ( i_type != VLC_VAR_BOOL ) &&
02391 ( !psz_value || !*psz_value ) ) goto cleanup;
02392
02393
02394
02395
02396 var_Create( p_input, psz_name, i_type );
02397
02398 switch( i_type )
02399 {
02400 case VLC_VAR_BOOL:
02401 val.b_bool = !b_isno;
02402 break;
02403
02404 case VLC_VAR_INTEGER:
02405 val.i_int = atoi( psz_value );
02406 break;
02407
02408 case VLC_VAR_FLOAT:
02409 val.f_float = atof( psz_value );
02410 break;
02411
02412 case VLC_VAR_STRING:
02413 case VLC_VAR_MODULE:
02414 case VLC_VAR_FILE:
02415 case VLC_VAR_DIRECTORY:
02416 val.psz_string = psz_value;
02417 break;
02418
02419 case VLC_VAR_LIST:
02420 {
02421 char *psz_orig, *psz_var;
02422 vlc_list_t *p_list = malloc(sizeof(vlc_list_t));
02423 val.p_list = p_list;
02424 p_list->i_count = 0;
02425
02426 psz_var = psz_orig = strdup(psz_value);
02427 while( psz_var && *psz_var )
02428 {
02429 char *psz_item = psz_var;
02430 vlc_value_t val2;
02431 while( *psz_var && *psz_var != ',' ) psz_var++;
02432 if( *psz_var == ',' )
02433 {
02434 *psz_var = '\0';
02435 psz_var++;
02436 }
02437 val2.i_int = strtol( psz_item, NULL, 0 );
02438 INSERT_ELEM( p_list->p_values, p_list->i_count,
02439 p_list->i_count, val2 );
02440
02441 p_list->i_count--;
02442 INSERT_ELEM( p_list->pi_types, p_list->i_count,
02443 p_list->i_count, VLC_VAR_INTEGER );
02444 }
02445 if( psz_orig ) free( psz_orig );
02446 break;
02447 }
02448
02449 default:
02450 goto cleanup;
02451 break;
02452 }
02453
02454 var_Set( p_input, psz_name, val );
02455
02456 msg_Dbg( p_input, "set input option: %s to %s", psz_name,
02457 psz_value ? psz_value : ( val.b_bool ? "true" : "false") );
02458
02459 cleanup:
02460 if( psz_name ) free( psz_name );
02461 return;
02462 }
02463
02464
02465
02466
02467
02468 void MRLSplit( vlc_object_t *p_input, char *psz_dup,
02469 char **ppsz_access, char **ppsz_demux, char **ppsz_path )
02470 {
02471 char *psz_access = NULL;
02472 char *psz_demux = NULL;
02473 char *psz_path = NULL;
02474 char *psz, *psz_check;
02475
02476 psz = strchr( psz_dup, ':' );
02477
02478
02479 psz_check = strchr( psz_dup, '@' );
02480 if( psz_check && psz_check < psz ) psz = 0;
02481
02482 #if defined( WIN32 ) || defined( UNDER_CE )
02483 if( psz - psz_dup == 1 )
02484 {
02485 msg_Warn( p_input, "drive letter %c: found in source", *psz_dup );
02486 psz_path = psz_dup;
02487 }
02488 else
02489 #endif
02490
02491 if( psz )
02492 {
02493 *psz++ = '\0';
02494 if( psz[0] == '/' && psz[1] == '/' ) psz += 2;
02495
02496 psz_path = psz;
02497
02498 psz = strchr( psz_dup, '/' );
02499 if( psz )
02500 {
02501 *psz++ = '\0';
02502 psz_demux = psz;
02503 }
02504
02505 psz_access = psz_dup;
02506 }
02507 else
02508 {
02509 psz_path = psz_dup;
02510 }
02511
02512 if( !psz_access ) *ppsz_access = "";
02513 else *ppsz_access = psz_access;
02514
02515 if( !psz_demux ) *ppsz_demux = "";
02516 else *ppsz_demux = psz_demux;
02517
02518 if( !psz_path ) *ppsz_path = "";
02519 else *ppsz_path = psz_path;
02520 }
02521
02522
02523
02524
02525
02526
02527
02528 static void MRLSections( input_thread_t *p_input, char *psz_source,
02529 int *pi_title_start, int *pi_title_end,
02530 int *pi_chapter_start, int *pi_chapter_end )
02531 {
02532 char *psz, *psz_end, *psz_next, *psz_check;
02533
02534 *pi_title_start = *pi_title_end = -1;
02535 *pi_chapter_start = *pi_chapter_end = -1;
02536
02537
02538 if( !psz_source || !( psz = strrchr( psz_source, '@' ) ) ) return;
02539
02540
02541 psz_check = psz + 1;
02542 if( !*psz_check ) return;
02543 if( isdigit(*psz_check) ) strtol( psz_check, &psz_check, 0 );
02544 if( *psz_check != ':' && *psz_check != '-' && *psz_check ) return;
02545 if( *psz_check == ':' && ++psz_check )
02546 if( isdigit(*psz_check) ) strtol( psz_check, &psz_check, 0 );
02547 if( *psz_check != '-' && *psz_check ) return;
02548 if( *psz_check == '-' && ++psz_check )
02549 if( isdigit(*psz_check) ) strtol( psz_check, &psz_check, 0 );
02550 if( *psz_check != ':' && *psz_check ) return;
02551 if( *psz_check == ':' && ++psz_check )
02552 if( isdigit(*psz_check) ) strtol( psz_check, &psz_check, 0 );
02553 if( *psz_check ) return;
02554
02555
02556 *psz++ = 0;
02557 if( ( psz_end = strchr( psz, '-' ) ) ) *psz_end++ = 0;
02558
02559
02560 *pi_title_start = strtol( psz, &psz_next, 0 );
02561 if( !*pi_title_start && psz == psz_next ) *pi_title_start = -1;
02562 *pi_title_end = *pi_title_start;
02563 psz = psz_next;
02564
02565
02566 if( *psz ) psz++;
02567 *pi_chapter_start = strtol( psz, &psz_next, 0 );
02568 if( !*pi_chapter_start && psz == psz_next ) *pi_chapter_start = -1;
02569 *pi_chapter_end = *pi_chapter_start;
02570
02571 if( psz_end )
02572 {
02573
02574 *pi_title_end = strtol( psz_end, &psz_next, 0 );
02575 if( !*pi_title_end && psz_end == psz_next ) *pi_title_end = -1;
02576 psz_end = psz_next;
02577
02578
02579 if( *psz_end ) psz_end++;
02580 *pi_chapter_end = strtol( psz_end, &psz_next, 0 );
02581 if( !*pi_chapter_end && psz_end == psz_next ) *pi_chapter_end = -1;
02582 }
02583
02584 msg_Dbg( p_input, "source=`%s' title=%d/%d seekpoint=%d/%d",
02585 psz_source, *pi_title_start, *pi_chapter_start,
02586 *pi_title_end, *pi_chapter_end );
02587 }
02588
02589
02590
02591
02592
02603 char *vlc_input_item_GetInfo( input_item_t *p_i,
02604 const char *psz_cat,
02605 const char *psz_name )
02606 {
02607 int i,j;
02608
02609 vlc_mutex_lock( &p_i->lock );
02610
02611 for( i = 0 ; i< p_i->i_categories ; i++ )
02612 {
02613 info_category_t *p_cat = p_i->pp_categories[i];
02614
02615 if( !psz_cat || strcmp( p_cat->psz_name, psz_cat ) )
02616 continue;
02617
02618 for( j = 0; j < p_cat->i_infos ; j++ )
02619 {
02620 if( !strcmp( p_cat->pp_infos[j]->psz_name, psz_name ) )
02621 {
02622 char *psz_ret = strdup( p_cat->pp_infos[j]->psz_value );
02623 vlc_mutex_unlock( &p_i->lock );
02624 return psz_ret;
02625 }
02626 }
02627 }
02628 vlc_mutex_unlock( &p_i->lock );
02629 return strdup( "" );
02630 }
02631
02632 int vlc_input_item_AddInfo( input_item_t *p_i,
02633 const char *psz_cat,
02634 const char *psz_name,
02635 const char *psz_format, ... )
02636 {
02637 va_list args;
02638 int i;
02639 info_t *p_info = NULL;
02640 info_category_t *p_cat = NULL ;
02641
02642 vlc_mutex_lock( &p_i->lock );
02643
02644 for( i = 0 ; i < p_i->i_categories ; i ++ )
02645 {
02646 if( !strcmp( p_i->pp_categories[i]->psz_name, psz_cat ) )
02647 {
02648 p_cat = p_i->pp_categories[i];
02649 break;
02650 }
02651 }
02652 if( !p_cat )
02653 {
02654 if( !(p_cat = (info_category_t *)malloc( sizeof(info_category_t) )) )
02655 {
02656 vlc_mutex_unlock( &p_i->lock );
02657 return VLC_EGENERIC;
02658 }
02659 p_cat->psz_name = strdup( psz_cat );
02660 p_cat->i_infos = 0;
02661 p_cat->pp_infos = 0;
02662 INSERT_ELEM( p_i->pp_categories, p_i->i_categories, p_i->i_categories,
02663 p_cat );
02664 }
02665
02666 for( i = 0; i< p_cat->i_infos; i++ )
02667 {
02668 if( !strcmp( p_cat->pp_infos[i]->psz_name, psz_name ) )
02669 {
02670 p_info = p_cat->pp_infos[i];
02671 break;
02672 }
02673 }
02674
02675 if( !p_info )
02676 {
02677 if( ( p_info = (info_t *)malloc( sizeof( info_t ) ) ) == NULL )
02678 {
02679 vlc_mutex_unlock( &p_i->lock );
02680 return VLC_EGENERIC;
02681 }
02682 INSERT_ELEM( p_cat->pp_infos, p_cat->i_infos, p_cat->i_infos, p_info );
02683 p_info->psz_name = strdup( psz_name );
02684 }
02685 else
02686 {
02687 if( p_info->psz_value ) free( p_info->psz_value );
02688 }
02689
02690 va_start( args, psz_format );
02691 vasprintf( &p_info->psz_value, psz_format, args);
02692 va_end( args );
02693
02694 vlc_mutex_unlock( &p_i->lock );
02695
02696 return VLC_SUCCESS;
02697 }
02698