]> git.sesse.net Git - vlc/blob - src/playlist/item.c
Re-enable PLAYLIST_GO
[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     p_input->i_id = ++p_playlist->i_last_input_id;
241
242     msg_Dbg( p_playlist, "adding playlist item `%s' ( %s )",
243              p_input->psz_name, p_input->psz_uri );
244
245     vlc_mutex_lock( &p_playlist->object_lock );
246
247     /* Add to ONELEVEL */
248     p_item_one = playlist_ItemNewFromInput( p_playlist, p_input );
249     if( p_item_one == NULL ) return VLC_EGENERIC;
250     AddItem( p_playlist, p_item_one ,p_playlist->p_local_onelevel, i_pos );
251
252     /* Add to CATEGORY */
253     p_item_cat = playlist_ItemNewFromInput( p_playlist, p_input );
254     if( p_item_cat == NULL ) return VLC_EGENERIC;
255     AddItem( p_playlist, p_item_cat, p_playlist->p_local_category, i_pos );
256
257     GoAndPreparse( p_playlist, i_mode, p_item_cat, p_item_one );
258
259     vlc_mutex_unlock( &p_playlist->object_lock );
260     return VLC_SUCCESS;
261 }
262
263 /** Add an input item to p_direct_parent in the category tree, and to the
264  *  matching top category in onelevel **/
265 int playlist_BothAddInput( playlist_t *p_playlist,
266                            input_item_t *p_input,
267                            playlist_item_t *p_direct_parent,
268                            int i_mode, int i_pos )
269 {
270     playlist_item_t *p_item_cat, *p_item_one, *p_up;
271     int i_top;
272     assert( p_input );
273     vlc_mutex_lock( & p_playlist->object_lock );
274
275     /* Add to category */
276     p_item_cat = playlist_ItemNewFromInput( p_playlist, p_input );
277     if( p_item_cat == NULL ) return VLC_EGENERIC;
278     AddItem( p_playlist, p_item_cat, p_direct_parent, i_pos );
279
280     /* Add to onelevel */
281     p_item_one = playlist_ItemNewFromInput( p_playlist, p_input );
282     if( p_item_one == NULL ) return VLC_EGENERIC;
283
284     p_up = p_direct_parent;
285     while( p_up->p_parent != p_playlist->p_root_category )
286     {
287         p_up = p_up->p_parent;
288     }
289     for( i_top = 0 ; i_top < p_playlist->p_root_onelevel->i_children; i_top++ )
290     {
291         if( p_playlist->p_root_onelevel->pp_children[i_top]->p_input->i_id == p_up->p_input->i_id )
292         {
293             AddItem( p_playlist, p_item_one,
294                      p_playlist->p_root_onelevel->pp_children[i_top], i_pos );
295             break;
296         }
297     }
298     GoAndPreparse( p_playlist, i_mode, p_item_cat, p_item_one );
299
300     vlc_mutex_unlock( &p_playlist->object_lock );
301     return VLC_SUCCESS;
302 }
303
304 /**
305  * Add an item where it should be added, when adding from a node
306  * (ex: directory access, playlist demuxers, services discovery, ... )
307  * \param p_playlist the playlist
308  * \param p_input the input to add
309  * \param p_parent the direct node
310  * \param p_item_in_category the item within category root (as returned by playlist_ItemToNode)
311  * \param b_forced_parent Are we forced to add only to p_parent ?
312  */
313 void playlist_AddWhereverNeeded( playlist_t *p_playlist, input_item_t *p_input,
314                                  playlist_item_t *p_parent,
315                                  playlist_item_t *p_item_in_category,
316                                  vlc_bool_t b_forced_parent, int i_mode )
317 {
318     /* If we have forced a parent :
319      *   - Just add the input to the forced parent (which should be p_parent)
320      * Else
321      *    - If we have item in category, add to it, and to onelevel (bothadd)
322      *    - If we don't, just add to p_parent
323      */
324     if( b_forced_parent == VLC_TRUE || !p_item_in_category  )
325     {
326         playlist_NodeAddInput( p_playlist, p_input, p_parent, i_mode,
327                                PLAYLIST_END );
328     }
329     else
330     {
331         playlist_BothAddInput( p_playlist, p_input, p_item_in_category,
332                                i_mode, PLAYLIST_END );
333     }
334 }
335
336
337 /** Add an input item to a given node */
338 playlist_item_t * playlist_NodeAddInput( playlist_t *p_playlist,
339                                          input_item_t *p_input,
340                                          playlist_item_t *p_parent,
341                                          int i_mode, int i_pos )
342 {
343     playlist_item_t *p_item;
344     assert( p_input );
345     assert( p_parent && p_parent->i_children != -1 );
346
347     vlc_mutex_lock( &p_playlist->object_lock );
348
349     p_item = playlist_ItemNewFromInput( p_playlist, p_input );
350     if( p_item == NULL ) return NULL;
351     AddItem( p_playlist, p_item, p_parent, i_pos );
352
353     vlc_mutex_unlock( &p_playlist->object_lock );
354
355     return p_item;
356 }
357
358 /** Add a playlist item to a given node */
359 void playlist_NodeAddItem( playlist_t *p_playlist, playlist_item_t *p_item,
360                            playlist_item_t *p_parent, int i_mode, int i_pos )
361 {
362     vlc_mutex_lock( &p_playlist->object_lock );
363     AddItem( p_playlist, p_item, p_parent, i_pos );
364     vlc_mutex_unlock( &p_playlist->object_lock );
365 }
366
367 /*****************************************************************************
368  * Playlist item misc operations
369  *****************************************************************************/
370
371 /**
372  * Transform an item to a node. Return the node in the category tree, or NULL
373  * if not found there
374  * This function must be entered without the playlist lock
375  */
376 playlist_item_t *playlist_ItemToNode( playlist_t *p_playlist,
377                                       playlist_item_t *p_item )
378 {
379     /* What we do
380      * Find the input in CATEGORY.
381      *  - If we find it
382      *    - change it to node
383      *    - we'll return it at the end
384      *    - If we are a direct child of onelevel root, change to node, else
385      *      delete the input from ONELEVEL
386      *  - If we don't find it, just change to node (we are probably in VLM)
387      *    and return NULL
388      *
389      * If we were in ONELEVEL, we thus retrieve the node in CATEGORY (will be
390      * useful for later BothAddInput )
391      */
392
393     /** \todo First look if we don't already have it */
394     playlist_item_t *p_item_in_category = playlist_ItemFindFromInputAndRoot(
395                                             p_playlist, p_item->p_input->i_id,
396                                             p_playlist->p_root_category );
397
398     if( p_item_in_category )
399     {
400         playlist_item_t *p_item_in_one = playlist_ItemFindFromInputAndRoot(
401                                             p_playlist, p_item->p_input->i_id,
402                                             p_playlist->p_root_onelevel );
403         ChangeToNode( p_playlist, p_item_in_category );
404         if( p_item_in_one->p_parent == p_playlist->p_root_onelevel )
405         {
406             ChangeToNode( p_playlist, p_item_in_one );
407         }
408         else
409         {
410             playlist_DeleteFromInput( p_playlist, p_item->p_input->i_id,
411                                       p_playlist->p_root_onelevel, VLC_FALSE );
412         }
413         var_SetInteger( p_playlist, "item-change", p_item->p_input->i_id );
414         return p_item_in_category;
415     }
416     else
417     {
418         ChangeToNode( p_playlist, p_item );
419         return NULL;
420     }
421 }
422
423 /** Transform an item to a node
424  *  This function must be entered without the playlist lock
425  *  \see playlist_ItemToNode
426  */
427 playlist_item_t * playlist_LockItemToNode( playlist_t *p_playlist,
428                                            playlist_item_t *p_item )
429 {
430     playlist_item_t *p_ret;
431     vlc_mutex_lock( &p_playlist->object_lock );
432     p_ret = playlist_ItemToNode( p_playlist, p_item );
433     vlc_mutex_unlock( &p_playlist->object_lock );
434     return p_ret;
435 }
436
437 /** Find an item within a root, given its input id.
438  * \return the first found item, or NULL if not found
439  */
440 playlist_item_t *playlist_ItemFindFromInputAndRoot( playlist_t *p_playlist,
441                                                     int i_input_id,
442                                                     playlist_item_t *p_root )
443 {
444     int i;
445     for( i = 0 ; i< p_root->i_children ; i++ )
446     {
447         if( p_root->pp_children[i]->i_children == -1 &&
448             p_root->pp_children[i]->p_input->i_id == i_input_id )
449         {
450             return p_root->pp_children[i];
451         }
452         else if( p_root->pp_children[i]->i_children >= 0 )
453         {
454             playlist_item_t *p_search =
455                  playlist_ItemFindFromInputAndRoot( p_playlist, i_input_id,
456                                                     p_root->pp_children[i] );
457             if( p_search ) return p_search;
458         }
459     }
460     return NULL;
461 }
462
463
464 /**
465  * Moves an item
466  *
467  * This function must be entered with the playlist lock
468  *
469  * \param p_playlist the playlist
470  * \param p_item the item to move
471  * \param p_node the new parent of the item
472  * \param i_newpos the new position under this new parent
473  * \return VLC_SUCCESS or an error
474  */
475 int playlist_TreeMove( playlist_t * p_playlist, playlist_item_t *p_item,
476                        playlist_item_t *p_node, int i_newpos )
477 {
478     int j;
479     playlist_item_t *p_detach = NULL;
480
481     if( p_node->i_children == -1 ) return VLC_EGENERIC;
482
483     p_detach = p_item->p_parent;
484     for( j = 0; j < p_detach->i_children; j++ )
485     {
486          if( p_detach->pp_children[j] == p_item ) break;
487     }
488     REMOVE_ELEM( p_detach->pp_children, p_detach->i_children, j );
489
490     /* Attach to new parent */
491     INSERT_ELEM( p_node->pp_children, p_node->i_children, i_newpos, p_item );
492
493     return VLC_SUCCESS;
494 }
495
496 /** Send a notification that an item has been added to a node */
497 void playlist_SendAddNotify( playlist_t *p_playlist, int i_item_id,
498                              int i_node_id )
499 {
500     vlc_value_t val;
501     playlist_add_t *p_add = (playlist_add_t *)malloc(sizeof( playlist_add_t));
502     p_add->i_item = i_item_id;
503     p_add->i_node = i_node_id;
504     val.p_address = p_add;
505     var_Set( p_playlist, "item-append", val );
506     free( p_add );
507 }
508
509 /*****************************************************************************
510  * Playlist item accessors
511  *****************************************************************************/
512
513 /** Set the name of a playlist item */
514 int playlist_ItemSetName( playlist_item_t *p_item, char *psz_name )
515 {
516     if( psz_name && p_item )
517     {
518         if( p_item->p_input->psz_name ) free( p_item->p_input->psz_name );
519         p_item->p_input->psz_name = strdup( psz_name );
520         return VLC_SUCCESS;
521     }
522     return VLC_EGENERIC;
523 }
524
525 /** Set the duration of a playlist item
526  * \param i_duration the new duration in microseconds
527  */
528 int playlist_ItemSetDuration( playlist_item_t *p_item, mtime_t i_duration )
529 {
530     char psz_buffer[MSTRTIME_MAX_SIZE];
531     if( p_item )
532     {
533         p_item->p_input->i_duration = i_duration;
534         if( i_duration != -1 )
535         {
536             secstotimestr( psz_buffer, (int)(i_duration/1000000) );
537         }
538         else
539         {
540             memcpy( psz_buffer, "--:--:--", sizeof("--:--:--") );
541         }
542         vlc_input_item_AddInfo( p_item->p_input, _("General") , _("Duration"),
543                                 "%s", psz_buffer );
544
545         return VLC_SUCCESS;
546     }
547     return VLC_EGENERIC;
548 }
549
550 /** Add an option to a playlist item */
551 void playlist_ItemAddOption( playlist_item_t *p_item,
552                              const char *psz_option)
553 {
554     vlc_input_item_AddOption( p_item->p_input, psz_option );
555 }
556
557 /***************************************************************************
558  * The following functions are local
559  ***************************************************************************/
560
561 /* Enqueue an item for preparsing, and play it, if needed */
562 void GoAndPreparse( playlist_t *p_playlist, int i_mode,
563                     playlist_item_t *p_item_cat, playlist_item_t *p_item_one )
564 {
565     if( (i_mode & PLAYLIST_GO ) )
566     {
567         playlist_item_t *p_parent = p_item_one;
568         playlist_item_t *p_toplay = NULL;
569         while( p_parent )
570         {
571             if( p_parent == p_playlist->p_root_category )
572             {
573                 p_toplay = p_item_cat; break;
574             }
575             else if( p_parent == p_playlist->p_root_onelevel )
576             {
577                 p_toplay = p_item_one; break;
578             }
579             p_parent = p_parent->p_parent;
580         }
581         assert( p_toplay );
582         p_playlist->request.b_request = VLC_TRUE;
583         p_playlist->request.p_item = p_toplay;
584         if( p_playlist->p_input )
585         {
586             input_StopThread( p_playlist->p_input );
587         }
588         p_playlist->request.i_status = PLAYLIST_RUNNING;
589     }
590     if( i_mode & PLAYLIST_PREPARSE &&
591         var_CreateGetBool( p_playlist, "auto-preparse" ) )
592     {
593         playlist_PreparseEnqueue( p_playlist, p_item_cat->p_input );
594     }
595 }
596
597 /* Add the playlist item to the requested node and fire a notification */
598 void AddItem( playlist_t *p_playlist, playlist_item_t *p_item,
599               playlist_item_t *p_node, int i_pos )
600 {
601     INSERT_ELEM( p_playlist->pp_items, p_playlist->i_size,
602                  p_playlist->i_size, p_item );
603 #if 0
604     fprintf( stderr, "Adding input %s (id %i) - playlist item id %i "
605                      "to node %s (id %i)\n",
606                      p_item->p_input->psz_name, p_item->p_input->i_id,
607                      p_item->i_id, p_node->p_input->psz_name,
608                      p_node->i_id );
609 #endif
610     INSERT_ELEM( p_playlist->pp_all_items, p_playlist->i_all_size,
611                  p_playlist->i_all_size, p_item );
612     p_playlist->i_enabled ++;
613
614     if( i_pos == PLAYLIST_END )
615     {
616         playlist_NodeAppend( p_playlist, p_item, p_node );
617     }
618     else
619     {
620         playlist_NodeInsert( p_playlist, p_item, p_node, i_pos );
621     }
622
623     playlist_SendAddNotify( p_playlist, p_item->i_id, p_node->i_id );
624 }
625
626 /* Actually convert an item to a node */
627 void ChangeToNode( playlist_t *p_playlist, playlist_item_t *p_item )
628 {
629     int i;
630     if( p_item->i_children == -1 )
631         p_item->i_children = 0;
632
633     /* Remove it from the array of available items */
634     for( i = 0 ; i < p_playlist->i_size ; i++ )
635     {
636         if( p_item == p_playlist->pp_items[i] )
637         {
638             REMOVE_ELEM( p_playlist->pp_items, p_playlist->i_size, i );
639         }
640     }
641 }
642
643 /* Do the actual removal */
644 int DeleteInner( playlist_t * p_playlist, playlist_item_t *p_item,
645                 vlc_bool_t b_stop )
646 {
647     int i, i_top, i_bottom;
648     int i_id = p_item->i_id;
649     vlc_bool_t b_flag = VLC_FALSE;
650
651     //fprintf( stderr, "Deleting item %i - %s\n", i_id,
652     //                                            p_item->p_input->psz_name );
653
654     if( p_item->i_children > -1 )
655     {
656         return playlist_NodeDelete( p_playlist, p_item, VLC_TRUE, VLC_FALSE );
657     }
658     var_SetInteger( p_playlist, "item-deleted", i_id );
659
660     /* Remove the item from the bank */
661     i_bottom = 0; i_top = p_playlist->i_all_size - 1;
662     i = i_top / 2;
663     while( p_playlist->pp_all_items[i]->i_id != i_id &&
664            i_top > i_bottom )
665     {
666         if( p_playlist->pp_all_items[i]->i_id < i_id )
667         {
668             i_bottom = i + 1;
669         }
670         else
671         {
672             i_top = i - 1;
673         }
674         i = i_bottom + ( i_top - i_bottom ) / 2;
675     }
676     if( p_playlist->pp_all_items[i]->i_id == i_id )
677     {
678         REMOVE_ELEM( p_playlist->pp_all_items, p_playlist->i_all_size, i );
679     }
680
681     /* Check if it is the current item */
682     if( p_playlist->status.p_item == p_item )
683     {
684         /* Hack we don't call playlist_Control for lock reasons */
685         if( b_stop )
686         {
687             p_playlist->status.i_status = PLAYLIST_STOPPED;
688             p_playlist->request.b_request = VLC_TRUE;
689             p_playlist->request.p_item = NULL;
690             msg_Info( p_playlist, "stopping playback" );
691         }
692         b_flag = VLC_TRUE;
693     }
694
695     msg_Dbg( p_playlist, "deleting playlist item `%s'",
696                           p_item->p_input->psz_name );
697
698     /* Remove the item from its parent */
699     playlist_NodeRemoveItem( p_playlist, p_item, p_item->p_parent );
700
701     if( b_flag == VLC_FALSE )
702         playlist_ItemDelete( p_item );
703     else
704         p_item->i_flags |= PLAYLIST_REMOVE_FLAG;
705
706     return VLC_SUCCESS;
707 }