playlist.c 35.1 KB
Newer Older
1
2
3
4
/*****************************************************************************
 * playlist.c : Playlist management functions
 *****************************************************************************
 * Copyright (C) 1999-2001 VideoLAN
5
 * $Id: playlist.c,v 1.58 2003/10/09 18:05:32 massiot Exp $
6
7
8
9
10
11
12
 *
 * Authors: Samuel Hocevar <sam@zoy.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
13
 *
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/
#include <stdlib.h>                                      /* free(), strtol() */
#include <stdio.h>                                              /* sprintf() */
#include <string.h>                                            /* strerror() */

#include <vlc/vlc.h>
28
29
#include <vlc/vout.h>
#include <vlc/sout.h>
30
31
32
33

#include "stream_control.h"
#include "input_ext-intf.h"

34
#include "vlc_playlist.h"
35

36
#define PLAYLIST_FILE_HEADER_0_5  "# vlc playlist file version 0.5"
zorglub's avatar
zorglub committed
37
#define PLAYLIST_FILE_HEADER_0_6  "# vlc playlist file version 0.6"
38

39
40
41
42
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
static void RunThread ( playlist_t * );
43
44
45
46
static void SkipItem  ( playlist_t *, int );
static void PlayItem  ( playlist_t * );

static void Poubellize ( playlist_t *, input_thread_t * );
47

sigmunau's avatar
sigmunau committed
48
49
50
/**
 * Create playlist
 *
51
 * Create a playlist structure.
sigmunau's avatar
sigmunau committed
52
53
54
 * \param p_parent the vlc object that is to be the parent of this playlist
 * \return a pointer to the created playlist, or NULL on error
 */
55
playlist_t * __playlist_Create ( vlc_object_t *p_parent )
56
57
{
    playlist_t *p_playlist;
hartman's avatar
hartman committed
58
    vlc_value_t     val;
59
60
61
62
63
64
65
66
67

    /* Allocate structure */
    p_playlist = vlc_object_create( p_parent, VLC_OBJECT_PLAYLIST );
    if( !p_playlist )
    {
        msg_Err( p_parent, "out of memory" );
        return NULL;
    }

hartman's avatar
hartman committed
68
69
70
71
    var_Create( p_playlist, "intf-change", VLC_VAR_BOOL );
    val.b_bool = VLC_TRUE;
    var_Set( p_playlist, "intf-change", val );

72
    var_Create( p_playlist, "intf-popupmenu", VLC_VAR_BOOL );
gbazin's avatar
   
gbazin committed
73

74
75
76
    var_Create( p_playlist, "intf-show", VLC_VAR_BOOL );
    val.b_bool = VLC_TRUE;
    var_Set( p_playlist, "intf-show", val );
77

hartman's avatar
hartman committed
78
79
80
    var_Create( p_playlist, "random", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Create( p_playlist, "repeat", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Create( p_playlist, "loop", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
81

82
    p_playlist->p_input = NULL;
83
    p_playlist->i_status = PLAYLIST_STOPPED;
84
85
86
    p_playlist->i_index = -1;
    p_playlist->i_size = 0;
    p_playlist->pp_items = NULL;
Sam Hocevar's avatar
Sam Hocevar committed
87

88
89
    if( vlc_thread_create( p_playlist, "playlist", RunThread,
                           VLC_THREAD_PRIORITY_LOW, VLC_TRUE ) )
90
91
92
93
94
95
    {
        msg_Err( p_playlist, "cannot spawn playlist thread" );
        vlc_object_destroy( p_playlist );
        return NULL;
    }

96
97
98
    /* The object has been initialized, now attach it */
    vlc_object_attach( p_playlist, p_parent );

99
100
101
    return p_playlist;
}

sigmunau's avatar
sigmunau committed
102
103
104
/**
 * Destroy the playlist.
 *
105
 * Delete all items in the playlist and free the playlist structure.
sigmunau's avatar
sigmunau committed
106
107
 * \param p_playlist the playlist structure to destroy
 */
108
109
110
111
112
113
void playlist_Destroy( playlist_t * p_playlist )
{
    p_playlist->b_die = 1;

    vlc_thread_join( p_playlist );

hartman's avatar
hartman committed
114
115
    var_Destroy( p_playlist, "intf-change" );

116
117
118
    vlc_object_destroy( p_playlist );
}

sigmunau's avatar
sigmunau committed
119
120
121
122
123
124
/**
 * Add an MRL to the playlist. This is a simplified version of
 * playlist_AddExt inculded for convenince. It equals calling playlist_AddExt
 * with psz_name == psz_target and i_duration == -1
 */

gbazin's avatar
   
gbazin committed
125
126
127
int playlist_Add( playlist_t *p_playlist, const char *psz_target,
                  const char **ppsz_options, int i_options,
                  int i_mode, int i_pos )
128
{
sigmunau's avatar
sigmunau committed
129
130
    return playlist_AddExt( p_playlist, psz_target, psz_target, -1,
                            ppsz_options, i_options, i_mode, i_pos );
131
}
132

sigmunau's avatar
sigmunau committed
133
134
135
136
/**
 * Add a MRL into the playlist.
 *
 * \param p_playlist the playlist to add into
sigmunau's avatar
sigmunau committed
137
 * \param psz_uri the mrl to add to the playlist
sigmunau's avatar
sigmunau committed
138
139
140
 * \param psz_name a text giving a name or description of this item
 * \param i_duration a hint about the duration of this item, in miliseconds, or
 *        -1 if unknown.
sigmunau's avatar
sigmunau committed
141
142
 * \param ppsz_options array of options
 * \param i_options number of items in ppsz_options
sigmunau's avatar
sigmunau committed
143
 * \param i_mode the mode used when adding
144
 * \param i_pos the position in the playlist where to add. If this is
sigmunau's avatar
sigmunau committed
145
146
147
148
149
150
151
152
 *        PLAYLIST_END the item will be added at the end of the playlist
 *        regardless of it's size
 * \return always returns 0
*/
int playlist_AddExt( playlist_t *p_playlist, const char * psz_uri,
                     const char * psz_name, mtime_t i_duration,
                     const char **ppsz_options, int i_options, int i_mode,
                     int i_pos )
zorglub's avatar
   
zorglub committed
153
154
155
156
157
158
159
160
161
{
    playlist_item_t * p_item;

    p_item = malloc( sizeof( playlist_item_t ) );
    if( p_item == NULL )
    {
        msg_Err( p_playlist, "out of memory" );
    }

zorglub's avatar
zorglub committed
162
163
164
    p_item->psz_name   = strdup( psz_name );
    p_item->psz_uri    = strdup( psz_uri );
    p_item->psz_author = strdup( "" );
sigmunau's avatar
sigmunau committed
165
    p_item->i_duration = i_duration;
zorglub's avatar
   
zorglub committed
166
167
168
    p_item->i_type = 0;
    p_item->i_status = 0;
    p_item->b_autodeletion = VLC_FALSE;
zorglub's avatar
zorglub committed
169
170
    p_item->b_enabled = VLC_TRUE;
    p_item->i_group = PLAYLIST_TYPE_MANUAL;
zorglub's avatar
   
zorglub committed
171

gbazin's avatar
   
gbazin committed
172
173
174
175
176
177
178
179
180
181
182
183
184
    p_item->ppsz_options = NULL;
    p_item->i_options = i_options;

    if( i_options )
    {
        int i;

        p_item->ppsz_options = (char **)malloc( i_options * sizeof(char *) );
        for( i = 0; i < i_options; i++ )
            p_item->ppsz_options[i] = strdup( ppsz_options[i] );

    }

zorglub's avatar
   
zorglub committed
185
186
    return playlist_AddItem( p_playlist, p_item, i_mode, i_pos );
}
187

sigmunau's avatar
sigmunau committed
188
189
190
191
192
193
194
195
196
197
198
/**
 * Add a playlist item into a playlist
 *
 * \param p_playlist the playlist to insert into
 * \param p_item the playlist item to insert
 * \param i_mode the mode used when adding
 * \param i_pos the possition in the playlist where to add. If this is
 *        PLAYLIST_END the item will be added at the end of the playlist
 *        regardless of it's size
 * \return always returns 0
*/
199
200
201
int playlist_AddItem( playlist_t *p_playlist, playlist_item_t * p_item,
                int i_mode, int i_pos)
{
hartman's avatar
hartman committed
202
    vlc_value_t     val;
203

204
205
206
    vlc_mutex_lock( &p_playlist->object_lock );

    /*
207
     * CHECK_INSERT : checks if the item is already enqued before
208
209
210
211
212
     * enqueing it
     */
    if ( i_mode & PLAYLIST_CHECK_INSERT )
    {
         int j;
213

214
215
216
217
         if ( p_playlist->pp_items )
         {
             for ( j = 0; j < p_playlist->i_size; j++ )
             {
218
                 if ( !strcmp( p_playlist->pp_items[j]->psz_uri, p_item->psz_uri ) )
219
                 {
220
                      if( p_item->psz_name )
221
222
223
224
225
226
227
228
                      {
                          free( p_item->psz_name );
                      }
                      if( p_item->psz_uri )
                      {
                          free( p_item->psz_uri );
                      }
                      free( p_item );
229
                      vlc_mutex_unlock( &p_playlist->object_lock );
230
                      return 0;
231
232
233
234
235
236
237
                 }
             }
         }
         i_mode &= ~PLAYLIST_CHECK_INSERT;
         i_mode |= PLAYLIST_APPEND;
    }

238

zorglub's avatar
   
zorglub committed
239
    msg_Dbg( p_playlist, "adding playlist item  %s  ( %s )", p_item->psz_name, p_item->psz_uri);
240

241
242
    /* Create the new playlist item */

243

244
245
246
    /* Do a few boundary checks and allocate space for the item */
    if( i_pos == PLAYLIST_END )
    {
247
248
249
250
251
252
        if( i_mode & PLAYLIST_INSERT )
        {
            i_mode &= ~PLAYLIST_INSERT;
            i_mode |= PLAYLIST_APPEND;
        }

253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
        i_pos = p_playlist->i_size - 1;
    }

    if( !(i_mode & PLAYLIST_REPLACE)
         || i_pos < 0 || i_pos >= p_playlist->i_size )
    {
        /* Additional boundary checks */
        if( i_mode & PLAYLIST_APPEND )
        {
            i_pos++;
        }

        if( i_pos < 0 )
        {
            i_pos = 0;
        }
269
        else if( i_pos > p_playlist->i_size )
270
        {
271
            i_pos = p_playlist->i_size;
272
273
        }

274
275
276
277
        INSERT_ELEM( p_playlist->pp_items,
                     p_playlist->i_size,
                     i_pos,
                     p_item );
zorglub's avatar
zorglub committed
278
        p_playlist->i_enabled ++;
279

280
281
        if( p_playlist->i_index >= i_pos )
        {
282
            p_playlist->i_index++;
283
284
285
286
287
        }
    }
    else
    {
        /* i_mode == PLAYLIST_REPLACE and 0 <= i_pos < p_playlist->i_size */
288
289
290
291
292
293
294
295
        if( p_playlist->pp_items[i_pos]->psz_name )
        {
            free( p_playlist->pp_items[i_pos]->psz_name );
        }
        if( p_playlist->pp_items[i_pos]->psz_uri )
        {
            free( p_playlist->pp_items[i_pos]->psz_uri );
        }
296
        /* XXX: what if the item is still in use? */
297
298
        free( p_playlist->pp_items[i_pos] );
        p_playlist->pp_items[i_pos] = p_item;
299
300
    }

301
302
303
304
305
306
307
308
309
    if( i_mode & PLAYLIST_GO )
    {
        p_playlist->i_index = i_pos;
        if( p_playlist->p_input )
        {
            input_StopThread( p_playlist->p_input );
        }
        p_playlist->i_status = PLAYLIST_RUNNING;
    }
Sam Hocevar's avatar
Sam Hocevar committed
310

311
    vlc_mutex_unlock( &p_playlist->object_lock );
312

hartman's avatar
hartman committed
313
314
315
    val.b_bool = VLC_TRUE;
    var_Set( p_playlist, "intf-change", val );

316
317
318
    return 0;
}

sigmunau's avatar
sigmunau committed
319
320
321
322
323
324
325
/**
 * delete an item from a playlist.
 *
 * \param p_playlist the playlist to remove from.
 * \param i_pos the position of the item to remove
 * \return returns 0
 */
326
327
int playlist_Delete( playlist_t * p_playlist, int i_pos )
{
hartman's avatar
hartman committed
328
    vlc_value_t     val;
329
    vlc_mutex_lock( &p_playlist->object_lock );
Sam Hocevar's avatar
Sam Hocevar committed
330

331
332
    if( i_pos >= 0 && i_pos < p_playlist->i_size )
    {
333
334
        msg_Dbg( p_playlist, "deleting playlist item  %s ",
                             p_playlist->pp_items[i_pos]->psz_name );
335

336
337
338
339
340
341
342
343
        if( p_playlist->pp_items[i_pos]->psz_name )
        {
            free( p_playlist->pp_items[i_pos]->psz_name );
        }
        if( p_playlist->pp_items[i_pos]->psz_uri )
        {
            free( p_playlist->pp_items[i_pos]->psz_uri );
        }
gbazin's avatar
   
gbazin committed
344
345
346
347
348
349
350
351
352
        if( p_playlist->pp_items[i_pos]->i_options )
        {
            int i;

            for( i = 0; i < p_playlist->pp_items[i_pos]->i_options; i++ )
                free( p_playlist->pp_items[i_pos]->ppsz_options[i] );

            free( p_playlist->pp_items[i_pos]->ppsz_options );
        }
353

354
        /* XXX: what if the item is still in use? */
355
        free( p_playlist->pp_items[i_pos] );
356

gbazin's avatar
   
gbazin committed
357
        if( i_pos <= p_playlist->i_index )
358
359
360
361
362
        {
            p_playlist->i_index--;
        }

        /* Renumber the playlist */
363
364
365
        REMOVE_ELEM( p_playlist->pp_items,
                     p_playlist->i_size,
                     i_pos );
zorglub's avatar
zorglub committed
366
367
        if( p_playlist->i_enabled > 0 )
            p_playlist->i_enabled--;
368
369
    }

370
    vlc_mutex_unlock( &p_playlist->object_lock );
hartman's avatar
hartman committed
371
372
373
374
375
376
377

    val.b_bool = VLC_TRUE;
    var_Set( p_playlist, "intf-change", val );

    return 0;
}

zorglub's avatar
zorglub committed
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
/**
 * Disables a playlist item
 *
 * \param p_playlist the playlist to disable from.
 * \param i_pos the position of the item to disable
 * \return returns 0
 */
int playlist_Disable( playlist_t * p_playlist, int i_pos )
{
    vlc_value_t     val;
    vlc_mutex_lock( &p_playlist->object_lock );


    if( i_pos >= 0 && i_pos < p_playlist->i_size )
    {
        msg_Dbg( p_playlist, "disabling playlist item  %s ",
                             p_playlist->pp_items[i_pos]->psz_name );

        if( p_playlist->pp_items[i_pos]->b_enabled == VLC_TRUE )
            p_playlist->i_enabled--;
        p_playlist->pp_items[i_pos]->b_enabled = VLC_FALSE;
    }

    vlc_mutex_unlock( &p_playlist->object_lock );

    val.b_bool = VLC_TRUE;
    var_Set( p_playlist, "intf-change", val );

    return 0;
}

/**
 * Enables a playlist item
 *
 * \param p_playlist the playlist to enable from.
 * \param i_pos the position of the item to enable
 * \return returns 0
 */
int playlist_Enable( playlist_t * p_playlist, int i_pos )
{
    vlc_value_t     val;
    vlc_mutex_lock( &p_playlist->object_lock );

    if( i_pos >= 0 && i_pos < p_playlist->i_size )
    {
        msg_Dbg( p_playlist, "enabling playlist item  %s ",
                             p_playlist->pp_items[i_pos]->psz_name );

        if( p_playlist->pp_items[i_pos]->b_enabled == VLC_FALSE )
            p_playlist->i_enabled++;

        p_playlist->pp_items[i_pos]->b_enabled = VLC_TRUE;
    }

    vlc_mutex_unlock( &p_playlist->object_lock );

    val.b_bool = VLC_TRUE;
    var_Set( p_playlist, "intf-change", val );

    return 0;
}

/**
 * Disables a playlist group
 *
 * \param p_playlist the playlist to disable from.
 * \param i_pos the id of the group to disable
 * \return returns 0
 */
int playlist_DisableGroup( playlist_t * p_playlist, int i_group)
{
    vlc_value_t     val;
    int i;
451
    vlc_mutex_lock( &p_playlist->object_lock );
zorglub's avatar
zorglub committed
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485

    msg_Dbg(p_playlist,"Disabling group %i",i_group);
    for( i = 0 ; i< p_playlist->i_size; i++ )
    {
        if( p_playlist->pp_items[i]->i_group == i_group )
        {
            msg_Dbg( p_playlist, "disabling playlist item  %s ",
                           p_playlist->pp_items[i]->psz_name );

            if( p_playlist->pp_items[i]->b_enabled == VLC_TRUE )
                p_playlist->i_enabled--;

            p_playlist->pp_items[i]->b_enabled = VLC_FALSE;
        }
    }
    vlc_mutex_unlock( &p_playlist->object_lock );

    val.b_bool = VLC_TRUE;
    var_Set( p_playlist, "intf-change", val );

    return 0;
}

/**
 * Enables a playlist group
 *
 * \param p_playlist the playlist to enable from.
 * \param i_pos the id of the group to enable
 * \return returns 0
 */
int playlist_EnableGroup( playlist_t * p_playlist, int i_group)
{
    vlc_value_t     val;
    int i;
486
    vlc_mutex_lock( &p_playlist->object_lock );
zorglub's avatar
zorglub committed
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507

    for( i = 0 ; i< p_playlist->i_size; i++ )
    {
        if( p_playlist->pp_items[i]->i_group == i_group )
        {
            msg_Dbg( p_playlist, "enabling playlist item  %s ",
                           p_playlist->pp_items[i]->psz_name );

            if( p_playlist->pp_items[i]->b_enabled == VLC_FALSE )
                p_playlist->i_enabled++;

            p_playlist->pp_items[i]->b_enabled = VLC_TRUE;
        }
    }
    vlc_mutex_unlock( &p_playlist->object_lock );

    val.b_bool = VLC_TRUE;
    var_Set( p_playlist, "intf-change", val );

    return 0;
}
zorglub's avatar
zorglub committed
508
509
510
511
512
513
514

/**
 * Sort the playlist
 *
 */
int playlist_Sort( playlist_t * p_playlist , int i_type )
{
515
    int i , i_small , i_position;
zorglub's avatar
zorglub committed
516
517
518
    playlist_item_t *p_temp;

    vlc_mutex_lock( &p_playlist->object_lock );
519

520
    for( i_position = 0; i_position < p_playlist->i_size -1 ; i_position ++ )
zorglub's avatar
zorglub committed
521
522
523
524
    {
        i_small  = i_position;
        for( i = i_position + 1 ; i<  p_playlist->i_size ; i++)
        {
525
526
527
528
529
            int i_test;

            i_test = strcasecmp( p_playlist->pp_items[i]->psz_name,
                                 p_playlist->pp_items[i_small]->psz_name );

530
531
            if( ( i_type == SORT_NORMAL  && i_test < 0 ) ||
                ( i_type == SORT_REVERSE && i_test > 0 ) )
532
533
534
535
            {
                i_small = i;
            }
        }
zorglub's avatar
zorglub committed
536
537
538
539
540
541
        /* Keep the correct current index */
        if( i_small == p_playlist->i_index )
            p_playlist->i_index = i_position;
        else if( i_position == p_playlist->i_index )
            p_playlist->i_index = i_small;

542
543
544
        p_temp = p_playlist->pp_items[i_position];
        p_playlist->pp_items[i_position] = p_playlist->pp_items[i_small];
        p_playlist->pp_items[i_small] = p_temp;
545
    }
zorglub's avatar
zorglub committed
546
547
    vlc_mutex_unlock( &p_playlist->object_lock );

548
    return 0;
zorglub's avatar
zorglub committed
549
550
}

sigmunau's avatar
sigmunau committed
551
552
553
/**
 * Move an item in a playlist
 *
hartman's avatar
hartman committed
554
555
 * Move the item in the playlist with position i_pos before the current item
 * at position i_newpos.
sigmunau's avatar
sigmunau committed
556
557
558
559
560
561
 * \param p_playlist the playlist to move items in
 * \param i_pos the position of the item to move
 * \param i_newpos the position of the item that will be behind the moved item
 *        after the move
 * \return returns 0
 */
hartman's avatar
hartman committed
562
563
564
565
566
567
568
569
int playlist_Move( playlist_t * p_playlist, int i_pos, int i_newpos)
{
    vlc_value_t     val;
    vlc_mutex_lock( &p_playlist->object_lock );

    /* take into account that our own row disappears. */
    if ( i_pos < i_newpos ) i_newpos--;

zorglub's avatar
zorglub committed
570
    if( i_pos >= 0 && i_newpos >=0 && i_pos <= p_playlist->i_size
hartman's avatar
hartman committed
571
572
                     && i_newpos <= p_playlist->i_size )
    {
gbazin's avatar
   
gbazin committed
573
574
        playlist_item_t * temp;

hartman's avatar
hartman committed
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
        msg_Dbg( p_playlist, "moving playlist item  %s ",
                             p_playlist->pp_items[i_pos]->psz_name );

        if( i_pos == p_playlist->i_index )
        {
            p_playlist->i_index = i_newpos;
        }
        else if( i_pos > p_playlist->i_index && i_newpos <= p_playlist->i_index )
        {
            p_playlist->i_index++;
        }
        else if( i_pos < p_playlist->i_index && i_newpos >= p_playlist->i_index )
        {
            p_playlist->i_index--;
        }
gbazin's avatar
   
gbazin committed
590

hartman's avatar
hartman committed
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
        if ( i_pos < i_newpos )
        {
            temp = p_playlist->pp_items[i_pos];
            while ( i_pos < i_newpos )
            {
                p_playlist->pp_items[i_pos] = p_playlist->pp_items[i_pos+1];
                i_pos++;
            }
            p_playlist->pp_items[i_newpos] = temp;
        }
        else if ( i_pos > i_newpos )
        {
            temp = p_playlist->pp_items[i_pos];
            while ( i_pos > i_newpos )
            {
                p_playlist->pp_items[i_pos] = p_playlist->pp_items[i_pos-1];
                i_pos--;
            }
            p_playlist->pp_items[i_newpos] = temp;
        }
    }

    vlc_mutex_unlock( &p_playlist->object_lock );
Sam Hocevar's avatar
Sam Hocevar committed
614

hartman's avatar
hartman committed
615
616
617
    val.b_bool = VLC_TRUE;
    var_Set( p_playlist, "intf-change", val );

618
619
620
    return 0;
}

sigmunau's avatar
sigmunau committed
621
622
/**
 * Do a playlist action
623
 *
sigmunau's avatar
sigmunau committed
624
625
626
627
628
629
 * \param p_playlist the playlist to do the command on
 * \param i_command the command to do
 * \param i_arg the argument to the command. See playlist_command_t for details
 */
 void playlist_Command( playlist_t * p_playlist, playlist_command_t i_command,
                       int i_arg )
630
{
631
632
    vlc_value_t val;

633
    vlc_mutex_lock( &p_playlist->object_lock );
Sam Hocevar's avatar
Sam Hocevar committed
634

635
636
637
638
    switch( i_command )
    {
    case PLAYLIST_STOP:
        p_playlist->i_status = PLAYLIST_STOPPED;
639
640
641
642
        if( p_playlist->p_input )
        {
            input_StopThread( p_playlist->p_input );
        }
643
        break;
644

645
646
    case PLAYLIST_PLAY:
        p_playlist->i_status = PLAYLIST_RUNNING;
zorglub's avatar
zorglub committed
647
        if( !p_playlist->p_input && p_playlist->i_enabled != 0 )
648
        {
649
            PlayItem( p_playlist );
gbazin's avatar
   
gbazin committed
650
651
652
        }
        if( p_playlist->p_input )
        {
653
654
            val.i_int = PLAYING_S;
            var_Set( p_playlist->p_input, "state", val );
655
        }
656
        break;
657

658
659
660
661
    case PLAYLIST_PAUSE:
        p_playlist->i_status = PLAYLIST_PAUSED;
        if( p_playlist->p_input )
        {
662
663
            val.i_int = PAUSE_S;
            var_Set( p_playlist->p_input, "state", val );
664
665
666
        }
        break;

667
    case PLAYLIST_SKIP:
668
        p_playlist->i_status = PLAYLIST_STOPPED;
zorglub's avatar
zorglub committed
669
670
671
672
        if( p_playlist->i_enabled == 0)
        {
            break;
        }
673
674
        SkipItem( p_playlist, i_arg );
        if( p_playlist->p_input )
675
        {
676
677
678
679
680
681
            input_StopThread( p_playlist->p_input );
        }
        p_playlist->i_status = PLAYLIST_RUNNING;
        break;

    case PLAYLIST_GOTO:
zorglub's avatar
zorglub committed
682
683
        if( i_arg >= 0 && i_arg < p_playlist->i_size &&
            p_playlist->i_enabled != 0 )
684
685
686
687
688
689
        {
            p_playlist->i_index = i_arg;
            if( p_playlist->p_input )
            {
                input_StopThread( p_playlist->p_input );
            }
690
691
692
            p_playlist->i_status = PLAYLIST_RUNNING;
        }
        break;
693

694
    default:
695
        msg_Err( p_playlist, "unknown playlist command" );
696
697
698
        break;
    }

699
    vlc_mutex_unlock( &p_playlist->object_lock );
Sam Hocevar's avatar
Sam Hocevar committed
700

701
702
703
704
    return;
}
/* Following functions are local */

705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
static void ObjectGarbageCollector( playlist_t *p_playlist,
                                    int i_type,
                                    vlc_bool_t *pb_obj_destroyed,
                                    mtime_t *pi_obj_destroyed_date )
{
    vlc_object_t *p_obj;
    if( *pb_obj_destroyed || *pi_obj_destroyed_date > mdate() )
    {
        return;
    }

    if( *pi_obj_destroyed_date == 0 )
    {
        /* give a little time */
        *pi_obj_destroyed_date = mdate() + 300000LL;
    }
    else
    {
        while( ( p_obj = vlc_object_find( p_playlist,
                                           i_type,
                                           FIND_CHILD ) ) )
        {
            if( p_obj->p_parent != (vlc_object_t*)p_playlist )
            {
                /* only first chiled (ie unused) */
                vlc_object_release( p_obj );
                break;
            }
            if( i_type == VLC_OBJECT_VOUT )
            {
                msg_Dbg( p_playlist, "vout garbage collector destroying 1 vout" );
                vlc_object_detach( p_obj );
                vlc_object_release( p_obj );
                vout_Destroy( (vout_thread_t *)p_obj );
            }
            else if( i_type == VLC_OBJECT_SOUT )
            {
                vlc_object_release( p_obj );
                sout_DeleteInstance( (sout_instance_t*)p_obj );
            }
        }
        *pb_obj_destroyed = VLC_TRUE;
    }
}

750
751
752
753
754
/*****************************************************************************
 * RunThread: main playlist thread
 *****************************************************************************/
static void RunThread ( playlist_t *p_playlist )
{
755
756
757
758
759
760
761
    vlc_object_t *p_obj;
    vlc_bool_t b_vout_destroyed = VLC_FALSE; /*we do vout garbage collector */
    mtime_t    i_vout_destroyed_date = 0;

    vlc_bool_t b_sout_destroyed = VLC_FALSE; /*we do vout garbage collector */
    mtime_t    i_sout_destroyed_date = 0;

762
763
764
    /* Tell above that we're ready */
    vlc_thread_ready( p_playlist );

765
766
    while( !p_playlist->b_die )
    {
767
768
        vlc_mutex_lock( &p_playlist->object_lock );

769
770
771
        /* If there is an input, check that it doesn't need to die. */
        if( p_playlist->p_input )
        {
Sam Hocevar's avatar
Sam Hocevar committed
772
            /* This input is dead. Remove it ! */
Sam Hocevar's avatar
Sam Hocevar committed
773
            if( p_playlist->p_input->b_dead )
774
775
776
777
778
            {
                input_thread_t *p_input;

                p_input = p_playlist->p_input;
                p_playlist->p_input = NULL;
779
780
781
782

                /* Release the playlist lock, because we may get stuck
                 * in input_DestroyThread() for some time. */
                vlc_mutex_unlock( &p_playlist->object_lock );
783
784
785

                /* Destroy input */
                input_DestroyThread( p_input );
786
787
788
789
790

                /* Unlink current input (_after_ input_DestroyThread for vout garbage collector)*/
                vlc_object_detach( p_input );

                /* Destroy object */
Sam Hocevar's avatar
Sam Hocevar committed
791
                vlc_object_destroy( p_input );
792
793
794
795
796

                b_vout_destroyed = VLC_FALSE;
                i_vout_destroyed_date = 0;
                b_sout_destroyed = VLC_FALSE;
                i_sout_destroyed_date = 0;
797
                continue;
798
            }
Sam Hocevar's avatar
Sam Hocevar committed
799
800
801
802
803
804
            /* This input is dying, let him do */
            else if( p_playlist->p_input->b_die )
            {
                ;
            }
            /* This input has finished, ask him to die ! */
Sam Hocevar's avatar
Sam Hocevar committed
805
806
            else if( p_playlist->p_input->b_error
                      || p_playlist->p_input->b_eof )
807
            {
gbazin's avatar
   
gbazin committed
808
809
810
                /* Check for autodeletion */
                if( p_playlist->pp_items[p_playlist->i_index]->b_autodeletion )
                {
gbazin's avatar
   
gbazin committed
811
                    vlc_mutex_unlock( &p_playlist->object_lock );
gbazin's avatar
   
gbazin committed
812
                    playlist_Delete( p_playlist, p_playlist->i_index );
gbazin's avatar
   
gbazin committed
813
                    vlc_mutex_lock( &p_playlist->object_lock );
gbazin's avatar
   
gbazin committed
814
815
816
817
818
                }

                /* Select the next playlist item */
                SkipItem( p_playlist, 1 );

Sam Hocevar's avatar
Sam Hocevar committed
819
                input_StopThread( p_playlist->p_input );
820
                vlc_mutex_unlock( &p_playlist->object_lock );
821
                continue;
822
            }
823
824
            else if( p_playlist->p_input->stream.control.i_status != INIT_S )
            {
825
                vlc_mutex_unlock( &p_playlist->object_lock );
826
                ObjectGarbageCollector( p_playlist, VLC_OBJECT_VOUT,
827
828
                                        &b_vout_destroyed,
                                        &i_vout_destroyed_date );
829
                ObjectGarbageCollector( p_playlist, VLC_OBJECT_SOUT,
830
831
832
                                        &b_sout_destroyed,
                                        &i_sout_destroyed_date );
                vlc_mutex_lock( &p_playlist->object_lock );
833
            }
834
835
836
        }
        else if( p_playlist->i_status != PLAYLIST_STOPPED )
        {
837
            SkipItem( p_playlist, 0 );
838
            PlayItem( p_playlist );
839
        }
840
841
        else if( p_playlist->i_status == PLAYLIST_STOPPED )
        {
842
            vlc_mutex_unlock( &p_playlist->object_lock );
843
844
            ObjectGarbageCollector( p_playlist, VLC_OBJECT_SOUT,
                                    &b_sout_destroyed, &i_sout_destroyed_date );
845
846
            ObjectGarbageCollector( p_playlist, VLC_OBJECT_VOUT,
                                    &b_vout_destroyed, &i_vout_destroyed_date );
847
            vlc_mutex_lock( &p_playlist->object_lock );
848
        }
849
850
        vlc_mutex_unlock( &p_playlist->object_lock );

851
852
853
854
        msleep( INTF_IDLE_SLEEP );
    }

    /* If there is an input, kill it */
855
    while( 1 )
856
    {
857
858
859
860
861
862
863
864
        vlc_mutex_lock( &p_playlist->object_lock );

        if( p_playlist->p_input == NULL )
        {
            vlc_mutex_unlock( &p_playlist->object_lock );
            break;
        }

Sam Hocevar's avatar
Sam Hocevar committed
865
        if( p_playlist->p_input->b_dead )
866
867
868
869
870
871
        {
            input_thread_t *p_input;

            /* Unlink current input */
            p_input = p_playlist->p_input;
            p_playlist->p_input = NULL;
872
            vlc_mutex_unlock( &p_playlist->object_lock );
873
874
875

            /* Destroy input */
            input_DestroyThread( p_input );
876
877
878
879
880
            /* Unlink current input (_after_ input_DestroyThread for vout
             * garbage collector)*/
            vlc_object_detach( p_input );

            /* Destroy object */
Sam Hocevar's avatar
Sam Hocevar committed
881
            vlc_object_destroy( p_input );
882
            continue;
883
        }
Sam Hocevar's avatar
Sam Hocevar committed
884
885
        else if( p_playlist->p_input->b_die )
        {
886
            /* This input is dying, leave him alone */
Sam Hocevar's avatar
Sam Hocevar committed
887
888
            ;
        }
Sam Hocevar's avatar
Sam Hocevar committed
889
        else if( p_playlist->p_input->b_error || p_playlist->p_input->b_eof )
890
        {
Sam Hocevar's avatar
Sam Hocevar committed
891
            input_StopThread( p_playlist->p_input );
892
            vlc_mutex_unlock( &p_playlist->object_lock );
893
            continue;
894
895
896
897
898
899
        }
        else
        {
            p_playlist->p_input->b_eof = 1;
        }

900
901
        vlc_mutex_unlock( &p_playlist->object_lock );

902
903
        msleep( INTF_IDLE_SLEEP );
    }
904

905
    /* close all remaining sout */
906
    while( ( p_obj = vlc_object_find( p_playlist,
907
                                      VLC_OBJECT_SOUT, FIND_CHILD ) ) )
908
909
    {
        vlc_object_release( p_obj );
910
        sout_DeleteInstance( (sout_instance_t*)p_obj );
911
    }
912
913

    /* close all remaining vout */
914
    while( ( p_obj = vlc_object_find( p_playlist,
915
                                      VLC_OBJECT_VOUT, FIND_CHILD ) ) )
916
    {
917
        vlc_object_detach( p_obj );
918
        vlc_object_release( p_obj );
919
        vout_Destroy( (vout_thread_t *)p_obj );
920
    }
921
922
}

923
924
925
926
927
928
929
930
931
/*****************************************************************************
 * SkipItem: go to Xth playlist item
 *****************************************************************************
 * This function calculates the position of the next playlist item, depending
 * on the playlist course mode (forward, backward, random...).
 *****************************************************************************/
static void SkipItem( playlist_t *p_playlist, int i_arg )
{
    int i_oldindex = p_playlist->i_index;
hartman's avatar
hartman committed
932
    vlc_bool_t b_random, b_repeat, b_loop;
933
    vlc_value_t val;
934

zorglub's avatar
zorglub committed
935
    msg_Dbg(p_playlist,"%i",p_playlist->i_enabled);
936
937
938
939
940
941
942
    /* If the playlist is empty, there is no current item */
    if( p_playlist->i_size == 0 )
    {
        p_playlist->i_index = -1;
        return;
    }

hartman's avatar
hartman committed
943
944
945
946
947
948
    var_Get( p_playlist, "random", &val );
    b_random = val.b_bool;
    var_Get( p_playlist, "repeat", &val );
    b_repeat = val.b_bool;
    var_Get( p_playlist, "loop", &val );
    b_loop = val.b_bool;
949

950
    /* Increment */
951
    if( b_random )
952
    {
953
        srand( (unsigned int)mdate() );
954
955
956
957
958
959
960
961

        /* Simple random stuff - we cheat a bit to minimize the chances to
         * get the same index again. */
        i_arg = (int)((float)p_playlist->i_size * rand() / (RAND_MAX+1.0));
        if( i_arg == 0 )
        {
            i_arg = (int)((float)p_playlist->i_size * rand() / (RAND_MAX+1.0));
        }
962
    }
hartman's avatar
hartman committed
963
964
965
966
    if( b_repeat )
    {
        i_arg = 0;
    }
967
968
    p_playlist->i_index += i_arg;

969
970
971
972
    /* Boundary check */
    if( p_playlist->i_index >= p_playlist->i_size )
    {
        if( p_playlist->i_status == PLAYLIST_STOPPED
973
             || b_random
hartman's avatar
hartman committed
974
             || b_loop )
975
        {
976
977
            p_playlist->i_index -= p_playlist->i_size
                         * ( p_playlist->i_index / p_playlist->i_size );
978
979
980
981
982
983
984
985
986
987
988
989
        }
        else
        {
            /* Don't loop by default: stop at playlist end */
            p_playlist->i_index = i_oldindex;
            p_playlist->i_status = PLAYLIST_STOPPED;
        }
    }
    else if( p_playlist->i_index < 0 )
    {
        p_playlist->i_index = p_playlist->i_size - 1;
    }
990

zorglub's avatar
zorglub committed
991
992
993
994
995
996
    /* Check that the item is enabled */
   if( p_playlist->pp_items[p_playlist->i_index]->b_enabled == VLC_FALSE &&
       p_playlist->i_enabled != 0)
   {
        SkipItem( p_playlist , 1 );
    }
997
998
    val.b_bool = VLC_TRUE;
    var_Set( p_playlist, "intf-change", val );
999
1000
}

For faster browsing, not all history is shown. View entire blame