00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <stdlib.h>
00025 #include <stdio.h>
00026 #include <string.h>
00027
00028 #include <vlc/vlc.h>
00029 #include <vlc/vout.h>
00030 #include <vlc/sout.h>
00031 #include <vlc/input.h>
00032
00033 #include "vlc_playlist.h"
00034
00035 #define TITLE_CATEGORY N_( "By category" )
00036 #define TITLE_SIMPLE N_( "Manually added" )
00037 #define TITLE_ALL N_( "All items, unsorted" )
00038
00039 #undef PLAYLIST_PROFILE
00040 #undef PLAYLIST_DEBUG
00041
00042
00043
00044
00045 static void RunThread ( playlist_t * );
00046 static void RunPreparse( playlist_preparse_t * );
00047 static playlist_item_t * NextItem ( playlist_t * );
00048 static int PlayItem ( playlist_t *, playlist_item_t * );
00049
00050 static int ItemChange( vlc_object_t *, const char *,
00051 vlc_value_t, vlc_value_t, void * );
00052
00053 int playlist_vaControl( playlist_t * p_playlist, int i_query, va_list args );
00054
00055 void playlist_PreparseEnqueueItemSub( playlist_t *, playlist_item_t * );
00056
00057 playlist_item_t *playlist_RecursiveFindLast(playlist_t *p_playlist,
00058 playlist_item_t *p_node );
00059
00060
00061
00062
00063
00064 playlist_item_t *playlist_RecursiveFindLast(playlist_t *p_playlist,
00065 playlist_item_t *p_node )
00066 {
00067 int i;
00068 playlist_item_t *p_item;
00069 for ( i = p_node->i_children - 1; i >= 0; i-- )
00070 {
00071 if( p_node->pp_children[i]->i_children == -1 )
00072 return p_node->pp_children[i];
00073 else if(p_node->pp_children[i]->i_children > 0)
00074 {
00075 p_item = playlist_RecursiveFindLast( p_playlist,
00076 p_node->pp_children[i] );
00077 if ( p_item != NULL )
00078 return p_item;
00079 }
00080 else if( i == 0 )
00081 return NULL;
00082 }
00083 return NULL;
00084 }
00085
00086
00094 playlist_t * __playlist_Create ( vlc_object_t *p_parent )
00095 {
00096 playlist_t *p_playlist;
00097 playlist_view_t *p_view;
00098 vlc_value_t val;
00099
00100
00101 p_playlist = vlc_object_create( p_parent, VLC_OBJECT_PLAYLIST );
00102 if( !p_playlist )
00103 {
00104 msg_Err( p_parent, "out of memory" );
00105 return NULL;
00106 }
00107
00108
00109 var_Create( p_playlist, "intf-change", VLC_VAR_BOOL );
00110 val.b_bool = VLC_TRUE;
00111 var_Set( p_playlist, "intf-change", val );
00112
00113 var_Create( p_playlist, "item-change", VLC_VAR_INTEGER );
00114 val.i_int = -1;
00115 var_Set( p_playlist, "item-change", val );
00116
00117 var_Create( p_playlist, "item-deleted", VLC_VAR_INTEGER );
00118 val.i_int = -1;
00119 var_Set( p_playlist, "item-deleted", val );
00120
00121 var_Create( p_playlist, "item-append", VLC_VAR_ADDRESS );
00122
00123 var_Create( p_playlist, "playlist-current", VLC_VAR_INTEGER );
00124 val.i_int = -1;
00125 var_Set( p_playlist, "playlist-current", val );
00126
00127 var_Create( p_playlist, "intf-popupmenu", VLC_VAR_BOOL );
00128
00129 var_Create( p_playlist, "intf-show", VLC_VAR_BOOL );
00130 val.b_bool = VLC_TRUE;
00131 var_Set( p_playlist, "intf-show", val );
00132
00133
00134
00135 var_CreateGetBool( p_playlist, "play-and-stop" );
00136 var_CreateGetBool( p_playlist, "random" );
00137 var_CreateGetBool( p_playlist, "repeat" );
00138 var_CreateGetBool( p_playlist, "loop" );
00139
00140
00141 vlc_mutex_init( p_playlist, &p_playlist->gc_lock );
00142 p_playlist->i_last_id = 0;
00143 p_playlist->b_go_next = VLC_TRUE;
00144 p_playlist->p_input = NULL;
00145
00146 p_playlist->request_date = 0;
00147
00148 p_playlist->i_views = 0;
00149 p_playlist->pp_views = NULL;
00150
00151 p_playlist->i_index = -1;
00152 p_playlist->i_size = 0;
00153 p_playlist->pp_items = NULL;
00154 p_playlist->i_all_size = 0;
00155 p_playlist->pp_all_items = 0;
00156
00157 playlist_ViewInsert( p_playlist, VIEW_CATEGORY, TITLE_CATEGORY );
00158 playlist_ViewInsert( p_playlist, VIEW_ALL, TITLE_ALL );
00159
00160 p_view = playlist_ViewFind( p_playlist, VIEW_CATEGORY );
00161
00162 p_playlist->p_general =
00163 playlist_NodeCreate( p_playlist, VIEW_CATEGORY,
00164 _( "General" ), p_view->p_root );
00165 p_playlist->p_general->i_flags |= PLAYLIST_RO_FLAG;
00166
00167
00168
00169
00170 p_view = playlist_ViewFind( p_playlist, VIEW_CATEGORY );
00171 p_playlist->status.i_view = VIEW_CATEGORY;
00172 p_playlist->status.p_item = NULL;
00173 p_playlist->status.p_node = p_view->p_root;
00174 p_playlist->request.b_request = VLC_FALSE;
00175 p_playlist->status.i_status = PLAYLIST_STOPPED;
00176
00177
00178 p_playlist->i_sort = SORT_ID;
00179 p_playlist->i_order = ORDER_NORMAL;
00180
00181
00182 if( vlc_thread_create( p_playlist, "playlist", RunThread,
00183 VLC_THREAD_PRIORITY_LOW, VLC_TRUE ) )
00184 {
00185 msg_Err( p_playlist, "cannot spawn playlist thread" );
00186 vlc_object_destroy( p_playlist );
00187 return NULL;
00188 }
00189
00190
00191 p_playlist->p_preparse = vlc_object_create( p_playlist,
00192 sizeof( playlist_preparse_t ) );
00193 if( !p_playlist->p_preparse )
00194 {
00195 msg_Err( p_playlist, "unable to create preparser" );
00196 vlc_object_destroy( p_playlist );
00197 return NULL;
00198 }
00199
00200 p_playlist->p_preparse->i_waiting = 0;
00201 p_playlist->p_preparse->pp_waiting = NULL;
00202
00203 vlc_object_attach( p_playlist->p_preparse, p_playlist );
00204 if( vlc_thread_create( p_playlist->p_preparse, "preparser",
00205 RunPreparse, VLC_THREAD_PRIORITY_LOW, VLC_TRUE ) )
00206 {
00207 msg_Err( p_playlist, "cannot spawn preparse thread" );
00208 vlc_object_detach( p_playlist->p_preparse );
00209 vlc_object_destroy( p_playlist->p_preparse );
00210 return NULL;
00211 }
00212
00213
00214 vlc_object_attach( p_playlist, p_parent );
00215
00216 return p_playlist;
00217 }
00218
00226 int playlist_Destroy( playlist_t * p_playlist )
00227 {
00228 int i;
00229 p_playlist->b_die = 1;
00230
00231 while( p_playlist->i_sds )
00232 {
00233 playlist_ServicesDiscoveryRemove( p_playlist,
00234 p_playlist->pp_sds[0]->psz_module );
00235 }
00236
00237 vlc_thread_join( p_playlist->p_preparse );
00238 vlc_thread_join( p_playlist );
00239
00240 vlc_object_detach( p_playlist->p_preparse );
00241
00242 var_Destroy( p_playlist, "intf-change" );
00243 var_Destroy( p_playlist, "item-change" );
00244 var_Destroy( p_playlist, "playlist-current" );
00245 var_Destroy( p_playlist, "intf-popmenu" );
00246 var_Destroy( p_playlist, "intf-show" );
00247 var_Destroy( p_playlist, "play-and-stop" );
00248 var_Destroy( p_playlist, "random" );
00249 var_Destroy( p_playlist, "repeat" );
00250 var_Destroy( p_playlist, "loop" );
00251
00252 playlist_Clear( p_playlist );
00253
00254 for( i = p_playlist->i_views - 1; i >= 0 ; i-- )
00255 {
00256 playlist_view_t *p_view = p_playlist->pp_views[i];
00257 if( p_view->psz_name )
00258 free( p_view->psz_name );
00259 playlist_ItemDelete( p_view->p_root );
00260 REMOVE_ELEM( p_playlist->pp_views, p_playlist->i_views, i );
00261 free( p_view );
00262 }
00263
00264 vlc_mutex_destroy( &p_playlist->gc_lock );
00265 vlc_object_destroy( p_playlist->p_preparse );
00266 vlc_object_destroy( p_playlist );
00267
00268 return VLC_SUCCESS;
00269 }
00270
00271
00284 int playlist_LockControl( playlist_t * p_playlist, int i_query, ... )
00285 {
00286 va_list args;
00287 int i_result;
00288 va_start( args, i_query );
00289 vlc_mutex_lock( &p_playlist->object_lock );
00290 i_result = playlist_vaControl( p_playlist, i_query, args );
00291 va_end( args );
00292 vlc_mutex_unlock( &p_playlist->object_lock );
00293 return i_result;
00294 }
00295
00308 int playlist_Control( playlist_t * p_playlist, int i_query, ... )
00309 {
00310 va_list args;
00311 int i_result;
00312 va_start( args, i_query );
00313 i_result = playlist_vaControl( p_playlist, i_query, args );
00314 va_end( args );
00315
00316 return i_result;
00317 }
00318
00319 int playlist_vaControl( playlist_t * p_playlist, int i_query, va_list args )
00320 {
00321 playlist_view_t *p_view;
00322 playlist_item_t *p_item, *p_node;
00323 int i_view;
00324 vlc_value_t val;
00325
00326 #ifdef PLAYLIST_PROFILE
00327 p_playlist->request_date = mdate();
00328 #endif
00329
00330 if( p_playlist->i_size <= 0 )
00331 {
00332 return VLC_EGENERIC;
00333 }
00334
00335 switch( i_query )
00336 {
00337 case PLAYLIST_STOP:
00338 p_playlist->status.i_status = PLAYLIST_STOPPED;
00339 p_playlist->request.b_request = VLC_TRUE;
00340 p_playlist->request.p_item = NULL;
00341 break;
00342
00343 case PLAYLIST_ITEMPLAY:
00344 p_item = (playlist_item_t *)va_arg( args, playlist_item_t * );
00345 if ( p_item == NULL || p_item->input.psz_uri == NULL )
00346 return VLC_EGENERIC;
00347 p_playlist->status.i_status = PLAYLIST_RUNNING;
00348 p_playlist->request.i_skip = 0;
00349 p_playlist->request.b_request = VLC_TRUE;
00350 p_playlist->request.p_item = p_item;
00351 p_playlist->request.i_view = p_playlist->status.i_view;
00352 p_view = playlist_ViewFind( p_playlist, p_playlist->status.i_view );
00353 if( p_view )
00354 {
00355 p_playlist->request.p_node = p_view->p_root;
00356 }
00357 else
00358 {
00359 p_playlist->request.p_node = NULL;
00360 }
00361 break;
00362
00363 case PLAYLIST_VIEWPLAY:
00364 i_view = (int)va_arg( args,int );
00365 p_node = (playlist_item_t *)va_arg( args, playlist_item_t * );
00366 p_item = (playlist_item_t *)va_arg( args, playlist_item_t * );
00367 if ( p_node == NULL || (p_item != NULL && p_item->input.psz_uri
00368 == NULL ))
00369 {
00370 p_playlist->status.i_status = PLAYLIST_STOPPED;
00371 p_playlist->request.b_request = VLC_TRUE;
00372 return VLC_SUCCESS;
00373 }
00374 p_playlist->status.i_status = PLAYLIST_RUNNING;
00375 p_playlist->request.i_skip = 0;
00376 p_playlist->request.b_request = VLC_TRUE;
00377 p_playlist->request.i_view = i_view;
00378 p_playlist->request.p_node = p_node;
00379 p_playlist->request.p_item = p_item;
00380
00381
00382
00383 if( p_playlist->request.p_item == NULL ||
00384 ! p_playlist->request.p_node->i_flags & PLAYLIST_SKIP_FLAG )
00385 {
00386 p_playlist->b_go_next = VLC_FALSE;
00387 }
00388 else
00389 {
00390 p_playlist->b_go_next = VLC_TRUE;
00391 }
00392 break;
00393
00394 case PLAYLIST_PLAY:
00395 p_playlist->status.i_status = PLAYLIST_RUNNING;
00396
00397 if( p_playlist->p_input )
00398 {
00399 val.i_int = PLAYING_S;
00400 var_Set( p_playlist->p_input, "state", val );
00401 break;
00402 }
00403
00404
00405 p_playlist->request.b_request = VLC_TRUE;
00406 p_playlist->request.i_view = p_playlist->status.i_view;
00407 p_playlist->request.p_node = p_playlist->status.p_node;
00408 p_playlist->request.p_item = p_playlist->status.p_item;
00409 p_playlist->request.i_skip = 0;
00410 p_playlist->request.i_goto = -1;
00411 break;
00412
00413 case PLAYLIST_AUTOPLAY:
00414 p_playlist->status.i_status = PLAYLIST_RUNNING;
00415 p_playlist->status.p_node = p_playlist->p_general;
00416
00417 p_playlist->request.b_request = VLC_FALSE;
00418 break;
00419
00420 case PLAYLIST_PAUSE:
00421 val.i_int = 0;
00422 if( p_playlist->p_input )
00423 var_Get( p_playlist->p_input, "state", &val );
00424
00425 if( val.i_int == PAUSE_S )
00426 {
00427 p_playlist->status.i_status = PLAYLIST_RUNNING;
00428 if( p_playlist->p_input )
00429 {
00430 val.i_int = PLAYING_S;
00431 var_Set( p_playlist->p_input, "state", val );
00432 }
00433 }
00434 else
00435 {
00436 p_playlist->status.i_status = PLAYLIST_PAUSED;
00437 if( p_playlist->p_input )
00438 {
00439 val.i_int = PAUSE_S;
00440 var_Set( p_playlist->p_input, "state", val );
00441 }
00442 }
00443 break;
00444
00445 case PLAYLIST_SKIP:
00446 p_playlist->request.i_view = p_playlist->status.i_view;
00447 if( p_playlist->status.i_view > -1 )
00448 {
00449 p_playlist->request.p_node = p_playlist->status.p_node;
00450 p_playlist->request.p_item = p_playlist->status.p_item;
00451 }
00452 else
00453 {
00454 p_playlist->request.p_node = NULL;
00455 p_playlist->request.p_item = NULL;
00456 }
00457 p_playlist->request.i_skip = (int) va_arg( args, int );
00458 p_playlist->request.b_request = VLC_TRUE;
00459 break;
00460
00461 case PLAYLIST_GOTO:
00462 p_playlist->status.i_status = PLAYLIST_RUNNING;
00463 p_playlist->request.p_node = NULL;
00464 p_playlist->request.p_item = NULL;
00465 p_playlist->request.i_view = -1;
00466 p_playlist->request.i_goto = (int) va_arg( args, int );
00467 p_playlist->request.b_request = VLC_TRUE;
00468 break;
00469
00470 default:
00471 msg_Err( p_playlist, "unimplemented playlist query" );
00472 return VLC_EBADVAR;
00473 break;
00474 }
00475
00476 return VLC_SUCCESS;
00477 }
00478
00479 int playlist_PreparseEnqueue( playlist_t *p_playlist,
00480 input_item_t *p_item )
00481 {
00482 vlc_mutex_lock( &p_playlist->p_preparse->object_lock );
00483 INSERT_ELEM( p_playlist->p_preparse->pp_waiting,
00484 p_playlist->p_preparse->i_waiting,
00485 p_playlist->p_preparse->i_waiting,
00486 p_item );
00487 vlc_mutex_unlock( &p_playlist->p_preparse->object_lock );
00488 return VLC_SUCCESS;
00489 }
00490
00491
00492 void playlist_PreparseEnqueueItemSub( playlist_t *p_playlist,
00493 playlist_item_t *p_item )
00494 {
00495 int i;
00496 if( p_item->i_children == -1 )
00497 {
00498 INSERT_ELEM( p_playlist->p_preparse->pp_waiting,
00499 p_playlist->p_preparse->i_waiting,
00500 p_playlist->p_preparse->i_waiting,
00501 &(p_item->input) );
00502 }
00503 else
00504 {
00505 for( i = 0; i < p_item->i_children; i++)
00506 {
00507 playlist_PreparseEnqueueItemSub( p_playlist,
00508 p_item->pp_children[i] );
00509 }
00510 }
00511 }
00512
00513 int playlist_PreparseEnqueueItem( playlist_t *p_playlist,
00514 playlist_item_t *p_item )
00515 {
00516 vlc_mutex_lock( &p_playlist->object_lock );
00517 vlc_mutex_lock( &p_playlist->p_preparse->object_lock );
00518 playlist_PreparseEnqueueItemSub( p_playlist, p_item );
00519 vlc_mutex_unlock( &p_playlist->p_preparse->object_lock );
00520 vlc_mutex_unlock( &p_playlist->object_lock );
00521 return VLC_SUCCESS;
00522 }
00523
00524
00525
00526 static mtime_t ObjectGarbageCollector( playlist_t *p_playlist, int i_type,
00527 mtime_t destroy_date )
00528 {
00529 vlc_object_t *p_obj;
00530
00531 if( destroy_date > mdate() ) return destroy_date;
00532
00533 if( destroy_date == 0 )
00534 {
00535
00536 return mdate() + I64C(1000000);
00537 }
00538 else
00539 {
00540 vlc_mutex_lock( &p_playlist->gc_lock );
00541 while( ( p_obj = vlc_object_find( p_playlist, i_type, FIND_CHILD ) ) )
00542 {
00543 if( p_obj->p_parent != (vlc_object_t*)p_playlist )
00544 {
00545
00546 vlc_object_release( p_obj );
00547 break;
00548 }
00549 if( i_type == VLC_OBJECT_VOUT )
00550 {
00551 msg_Dbg( p_playlist, "garbage collector destroying 1 vout" );
00552 vlc_object_detach( p_obj );
00553 vlc_object_release( p_obj );
00554 vout_Destroy( (vout_thread_t *)p_obj );
00555 }
00556 else if( i_type == VLC_OBJECT_SOUT )
00557 {
00558 vlc_object_release( p_obj );
00559 sout_DeleteInstance( (sout_instance_t*)p_obj );
00560 }
00561 }
00562 vlc_mutex_unlock( &p_playlist->gc_lock );
00563 return 0;
00564 }
00565 }
00566
00567
00568
00569
00570 static void RunThread ( playlist_t *p_playlist )
00571 {
00572 vlc_object_t *p_obj;
00573 playlist_item_t *p_item = NULL;
00574
00575 mtime_t i_vout_destroyed_date = 0;
00576 mtime_t i_sout_destroyed_date = 0;
00577
00578 playlist_item_t *p_autodelete_item = NULL;
00579
00580
00581 vlc_thread_ready( p_playlist );
00582
00583 while( !p_playlist->b_die )
00584 {
00585 vlc_mutex_lock( &p_playlist->object_lock );
00586
00587
00588
00589 if( p_playlist->request.b_request )
00590 {
00591 #ifdef PLAYLIST_PROFILE
00592 msg_Dbg(p_playlist, "beginning processing of request, "
00593 I64Fi" us ", mdate() - p_playlist->request_date );
00594 #endif
00595
00596 if( p_playlist->p_input )
00597 {
00598 input_StopThread( p_playlist->p_input );
00599 }
00600
00601 if( p_playlist->status.i_status == PLAYLIST_STOPPED )
00602 {
00603 p_playlist->request.b_request = VLC_FALSE;
00604 }
00605 }
00606
00607
00608 if( p_playlist->p_input )
00609 {
00610
00611 if( p_playlist->p_input->b_dead )
00612 {
00613 input_thread_t *p_input;
00614
00615 p_input = p_playlist->p_input;
00616 p_playlist->p_input = NULL;
00617
00618
00619
00620 vlc_mutex_unlock( &p_playlist->object_lock );
00621
00622
00623 input_DestroyThread( p_input );
00624
00625
00626
00627 vlc_object_detach( p_input );
00628
00629
00630 vlc_object_destroy( p_input );
00631
00632 i_vout_destroyed_date = 0;
00633 i_sout_destroyed_date = 0;
00634
00635 if( p_playlist->status.p_item->i_flags
00636 & PLAYLIST_REMOVE_FLAG )
00637 {
00638 playlist_ItemDelete( p_item );
00639 p_playlist->status.p_item = NULL;
00640 }
00641
00642 continue;
00643 }
00644
00645 else if( p_playlist->p_input->b_die )
00646 {
00647 ;
00648 }
00649
00650 else if( p_playlist->p_input->b_error
00651 || p_playlist->p_input->b_eof )
00652 {
00653
00654
00655
00656 if( p_playlist->status.p_item->i_flags & PLAYLIST_DEL_FLAG )
00657 {
00658 p_autodelete_item = p_playlist->status.p_item;
00659 }
00660 input_StopThread( p_playlist->p_input );
00661
00662 vlc_mutex_unlock( &p_playlist->object_lock );
00663 continue;
00664 }
00665 else if( p_playlist->p_input->i_state != INIT_S )
00666 {
00667 vlc_mutex_unlock( &p_playlist->object_lock );
00668 i_vout_destroyed_date =
00669 ObjectGarbageCollector( p_playlist, VLC_OBJECT_VOUT,
00670 i_vout_destroyed_date );
00671 i_sout_destroyed_date =
00672 ObjectGarbageCollector( p_playlist, VLC_OBJECT_SOUT,
00673 i_sout_destroyed_date );
00674 vlc_mutex_lock( &p_playlist->object_lock );
00675 }
00676 }
00677 else if( p_playlist->status.i_status != PLAYLIST_STOPPED )
00678 {
00679
00680
00681 p_item = NextItem( p_playlist );
00682
00683
00684
00685 if( p_item == NULL )
00686 {
00687 if( p_autodelete_item )
00688 {
00689 playlist_Delete( p_playlist,
00690 p_autodelete_item->input.i_id );
00691 p_autodelete_item = NULL;
00692 }
00693 p_playlist->status.i_status = PLAYLIST_STOPPED;
00694 vlc_mutex_unlock( &p_playlist->object_lock );
00695 continue;
00696 }
00697
00698 PlayItem( p_playlist, p_item );
00699
00700 if( p_autodelete_item )
00701 {
00702 playlist_Delete( p_playlist, p_autodelete_item->input.i_id );
00703 p_autodelete_item = NULL;
00704 }
00705 }
00706 else if( p_playlist->status.i_status == PLAYLIST_STOPPED )
00707 {
00708 if( p_item && p_playlist->status.p_item &&
00709 p_playlist->status.p_item->i_flags & PLAYLIST_REMOVE_FLAG )
00710 {
00711 playlist_ItemDelete( p_item );
00712 p_playlist->status.p_item = NULL;
00713 }
00714
00715
00716 vlc_mutex_unlock( &p_playlist->object_lock );
00717 i_sout_destroyed_date =
00718 ObjectGarbageCollector( p_playlist, VLC_OBJECT_SOUT, mdate() );
00719 i_vout_destroyed_date =
00720 ObjectGarbageCollector( p_playlist, VLC_OBJECT_VOUT, mdate() );
00721 vlc_mutex_lock( &p_playlist->object_lock );
00722 }
00723 vlc_mutex_unlock( &p_playlist->object_lock );
00724
00725 msleep( INTF_IDLE_SLEEP / 2 );
00726
00727
00728
00729 if ( p_playlist->request.b_request &&
00730 p_playlist->status.i_status == PLAYLIST_RUNNING )
00731 {
00732 continue;
00733 }
00734
00735 msleep( INTF_IDLE_SLEEP / 2 );
00736 }
00737
00738
00739
00740
00741 while( 1 )
00742 {
00743 vlc_mutex_lock( &p_playlist->object_lock );
00744
00745 if( p_playlist->p_input == NULL )
00746 {
00747 vlc_mutex_unlock( &p_playlist->object_lock );
00748 break;
00749 }
00750
00751 if( p_playlist->p_input->b_dead )
00752 {
00753 input_thread_t *p_input;
00754
00755
00756 p_input = p_playlist->p_input;
00757 p_playlist->p_input = NULL;
00758 vlc_mutex_unlock( &p_playlist->object_lock );
00759
00760
00761 input_DestroyThread( p_input );
00762
00763
00764 vlc_object_detach( p_input );
00765
00766
00767 vlc_object_destroy( p_input );
00768 continue;
00769 }
00770 else if( p_playlist->p_input->b_die )
00771 {
00772
00773 ;
00774 }
00775 else if( p_playlist->p_input->b_error || p_playlist->p_input->b_eof )
00776 {
00777 input_StopThread( p_playlist->p_input );
00778 vlc_mutex_unlock( &p_playlist->object_lock );
00779 continue;
00780 }
00781 else
00782 {
00783 p_playlist->p_input->b_eof = 1;
00784 }
00785
00786 vlc_mutex_unlock( &p_playlist->object_lock );
00787
00788 msleep( INTF_IDLE_SLEEP );
00789 }
00790
00791
00792 while( ( p_obj = vlc_object_find( p_playlist,
00793 VLC_OBJECT_SOUT, FIND_CHILD ) ) )
00794 {
00795 vlc_object_release( p_obj );
00796 sout_DeleteInstance( (sout_instance_t*)p_obj );
00797 }
00798
00799
00800 while( ( p_obj = vlc_object_find( p_playlist,
00801 VLC_OBJECT_VOUT, FIND_CHILD ) ) )
00802 {
00803 vlc_object_detach( p_obj );
00804 vlc_object_release( p_obj );
00805 vout_Destroy( (vout_thread_t *)p_obj );
00806 }
00807 }
00808
00809
00810 static void RunPreparse ( playlist_preparse_t *p_obj )
00811 {
00812 playlist_t *p_playlist = (playlist_t *)p_obj->p_parent;
00813 vlc_bool_t b_sleep;
00814
00815
00816 vlc_thread_ready( p_obj );
00817
00818 while( !p_playlist->b_die )
00819 {
00820 vlc_mutex_lock( &p_obj->object_lock );
00821
00822 if( p_obj->i_waiting > 0 )
00823 {
00824 input_item_t *p_current = p_obj->pp_waiting[0];
00825 REMOVE_ELEM( p_obj->pp_waiting, p_obj->i_waiting, 0 );
00826 vlc_mutex_unlock( &p_obj->object_lock );
00827 input_Preparse( p_playlist, p_current );
00828 var_SetInteger( p_playlist, "item-change", p_current->i_id );
00829 vlc_mutex_lock( &p_obj->object_lock );
00830 }
00831 b_sleep = ( p_obj->i_waiting == 0 );
00832
00833 vlc_mutex_unlock( &p_obj->object_lock );
00834
00835 if( p_obj->i_waiting == 0 )
00836 {
00837 msleep( INTF_IDLE_SLEEP );
00838 }
00839 }
00840 }
00841
00842
00843
00844
00845
00846
00847
00848 static playlist_item_t * NextItem( playlist_t *p_playlist )
00849 {
00850 playlist_item_t *p_new = NULL;
00851 int i_skip,i_goto,i, i_new, i_count ;
00852 playlist_view_t *p_view;
00853
00854 vlc_bool_t b_loop = var_GetBool( p_playlist, "loop" );
00855 vlc_bool_t b_random = var_GetBool( p_playlist, "random" );
00856 vlc_bool_t b_repeat = var_GetBool( p_playlist, "repeat" );
00857 vlc_bool_t b_playstop = var_GetBool( p_playlist, "play-and-stop" );
00858
00859 #ifdef PLAYLIST_PROFILE
00860
00861 int64_t start = mdate();
00862 #endif
00863
00864
00865
00866
00867 if( p_playlist->i_size == 0 )
00868 {
00869 msg_Info( p_playlist, "playlist is empty" );
00870 return NULL;
00871 }
00872
00873 if( !p_playlist->request.b_request && p_playlist->status.p_item == NULL )
00874 {
00875 msg_Dbg( p_playlist,"nothing requested, starting" );
00876 }
00877
00878
00879 if( !p_playlist->request.b_request && b_repeat == VLC_TRUE )
00880 {
00881 msg_Dbg( p_playlist,"repeating item" );
00882 return p_playlist->status.p_item;
00883 }
00884
00885 if( !p_playlist->request.b_request && b_playstop == VLC_TRUE )
00886 {
00887 msg_Dbg( p_playlist,"stopping (play and stop)");
00888 return NULL;
00889 }
00890
00891 if( !p_playlist->request.b_request && p_playlist->status.p_item &&
00892 !( p_playlist->status.p_item->i_flags & PLAYLIST_SKIP_FLAG ) )
00893 {
00894 msg_Dbg( p_playlist, "no-skip mode, stopping") ;
00895 return NULL;
00896 }
00897
00898
00899
00900
00901
00902 if( b_random &&
00903 ( !p_playlist->request.b_request ||
00904 ( p_playlist->request.b_request && ( p_playlist->request.p_item == NULL ||
00905 p_playlist->request.i_skip == 1 || p_playlist->request.i_skip == -1 ) ) ) )
00906 {
00907
00908 i_count = 0;
00909 for ( i = 0; i < p_playlist->i_size; i++ )
00910 {
00911 if ( p_playlist->pp_items[i]->i_nb_played == 0 )
00912 i_count++;
00913 }
00914
00915 if ( i_count == 0 )
00916 {
00917
00918 if( !b_loop )
00919 return NULL;
00920
00921 for ( i = 0; i < p_playlist->i_size; i++ )
00922 {
00923 p_playlist->pp_items[i]->i_nb_played = 0;
00924 }
00925 i_count = p_playlist->i_size;
00926 }
00927 srand( (unsigned int)mdate() );
00928 i = rand() % i_count + 1 ;
00929
00930 for ( i_new = 0; i_new < p_playlist->i_size && i > 0; i_new++ )
00931 {
00932 if ( p_playlist->pp_items[i_new]->i_nb_played == 0 )
00933 i--;
00934 }
00935 i_new--;
00936
00937 p_playlist->request.i_skip = 0;
00938 p_playlist->request.b_request = VLC_FALSE;
00939 return p_playlist->pp_items[i_new];
00940 }
00941
00942
00943 if( p_playlist->request.b_request )
00944 {
00945 #ifdef PLAYLIST_DEBUG
00946 msg_Dbg( p_playlist,"processing request" );
00947 #endif
00948
00949 if( p_playlist->request.i_view == -1 )
00950 {
00951 #ifdef PLAYLIST_DEBUG
00952 msg_Dbg( p_playlist, "non-view mode request");
00953 #endif
00954
00955 p_new = p_playlist->request.p_item;
00956 i_skip = p_playlist->request.i_skip;
00957 i_goto = p_playlist->request.i_goto;
00958
00959 if( p_playlist->i_index < 0 ) p_playlist->i_index = 0;
00960 if ( p_new == NULL )
00961 p_new = p_playlist->pp_items[p_playlist->i_index];
00962
00963 if( i_goto >= 0 && i_goto < p_playlist->i_size )
00964 {
00965 p_playlist->i_index = i_goto;
00966 p_new = p_playlist->pp_items[p_playlist->i_index];
00967 p_playlist->request.i_goto = -1;
00968 }
00969
00970 if( i_skip != 0 )
00971 {
00972 if( p_playlist->i_index + i_skip < p_playlist->i_size &&
00973 p_playlist->i_index + i_skip >= 0 )
00974 {
00975 p_playlist->i_index += i_skip;
00976 p_new = p_playlist->pp_items[p_playlist->i_index];
00977 }
00978 p_playlist->request.i_skip = 0;
00979 }
00980 }
00981 else
00982 {
00983 #ifdef PLAYLIST_DEBUG
00984 msg_Dbg( p_playlist, "view mode request" );
00985 #endif
00986 p_new = p_playlist->request.p_item;
00987 i_skip = p_playlist->request.i_skip;
00988
00989
00990 if( p_playlist->request.p_item == NULL && i_skip == 0 )
00991 {
00992 i_skip++;
00993 }
00994
00995 p_view = playlist_ViewFind( p_playlist,p_playlist->request.i_view );
00996 p_playlist->status.p_node = p_playlist->request.p_node;
00997 p_playlist->status.i_view = p_playlist->request.i_view;
00998 if( !p_view )
00999 {
01000 msg_Err( p_playlist, "p_view is NULL and should not! (requested view is %i", p_playlist->request.i_view );
01001 }
01002 else if( i_skip > 0 )
01003 {
01004 for( i = i_skip; i > 0 ; i-- )
01005 {
01006 p_new = playlist_FindNextFromParent( p_playlist,
01007 p_playlist->request.i_view,
01008 p_view->p_root,
01009 p_playlist->request.p_node,
01010 p_new );
01011 if( p_new == NULL )
01012 {
01013 #ifdef PLAYLIST_DEBUG
01014 msg_Dbg( p_playlist, "looping" );
01015 #endif
01016 p_new = playlist_FindNextFromParent( p_playlist,
01017 p_playlist->request.i_view,
01018 p_view->p_root,
01019 p_view->p_root,
01020 NULL );
01021 if( p_new == NULL ) break;
01022 }
01023 }
01024 }
01025 else if( i_skip < 0 )
01026 {
01027 for( i = i_skip; i < 0 ; i++ )
01028 {
01029 p_new = playlist_FindPrevFromParent( p_playlist,
01030 p_playlist->request.i_view,
01031 p_view->p_root,
01032 p_playlist->request.p_node,
01033 p_new );
01034 if( p_new == NULL )
01035 {
01036
01037
01038 p_new = playlist_RecursiveFindLast( p_playlist,
01039 p_view->p_root );
01040 }
01041 if( p_new == NULL ) break;
01042 }
01043
01044 }
01045 }
01046
01047 p_playlist->request.b_request = VLC_FALSE;
01048 }
01049
01050 else
01051 {
01052 p_playlist->request_date = 0;
01053
01054 if( p_playlist->status.i_view == -1 )
01055 {
01056 #ifdef PLAYLIST_DEBUG
01057 msg_Dbg( p_playlist, "no request - old mode" );
01058 #endif
01059 if( p_playlist->i_index + 1 < p_playlist->i_size )
01060 {
01061 p_playlist->i_index++;
01062 p_new = p_playlist->pp_items[p_playlist->i_index];
01063 if( !( p_new->i_flags & PLAYLIST_SKIP_FLAG ) )
01064 {
01065 return NULL;
01066 }
01067 }
01068 else
01069 {
01070 if( b_loop && p_playlist->i_size > 0)
01071 {
01072 p_playlist->i_index = 0;
01073 p_new = p_playlist->pp_items[0];
01074 }
01075 else
01076 p_new = NULL;
01077 }
01078 }
01079
01080 else
01081 {
01082 #ifdef PLAYLIST_DEBUG
01083 msg_Dbg( p_playlist,"no request - from a view" );
01084 #endif
01085 playlist_view_t *p_view =
01086 playlist_ViewFind( p_playlist,
01087 p_playlist->status.i_view );
01088 if( !p_view )
01089 {
01090 msg_Err( p_playlist, "p_view is NULL and should not! (FIXME)" );
01091 }
01092 else
01093 {
01094 p_new = playlist_FindNextFromParent( p_playlist,
01095 p_playlist->status.i_view,
01096 p_view->p_root,
01097 p_playlist->status.p_node,
01098 p_playlist->status.p_item );
01099 if( p_new == NULL && b_loop )
01100 {
01101 #ifdef PLAYLIST_DEBUG
01102 msg_Dbg( p_playlist, "looping" );
01103 #endif
01104 p_new = playlist_FindNextFromParent( p_playlist,
01105 p_playlist->status.i_view,
01106 p_view->p_root,
01107 p_view->p_root,
01108 NULL );
01109 }
01110 if( p_new != NULL && !(p_new->i_flags & PLAYLIST_SKIP_FLAG) )
01111 return NULL;
01112 }
01113 }
01114 }
01115
01116
01117 if( p_playlist->i_index >= 0 && p_new != NULL &&
01118 p_playlist->pp_items[p_playlist->i_index] != p_new )
01119 {
01120 p_playlist->i_index = playlist_GetPositionById( p_playlist,
01121 p_new->input.i_id );
01122 }
01123
01124 #ifdef PLAYLIST_PROFILE
01125 msg_Dbg(p_playlist,"next item found in "I64Fi " us", mdate()-start );
01126 #endif
01127
01128 if( p_new == NULL )
01129 {
01130 msg_Info( p_playlist, "nothing to play" );
01131 }
01132 return p_new;
01133 }
01134
01135
01136
01137
01138 static int PlayItem( playlist_t *p_playlist, playlist_item_t *p_item )
01139 {
01140 vlc_value_t val;
01141
01142 msg_Dbg( p_playlist, "creating new input thread" );
01143
01144 p_item->i_nb_played++;
01145 p_playlist->status.p_item = p_item;
01146
01147 p_playlist->i_index = playlist_GetPositionById( p_playlist,
01148 p_item->input.i_id );
01149
01150 #ifdef PLAYLIST_PROFILE
01151 if( p_playlist->request_date != 0 )
01152 {
01153 msg_Dbg( p_playlist, "request processed after "I64Fi " us",
01154 mdate() - p_playlist->request_date );
01155 }
01156 #endif
01157
01158 p_playlist->p_input = input_CreateThread( p_playlist, &p_item->input );
01159
01160 var_AddCallback( p_playlist->p_input, "item-change",
01161 ItemChange, p_playlist );
01162
01163 val.i_int = p_item->input.i_id;
01164
01165 vlc_mutex_unlock( &p_playlist->object_lock);
01166 var_Set( p_playlist, "playlist-current", val);
01167 vlc_mutex_lock( &p_playlist->object_lock);
01168
01169 return VLC_SUCCESS;
01170
01171 }
01172
01173
01174 static int ItemChange( vlc_object_t *p_obj, const char *psz_var,
01175 vlc_value_t oldval, vlc_value_t newval, void *param )
01176 {
01177 playlist_t *p_playlist = (playlist_t *)param;
01178
01179
01180 var_SetInteger( p_playlist, "item-change", newval.i_int );
01181
01182
01183
01184
01185
01186 return VLC_SUCCESS;
01187 }