]> git.sesse.net Git - vlc/blob - src/playlist/item-ext.c
* src/input/control.c: added INPUT_ADD_INFO/INPUT_SET_NAME to input_Control().
[vlc] / src / playlist / item-ext.c
1 /*****************************************************************************
2  * item-ext.c : Playlist item management functions
3  *****************************************************************************
4  * Copyright (C) 1999-2004 VideoLAN
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24 #include <stdlib.h>                                      /* free(), strtol() */
25 #include <stdio.h>                                              /* sprintf() */
26 #include <string.h>                                            /* strerror() */
27
28 #include <vlc/vlc.h>
29 #include <vlc/input.h>
30
31 #include "vlc_playlist.h"
32
33 /***************************************************************************
34  * Item creation/addition functions
35  ***************************************************************************/
36
37 /**
38  * Add a MRL into the playlist, duration and options given
39  *
40  * \param p_playlist the playlist to add into
41  * \param psz_uri the mrl to add to the playlist
42  * \param psz_name a text giving a name or description of this item
43  * \param i_mode the mode used when adding
44  * \param i_pos the position in the playlist where to add. If this is
45  *        PLAYLIST_END the item will be added at the end of the playlist
46  *        regardless of it's size
47  * \param i_duration length of the item in milliseconds.
48  * \param ppsz_options an array of options
49  * \param i_options the number of options
50  * \return The id of the playlist item
51 */
52 int playlist_AddExt( playlist_t *p_playlist, const char * psz_uri,
53                      const char *psz_name, int i_mode, int i_pos,
54                      mtime_t i_duration, const char **ppsz_options,
55                      int i_options )
56 {
57     playlist_item_t *p_item =
58         playlist_ItemNew( p_playlist , psz_uri, psz_name );
59
60     int i;
61
62     if( p_item == NULL )
63     {
64         msg_Err( p_playlist, "unable to add item to playlist" );
65         return -1;
66     }
67
68     p_item->input.i_duration = i_duration;
69
70     p_item->input.i_options = i_options;
71     p_item->input.ppsz_options = NULL;
72     for( i = 0; i < i_options; i++ )
73     {
74         if( i == 0 )
75         {
76             p_item->input.ppsz_options = malloc( i_options * sizeof(char *) );
77             if( !p_item->input.ppsz_options )
78             {
79                 p_item->input.i_options = 0;
80                 break;
81             }
82         }
83
84         p_item->input.ppsz_options[i] = strdup( ppsz_options[i] );
85     }
86
87     return playlist_AddItem( p_playlist, p_item, i_mode, i_pos );
88 }
89
90 /**
91  * Add a MRL into the playlist.
92  *
93  * \param p_playlist the playlist to add into
94  * \param psz_uri the mrl to add to the playlist
95  * \param psz_name a text giving a name or description of this item
96  * \param i_mode the mode used when adding
97  * \param i_pos the position in the playlist where to add. If this is
98  *        PLAYLIST_END the item will be added at the end of the playlist
99  *        regardless of it's size
100  * \return The id of the playlist item
101 */
102 int playlist_Add( playlist_t *p_playlist, const char *psz_uri,
103                   const char *psz_name, int i_mode, int i_pos )
104 {
105     return playlist_AddExt( p_playlist, psz_uri, psz_name, i_mode, i_pos,
106                             -1, NULL, 0 );
107 }
108
109 /***************************************************************************
110  * Item search functions
111  ***************************************************************************/
112
113 /**
114  * Search the position of an item by its id
115  * This function must be entered with the playlist lock
116  *
117  * \param p_playlist the playlist
118  * \param i_id the id to find
119  * \return the position, or VLC_EGENERIC on failure
120  */
121 int playlist_GetPositionById( playlist_t * p_playlist , int i_id )
122 {
123     int i;
124     for( i =  0 ; i < p_playlist->i_size ; i++ )
125     {
126         if( p_playlist->pp_items[i]->i_id == i_id )
127         {
128             return i;
129         }
130     }
131     return VLC_EGENERIC;
132 }
133
134 /**
135  * Search an item by its id
136  *
137  * \param p_playlist the playlist
138  * \param i_id the id to find
139  * \return the item, or NULL on failure
140  */
141 playlist_item_t * playlist_ItemGetById( playlist_t * p_playlist , int i_id )
142 {
143     int i;
144     for( i =  0 ; i < p_playlist->i_size ; i++ )
145     {
146         if( p_playlist->pp_items[i]->i_id == i_id )
147         {
148             return p_playlist->pp_items[i];
149         }
150     }
151     return NULL;
152 }
153
154 /**
155  * Search an item by its position
156  * This function must be entered with the playlist lock
157  *
158  * \param p_playlist the playlist
159  * \param i_id the id to find
160  * \return the item, or NULL on failure
161  */
162 playlist_item_t * playlist_ItemGetByPos( playlist_t * p_playlist , int i_pos )
163 {
164     if( i_pos >= 0 && i_pos < p_playlist->i_size)
165     {
166         return p_playlist->pp_items[i_pos];
167     }
168     else if( p_playlist->i_size > 0)
169     {
170         return p_playlist->pp_items[p_playlist->i_index];
171     }
172     else
173     {
174         return NULL;
175     }
176 }
177
178 /**********************************************************************
179  * playlist_item_t structure accessors
180  * These functions give access to the fields of the playlist_item_t
181  * structure
182  **********************************************************************/
183
184 /**
185  * Set the group of a playlist item
186  *
187  * \param p_item the item
188  * \return VLC_SUCCESS on success
189  */
190 int playlist_ItemSetGroup( playlist_item_t *p_item, int i_group)
191 {
192     p_item->i_group = i_group;
193     return VLC_SUCCESS;
194 }
195
196 /**
197  * Set the group of a playlist item (by position)
198  * This function must be entered with the playlist lock
199  * Legacy function due to disappear (locks the whole playlist)
200  *
201  * \param p_playlist the playlist
202  * \param i_pos the postition of the item of which we change the group
203  * \param i_group the new group
204  * \return VLC_SUCCESS on success, VLC_EGENERIC on failure
205  */
206 int playlist_SetGroup( playlist_t *p_playlist, int i_pos, int i_group )
207 {
208     vlc_value_t val;
209     playlist_item_t *p_item;
210     if( !p_playlist )
211     {
212         return VLC_ENOOBJ;
213     }
214
215     p_item = playlist_ItemGetByPos( p_playlist , i_pos );
216     if( !p_item )
217     {
218         return VLC_ENOOBJ;
219     }
220
221     vlc_mutex_lock( &p_item->input.lock );
222     playlist_ItemSetGroup( p_item , i_group );
223     vlc_mutex_unlock( &p_item->input.lock );
224
225     val.b_bool = (i_pos >= 0 && i_pos < p_playlist->i_size ) ? i_pos : -1;
226     var_Set( p_playlist, "item-change", val );
227
228     return VLC_SUCCESS;
229 }
230
231 /**
232  * Set the name of a playlist item
233  *
234  * \param p_item the item
235  * \param psz_name the new name
236  * \return VLC_SUCCESS on success, VLC_EGENERIC on failure
237  */
238 int playlist_ItemSetName( playlist_item_t *p_item, char *psz_name )
239 {
240     if( psz_name && p_item )
241     {
242         p_item->input.psz_name = strdup( psz_name );
243         return VLC_SUCCESS;
244     }
245     return VLC_EGENERIC;
246 }
247
248 /**
249  * Set the name of a playlist item (by position)
250  * This function must be entered with the playlist lock
251  * Legacy function due to disappear (locks the whole playlist)
252  *
253  * \param p_playlist the playlist
254  * \param i_pos the position of the item of which we change the name
255  * \param psz_name the new name
256  * \return VLC_SUCCESS on success, VLC_EGENERIC on failure
257  */
258 int playlist_SetName( playlist_t *p_playlist, int i_pos, char *psz_name )
259 {
260     vlc_value_t val;
261     playlist_item_t *p_item;
262     if( !p_playlist )
263     {
264         return VLC_ENOOBJ;
265     }
266
267     p_item = playlist_ItemGetByPos( p_playlist , i_pos );
268     if( !p_item )
269     {
270         return VLC_ENOOBJ;
271     }
272
273     vlc_mutex_lock( &p_item->input.lock );
274     playlist_ItemSetName( p_item , psz_name );
275     vlc_mutex_unlock( &p_item->input.lock );
276
277     val.b_bool = (i_pos >= 0 && i_pos < p_playlist->i_size ) ? i_pos : -1;
278     var_Set( p_playlist, "item-change", val );
279
280     return VLC_SUCCESS;
281 }
282
283 /**
284  * Set the duration of a playlist item
285  * This function must be entered with the item lock
286  *
287  * \param p_item the item
288  * \param psz_name the new name
289  * \return VLC_SUCCESS on success, VLC_EGENERIC on failure
290  */
291 int playlist_ItemSetDuration( playlist_item_t *p_item, mtime_t i_duration )
292 {
293     char psz_buffer[MSTRTIME_MAX_SIZE];
294     if( p_item )
295     {
296         p_item->input.i_duration = i_duration;
297         if( i_duration != -1 )
298         {
299             secstotimestr( psz_buffer, i_duration/1000000 );
300         }
301         else
302         {
303             memcpy( psz_buffer, "--:--:--", sizeof("--:--:--") );
304         }
305         playlist_ItemAddInfo( p_item, _("General") , _("Duration"),
306                               "%s", psz_buffer );
307
308         return VLC_SUCCESS;
309     }
310     return VLC_EGENERIC;
311 }
312
313 /**
314  * Set the duration of a playlist item
315  * This function must be entered with the playlist lock
316  * Legacy function due to disappear (locks the whole playlist)
317  *
318  * \param p_playlist the playlist
319  * \param i_pos the position of the item of which we change the duration
320  * \param i_duration the duration to set
321  * \return VLC_SUCCESS on success, VLC_EGENERIC on failure
322  */
323 int playlist_SetDuration( playlist_t *p_playlist, int i_pos, mtime_t i_duration )
324 {
325     vlc_value_t val;
326     playlist_item_t *p_item;
327     if( !p_playlist )
328     {
329         return VLC_ENOOBJ;
330     }
331
332     p_item = playlist_ItemGetByPos( p_playlist , i_pos );
333     if( !p_item )
334     {
335         return VLC_ENOOBJ;
336     }
337
338     vlc_mutex_lock( &p_item->input.lock );
339     playlist_ItemSetDuration( p_item , i_duration );
340     vlc_mutex_unlock( &p_item->input.lock );
341
342     val.b_bool = (i_pos >= 0 && i_pos < p_playlist->i_size ) ? i_pos : -1;
343     var_Set( p_playlist, "item-change", val );
344
345     return VLC_SUCCESS;
346 }
347
348 /**********************************************************************
349  * Actions on existing playlist items
350  **********************************************************************/
351
352 /**
353  * delete an item from a playlist.
354  *
355  * \param p_playlist the playlist to remove from.
356  * \param i_pos the position of the item to remove
357  * \return returns 0
358  */
359 int playlist_Delete( playlist_t * p_playlist, int i_pos )
360 {
361     vlc_value_t     val;
362
363     /* if i_pos is the current played item, playlist should stop playing it */
364     if( ( p_playlist->i_status == PLAYLIST_RUNNING) &&
365                     (p_playlist->i_index == i_pos) )
366     {
367         playlist_Command( p_playlist, PLAYLIST_STOP, 0 );
368     }
369
370     vlc_mutex_lock( &p_playlist->object_lock );
371     if( i_pos >= 0 && i_pos < p_playlist->i_size )
372     {
373         playlist_item_t *p_item = p_playlist->pp_items[i_pos];
374
375         msg_Dbg( p_playlist, "deleting playlist item `%s'",
376                  p_item->input.psz_name );
377 #if 0
378         int i,j;
379
380         vlc_mutex_lock( &p_item->lock );
381
382         if( p_item->psz_name )
383         {
384             free( p_item->psz_name );
385         }
386         if( p_item->psz_uri )
387         {
388             free( p_item->psz_uri );
389         }
390
391         /* Free the info categories. Welcome to the segfault factory */
392         if( p_item->i_categories > 0 )
393         {
394             for( i = 0; i < p_item->i_categories; i++ )
395             {
396                 for( j= 0 ; j < p_item->pp_categories[i]->i_infos; j++)
397                 {
398                     if( p_item->pp_categories[i]->pp_infos[j]->psz_name)
399                     {
400                         free( p_item->pp_categories[i]->
401                                       pp_infos[j]->psz_name);
402                     }
403                     if( p_item->pp_categories[i]->pp_infos[j]->psz_value)
404                     {
405                         free( p_item->pp_categories[i]->
406                                       pp_infos[j]->psz_value);
407                     }
408                     free( p_item->pp_categories[i]->pp_infos[j] );
409                 }
410                 if( p_item->pp_categories[i]->i_infos )
411                     free( p_item->pp_categories[i]->pp_infos );
412
413                 if( p_item->pp_categories[i]->psz_name)
414                 {
415                     free( p_item->pp_categories[i]->psz_name );
416                 }
417                 free( p_item->pp_categories[i] );
418             }
419             free( p_item->pp_categories );
420         }
421
422         /* XXX: what if the item is still in use? */
423 #endif
424         playlist_ItemDelete( p_item );
425 #if 0
426         free( p_item );
427 #endif
428         if( i_pos <= p_playlist->i_index )
429         {
430             p_playlist->i_index--;
431         }
432
433         /* Renumber the playlist */
434         REMOVE_ELEM( p_playlist->pp_items, p_playlist->i_size, i_pos );
435
436         if( p_playlist->i_enabled > 0 ) p_playlist->i_enabled--;
437     }
438
439     vlc_mutex_unlock( &p_playlist->object_lock );
440
441     val.b_bool = VLC_TRUE;
442     var_Set( p_playlist, "intf-change", val );
443
444     return 0;
445 }
446
447 /**
448  * Clear all playlist items
449  *
450  * \param p_playlist the playlist to be cleared.
451  * \return returns 0
452  */
453 int playlist_Clear( playlist_t * p_playlist )
454 {
455
456     while( p_playlist->i_groups > 0 )
457     {
458         playlist_DeleteGroup( p_playlist, p_playlist->pp_groups[0]->i_id );
459     }
460
461     while( p_playlist->i_size > 0 )
462     {
463         playlist_Delete( p_playlist, 0 );
464     }
465
466     p_playlist->i_index = -1;
467     p_playlist->i_size = 0;
468     p_playlist->pp_items = NULL;
469
470     p_playlist->i_groups = 0;
471     p_playlist->pp_groups = NULL;
472
473     return 0;
474 }
475
476 /**
477  * Disables a playlist item
478  *
479  * \param p_playlist the playlist to disable from.
480  * \param i_pos the position of the item to disable
481  * \return returns 0
482  */
483 int playlist_Disable( playlist_t * p_playlist, int i_pos )
484 {
485     vlc_value_t     val;
486     vlc_mutex_lock( &p_playlist->object_lock );
487
488
489     if( i_pos >= 0 && i_pos < p_playlist->i_size )
490     {
491         msg_Dbg( p_playlist, "disabling playlist item `%s'",
492                  p_playlist->pp_items[i_pos]->input.psz_name );
493
494         if( p_playlist->pp_items[i_pos]->b_enabled == VLC_TRUE )
495             p_playlist->i_enabled--;
496         p_playlist->pp_items[i_pos]->b_enabled = VLC_FALSE;
497     }
498
499     vlc_mutex_unlock( &p_playlist->object_lock );
500
501     val.b_bool = i_pos;
502     var_Set( p_playlist, "item-change", val );
503
504     return 0;
505 }
506
507 /**
508  * Enables a playlist item
509  *
510  * \param p_playlist the playlist to enable from.
511  * \param i_pos the position of the item to enable
512  * \return returns 0
513  */
514 int playlist_Enable( playlist_t * p_playlist, int i_pos )
515 {
516     vlc_value_t     val;
517     vlc_mutex_lock( &p_playlist->object_lock );
518
519     if( i_pos >= 0 && i_pos < p_playlist->i_size )
520     {
521         msg_Dbg( p_playlist, "enabling playlist item `%s'",
522                  p_playlist->pp_items[i_pos]->input.psz_name );
523
524         if( p_playlist->pp_items[i_pos]->b_enabled == VLC_FALSE )
525             p_playlist->i_enabled++;
526
527         p_playlist->pp_items[i_pos]->b_enabled = VLC_TRUE;
528     }
529
530     vlc_mutex_unlock( &p_playlist->object_lock );
531
532     val.b_bool = i_pos;
533     var_Set( p_playlist, "item-change", val );
534
535     return 0;
536 }
537
538 /**
539  * Disables a playlist group
540  *
541  * \param p_playlist the playlist to disable from.
542  * \param i_group the id of the group to disable
543  * \return returns 0
544  */
545 int playlist_DisableGroup( playlist_t * p_playlist, int i_group )
546 {
547     vlc_value_t     val;
548     int i;
549     vlc_mutex_lock( &p_playlist->object_lock );
550
551     msg_Dbg( p_playlist, "disabling group %i", i_group );
552     for( i = 0 ; i< p_playlist->i_size; i++ )
553     {
554         if( p_playlist->pp_items[i]->i_group == i_group )
555         {
556             msg_Dbg( p_playlist, "disabling playlist item `%s'",
557                      p_playlist->pp_items[i]->input.psz_name );
558
559             if( p_playlist->pp_items[i]->b_enabled == VLC_TRUE )
560                 p_playlist->i_enabled--;
561
562             p_playlist->pp_items[i]->b_enabled = VLC_FALSE;
563             val.b_bool = i;
564             var_Set( p_playlist, "item-change", val );
565         }
566     }
567     vlc_mutex_unlock( &p_playlist->object_lock );
568
569     return 0;
570 }
571
572 /**
573  * Enables a playlist group
574  *
575  * \param p_playlist the playlist to enable from.
576  * \param i_group the id of the group to enable
577  * \return returns 0
578  */
579 int playlist_EnableGroup( playlist_t * p_playlist, int i_group )
580 {
581     vlc_value_t val;
582     int i;
583     vlc_mutex_lock( &p_playlist->object_lock );
584
585     for( i = 0; i< p_playlist->i_size; i++ )
586     {
587         if( p_playlist->pp_items[i]->i_group == i_group )
588         {
589             msg_Dbg( p_playlist, "enabling playlist item `%s'",
590                      p_playlist->pp_items[i]->input.psz_name );
591
592             if( p_playlist->pp_items[i]->b_enabled == VLC_FALSE )
593                 p_playlist->i_enabled++;
594
595             p_playlist->pp_items[i]->b_enabled = VLC_TRUE;
596             val.b_bool = i;
597             var_Set( p_playlist, "item-change", val );
598         }
599     }
600     vlc_mutex_unlock( &p_playlist->object_lock );
601
602     return 0;
603 }
604
605 /**
606  * Move an item in a playlist
607  *
608  * Move the item in the playlist with position i_pos before the current item
609  * at position i_newpos.
610  * \param p_playlist the playlist to move items in
611  * \param i_pos the position of the item to move
612  * \param i_newpos the position of the item that will be behind the moved item
613  *        after the move
614  * \return returns VLC_SUCCESS
615  */
616 int playlist_Move( playlist_t * p_playlist, int i_pos, int i_newpos )
617 {
618     vlc_value_t val;
619     vlc_mutex_lock( &p_playlist->object_lock );
620
621     /* take into account that our own row disappears. */
622     if( i_pos < i_newpos ) i_newpos--;
623
624     if( i_pos >= 0 && i_newpos >=0 && i_pos <= p_playlist->i_size &&
625         i_newpos <= p_playlist->i_size )
626     {
627         playlist_item_t * temp;
628
629         msg_Dbg( p_playlist, "moving playlist item `%s' (%i -> %i)",
630                  p_playlist->pp_items[i_pos]->input.psz_name, i_pos, i_newpos);
631
632         if( i_pos == p_playlist->i_index )
633         {
634             p_playlist->i_index = i_newpos;
635         }
636         else if( i_pos > p_playlist->i_index && i_newpos <= p_playlist->i_index )
637         {
638             p_playlist->i_index++;
639         }
640         else if( i_pos < p_playlist->i_index && i_newpos >= p_playlist->i_index )
641         {
642             p_playlist->i_index--;
643         }
644
645         if ( i_pos < i_newpos )
646         {
647             temp = p_playlist->pp_items[i_pos];
648             while ( i_pos < i_newpos )
649             {
650                 p_playlist->pp_items[i_pos] = p_playlist->pp_items[i_pos+1];
651                 i_pos++;
652             }
653             p_playlist->pp_items[i_newpos] = temp;
654         }
655         else if ( i_pos > i_newpos )
656         {
657             temp = p_playlist->pp_items[i_pos];
658             while ( i_pos > i_newpos )
659             {
660                 p_playlist->pp_items[i_pos] = p_playlist->pp_items[i_pos-1];
661                 i_pos--;
662             }
663             p_playlist->pp_items[i_newpos] = temp;
664         }
665     }
666
667     vlc_mutex_unlock( &p_playlist->object_lock );
668
669     val.b_bool = VLC_TRUE;
670     var_Set( p_playlist, "intf-change", val );
671
672     return VLC_SUCCESS;
673 }