]> git.sesse.net Git - vlc/blob - src/playlist/item.c
* Fix skip in initial status
[vlc] / src / playlist / item.c
1 /*****************************************************************************
2  * item.c : Playlist item creation/deletion/add/removal functions
3  *****************************************************************************
4  * Copyright (C) 1999-2004 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *          ClĂ©ment Stenac <zorglub@videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24 #include <vlc/vlc.h>
25 #include <vlc/input.h>
26 #include <assert.h>
27 #include "vlc_playlist.h"
28
29 void AddItem( playlist_t *p_playlist, playlist_item_t *p_item,
30               playlist_item_t *p_node, int i_pos );
31 void GoAndPreparse( playlist_t *p_playlist, int i_mode,
32                     playlist_item_t *, playlist_item_t * );
33 void ChangeToNode( playlist_t *p_playlist, playlist_item_t *p_item );
34 int DeleteInner( playlist_t * p_playlist, playlist_item_t *p_item,
35                           vlc_bool_t b_stop );
36
37 /*****************************************************************************
38  * Playlist item creation
39  *****************************************************************************/
40 /**
41  * Create a new item, without adding it to the playlist
42  *
43  * \param p_obj a vlc object (anyone will do)
44  * \param psz_uri the mrl of the item
45  * \param psz_name a text giving a name or description of the item
46  * \return the new item or NULL on failure
47  */
48 playlist_item_t * __playlist_ItemNew( vlc_object_t *p_obj,
49                                       const char *psz_uri,
50                                       const char *psz_name )
51 {
52     return playlist_ItemNewWithType( p_obj, psz_uri,
53                                      psz_name, 0, NULL, -1,
54                                      ITEM_TYPE_UNKNOWN );
55 }
56
57 playlist_item_t * playlist_ItemNewWithType( vlc_object_t *p_obj,
58                                             const char *psz_uri,
59                                             const char *psz_name,
60                                             int i_options,
61                                             const char **ppsz_options,
62                                             int i_duration,
63                                             int i_type )
64 {
65     input_item_t *p_input;
66
67     if( psz_uri == NULL ) return NULL;
68     p_input = input_ItemNewWithType( p_obj, psz_uri,
69                                         psz_name, i_options, ppsz_options,
70                                         i_duration, i_type );
71     return playlist_ItemNewFromInput( p_obj, p_input );
72 }
73
74 playlist_item_t *__playlist_ItemNewFromInput( vlc_object_t *p_obj,
75                                             input_item_t *p_input )
76 {
77     /** FIXME !!!!! don't find playlist each time */
78     playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_obj, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
79     playlist_item_t * p_item;
80     p_item = malloc( sizeof( playlist_item_t ) );
81     if( p_item == NULL ) return NULL;
82
83     p_item->p_input = p_input;
84     vlc_gc_incref( p_item->p_input );
85
86     p_item->i_id = ++p_playlist->i_last_playlist_id;
87
88     p_item->p_parent = NULL;
89     p_item->i_children = -1;
90     p_item->pp_children = NULL;
91     p_item->i_flags = 0;
92
93     vlc_object_release( p_playlist );
94
95     return p_item;
96 }
97
98 /***************************************************************************
99  * Playlist item destruction
100  ***************************************************************************/
101
102 /** Delete a playlist item and detach its input item */
103 int playlist_ItemDelete( playlist_item_t *p_item )
104 {
105     vlc_gc_decref( p_item->p_input );
106     free( p_item );
107     return VLC_SUCCESS;
108 }
109
110 /** Remove an input item from ONELEVEL and CATEGORY */
111 int playlist_DeleteAllFromInput( playlist_t *p_playlist, int i_input_id )
112 {
113     playlist_DeleteFromInput( p_playlist, i_input_id,
114                               p_playlist->p_root_category, VLC_TRUE );
115     playlist_DeleteFromInput( p_playlist, i_input_id,
116                               p_playlist->p_root_onelevel, VLC_TRUE );
117     return VLC_SUCCESS;
118 }
119
120 /** Remove an input item from ONELEVEL and CATEGORY.
121  * This function must be entered without the playlist lock */
122 int playlist_LockDeleteAllFromInput( playlist_t * p_playlist, int i_id )
123 {
124     int i_ret;
125     vlc_mutex_lock( &p_playlist->object_lock );
126     i_ret = playlist_DeleteAllFromInput( p_playlist, i_id );
127     vlc_mutex_unlock( &p_playlist->object_lock );
128     return i_ret;
129 }
130
131 /** Remove an input item when it appears from a root playlist item */
132 int playlist_DeleteFromInput( playlist_t *p_playlist, int i_input_id,
133                               playlist_item_t *p_root, vlc_bool_t b_do_stop )
134 {
135     int i;
136     for( i = 0 ; i< p_root->i_children ; i++ )
137     {
138         if( p_root->pp_children[i]->i_children == -1 &&
139             p_root->pp_children[i]->p_input->i_id == i_input_id )
140         {
141             DeleteInner( p_playlist, p_root->pp_children[i], b_do_stop );
142         }
143         else if( p_root->pp_children[i]->i_children >= 0 )
144         {
145             return playlist_DeleteFromInput( p_playlist, i_input_id,
146                                         p_root->pp_children[i], b_do_stop );
147         }
148     }
149     return -1;
150 }
151
152 /** Remove a playlist item from the playlist, given its id */
153 int playlist_DeleteFromItemId( playlist_t *p_playlist, int i_id )
154 {
155     playlist_item_t *p_item = playlist_ItemGetById( p_playlist, i_id );
156     if( !p_item ) return VLC_EGENERIC;
157     return DeleteInner( p_playlist, p_item, VLC_TRUE );
158 }
159
160 /** Remove a playlist item from the playlist, given its id
161  * This function should be entered without the playlist lock */
162 int playlist_LockDelete( playlist_t * p_playlist, int i_id )
163 {
164     int i_ret;
165     vlc_mutex_lock( &p_playlist->object_lock );
166     i_ret = playlist_DeleteFromItemId( p_playlist, i_id );
167     vlc_mutex_unlock( &p_playlist->object_lock );
168     return i_ret;
169 }
170
171 /** Clear the playlist */
172 void playlist_Clear( playlist_t * p_playlist )
173 {
174     playlist_NodeEmpty( p_playlist, p_playlist->p_root_category, VLC_TRUE );
175     playlist_NodeEmpty( p_playlist, p_playlist->p_root_onelevel, VLC_TRUE );
176 }
177 /** Clear the playlist. This function must be entered without the lock */
178 void playlist_LockClear( playlist_t *p_playlist )
179 {
180     vlc_mutex_lock( &p_playlist->object_lock );
181     playlist_Clear( p_playlist );
182     vlc_mutex_unlock( &p_playlist->object_lock );
183 }
184
185 /***************************************************************************
186  * Playlist item addition
187  ***************************************************************************/
188
189 /**
190  * Add a MRL into the playlist.
191  *
192  * \param p_playlist the playlist to add into
193  * \param psz_uri the mrl to add to the playlist
194  * \param psz_name a text giving a name or description of this item
195  * \param i_mode the mode used when adding
196  * \param i_pos the position in the playlist where to add. If this is
197  *        PLAYLIST_END the item will be added at the end of the playlist
198  *        regardless of it's size
199  * \return The id of the playlist item
200  */
201 int playlist_PlaylistAdd( playlist_t *p_playlist, const char *psz_uri,
202                           const char *psz_name, int i_mode, int i_pos )
203 {
204     return playlist_PlaylistAddExt( p_playlist, psz_uri, psz_name,
205                                     i_mode, i_pos, -1, NULL, 0 );
206 }
207
208 /**
209  * Add a MRL into the playlist, duration and options given
210  *
211  * \param p_playlist the playlist to add into
212  * \param psz_uri the mrl to add to the playlist
213  * \param psz_name a text giving a name or description of this item
214  * \param i_mode the mode used when adding
215  * \param i_pos the position in the playlist where to add. If this is
216  *        PLAYLIST_END the item will be added at the end of the playlist
217  *        regardless of it's size
218  * \param i_duration length of the item in milliseconds.
219  * \param ppsz_options an array of options
220  * \param i_options the number of options
221  * \return The id of the playlist item
222 */
223 int playlist_PlaylistAddExt( playlist_t *p_playlist, const char * psz_uri,
224                              const char *psz_name, int i_mode, int i_pos,
225                              mtime_t i_duration, const char **ppsz_options,
226                              int i_options )
227 {
228     input_item_t *p_input = input_ItemNewExt( p_playlist, psz_uri, psz_name,
229                                               i_options, ppsz_options,
230                                               i_duration );
231
232     return playlist_PlaylistAddInput( p_playlist, p_input, i_mode, i_pos );
233 }
234
235 /** Add an input item to the playlist node */
236 int playlist_PlaylistAddInput( playlist_t* p_playlist, input_item_t *p_input,
237                                int i_mode, int i_pos )
238 {
239     playlist_item_t *p_item_cat, *p_item_one;
240
241     msg_Dbg( p_playlist, "adding playlist item `%s' ( %s )",
242              p_input->psz_name, p_input->psz_uri );
243
244     vlc_mutex_lock( &p_playlist->object_lock );
245
246     /* Add to ONELEVEL */
247     p_item_one = playlist_ItemNewFromInput( p_playlist, p_input );
248     if( p_item_one == NULL ) return VLC_EGENERIC;
249     AddItem( p_playlist, p_item_one ,p_playlist->p_local_onelevel, i_pos );
250
251     /* Add to CATEGORY */
252     p_item_cat = playlist_ItemNewFromInput( p_playlist, p_input );
253     if( p_item_cat == NULL ) return VLC_EGENERIC;
254     AddItem( p_playlist, p_item_cat, p_playlist->p_local_category, i_pos );
255
256     GoAndPreparse( p_playlist, i_mode, p_item_cat, p_item_one );
257
258     vlc_mutex_unlock( &p_playlist->object_lock );
259     return VLC_SUCCESS;
260 }
261
262 /** Add an input item to p_direct_parent in the category tree, and to the
263  *  matching top category in onelevel **/
264 int playlist_BothAddInput( playlist_t *p_playlist,
265                            input_item_t *p_input,
266                            playlist_item_t *p_direct_parent,
267                            int i_mode, int i_pos )
268 {
269     playlist_item_t *p_item_cat, *p_item_one, *p_up;
270     int i_top;
271     assert( p_input );
272     vlc_mutex_lock( & p_playlist->object_lock );
273
274     /* Add to category */
275     p_item_cat = playlist_ItemNewFromInput( p_playlist, p_input );
276     if( p_item_cat == NULL ) return VLC_EGENERIC;
277     AddItem( p_playlist, p_item_cat, p_direct_parent, i_pos );
278
279     /* Add to onelevel */
280     p_item_one = playlist_ItemNewFromInput( p_playlist, p_input );
281     if( p_item_one == NULL ) return VLC_EGENERIC;
282
283     p_up = p_direct_parent;
284     while( p_up->p_parent != p_playlist->p_root_category )
285     {
286         p_up = p_up->p_parent;
287     }
288     for( i_top = 0 ; i_top < p_playlist->p_root_onelevel->i_children; i_top++ )
289     {
290         if( p_playlist->p_root_onelevel->pp_children[i_top]->p_input->i_id == p_up->p_input->i_id )
291         {
292             AddItem( p_playlist, p_item_one,
293                      p_playlist->p_root_onelevel->pp_children[i_top], i_pos );
294             break;
295         }
296     }
297     GoAndPreparse( p_playlist, i_mode, p_item_cat, p_item_one );
298
299     vlc_mutex_unlock( &p_playlist->object_lock );
300     return VLC_SUCCESS;
301 }
302
303 /**
304  * Add an item where it should be added, when adding from a node
305  * (ex: directory access, playlist demuxers, services discovery, ... )
306  * \param p_playlist the playlist
307  * \param p_input the input to add
308  * \param p_parent the direct node
309  * \param p_item_in_category the item within category root (as returned by playlist_ItemToNode)
310  * \param b_forced_parent Are we forced to add only to p_parent ?
311  */
312 void playlist_AddWhereverNeeded( playlist_t *p_playlist, input_item_t *p_input,
313                                  playlist_item_t *p_parent,
314                                  playlist_item_t *p_item_in_category,
315                                  vlc_bool_t b_forced_parent, int i_mode )
316 {
317     /* If we have forced a parent :
318      *   - Just add the input to the forced parent (which should be p_parent)
319      * Else
320      *    - If we have item in category, add to it, and to onelevel (bothadd)
321      *    - If we don't, just add to p_parent
322      */
323     if( b_forced_parent == VLC_TRUE || !p_item_in_category  )
324     {
325         playlist_NodeAddInput( p_playlist, p_input, p_parent, i_mode,
326                                PLAYLIST_END );
327     }
328     else
329     {
330         playlist_BothAddInput( p_playlist, p_input, p_item_in_category,
331                                i_mode, PLAYLIST_END );
332     }
333 }
334
335
336 /** Add an input item to a given node */
337 playlist_item_t * playlist_NodeAddInput( playlist_t *p_playlist,
338                                          input_item_t *p_input,
339                                          playlist_item_t *p_parent,
340                                          int i_mode, int i_pos )
341 {
342     playlist_item_t *p_item;
343     assert( p_input );
344     assert( p_parent && p_parent->i_children != -1 );
345
346     vlc_mutex_lock( &p_playlist->object_lock );
347
348     p_item = playlist_ItemNewFromInput( p_playlist, p_input );
349     if( p_item == NULL ) return NULL;
350     AddItem( p_playlist, p_item, p_parent, i_pos );
351
352     vlc_mutex_unlock( &p_playlist->object_lock );
353
354     return p_item;
355 }
356
357 /** Add a playlist item to a given node */
358 void playlist_NodeAddItem( playlist_t *p_playlist, playlist_item_t *p_item,
359                            playlist_item_t *p_parent, int i_mode, int i_pos )
360 {
361     vlc_mutex_lock( &p_playlist->object_lock );
362     AddItem( p_playlist, p_item, p_parent, i_pos );
363     vlc_mutex_unlock( &p_playlist->object_lock );
364 }
365
366 /*****************************************************************************
367  * Playlist item misc operations
368  *****************************************************************************/
369
370 /**
371  * Transform an item to a node. Return the node in the category tree, or NULL
372  * if not found there
373  * This function must be entered without the playlist lock
374  */
375 playlist_item_t *playlist_ItemToNode( playlist_t *p_playlist,
376                                       playlist_item_t *p_item )
377 {
378     /* What we do
379      * Find the input in CATEGORY.
380      *  - If we find it
381      *    - change it to node
382      *    - we'll return it at the end
383      *    - If we are a direct child of onelevel root, change to node, else
384      *      delete the input from ONELEVEL
385      *  - If we don't find it, just change to node (we are probably in VLM)
386      *    and return NULL
387      *
388      * If we were in ONELEVEL, we thus retrieve the node in CATEGORY (will be
389      * useful for later BothAddInput )
390      */
391
392     /** \todo First look if we don't already have it */
393     playlist_item_t *p_item_in_category = playlist_ItemFindFromInputAndRoot(
394                                             p_playlist, p_item->p_input->i_id,
395                                             p_playlist->p_root_category );
396
397     if( p_item_in_category )
398     {
399         playlist_item_t *p_item_in_one = playlist_ItemFindFromInputAndRoot(
400                                             p_playlist, p_item->p_input->i_id,
401                                             p_playlist->p_root_onelevel );
402         ChangeToNode( p_playlist, p_item_in_category );
403         if( p_item_in_one->p_parent == p_playlist->p_root_onelevel )
404         {
405             ChangeToNode( p_playlist, p_item_in_one );
406         }
407         else
408         {
409             playlist_DeleteFromInput( p_playlist, p_item->p_input->i_id,
410                                       p_playlist->p_root_onelevel, VLC_FALSE );
411         }
412         var_SetInteger( p_playlist, "item-change", p_item->p_input->i_id );
413         return p_item_in_category;
414     }
415     else
416     {
417         ChangeToNode( p_playlist, p_item );
418         return NULL;
419     }
420 }
421
422 /** Transform an item to a node
423  *  This function must be entered without the playlist lock
424  *  \see playlist_ItemToNode
425  */
426 playlist_item_t * playlist_LockItemToNode( playlist_t *p_playlist,
427                                            playlist_item_t *p_item )
428 {
429     playlist_item_t *p_ret;
430     vlc_mutex_lock( &p_playlist->object_lock );
431     p_ret = playlist_ItemToNode( p_playlist, p_item );
432     vlc_mutex_unlock( &p_playlist->object_lock );
433     return p_ret;
434 }
435
436 /** Find an item within a root, given its input id.
437  * \return the first found item, or NULL if not found
438  */
439 playlist_item_t *playlist_ItemFindFromInputAndRoot( playlist_t *p_playlist,
440                                                     int i_input_id,
441                                                     playlist_item_t *p_root )
442 {
443     int i;
444     for( i = 0 ; i< p_root->i_children ; i++ )
445     {
446         if( p_root->pp_children[i]->i_children == -1 &&
447             p_root->pp_children[i]->p_input->i_id == i_input_id )
448         {
449             return p_root->pp_children[i];
450         }
451         else if( p_root->pp_children[i]->i_children >= 0 )
452         {
453             playlist_item_t *p_search =
454                  playlist_ItemFindFromInputAndRoot( p_playlist, i_input_id,
455                                                     p_root->pp_children[i] );
456             if( p_search ) return p_search;
457         }
458     }
459     return NULL;
460 }
461
462
463 /**
464  * Moves an item
465  *
466  * This function must be entered with the playlist lock
467  *
468  * \param p_playlist the playlist
469  * \param p_item the item to move
470  * \param p_node the new parent of the item
471  * \param i_newpos the new position under this new parent
472  * \return VLC_SUCCESS or an error
473  */
474 int playlist_TreeMove( playlist_t * p_playlist, playlist_item_t *p_item,
475                        playlist_item_t *p_node, int i_newpos )
476 {
477     int j;
478     playlist_item_t *p_detach = NULL;
479
480     if( p_node->i_children == -1 ) return VLC_EGENERIC;
481
482     p_detach = p_item->p_parent;
483     for( j = 0; j < p_detach->i_children; j++ )
484     {
485          if( p_detach->pp_children[j] == p_item ) break;
486     }
487     REMOVE_ELEM( p_detach->pp_children, p_detach->i_children, j );
488
489     /* Attach to new parent */
490     INSERT_ELEM( p_node->pp_children, p_node->i_children, i_newpos, p_item );
491
492     return VLC_SUCCESS;
493 }
494
495 /** Send a notification that an item has been added to a node */
496 void playlist_SendAddNotify( playlist_t *p_playlist, int i_item_id,
497                              int i_node_id )
498 {
499     vlc_value_t val;
500     playlist_add_t *p_add = (playlist_add_t *)malloc(sizeof( playlist_add_t));
501     p_add->i_item = i_item_id;
502     p_add->i_node = i_node_id;
503     val.p_address = p_add;
504     var_Set( p_playlist, "item-append", val );
505     free( p_add );
506 }
507
508 /*****************************************************************************
509  * Playlist item accessors
510  *****************************************************************************/
511
512 /** Set the name of a playlist item */
513 int playlist_ItemSetName( playlist_item_t *p_item, char *psz_name )
514 {
515     if( psz_name && p_item )
516     {
517         if( p_item->p_input->psz_name ) free( p_item->p_input->psz_name );
518         p_item->p_input->psz_name = strdup( psz_name );
519         return VLC_SUCCESS;
520     }
521     return VLC_EGENERIC;
522 }
523
524 /** Set the duration of a playlist item
525  * \param i_duration the new duration in microseconds
526  */
527 int playlist_ItemSetDuration( playlist_item_t *p_item, mtime_t i_duration )
528 {
529     char psz_buffer[MSTRTIME_MAX_SIZE];
530     if( p_item )
531     {
532         p_item->p_input->i_duration = i_duration;
533         if( i_duration != -1 )
534         {
535             secstotimestr( psz_buffer, (int)(i_duration/1000000) );
536         }
537         else
538         {
539             memcpy( psz_buffer, "--:--:--", sizeof("--:--:--") );
540         }
541         vlc_input_item_AddInfo( p_item->p_input, _("General") , _("Duration"),
542                                 "%s", psz_buffer );
543
544         return VLC_SUCCESS;
545     }
546     return VLC_EGENERIC;
547 }
548
549 /** Add an option to a playlist item */
550 void playlist_ItemAddOption( playlist_item_t *p_item,
551                              const char *psz_option)
552 {
553     vlc_input_item_AddOption( p_item->p_input, psz_option );
554 }
555
556 /***************************************************************************
557  * The following functions are local
558  ***************************************************************************/
559
560 /* Enqueue an item for preparsing, and play it, if needed */
561 void GoAndPreparse( playlist_t *p_playlist, int i_mode,
562                     playlist_item_t *p_item_cat, playlist_item_t *p_item_one )
563 {
564     if( (i_mode & PLAYLIST_GO ) )
565     {
566         playlist_item_t *p_parent = p_item_one;
567         playlist_item_t *p_toplay = NULL;
568         while( p_parent )
569         {
570             if( p_parent == p_playlist->p_root_category )
571             {
572                 p_toplay = p_item_cat; break;
573             }
574             else if( p_parent == p_playlist->p_root_onelevel )
575             {
576                 p_toplay = p_item_one; break;
577             }
578             p_parent = p_parent->p_parent;
579         }
580         assert( p_toplay );
581         p_playlist->request.b_request = VLC_TRUE;
582         p_playlist->request.p_item = p_toplay;
583         if( p_playlist->p_input )
584         {
585             input_StopThread( p_playlist->p_input );
586         }
587         p_playlist->request.i_status = PLAYLIST_RUNNING;
588     }
589     if( i_mode & PLAYLIST_PREPARSE &&
590         var_CreateGetBool( p_playlist, "auto-preparse" ) )
591     {
592         playlist_PreparseEnqueue( p_playlist, p_item_cat->p_input );
593     }
594 }
595
596 /* Add the playlist item to the requested node and fire a notification */
597 void AddItem( playlist_t *p_playlist, playlist_item_t *p_item,
598               playlist_item_t *p_node, int i_pos )
599 {
600     INSERT_ELEM( p_playlist->pp_items, p_playlist->i_size,
601                  p_playlist->i_size, p_item );
602 #if 0
603     fprintf( stderr, "Adding input %s (id %i) - playlist item id %i "
604                      "to node %s (id %i)\n",
605                      p_item->p_input->psz_name, p_item->p_input->i_id,
606                      p_item->i_id, p_node->p_input->psz_name,
607                      p_node->i_id );
608 #endif
609     INSERT_ELEM( p_playlist->pp_all_items, p_playlist->i_all_size,
610                  p_playlist->i_all_size, p_item );
611     p_playlist->i_enabled ++;
612
613     if( i_pos == PLAYLIST_END )
614     {
615         playlist_NodeAppend( p_playlist, p_item, p_node );
616     }
617     else
618     {
619         playlist_NodeInsert( p_playlist, p_item, p_node, i_pos );
620     }
621
622     playlist_SendAddNotify( p_playlist, p_item->i_id, p_node->i_id );
623 }
624
625 /* Actually convert an item to a node */
626 void ChangeToNode( playlist_t *p_playlist, playlist_item_t *p_item )
627 {
628     int i;
629     if( p_item->i_children == -1 )
630         p_item->i_children = 0;
631
632     /* Remove it from the array of available items */
633     for( i = 0 ; i < p_playlist->i_size ; i++ )
634     {
635         if( p_item == p_playlist->pp_items[i] )
636         {
637             REMOVE_ELEM( p_playlist->pp_items, p_playlist->i_size, i );
638         }
639     }
640 }
641
642 /* Do the actual removal */
643 int DeleteInner( playlist_t * p_playlist, playlist_item_t *p_item,
644                 vlc_bool_t b_stop )
645 {
646     int i, i_top, i_bottom;
647     int i_id = p_item->i_id;
648     vlc_bool_t b_flag = VLC_FALSE;
649
650     //fprintf( stderr, "Deleting item %i - %s\n", i_id,
651     //                                            p_item->p_input->psz_name );
652
653     if( p_item->i_children > -1 )
654     {
655         return playlist_NodeDelete( p_playlist, p_item, VLC_TRUE, VLC_FALSE );
656     }
657     var_SetInteger( p_playlist, "item-deleted", i_id );
658
659     /* Remove the item from the bank */
660     i_bottom = 0; i_top = p_playlist->i_all_size - 1;
661     i = i_top / 2;
662     while( p_playlist->pp_all_items[i]->i_id != i_id &&
663            i_top > i_bottom )
664     {
665         if( p_playlist->pp_all_items[i]->i_id < i_id )
666         {
667             i_bottom = i + 1;
668         }
669         else
670         {
671             i_top = i - 1;
672         }
673         i = i_bottom + ( i_top - i_bottom ) / 2;
674     }
675     if( p_playlist->pp_all_items[i]->i_id == i_id )
676     {
677         REMOVE_ELEM( p_playlist->pp_all_items, p_playlist->i_all_size, i );
678     }
679
680     /* Check if it is the current item */
681     if( p_playlist->status.p_item == p_item )
682     {
683         /* Hack we don't call playlist_Control for lock reasons */
684         if( b_stop )
685         {
686             p_playlist->status.i_status = PLAYLIST_STOPPED;
687             p_playlist->request.b_request = VLC_TRUE;
688             p_playlist->request.p_item = NULL;
689             msg_Info( p_playlist, "stopping playback" );
690         }
691         b_flag = VLC_TRUE;
692     }
693
694     msg_Dbg( p_playlist, "deleting playlist item `%s'",
695                           p_item->p_input->psz_name );
696
697     /* Remove the item from its parent */
698     playlist_NodeRemoveItem( p_playlist, p_item, p_item->p_parent );
699
700     if( b_flag == VLC_FALSE )
701         playlist_ItemDelete( p_item );
702     else
703         p_item->i_flags |= PLAYLIST_REMOVE_FLAG;
704
705     return VLC_SUCCESS;
706 }