]> git.sesse.net Git - vlc/blob - src/playlist/item.c
* all: fixed a lot of small memory leaks.
[vlc] / src / playlist / item.c
1 /*****************************************************************************
2  * item.c : Playlist item functions
3  *****************************************************************************
4  * Copyright (C) 1999-2001 VideoLAN
5  * $Id: item.c,v 1.4 2003/11/25 00:56:35 fenrir Exp $
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23 #include <stdlib.h>                                      /* free(), strtol() */
24 #include <stdio.h>                                              /* sprintf() */
25 #include <string.h>                                            /* strerror() */
26
27 #include <vlc/vlc.h>
28 #include <vlc/vout.h>
29 #include <vlc/sout.h>
30
31 #include "vlc_playlist.h"
32
33 /**
34  * Add an MRL to the playlist. This is a simplified version of
35  * playlist_AddExt inculded for convenince. It equals calling playlist_AddExt
36  * with psz_name == psz_target and i_duration == -1
37  */
38
39 int playlist_Add( playlist_t *p_playlist, const char *psz_target,
40                   const char **ppsz_options, int i_options,
41                   int i_mode, int i_pos )
42 {
43     return playlist_AddExt( p_playlist, psz_target, psz_target, -1,
44                             ppsz_options, i_options, i_mode, i_pos );
45 }
46
47 /**
48  * Add a MRL into the playlist.
49  *
50  * \param p_playlist the playlist to add into
51  * \param psz_uri the mrl to add to the playlist
52  * \param psz_name a text giving a name or description of this item
53  * \param i_duration a hint about the duration of this item, in miliseconds, or
54  *        -1 if unknown.
55  * \param ppsz_options array of options
56  * \param i_options number of items in ppsz_options
57  * \param i_mode the mode used when adding
58  * \param i_pos the position in the playlist where to add. If this is
59  *        PLAYLIST_END the item will be added at the end of the playlist
60  *        regardless of it's size
61  * \return always returns 0
62 */
63 int playlist_AddExt( playlist_t *p_playlist, const char * psz_uri,
64                      const char * psz_name, mtime_t i_duration,
65                      const char **ppsz_options, int i_options, int i_mode,
66                      int i_pos )
67 {
68     playlist_item_t * p_item;
69
70     p_item = malloc( sizeof( playlist_item_t ) );
71     if( p_item == NULL )
72     {
73         msg_Err( p_playlist, "out of memory" );
74     }
75
76     p_item->psz_name   = strdup( psz_name );
77     p_item->psz_uri    = strdup( psz_uri );
78     p_item->psz_author = strdup( "Arg" );
79     p_item->i_duration = i_duration;
80     p_item->i_type = 0;
81     p_item->i_status = 0;
82     p_item->b_autodeletion = VLC_FALSE;
83     p_item->b_enabled = VLC_TRUE;
84     p_item->i_group = PLAYLIST_TYPE_MANUAL;
85
86     p_item->ppsz_options = NULL;
87     p_item->i_options = i_options;
88
89     if( i_options > 0 )
90     {
91         int i;
92
93         p_item->ppsz_options = malloc( i_options * sizeof(char *) );
94         for( i = 0; i < i_options; i++ )
95         {
96             p_item->ppsz_options[i] = strdup( ppsz_options[i] );
97         }
98
99     }
100
101     return playlist_AddItem( p_playlist, p_item, i_mode, i_pos );
102 }
103
104 /**
105  * Add a playlist item into a playlist
106  *
107  * \param p_playlist the playlist to insert into
108  * \param p_item the playlist item to insert
109  * \param i_mode the mode used when adding
110  * \param i_pos the possition in the playlist where to add. If this is
111  *        PLAYLIST_END the item will be added at the end of the playlist
112  *        regardless of it's size
113  * \return always returns 0
114 */
115 int playlist_AddItem( playlist_t *p_playlist, playlist_item_t * p_item,
116                 int i_mode, int i_pos)
117 {
118     vlc_value_t     val;
119
120     vlc_mutex_lock( &p_playlist->object_lock );
121
122     /*
123      * CHECK_INSERT : checks if the item is already enqued before
124      * enqueing it
125      */
126     if ( i_mode & PLAYLIST_CHECK_INSERT )
127     {
128          int j;
129
130          if ( p_playlist->pp_items )
131          {
132              for ( j = 0; j < p_playlist->i_size; j++ )
133              {
134                  if ( !strcmp( p_playlist->pp_items[j]->psz_uri, p_item->psz_uri ) )
135                  {
136                       if( p_item->psz_name )
137                       {
138                           free( p_item->psz_name );
139                       }
140                       if( p_item->psz_uri )
141                       {
142                           free( p_item->psz_uri );
143                       }
144                       if( p_item->i_options )
145                       {
146                           int i_opt;
147                           for( i_opt = 0; i_opt < p_item->i_options; i_opt++ )
148                           {
149                               free( p_item->ppsz_options[i_opt] );
150                           }
151                           free( p_item->ppsz_options );
152                       }
153                       if( p_item->psz_author )
154                       {
155                           free( p_item->psz_author );
156                       }
157                       free( p_item );
158                       vlc_mutex_unlock( &p_playlist->object_lock );
159                       return 0;
160                  }
161              }
162          }
163          i_mode &= ~PLAYLIST_CHECK_INSERT;
164          i_mode |= PLAYLIST_APPEND;
165     }
166
167
168     msg_Dbg( p_playlist, "adding playlist item « %s » ( %s )", p_item->psz_name, p_item->psz_uri);
169
170     /* Create the new playlist item */
171
172
173     /* Do a few boundary checks and allocate space for the item */
174     if( i_pos == PLAYLIST_END )
175     {
176         if( i_mode & PLAYLIST_INSERT )
177         {
178             i_mode &= ~PLAYLIST_INSERT;
179             i_mode |= PLAYLIST_APPEND;
180         }
181
182         i_pos = p_playlist->i_size - 1;
183     }
184
185     if( !(i_mode & PLAYLIST_REPLACE)
186          || i_pos < 0 || i_pos >= p_playlist->i_size )
187     {
188         /* Additional boundary checks */
189         if( i_mode & PLAYLIST_APPEND )
190         {
191             i_pos++;
192         }
193
194         if( i_pos < 0 )
195         {
196             i_pos = 0;
197         }
198         else if( i_pos > p_playlist->i_size )
199         {
200             i_pos = p_playlist->i_size;
201         }
202
203         INSERT_ELEM( p_playlist->pp_items,
204                      p_playlist->i_size,
205                      i_pos,
206                      p_item );
207         p_playlist->i_enabled ++;
208
209         if( p_playlist->i_index >= i_pos )
210         {
211             p_playlist->i_index++;
212         }
213     }
214     else
215     {
216         /* i_mode == PLAYLIST_REPLACE and 0 <= i_pos < p_playlist->i_size */
217         if( p_playlist->pp_items[i_pos]->psz_name )
218         {
219             free( p_playlist->pp_items[i_pos]->psz_name );
220         }
221         if( p_playlist->pp_items[i_pos]->psz_uri )
222         {
223             free( p_playlist->pp_items[i_pos]->psz_uri );
224         }
225         if( p_playlist->pp_items[i_pos]->psz_author )
226         {
227             free( p_playlist->pp_items[i_pos]->psz_author );
228         }
229         /* XXX: what if the item is still in use? */
230         free( p_playlist->pp_items[i_pos] );
231         p_playlist->pp_items[i_pos] = p_item;
232     }
233
234     if( i_mode & PLAYLIST_GO )
235     {
236         p_playlist->i_index = i_pos;
237         if( p_playlist->p_input )
238         {
239             input_StopThread( p_playlist->p_input );
240         }
241         p_playlist->i_status = PLAYLIST_RUNNING;
242     }
243
244     vlc_mutex_unlock( &p_playlist->object_lock );
245
246     val.b_bool = VLC_TRUE;
247     var_Set( p_playlist, "intf-change", val );
248
249     return 0;
250 }
251
252 /**
253  * delete an item from a playlist.
254  *
255  * \param p_playlist the playlist to remove from.
256  * \param i_pos the position of the item to remove
257  * \return returns 0
258  */
259 int playlist_Delete( playlist_t * p_playlist, int i_pos )
260 {
261     vlc_value_t     val;
262
263     /* if i_pos is the current played item, playlist should stop playing it */
264     if( ( p_playlist->i_status == PLAYLIST_RUNNING) && (p_playlist->i_index == i_pos) )
265     {
266         playlist_Command( p_playlist, PLAYLIST_STOP, 0 );
267     }
268
269     vlc_mutex_lock( &p_playlist->object_lock );
270     if( i_pos >= 0 && i_pos < p_playlist->i_size )
271     {
272         playlist_item_t *p_item = p_playlist->pp_items[i_pos];
273
274         msg_Dbg( p_playlist, "deleting playlist item « %s »",
275                  p_item->psz_name );
276
277         if( p_item->psz_name )
278         {
279             free( p_item->psz_name );
280         }
281         if( p_item->psz_uri )
282         {
283             free( p_item->psz_uri );
284         }
285         if( p_item->psz_author )
286         {
287             free( p_item->psz_author );
288         }
289         if( p_item->i_options > 0 )
290         {
291             int i;
292
293             for( i = 0; i < p_item->i_options; i++ )
294             {
295                 free( p_item->ppsz_options[i] );
296             }
297
298             free( p_item->ppsz_options );
299         }
300
301         /* XXX: what if the item is still in use? */
302         free( p_item );
303
304         if( i_pos <= p_playlist->i_index )
305         {
306             p_playlist->i_index--;
307         }
308
309         /* Renumber the playlist */
310         REMOVE_ELEM( p_playlist->pp_items,
311                      p_playlist->i_size,
312                      i_pos );
313         if( p_playlist->i_enabled > 0 )
314             p_playlist->i_enabled--;
315     }
316
317     vlc_mutex_unlock( &p_playlist->object_lock );
318
319     val.b_bool = VLC_TRUE;
320     var_Set( p_playlist, "intf-change", val );
321
322     return 0;
323 }
324
325 /**
326  * Disables a playlist item
327  *
328  * \param p_playlist the playlist to disable from.
329  * \param i_pos the position of the item to disable
330  * \return returns 0
331  */
332 int playlist_Disable( playlist_t * p_playlist, int i_pos )
333 {
334     vlc_value_t     val;
335     vlc_mutex_lock( &p_playlist->object_lock );
336
337
338     if( i_pos >= 0 && i_pos < p_playlist->i_size )
339     {
340         msg_Dbg( p_playlist, "disabling playlist item « %s »",
341                              p_playlist->pp_items[i_pos]->psz_name );
342
343         if( p_playlist->pp_items[i_pos]->b_enabled == VLC_TRUE )
344             p_playlist->i_enabled--;
345         p_playlist->pp_items[i_pos]->b_enabled = VLC_FALSE;
346     }
347
348     vlc_mutex_unlock( &p_playlist->object_lock );
349
350     val.b_bool = VLC_TRUE;
351     var_Set( p_playlist, "intf-change", val );
352
353     return 0;
354 }
355
356 /**
357  * Enables a playlist item
358  *
359  * \param p_playlist the playlist to enable from.
360  * \param i_pos the position of the item to enable
361  * \return returns 0
362  */
363 int playlist_Enable( playlist_t * p_playlist, int i_pos )
364 {
365     vlc_value_t     val;
366     vlc_mutex_lock( &p_playlist->object_lock );
367
368     if( i_pos >= 0 && i_pos < p_playlist->i_size )
369     {
370         msg_Dbg( p_playlist, "enabling playlist item « %s »",
371                              p_playlist->pp_items[i_pos]->psz_name );
372
373         if( p_playlist->pp_items[i_pos]->b_enabled == VLC_FALSE )
374             p_playlist->i_enabled++;
375
376         p_playlist->pp_items[i_pos]->b_enabled = VLC_TRUE;
377     }
378
379     vlc_mutex_unlock( &p_playlist->object_lock );
380
381     val.b_bool = VLC_TRUE;
382     var_Set( p_playlist, "intf-change", val );
383
384     return 0;
385 }
386
387 /**
388  * Disables a playlist group
389  *
390  * \param p_playlist the playlist to disable from.
391  * \param i_pos the id of the group to disable
392  * \return returns 0
393  */
394 int playlist_DisableGroup( playlist_t * p_playlist, int i_group)
395 {
396     vlc_value_t     val;
397     int i;
398     vlc_mutex_lock( &p_playlist->object_lock );
399
400     msg_Dbg(p_playlist,"Disabling group %i",i_group);
401     for( i = 0 ; i< p_playlist->i_size; i++ )
402     {
403         if( p_playlist->pp_items[i]->i_group == i_group )
404         {
405             msg_Dbg( p_playlist, "disabling playlist item « %s »",
406                            p_playlist->pp_items[i]->psz_name );
407
408             if( p_playlist->pp_items[i]->b_enabled == VLC_TRUE )
409                 p_playlist->i_enabled--;
410
411             p_playlist->pp_items[i]->b_enabled = VLC_FALSE;
412         }
413     }
414     vlc_mutex_unlock( &p_playlist->object_lock );
415
416     val.b_bool = VLC_TRUE;
417     var_Set( p_playlist, "intf-change", val );
418
419     return 0;
420 }
421
422 /**
423  * Enables a playlist group
424  *
425  * \param p_playlist the playlist to enable from.
426  * \param i_pos the id of the group to enable
427  * \return returns 0
428  */
429 int playlist_EnableGroup( playlist_t * p_playlist, int i_group)
430 {
431     vlc_value_t     val;
432     int i;
433     vlc_mutex_lock( &p_playlist->object_lock );
434
435     for( i = 0 ; i< p_playlist->i_size; i++ )
436     {
437         if( p_playlist->pp_items[i]->i_group == i_group )
438         {
439             msg_Dbg( p_playlist, "enabling playlist item « %s »",
440                            p_playlist->pp_items[i]->psz_name );
441
442             if( p_playlist->pp_items[i]->b_enabled == VLC_FALSE )
443                 p_playlist->i_enabled++;
444
445             p_playlist->pp_items[i]->b_enabled = VLC_TRUE;
446         }
447     }
448     vlc_mutex_unlock( &p_playlist->object_lock );
449
450     val.b_bool = VLC_TRUE;
451     var_Set( p_playlist, "intf-change", val );
452
453     return 0;
454 }
455
456 /**
457  * Move an item in a playlist
458  *
459  * Move the item in the playlist with position i_pos before the current item
460  * at position i_newpos.
461  * \param p_playlist the playlist to move items in
462  * \param i_pos the position of the item to move
463  * \param i_newpos the position of the item that will be behind the moved item
464  *        after the move
465  * \return returns 0
466  */
467 int playlist_Move( playlist_t * p_playlist, int i_pos, int i_newpos)
468 {
469     vlc_value_t     val;
470     vlc_mutex_lock( &p_playlist->object_lock );
471
472     /* take into account that our own row disappears. */
473     if ( i_pos < i_newpos ) i_newpos--;
474
475     if( i_pos >= 0 && i_newpos >=0 && i_pos <= p_playlist->i_size
476                      && i_newpos <= p_playlist->i_size )
477     {
478         playlist_item_t * temp;
479
480         msg_Dbg( p_playlist, "moving playlist item « %s » (%i -> %i)",
481                              p_playlist->pp_items[i_pos]->psz_name, i_pos,
482                              i_newpos );
483
484         if( i_pos == p_playlist->i_index )
485         {
486             p_playlist->i_index = i_newpos;
487         }
488         else if( i_pos > p_playlist->i_index && i_newpos <= p_playlist->i_index )
489         {
490             p_playlist->i_index++;
491         }
492         else if( i_pos < p_playlist->i_index && i_newpos >= p_playlist->i_index )
493         {
494             p_playlist->i_index--;
495         }
496
497         if ( i_pos < i_newpos )
498         {
499             temp = p_playlist->pp_items[i_pos];
500             while ( i_pos < i_newpos )
501             {
502                 p_playlist->pp_items[i_pos] = p_playlist->pp_items[i_pos+1];
503                 i_pos++;
504             }
505             p_playlist->pp_items[i_newpos] = temp;
506         }
507         else if ( i_pos > i_newpos )
508         {
509             temp = p_playlist->pp_items[i_pos];
510             while ( i_pos > i_newpos )
511             {
512                 p_playlist->pp_items[i_pos] = p_playlist->pp_items[i_pos-1];
513                 i_pos--;
514             }
515             p_playlist->pp_items[i_newpos] = temp;
516         }
517     }
518
519     vlc_mutex_unlock( &p_playlist->object_lock );
520
521     val.b_bool = VLC_TRUE;
522     var_Set( p_playlist, "intf-change", val );
523
524     return 0;
525 }