Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
videolan
vlc
Commits
f9d5e2ba
Commit
f9d5e2ba
authored
Nov 06, 2004
by
Clément Stenac
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improvements to the playlist core
parent
07ec1808
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
2229 additions
and
857 deletions
+2229
-857
include/vlc_common.h
include/vlc_common.h
+10
-6
include/vlc_input.h
include/vlc_input.h
+15
-0
include/vlc_keys.h
include/vlc_keys.h
+2
-0
include/vlc_playlist.h
include/vlc_playlist.h
+163
-63
src/input/input.c
src/input/input.c
+6
-0
src/input/var.c
src/input/var.c
+3
-1
src/playlist/group.c
src/playlist/group.c
+0
-152
src/playlist/info.c
src/playlist/info.c
+1
-1
src/playlist/item-ext.c
src/playlist/item-ext.c
+336
-302
src/playlist/item.c
src/playlist/item.c
+174
-119
src/playlist/loadsave.c
src/playlist/loadsave.c
+37
-2
src/playlist/playlist.c
src/playlist/playlist.c
+442
-151
src/playlist/sort.c
src/playlist/sort.c
+151
-60
src/playlist/view.c
src/playlist/view.c
+889
-0
No files found.
include/vlc_common.h
View file @
f9d5e2ba
...
...
@@ -205,17 +205,21 @@ typedef struct msg_subscription_t msg_subscription_t;
* Playlist commands
*/
typedef
enum
{
PLAYLIST_PLAY
,
/**< Starts playing. No arg. */
PLAYLIST_PAUSE
,
/**< Toggles playlist pause. No arg. */
PLAYLIST_STOP
,
/**< Stops playing. No arg. */
PLAYLIST_SKIP
,
/**< Skip X items and play. */
PLAYLIST_GOTO
,
/**< Goto Xth item. */
PLAYLIST_PLAY
,
/**< No arg. res=can fail*/
PLAYLIST_VIEWPLAY
,
/**< arg1= int, arg2= playlist_item_t*,*/
/** arg3 = playlist_item_t* , res=can fail */
PLAYLIST_ITEMPLAY
,
/** <arg1 = playlist_item_t * , res=can fail */
PLAYLIST_PAUSE
,
/**< No arg res=can fail*/
PLAYLIST_STOP
,
/**< No arg res=can fail*/
PLAYLIST_SKIP
,
/**< arg1=int, res=can fail*/
PLAYLIST_GOTO
,
/**< arg1=int res=can fail */
PLAYLIST_VIEWGOTO
,
/**< arg1=int res=can fail */
}
playlist_command_t
;
typedef
struct
playlist_t
playlist_t
;
typedef
struct
playlist_item_t
playlist_item_t
;
typedef
struct
playlist_
group_t
playlist_group
_t
;
typedef
struct
playlist_
view_t
playlist_view
_t
;
typedef
struct
playlist_export_t
playlist_export_t
;
/* Modules */
...
...
include/vlc_input.h
View file @
f9d5e2ba
...
...
@@ -53,6 +53,9 @@ struct input_item_t
mtime_t
i_duration
;
/**< A hint about the duration of this
* item, in milliseconds*/
int
i_id
;
/**< Identifier of the item */
uint8_t
i_type
;
/**< Type (file, disc, ...) */
int
i_categories
;
/**< Number of info categories */
info_category_t
**
pp_categories
;
/**< Pointer to the first info category */
...
...
@@ -62,14 +65,26 @@ struct input_item_t
vlc_mutex_t
lock
;
/**< Item cannot be changed without this lock */
};
#define ITEM_TYPE_UNKNOWN 0
#define ITEM_TYPE_FILE 1
#define ITEM_TYPE_DIRECTORY 2
#define ITEM_TYPE_DISC 3
#define ITEM_TYPE_CARD 4
#define ITEM_TYPE_NET 5
#define ITEM_TYPE_PLAYLIST 6
static
inline
void
vlc_input_item_Init
(
vlc_object_t
*
p_o
,
input_item_t
*
p_i
)
{
memset
(
p_i
,
0
,
sizeof
(
input_item_t
)
);
p_i
->
i_options
=
0
;
p_i
->
i_es
=
0
;
p_i
->
i_categories
=
0
;
p_i
->
psz_name
=
0
;
p_i
->
psz_uri
=
0
;
p_i
->
ppsz_options
=
0
;
p_i
->
pp_categories
=
0
;
p_i
->
es
=
0
;
p_i
->
i_type
=
ITEM_TYPE_UNKNOWN
;
vlc_mutex_init
(
p_o
,
&
p_i
->
lock
);
}
...
...
include/vlc_keys.h
View file @
f9d5e2ba
...
...
@@ -232,5 +232,7 @@ static inline int StringToKey( char *psz_key )
#define ACTIONID_HISTORY_FORWARD 49
#define ACTIONID_AUDIO_TRACK 50
#define ACTIONID_SUBTITLE_TRACK 51
#define ACTIONID_CUBESPEED_UP 52
#define ACTIONID_CUBESPEED_DOWN 53
#define ACTIONID_INTF_SHOW 52
include/vlc_playlist.h
View file @
f9d5e2ba
...
...
@@ -42,35 +42,71 @@ struct playlist_export_t
FILE
*
p_file
;
};
struct
item_parent_t
{
int
i_view
;
playlist_item_t
*
p_parent
;
};
/**
* playlist item
* playlist item
/ node
* \see playlist_t
*/
struct
playlist_item_t
{
input_item_t
input
;
/**< input item descriptor */
int
i_nb_played
;
/**< How many times was this item played ? */
vlc_bool_t
b_autodeletion
;
/**< Indicates whther this item is to
* be deleted after playback. True mean
* that this item is to be deleted
* after playback, false otherwise */
vlc_bool_t
b_enabled
;
/**< Indicates whether this item is to be
* played or skipped */
int
i_group
;
/**< Which group does this item belongs to ? */
int
i_id
;
/**< Unique id to track this item */
input_item_t
input
;
/**< input item descriptor */
/* Tree specific fields */
int
i_children
;
/**< Number of children
-1 if not a node */
playlist_item_t
**
pp_children
;
/**< Children nodes/items */
int
i_parents
;
/**< Number of parents */
struct
item_parent_t
**
pp_parents
;
/**< Parents */
int
i_serial
;
/**< Has this node been updated ? */
uint8_t
i_flags
;
/**< Flags */
int
i_nb_played
;
/**< How many times was this item played ? */
vlc_bool_t
b_autodeletion
;
/**< Indicates whther this item is to
* be deleted after playback. True mean
* that this item is to be deleted
* after playback, false otherwise */
vlc_bool_t
b_enabled
;
/**< Indicates whether this item is to be
* played or skipped */
};
#define PLAYLIST_SAVE_FLAG 0x1
/**< Must it be saved */
#define PLAYLIST_SKIP_FLAG 0x2
/**< Must playlist skip after it ? */
#define PLAYLIST_ENA_FLAG 0x4
/**< Is it enabled ? */
#define PLAYLIST_DEL_FLAG 0x8
/**< Autodelete ? */
/**
* playlist
group
* playlist
view
* \see playlist_t
*/
struct
playlist_
group
_t
*/
struct
playlist_
view
_t
{
char
*
psz_name
;
/**< name of the group */
int
i_id
;
/**< Identifier for the group */
char
*
psz_name
;
/**< View name */
int
i_id
;
/**< Identifier for the view */
playlist_item_t
*
p_root
;
/**< Root node */
};
/**
* predefined views
*
*/
#define VIEW_CATEGORY 1
#define VIEW_SIMPLE 2
#define VIEW_ALL 3
#define VIEW_FIRST_SORTED 4
#define VIEW_S_AUTHOR 4
#define VIEW_LAST_SORTED 4
#define VIEW_FIRST_CUSTOM 100
/**
* Playlist status
*/
...
...
@@ -88,93 +124,153 @@ struct playlist_t
*/
/*@{*/
int
i_index
;
/**< current index into the playlist */
playlist_status_t
i_status
;
/**< current status of playlist */
int
i_size
;
/**< total size of the list */
int
i_enabled
;
/**< How many items are enabled ? */
int
i_size
;
/**< total size of the list */
playlist_item_t
**
pp_items
;
/**< array of pointers to the
* playlist items */
int
i_groups
;
/**< How many groups are in the playlist */
playlist_group_t
**
pp_groups
;
/**< array of pointers to the playlist
* groups */
int
i_last_group
;
/**< Maximal group id given */
int
i_views
;
/**< Number of views */
playlist_view_t
**
pp_views
;
/**< array of pointers to the
* playlist views */
input_thread_t
*
p_input
;
/**< the input thread ascosiated
* with the current item */
mtime_t
request_date
;
/**< Used for profiling */
int
i_last_id
;
/**< Last id to an item */
int
i_sort
;
/**< Last sorting applied to the playlist */
int
i_order
;
/**< Last ordering applied to the playlist */
playlist_item_t
*
p_general
;
/**< Keep a pointer on the "general"
category */
vlc_bool_t
b_go_next
;
/*< Go further than the parent node ? */
struct
{
/* Current status */
playlist_status_t
i_status
;
/**< Current status of playlist */
/* R/O fields, don't touch if you aren't the playlist thread */
/* Use a request */
playlist_item_t
*
p_item
;
/**< Currently playing/active item */
playlist_item_t
*
p_node
;
/**< Current node to play from */
int
i_view
;
/**< Current view */
}
status
;
struct
{
/* Request */
/* Playlist thread uses this info to calculate the next position */
int
i_view
;
/**< requested view id */
playlist_item_t
*
p_node
;
/**< requested node to play from */
playlist_item_t
*
p_item
;
/**< requested item to play in the node */
int
i_skip
;
/**< Number of items to skip */
int
i_goto
;
/**< Direct index to go to (non-view)*/
vlc_bool_t
b_request
;
/**< Set to true by the requester
The playlist sets it back to false
when processing the request */
vlc_mutex_t
lock
;
/**< Lock to protect request */
}
request
;
/*@}*/
};
#define SORT_ID 0
#define SORT_TITLE 1
#define SORT_AUTHOR 2
#define SORT_GROUP 3
#define SORT_RANDOM 4
#define SORT_DURATION 5
#define ORDER_NORMAL 0
#define ORDER_REVERSE 1
#define PLAYLIST_TYPE_MANUAL 1
#define PLAYLIST_TYPE_SAP 2
/*****************************************************************************
* Prototypes
*****************************************************************************/
/* Creation/Deletion */
#define playlist_Create(a) __playlist_Create(VLC_OBJECT(a))
playlist_t
*
__playlist_Create
(
vlc_object_t
*
);
void
playlist_Destroy
(
playlist_t
*
);
#define playlist_Play(p) playlist_Command(p,PLAYLIST_PLAY,0)
#define playlist_Pause(p) playlist_Command(p,PLAYLIST_PAUSE,0)
#define playlist_Stop(p) playlist_Command(p,PLAYLIST_STOP,0)
#define playlist_Next(p) playlist_Command(p,PLAYLIST_SKIP,1)
#define playlist_Prev(p) playlist_Command(p,PLAYLIST_SKIP,-1)
#define playlist_Skip(p,i) playlist_Command(p,PLAYLIST_SKIP,i)
#define playlist_Goto(p,i) playlist_Command(p,PLAYLIST_GOTO,i)
/* Playlist control */
#define playlist_Play(p) playlist_Control(p,PLAYLIST_PLAY )
#define playlist_Pause(p) playlist_Control(p,PLAYLIST_PAUSE )
#define playlist_Stop(p) playlist_Control(p,PLAYLIST_STOP )
#define playlist_Next(p) playlist_Control(p,PLAYLIST_SKIP , 1)
#define playlist_Prev(p) playlist_Control(p,PLAYLIST_SKIP , -1)
#define playlist_Skip(p,i) playlist_Control(p,PLAYLIST_SKIP,i)
#define playlist_Goto(p,i) playlist_Control(p,PLAYLIST_GOTO,i)
VLC_EXPORT
(
void
,
playlist_Command
,
(
playlist_t
*
,
playlist_command_t
,
int
)
);
VLC_EXPORT
(
int
,
playlist_Control
,
(
playlist_t
*
,
int
,
...
)
);
VLC_EXPORT
(
int
,
playlist_Clear
,
(
playlist_t
*
)
);
/* Item management functions */
/* Item management functions
(act on items)
*/
#define playlist_AddItem(p,pi,i1,i2) playlist_ItemAdd(p,pi,i1,i2)
#define playlist_ItemNew( a , b, c ) __playlist_ItemNew(VLC_OBJECT(a) , b , c )
VLC_EXPORT
(
playlist_item_t
*
,
__playlist_ItemNew
,
(
vlc_object_t
*
,
const
char
*
,
const
char
*
)
);
VLC_EXPORT
(
void
,
playlist_ItemDelete
,
(
playlist_item_t
*
)
);
VLC_EXPORT
(
int
,
playlist_ItemAdd
,
(
playlist_t
*
,
playlist_item_t
*
,
int
,
int
)
);
VLC_EXPORT
(
void
,
playlist_ItemAddParent
,
(
playlist_item_t
*
,
int
,
playlist_item_t
*
)
);
/* Item informations accessors */
VLC_EXPORT
(
int
,
playlist_ItemSetName
,
(
playlist_item_t
*
,
char
*
)
);
VLC_EXPORT
(
int
,
playlist_ItemSetDuration
,
(
playlist_item_t
*
,
mtime_t
)
);
/* Simple add/remove funcctions */
/* View management functions */
VLC_EXPORT
(
int
,
playlist_ViewInsert
,
(
playlist_t
*
,
int
,
char
*
)
);
VLC_EXPORT
(
void
,
playlist_ViewDelete
,
(
playlist_t
*
,
playlist_view_t
*
)
);
VLC_EXPORT
(
playlist_view_t
*
,
playlist_ViewFind
,
(
playlist_t
*
,
int
)
);
VLC_EXPORT
(
int
,
playlist_ViewUpdate
,
(
playlist_t
*
,
int
)
);
VLC_EXPORT
(
void
,
playlist_ViewDump
,
(
playlist_t
*
,
playlist_view_t
*
)
);
VLC_EXPORT
(
int
,
playlist_ViewEmpty
,
(
playlist_t
*
,
int
,
vlc_bool_t
)
);
/* Node management */
VLC_EXPORT
(
playlist_item_t
*
,
playlist_NodeCreate
,
(
playlist_t
*
,
int
,
char
*
,
playlist_item_t
*
p_parent
)
);
VLC_EXPORT
(
int
,
playlist_NodeAppend
,
(
playlist_t
*
,
int
,
playlist_item_t
*
,
playlist_item_t
*
)
);
VLC_EXPORT
(
int
,
playlist_NodeInsert
,
(
playlist_t
*
,
int
,
playlist_item_t
*
,
playlist_item_t
*
,
int
)
);
VLC_EXPORT
(
int
,
playlist_NodeRemoveItem
,
(
playlist_t
*
,
playlist_item_t
*
,
playlist_item_t
*
)
);
VLC_EXPORT
(
int
,
playlist_NodeChildrenCount
,
(
playlist_t
*
,
playlist_item_t
*
)
);
VLC_EXPORT
(
playlist_item_t
*
,
playlist_ChildSearchName
,
(
playlist_item_t
*
,
const
char
*
)
);
VLC_EXPORT
(
int
,
playlist_NodeDelete
,
(
playlist_t
*
,
playlist_item_t
*
,
vlc_bool_t
)
);
VLC_EXPORT
(
int
,
playlist_NodeEmpty
,
(
playlist_t
*
,
playlist_item_t
*
,
vlc_bool_t
)
);
/* Tree walking */
playlist_item_t
*
playlist_FindNextFromParent
(
playlist_t
*
p_playlist
,
int
i_view
,
playlist_item_t
*
p_root
,
playlist_item_t
*
p_node
,
playlist_item_t
*
p_item
);
playlist_item_t
*
playlist_FindPrevFromParent
(
playlist_t
*
p_playlist
,
int
i_view
,
playlist_item_t
*
p_root
,
playlist_item_t
*
p_node
,
playlist_item_t
*
p_item
);
/* Simple add/remove functions */
/* These functions add the item to the "simple" view (+all & category )*/
VLC_EXPORT
(
int
,
playlist_Add
,
(
playlist_t
*
,
const
char
*
,
const
char
*
,
int
,
int
)
);
VLC_EXPORT
(
int
,
playlist_AddExt
,
(
playlist_t
*
,
const
char
*
,
const
char
*
,
int
,
int
,
mtime_t
,
const
char
**
,
int
)
);
VLC_EXPORT
(
int
,
playlist_ItemAdd
,
(
playlist_t
*
,
playlist_item_t
*
,
int
,
int
)
);
VLC_EXPORT
(
int
,
playlist_NodeAddItem
,
(
playlist_t
*
,
playlist_item_t
*
,
int
,
playlist_item_t
*
,
int
,
int
)
);
VLC_EXPORT
(
int
,
playlist_Clear
,
(
playlist_t
*
)
);
/* Misc item operations (act on item+playlist) */
VLC_EXPORT
(
int
,
playlist_Delete
,
(
playlist_t
*
,
int
)
);
VLC_EXPORT
(
int
,
playlist_Disable
,
(
playlist_t
*
,
int
)
);
VLC_EXPORT
(
int
,
playlist_Enable
,
(
playlist_t
*
,
int
)
);
VLC_EXPORT
(
int
,
playlist_DisableGroup
,
(
playlist_t
*
,
int
)
);
VLC_EXPORT
(
int
,
playlist_EnableGroup
,
(
playlist_t
*
,
int
)
);
/* Basic item information accessors */
VLC_EXPORT
(
int
,
playlist_ItemSetGroup
,
(
playlist_item_t
*
,
int
)
);
VLC_EXPORT
(
int
,
playlist_ItemSetName
,
(
playlist_item_t
*
,
char
*
)
);
VLC_EXPORT
(
int
,
playlist_ItemSetDuration
,
(
playlist_item_t
*
,
mtime_t
)
);
VLC_EXPORT
(
int
,
playlist_Disable
,
(
playlist_t
*
,
playlist_item_t
*
)
);
VLC_EXPORT
(
int
,
playlist_Enable
,
(
playlist_t
*
,
playlist_item_t
*
)
);
VLC_EXPORT
(
void
,
playlist_ItemToNode
,
(
playlist_t
*
,
playlist_item_t
*
)
);
VLC_EXPORT
(
int
,
playlist_SetGroup
,
(
playlist_t
*
,
int
,
int
)
);
VLC_EXPORT
(
int
,
playlist_SetName
,
(
playlist_t
*
,
int
,
char
*
)
);
VLC_EXPORT
(
int
,
playlist_SetDuration
,
(
playlist_t
*
,
int
,
mtime_t
)
);
/* Item search functions */
VLC_EXPORT
(
int
,
playlist_GetPositionById
,
(
playlist_t
*
,
int
)
);
VLC_EXPORT
(
playlist_item_t
*
,
playlist_ItemGetById
,
(
playlist_t
*
,
int
)
);
VLC_EXPORT
(
playlist_item_t
*
,
playlist_ItemGetByPos
,
(
playlist_t
*
,
int
)
);
/* Group management functions */
VLC_EXPORT
(
playlist_group_t
*
,
playlist_CreateGroup
,
(
playlist_t
*
,
char
*
)
);
VLC_EXPORT
(
int
,
playlist_DeleteGroup
,
(
playlist_t
*
,
int
)
);
VLC_EXPORT
(
char
*
,
playlist_FindGroup
,
(
playlist_t
*
,
int
)
);
VLC_EXPORT
(
int
,
playlist_GroupToId
,
(
playlist_t
*
,
char
*
)
);
VLC_EXPORT
(
int
,
playlist_GetPositionById
,
(
playlist_t
*
,
int
)
);
/* Info functions */
VLC_EXPORT
(
char
*
,
playlist_GetInfo
,
(
playlist_t
*
,
int
,
const
char
*
,
const
char
*
)
);
...
...
@@ -186,8 +282,6 @@ VLC_EXPORT( info_category_t*, playlist_ItemCreateCategory, ( playlist_item_t *,
VLC_EXPORT
(
int
,
playlist_AddInfo
,
(
playlist_t
*
,
int
,
const
char
*
,
const
char
*
,
const
char
*
,
...)
);
VLC_EXPORT
(
int
,
playlist_ItemAddInfo
,
(
playlist_item_t
*
,
const
char
*
,
const
char
*
,
const
char
*
,
...)
);
/* Option functions */
VLC_EXPORT
(
int
,
playlist_ItemAddOption
,
(
playlist_item_t
*
,
const
char
*
)
);
/* Playlist sorting */
...
...
@@ -197,11 +291,17 @@ VLC_EXPORT( int, playlist_ItemAddOption, (playlist_item_t *, const char *) );
#define playlist_SortGroup(p, i) playlist_Sort( p, SORT_GROUP, i)
VLC_EXPORT
(
int
,
playlist_Sort
,
(
playlist_t
*
,
int
,
int
)
);
VLC_EXPORT
(
int
,
playlist_Move
,
(
playlist_t
*
,
int
,
int
)
);
VLC_EXPORT
(
int
,
playlist_NodeGroup
,
(
playlist_t
*
,
int
,
playlist_item_t
*
,
playlist_item_t
**
,
int
,
int
,
int
)
);
/* Load/Save */
VLC_EXPORT
(
int
,
playlist_Import
,
(
playlist_t
*
,
const
char
*
)
);
VLC_EXPORT
(
int
,
playlist_Export
,
(
playlist_t
*
,
const
char
*
,
const
char
*
)
);
/***********************************************************************
* Inline functions
***********************************************************************/
/**
* tell if a playlist is currently playing.
* \param p_playlist the playlist to check
...
...
@@ -212,7 +312,7 @@ static inline vlc_bool_t playlist_IsPlaying( playlist_t * p_playlist )
vlc_bool_t
b_playing
;
vlc_mutex_lock
(
&
p_playlist
->
object_lock
);
b_playing
=
p_playlist
->
i_status
==
PLAYLIST_RUNNING
;
b_playing
=
p_playlist
->
status
.
i_status
==
PLAYLIST_RUNNING
;
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
return
(
b_playing
);
...
...
src/input/input.c
View file @
f9d5e2ba
...
...
@@ -580,6 +580,7 @@ static int Init( input_thread_t * p_input )
var_Change
(
p_input
,
"length"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
UpdateItemLength
(
p_input
,
val
.
i_time
);
p_input
->
input
.
p_item
->
i_duration
=
val
.
i_time
;
}
/* Start title/chapter */
...
...
@@ -893,6 +894,11 @@ static int Init( input_thread_t * p_input )
msg_Dbg
(
p_input
,
"`%s' sucessfully opened"
,
p_input
->
input
.
p_item
->
psz_uri
);
/* Trigger intf update for this item */
/* Playlist has a callback on this variable and will forward
* it to intf */
var_SetInteger
(
p_input
,
"item-change"
,
p_input
->
input
.
p_item
->
i_id
);
/* initialization is complete */
p_input
->
i_state
=
PLAYING_S
;
...
...
src/input/var.c
View file @
f9d5e2ba
...
...
@@ -190,12 +190,14 @@ void input_ControlVarInit ( input_thread_t *p_input )
var_Change
(
p_input
,
"length"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
/* Special "intf-change" variable, it allows intf to set up a callback
* to be notified of some changes.
* TODO list all changes warn by this callbacks */
var_Create
(
p_input
,
"intf-change"
,
VLC_VAR_BOOL
);
var_SetBool
(
p_input
,
"intf-change"
,
VLC_TRUE
);
/* item-change variable */
var_Create
(
p_input
,
"item-change"
,
VLC_VAR_INTEGER
);
}
/*****************************************************************************
...
...
src/playlist/group.c
deleted
100644 → 0
View file @
07ec1808
/*****************************************************************************
* playlist.c : Playlist groups management functions
*****************************************************************************
* Copyright (C) 1999-2004 VideoLAN
* $Id$
*
* Authors: Clment Stenac <zorglub@videolan.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.
*
* 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>
#include <vlc/input.h>
#include "vlc_playlist.h"
/**
* Create a group
*
* Create a new group
* \param p_playlist pointer to a playlist
* \param psz_name the name of the group to be created
* \return a pointer to the created group, or NULL on error
*/
playlist_group_t
*
playlist_CreateGroup
(
playlist_t
*
p_playlist
,
char
*
psz_name
)
{
playlist_group_t
*
p_group
;
int
i
;
for
(
i
=
0
;
i
<
p_playlist
->
i_groups
;
i
++
)
{
if
(
!
strcasecmp
(
p_playlist
->
pp_groups
[
i
]
->
psz_name
,
psz_name
)
)
{
msg_Info
(
p_playlist
,
"this group already exists"
);
return
p_playlist
->
pp_groups
[
i
];
}
}
/* Allocate the group structure */
if
(
(
p_group
=
malloc
(
sizeof
(
playlist_group_t
)
)
)
==
NULL
)
{
msg_Err
(
p_playlist
,
"out of memory"
);
return
NULL
;
}
p_group
->
psz_name
=
strdup
(
psz_name
);
p_group
->
i_id
=
++
p_playlist
->
i_last_group
;
msg_Dbg
(
p_playlist
,
"creating group %s with id %i at position %i"
,
p_group
->
psz_name
,
p_group
->
i_id
,
p_playlist
->
i_groups
);
INSERT_ELEM
(
p_playlist
->
pp_groups
,
p_playlist
->
i_groups
,
p_playlist
->
i_groups
,
p_group
);
return
p_group
;
}
/**
* Destroy a group
*
* \param p_playlist the playlist to remove the group from
* \param i_id the identifier of the group to remove
* \return VLC_SUCCESS
*/
int
playlist_DeleteGroup
(
playlist_t
*
p_playlist
,
int
i_id
)
{
int
i
;
for
(
i
=
0
;
i
<=
p_playlist
->
i_groups
;
i
++
)
{
playlist_group_t
*
p_group
=
p_playlist
->
pp_groups
[
i
];
if
(
p_group
->
i_id
==
i_id
)
{
if
(
p_group
->
psz_name
)
{
free
(
p_group
->
psz_name
);
}
REMOVE_ELEM
(
p_playlist
->
pp_groups
,
p_playlist
->
i_groups
,
i
);
free
(
p_group
);
return
VLC_SUCCESS
;
}
}
return
VLC_SUCCESS
;
}
/**
* Find the name of the group given its ID
*
* \param p_playlist the playlist where to find the group
* \param i_id the ID to search for
* \return the name of the group
*/
char
*
playlist_FindGroup
(
playlist_t
*
p_playlist
,
int
i_id
)
{
int
i
;
for
(
i
=
0
;
i
<
p_playlist
->
i_groups
;
i
++
)
{
if
(
p_playlist
->
pp_groups
[
i
]
->
i_id
==
i_id
)
{
if
(
p_playlist
->
pp_groups
[
i
]
->
psz_name
)
return
strdup
(
p_playlist
->
pp_groups
[
i
]
->
psz_name
);
}
}
return
NULL
;
}
/**
* Find the id of a group given its name
*
* \param p_playlist the playlist where to find the group
* \param psz_name the name to search for
* \return the id of the group
*/
int
playlist_GroupToId
(
playlist_t
*
p_playlist
,
char
*
psz_name
)
{
int
i
;
for
(
i
=
0
;
i
<
p_playlist
->
i_groups
;
i
++
)
{
if
(
p_playlist
->
pp_groups
[
i
]
->
psz_name
)
{
if
(
!
strcasecmp
(
p_playlist
->
pp_groups
[
i
]
->
psz_name
,
psz_name
)
)
{
return
p_playlist
->
pp_groups
[
i
]
->
i_id
;
}
}
}
return
VLC_SUCCESS
;
}
src/playlist/info.c
View file @
f9d5e2ba
...
...
@@ -122,7 +122,7 @@ info_category_t * playlist_ItemGetCategory( playlist_item_t *p_item,
* \return the info category.
*/
info_category_t
*
playlist_ItemCreateCategory
(
playlist_item_t
*
p_item
,
const
char
*
psz_cat
)
const
char
*
psz_cat
)
{
info_category_t
*
p_cat
;
int
i
;
...
...
src/playlist/item-ext.c
View file @
f9d5e2ba
/*****************************************************************************
* item-ext.c : Playlist item management functions
* item-ext.c : Playlist item management functions
(act on the playlist)
*****************************************************************************
* Copyright (C) 1999-2004 VideoLAN
* $Id$
...
...
@@ -54,8 +54,8 @@ int playlist_AddExt( playlist_t *p_playlist, const char * psz_uri,
mtime_t
i_duration
,
const
char
**
ppsz_options
,
int
i_options
)
{
playlist_item_t
*
p_item
=
playlist_ItemNew
(
p_playlist
,
psz_uri
,
psz_name
);
playlist_item_t
*
p_item
;
p_item
=
playlist_ItemNew
(
p_playlist
,
psz_uri
,
psz_name
);
if
(
p_item
==
NULL
)
{
...
...
@@ -102,295 +102,416 @@ int playlist_Add( playlist_t *p_playlist, const char *psz_uri,
-
1
,
NULL
,
0
);
}
/***************************************************************************
* Item search functions
***************************************************************************/
/**
* Search the position of an item by its id
* This function must be entered with the playlist lock
* Add a playlist item into a playlist
*
* \param p_playlist the playlist
* \param i_id the id to find
* \return the position, or VLC_EGENERIC on failure
* \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 The id of the playlist item
*/
int
playlist_GetPositionById
(
playlist_t
*
p_playlist
,
int
i_id
)
int
playlist_AddItem
(
playlist_t
*
p_playlist
,
playlist_item_t
*
p_item
,
int
i_mode
,
int
i_pos
)
{
int
i
;
for
(
i
=
0
;
i
<
p_playlist
->
i_size
;
i
++
)
vlc_value_t
val
;
vlc_bool_t
b_end
=
VLC_FALSE
;
playlist_view_t
*
p_view
;
vlc_mutex_lock
(
&
p_playlist
->
object_lock
);
/*
* CHECK_INSERT : checks if the item is already enqued before
* enqueing it
*/
/* That should not change */
if
(
i_mode
&
PLAYLIST_CHECK_INSERT
)
{
if
(
p_playlist
->
pp_items
[
i
]
->
i_id
==
i_id
)
int
j
;
if
(
p_playlist
->
pp_items
)
{
return
i
;
}
for
(
j
=
0
;
j
<
p_playlist
->
i_size
;
j
++
)
{
if
(
!
strcmp
(
p_playlist
->
pp_items
[
j
]
->
input
.
psz_uri
,
p_item
->
input
.
psz_uri
)
)
{
playlist_ItemDelete
(
p_item
);
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
return
-
1
;
}
}
}
i_mode
&=
~
PLAYLIST_CHECK_INSERT
;
i_mode
|=
PLAYLIST_APPEND
;
}
return
VLC_EGENERIC
;
}
/**
* Search an item by its id
*
* \param p_playlist the playlist
* \param i_id the id to find
* \return the item, or NULL on failure
*/
playlist_item_t
*
playlist_ItemGetById
(
playlist_t
*
p_playlist
,
int
i_id
)
{
int
i
;
for
(
i
=
0
;
i
<
p_playlist
->
i_size
;
i
++
)
msg_Dbg
(
p_playlist
,
"adding playlist item `%s' ( %s )"
,
p_item
->
input
.
psz_name
,
p_item
->
input
.
psz_uri
);
p_item
->
input
.
i_id
=
++
p_playlist
->
i_last_id
;
/* Do a few boundary checks and allocate space for the item */
if
(
i_pos
==
PLAYLIST_END
)
{
if
(
p_playlist
->
pp_items
[
i
]
->
i_id
==
i_id
)
b_end
=
VLC_TRUE
;
if
(
i_mode
&
PLAYLIST_INSERT
)
{
return
p_playlist
->
pp_items
[
i
];
i_mode
&=
~
PLAYLIST_INSERT
;
i_mode
|=
PLAYLIST_APPEND
;
}
i_pos
=
p_playlist
->
i_size
-
1
;
}
return
NULL
;
}
/**
* Search an item by its position
* This function must be entered with the playlist lock
*
* \param p_playlist the playlist
* \param i_pos the position of the item to find
* \return the item, or NULL on failure
*/
playlist_item_t
*
playlist_ItemGetByPos
(
playlist_t
*
p_playlist
,
int
i_pos
)
{
if
(
i_pos
>=
0
&&
i_pos
<
p_playlist
->
i_size
)
if
(
!
(
i_mode
&
PLAYLIST_REPLACE
)
||
i_pos
<
0
||
i_pos
>=
p_playlist
->
i_size
)
{
return
p_playlist
->
pp_items
[
i_pos
];
/* Additional boundary checks */
if
(
i_mode
&
PLAYLIST_APPEND
)
{
i_pos
++
;
}
if
(
i_pos
<
0
)
{
i_pos
=
0
;
}
else
if
(
i_pos
>
p_playlist
->
i_size
)
{
i_pos
=
p_playlist
->
i_size
;
}
INSERT_ELEM
(
p_playlist
->
pp_items
,
p_playlist
->
i_size
,
i_pos
,
p_item
);
p_playlist
->
i_enabled
++
;
/* We update the ALL view directly */
playlist_ViewUpdate
(
p_playlist
,
VIEW_ALL
);
/* Add the item to the General category */
if
(
b_end
==
VLC_TRUE
)
{
playlist_NodeAppend
(
p_playlist
,
VIEW_CATEGORY
,
p_item
,
p_playlist
->
p_general
);
}
else
{
playlist_NodeInsert
(
p_playlist
,
VIEW_CATEGORY
,
p_item
,
p_playlist
->
p_general
,
i_pos
);
}
p_view
=
playlist_ViewFind
(
p_playlist
,
VIEW_ALL
);
playlist_ItemAddParent
(
p_item
,
VIEW_ALL
,
p_view
->
p_root
);
/* Also add the item to the "simple" view */
p_view
=
playlist_ViewFind
(
p_playlist
,
VIEW_SIMPLE
);
if
(
b_end
==
VLC_TRUE
)
{
playlist_NodeAppend
(
p_playlist
,
VIEW_SIMPLE
,
p_item
,
p_view
->
p_root
);
}
else
{
playlist_NodeInsert
(
p_playlist
,
VIEW_SIMPLE
,
p_item
,
p_view
->
p_root
,
i_pos
);
}
/* FIXME : Update sorted views */
if
(
p_playlist
->
i_index
>=
i_pos
)
{
p_playlist
->
i_index
++
;
}
}
else
if
(
p_playlist
->
i_size
>
0
)
else
{
return
p_playlist
->
pp_items
[
p_playlist
->
i_index
]
;
msg_Err
(
p_playlist
,
"Insert mode not implemented"
)
;
}
else
if
(
i_mode
&
PLAYLIST_GO
)
{
return
NULL
;
p_playlist
->
request
.
b_request
=
VLC_TRUE
;
/* FIXME ... */
p_playlist
->
request
.
i_view
=
VIEW_SIMPLE
;
p_playlist
->
request
.
p_node
=
p_view
->
p_root
;
p_playlist
->
request
.
p_item
=
p_item
;
if
(
p_playlist
->
p_input
)
{
input_StopThread
(
p_playlist
->
p_input
);
}
p_playlist
->
status
.
i_status
=
PLAYLIST_RUNNING
;
}
}
/**********************************************************************
* playlist_item_t structure accessors
* These functions give access to the fields of the playlist_item_t
* structure
**********************************************************************/
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
/**
* Set the group of a playlist item
*
* \param p_item the item
* \param i_group the group to set
* \return VLC_SUCCESS on success
*/
int
playlist_ItemSetGroup
(
playlist_item_t
*
p_item
,
int
i_group
)
{
p_item
->
i_group
=
i_group
;
return
VLC_SUCCESS
;
val
.
b_bool
=
VLC_TRUE
;
var_Set
(
p_playlist
,
"intf-change"
,
val
);
return
p_item
->
input
.
i_id
;
}
/**
* Set the group of a playlist item (by position)
* This function must be entered with the playlist lock
* Legacy function due to disappear (locks the whole playlist)
* Add a playlist item to a given node (in the category view )
*
* \param p_playlist the playlist
* \param i_pos the postition of the item of which we change the group
* \param i_group the new group
* \return VLC_SUCCESS on success, VLC_EGENERIC on failure
* \param p_playlist the playlist to insert into
* \param p_item the playlist item to insert
* \param i_view the view for which to add or TODO: ALL_VIEWS
* \param p_parent the parent node
* \param i_mode the mode used when adding
* \param i_pos the possition in the node where to add. If this is
* PLAYLIST_END the item will be added at the end of the node
** \return The id of the playlist item
*/
int
playlist_SetGroup
(
playlist_t
*
p_playlist
,
int
i_pos
,
int
i_group
)
int
playlist_NodeAddItem
(
playlist_t
*
p_playlist
,
playlist_item_t
*
p_item
,
int
i_view
,
playlist_item_t
*
p_parent
,
int
i_mode
,
int
i_pos
)
{
vlc_value_t
val
;
playlist_item_t
*
p_item
;
if
(
!
p_playlist
)
int
i_position
;
playlist_view_t
*
p_view
;
vlc_mutex_lock
(
&
p_playlist
->
object_lock
);
/* Sanity checks */
if
(
!
p_parent
||
p_parent
->
i_children
==
-
1
)
{
return
VLC_ENOOBJ
;
msg_Err
(
p_playlist
,
"invalid node"
)
;
}
p_item
=
playlist_ItemGetByPos
(
p_playlist
,
i_pos
);
if
(
!
p_item
)
/*
* CHECK_INSERT : checks if the item is already enqued before
* enqueing it
*/
if
(
i_mode
&
PLAYLIST_CHECK_INSERT
)
{
return
VLC_ENOOBJ
;
int
j
;
if
(
p_playlist
->
pp_items
)
{
for
(
j
=
0
;
j
<
p_playlist
->
i_size
;
j
++
)
{
if
(
!
strcmp
(
p_playlist
->
pp_items
[
j
]
->
input
.
psz_uri
,
p_item
->
input
.
psz_uri
)
)
{
playlist_ItemDelete
(
p_item
);
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
return
-
1
;
}
}
}
i_mode
&=
~
PLAYLIST_CHECK_INSERT
;
i_mode
|=
PLAYLIST_APPEND
;
}
vlc_mutex_lock
(
&
p_item
->
input
.
lock
);
playlist_ItemSetGroup
(
p_item
,
i_group
);
vlc_mutex_unlock
(
&
p_item
->
input
.
lock
);
msg_Dbg
(
p_playlist
,
"adding playlist item `%s' ( %s )"
,
p_item
->
input
.
psz_name
,
p_item
->
input
.
psz_uri
);
val
.
b_bool
=
(
i_pos
>=
0
&&
i_pos
<
p_playlist
->
i_size
)
?
i_pos
:
-
1
;
var_Set
(
p_playlist
,
"item-change"
,
val
);
p_item
->
input
.
i_id
=
++
p_playlist
->
i_last_id
;
return
VLC_SUCCESS
;
/* First, add the item at the right position in the item bank */
/* WHY THAT ? */
//i_position = p_playlist->i_index == -1 ? 0 : p_playlist->i_index;
i_position
=
p_playlist
->
i_size
;
INSERT_ELEM
(
p_playlist
->
pp_items
,
p_playlist
->
i_size
,
i_position
,
p_item
);
p_playlist
->
i_enabled
++
;
/* TODO: Handle modes */
playlist_NodeAppend
(
p_playlist
,
i_view
,
p_item
,
p_parent
);
/* We update the ALL view directly */
p_view
=
playlist_ViewFind
(
p_playlist
,
VIEW_ALL
);
playlist_ItemAddParent
(
p_item
,
VIEW_ALL
,
p_view
->
p_root
);
playlist_ViewUpdate
(
p_playlist
,
VIEW_ALL
);
/* TODO : Update sorted views*/
if
(
i_mode
&
PLAYLIST_GO
)
{
p_playlist
->
request
.
b_request
=
VLC_TRUE
;
p_playlist
->
request
.
i_view
=
VIEW_CATEGORY
;
p_playlist
->
request
.
p_node
=
p_parent
;
p_playlist
->
request
.
p_item
=
p_item
;
if
(
p_playlist
->
p_input
)
{
input_StopThread
(
p_playlist
->
p_input
);
}
p_playlist
->
status
.
i_status
=
PLAYLIST_RUNNING
;
}
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
val
.
b_bool
=
VLC_TRUE
;
var_Set
(
p_playlist
,
"intf-change"
,
val
);
return
p_item
->
input
.
i_id
;
}
/***************************************************************************
* Item search functions
***************************************************************************/
/**
* Set the name of a playlist item
* Search the position of an item by its id
* This function must be entered with the playlist lock
*
* \param p_
item the item
* \param
psz_name the new name
* \return
VLC_SUCCESS on success,
VLC_EGENERIC on failure
* \param p_
playlist the playlist
* \param
i_id the id to find
* \return
the position, or
VLC_EGENERIC on failure
*/
int
playlist_
ItemSetName
(
playlist_item_t
*
p_item
,
char
*
psz_name
)
int
playlist_
GetPositionById
(
playlist_t
*
p_playlist
,
int
i_id
)
{
if
(
psz_name
&&
p_item
)
int
i
;
for
(
i
=
0
;
i
<
p_playlist
->
i_size
;
i
++
)
{
p_item
->
input
.
psz_name
=
strdup
(
psz_name
);
return
VLC_SUCCESS
;
if
(
p_playlist
->
pp_items
[
i
]
->
input
.
i_id
==
i_id
)
{
return
i
;
}
}
return
VLC_EGENERIC
;
}
/**
* Se
t the name of a playlist item (by position)
* Se
arch an item by its position
* This function must be entered with the playlist lock
* Legacy function due to disappear (locks the whole playlist)
*
* \param p_playlist the playlist
* \param i_pos the position of the item of which we change the name
* \param psz_name the new name
* \return VLC_SUCCESS on success, VLC_EGENERIC on failure
* \param i_pos the position of the item to find
* \return the item, or NULL on failure
*/
int
playlist_SetName
(
playlist_t
*
p_playlist
,
int
i_pos
,
char
*
psz_name
)
playlist_item_t
*
playlist_ItemGetByPos
(
playlist_t
*
p_playlist
,
int
i_pos
)
{
vlc_value_t
val
;
playlist_item_t
*
p_item
;
if
(
!
p_playlist
)
if
(
i_pos
>=
0
&&
i_pos
<
p_playlist
->
i_size
)
{
return
VLC_ENOOBJ
;
return
p_playlist
->
pp_items
[
i_pos
]
;
}
p_item
=
playlist_ItemGetByPos
(
p_playlist
,
i_pos
);
if
(
!
p_item
)
else
if
(
p_playlist
->
i_size
>
0
)
{
return
VLC_ENOOBJ
;
return
p_playlist
->
pp_items
[
p_playlist
->
i_index
];
}
else
{
return
NULL
;
}
vlc_mutex_lock
(
&
p_item
->
input
.
lock
);
playlist_ItemSetName
(
p_item
,
psz_name
);
vlc_mutex_unlock
(
&
p_item
->
input
.
lock
);
val
.
b_bool
=
(
i_pos
>=
0
&&
i_pos
<
p_playlist
->
i_size
)
?
i_pos
:
-
1
;
var_Set
(
p_playlist
,
"item-change"
,
val
);
return
VLC_SUCCESS
;
}
/**
* Set the duration of a playlist item
* This function must be entered with the item lock
* Search an item by its id
*
* \param p_
item the item
* \param i_
duration the new duration
* \return
VLC_SUCCESS on success, VLC_EGENERIC
on failure
* \param p_
playlist the playlist
* \param i_
id the id to find
* \return
the item, or NULL
on failure
*/
int
playlist_ItemSetDuration
(
playlist_item_t
*
p_item
,
mtime_t
i_duration
)
playlist_item_t
*
playlist_ItemGetById
(
playlist_t
*
p_playlist
,
int
i_id
)
{
char
psz_buffer
[
MSTRTIME_MAX_SIZE
]
;
if
(
p_item
)
int
i
;
for
(
i
=
0
;
i
<
p_playlist
->
i_size
;
i
++
)
{
p_item
->
input
.
i_duration
=
i_duration
;
if
(
i_duration
!=
-
1
)
if
(
p_playlist
->
pp_items
[
i
]
->
input
.
i_id
==
i_id
)
{
secstotimestr
(
psz_buffer
,
i_duration
/
1000000
);
}
else
{
memcpy
(
psz_buffer
,
"--:--:--"
,
sizeof
(
"--:--:--"
)
);
return
p_playlist
->
pp_items
[
i
];
}
playlist_ItemAddInfo
(
p_item
,
_
(
"General"
)
,
_
(
"Duration"
),
"%s"
,
psz_buffer
);
return
VLC_SUCCESS
;
}
return
VLC_EGENERIC
;
return
NULL
;
}
/***********************************************************************
* Misc functions
***********************************************************************/
/**
* Set the duration of a playlist item
* This function must be entered with the playlist lock
* Legacy function due to disappear (locks the whole playlist)
* Transform an item to a node
*
* \param p_playlist the playlist
* \param i_pos the position of the item of which we change the duration
* \param i_duration the duration to set
* \return VLC_SUCCESS on success, VLC_EGENERIC on failure
* \param p_playlist the playlist object
* \param p_item the item to transform
* \return nothing
*/
int
playlist_SetDuration
(
playlist_t
*
p_playlist
,
int
i_pos
,
mtime_t
i_duration
)
void
playlist_ItemToNode
(
playlist_t
*
p_playlist
,
playlist_item_t
*
p_item
)
{
vlc_value_t
val
;
playlist_item_t
*
p_item
;
if
(
!
p_playlist
)
int
i
=
0
;
if
(
p_item
->
i_children
==
-
1
)
{
return
VLC_ENOOBJ
;
p_item
->
i_children
=
0
;
}
p_item
=
playlist_ItemGetByPos
(
p_playlist
,
i_pos
);
if
(
!
p_item
)
vlc_mutex_lock
(
&
p_playlist
->
object_lock
);
/* Remove it from the array of available items */
for
(
i
=
0
;
i
<
p_playlist
->
i_size
;
i
++
)
{
return
VLC_ENOOBJ
;
if
(
p_item
==
p_playlist
->
pp_items
[
i
]
)
{
REMOVE_ELEM
(
p_playlist
->
pp_items
,
p_playlist
->
i_size
,
i
);
}
}
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
vlc_mutex_lock
(
&
p_item
->
input
.
lock
);
playlist_ItemSetDuration
(
p_item
,
i_duration
);
vlc_mutex_unlock
(
&
p_item
->
input
.
lock
);
val
.
b_bool
=
(
i_pos
>=
0
&&
i_pos
<
p_playlist
->
i_size
)
?
i_pos
:
-
1
;
var_Set
(
p_playlist
,
"item-change"
,
val
);
return
VLC_SUCCESS
;
/* Handle the parents
* Nothing to do ! */
}
/**********************************************************************
* Actions on existing playlist items
**********************************************************************/
/**
* delete an item from a playlist.
*
* \param p_playlist the playlist to remove from.
* \param i_
pos the position of the item to remov
e
* \return returns
0
* \param i_
id the identifier of the item to delet
e
* \return returns
VLC_SUCCESS or an error
*/
int
playlist_Delete
(
playlist_t
*
p_playlist
,
int
i_
pos
)
int
playlist_Delete
(
playlist_t
*
p_playlist
,
int
i_
id
)
{
vlc_value_t
val
;
int
i
;
/* if i_pos is the current played item, playlist should stop playing it */
if
(
(
p_playlist
->
i_status
==
PLAYLIST_RUNNING
)
&&
(
p_playlist
->
i_index
==
i_pos
)
)
playlist_item_t
*
p_item
=
playlist_ItemGetById
(
p_playlist
,
i_id
);
if
(
p_item
==
NULL
)
return
VLC_EGENERIC
;
/* Check if it is the current item */
if
(
p_playlist
->
status
.
p_item
==
p_item
)
{
playlist_Command
(
p_playlist
,
PLAYLIST_STOP
,
0
);
playlist_Control
(
p_playlist
,
PLAYLIST_STOP
);
p_playlist
->
status
.
p_item
=
NULL
;
}
vlc_mutex_lock
(
&
p_playlist
->
object_lock
);
if
(
i_pos
>=
0
&&
i_pos
<
p_playlist
->
i_size
)
{
playlist_item_t
*
p_item
=
p_playlist
->
pp_items
[
i_pos
];
msg_Dbg
(
p_playlist
,
"deleting playlist item `%s'"
,
p_item
->
input
.
psz_name
);
playlist_ItemDelete
(
p_item
);
msg_Dbg
(
p_playlist
,
"deleting playlist item `%s'"
,
p_item
->
input
.
psz_name
);
if
(
i_pos
<=
p_playlist
->
i_index
)
/* Remove the item from all its parent nodes */
for
(
i
=
0
;
i
<
p_item
->
i_parents
;
i
++
)
{
playlist_NodeRemoveItem
(
p_playlist
,
p_item
,
p_item
->
pp_parents
[
i
]
->
p_parent
);
if
(
p_item
->
pp_parents
[
i
]
->
i_view
==
VIEW_ALL
)
{
p_playlist
->
i_
index
--
;
p_playlist
->
i_
size
--
;
}
}
/* Renumber the playlist */
REMOVE_ELEM
(
p_playlist
->
pp_items
,
p_playlist
->
i_size
,
i_pos
);
/* TODO : Update views */
if
(
p_playlist
->
i_enabled
>
0
)
p_playlist
->
i_enabled
--
;
}
playlist_ItemDelete
(
p_item
);
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
val
.
b_bool
=
VLC_TRUE
;
var_Set
(
p_playlist
,
"intf-change"
,
val
);
return
0
;
return
VLC_SUCCESS
;
}
/**
...
...
@@ -401,27 +522,15 @@ int playlist_Delete( playlist_t * p_playlist, int i_pos )
*/
int
playlist_Clear
(
playlist_t
*
p_playlist
)
{
while
(
p_playlist
->
i_groups
>
0
)
{
playlist_DeleteGroup
(
p_playlist
,
p_playlist
->
pp_groups
[
0
]
->
i_id
);
}
while
(
p_playlist
->
i_size
>
0
)
int
i
;
for
(
i
=
p_playlist
->
i_size
;
i
>
0
;
i
--
)
{
playlist_Delete
(
p_playlist
,
0
);
playlist_Delete
(
p_playlist
,
p_playlist
->
pp_items
[
0
]
->
input
.
i_id
);
}
p_playlist
->
i_index
=
-
1
;
p_playlist
->
i_size
=
0
;
p_playlist
->
pp_items
=
NULL
;
p_playlist
->
i_groups
=
0
;
p_playlist
->
pp_groups
=
NULL
;
return
0
;
return
VLC_SUCCESS
;
}
/**
* Disables a playlist item
*
...
...
@@ -429,28 +538,23 @@ int playlist_Clear( playlist_t * p_playlist )
* \param i_pos the position of the item to disable
* \return returns 0
*/
int
playlist_Disable
(
playlist_t
*
p_playlist
,
int
i_pos
)
int
playlist_Disable
(
playlist_t
*
p_playlist
,
playlist_item_t
*
p_item
)
{
vlc_value_t
val
;
vlc_mutex_lock
(
&
p_playlist
->
object_lock
);
if
(
!
p_item
)
return
VLC_EGENERIC
;
if
(
i_pos
>=
0
&&
i_pos
<
p_playlist
->
i_size
)
{
msg_Dbg
(
p_playlist
,
"disabling playlist item `%s'"
,
p_playlist
->
pp_items
[
i_pos
]
->
input
.
psz_name
);
msg_Dbg
(
p_playlist
,
"disabling playlist item `%s'"
,
p_item
->
input
.
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
;
if
(
p_item
->
i_flags
&
PLAYLIST_ENA_FLAG
)
{
p_playlist
->
i_enabled
--
;
}
p_item
->
i_flags
&=
~
PLAYLIST_ENA_FLAG
;
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
val
.
b_bool
=
i_pos
;
var_Set
(
p_playlist
,
"item-change"
,
val
);
return
0
;
var_SetInteger
(
p_playlist
,
"item-change"
,
p_item
->
input
.
i_id
);
return
VLC_SUCCESS
;
}
/**
...
...
@@ -460,95 +564,23 @@ int playlist_Disable( playlist_t * p_playlist, int i_pos )
* \param i_pos the position of the item to enable
* \return returns 0
*/
int
playlist_Enable
(
playlist_t
*
p_playlist
,
int
i_pos
)
int
playlist_Enable
(
playlist_t
*
p_playlist
,
playlist_item_t
*
p_item
)
{
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
]
->
input
.
psz_name
);
if
(
p_playlist
->
pp_items
[
i_pos
]
->
b_enabled
==
VLC_FALSE
)
p_playlist
->
i_enabled
++
;
if
(
!
p_item
)
return
VLC_EGENERIC
;
p_playlist
->
pp_items
[
i_pos
]
->
b_enabled
=
VLC_TRUE
;
}
msg_Dbg
(
p_playlist
,
"enabling playlist item `%s'"
,
p_item
->
input
.
psz_name
);
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
val
.
b_bool
=
i_pos
;
var_Set
(
p_playlist
,
"item-change"
,
val
);
return
0
;
}
/**
* Disables a playlist group
*
* \param p_playlist the playlist to disable from.
* \param i_group 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
;
vlc_mutex_lock
(
&
p_playlist
->
object_lock
);
msg_Dbg
(
p_playlist
,
"disabling group %i"
,
i_group
);
for
(
i
=
0
;
i
<
p_playlist
->
i_size
;
i
++
)
if
(
p_item
->
i_flags
&
~
PLAYLIST_ENA_FLAG
)
{
if
(
p_playlist
->
pp_items
[
i
]
->
i_group
==
i_group
)
{
msg_Dbg
(
p_playlist
,
"disabling playlist item `%s'"
,
p_playlist
->
pp_items
[
i
]
->
input
.
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
;
val
.
b_bool
=
i
;
var_Set
(
p_playlist
,
"item-change"
,
val
);
}
p_playlist
->
i_enabled
++
;
}
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
return
0
;
}
p_item
->
i_flags
|=
PLAYLIST_ENA_FLAG
;
/**
* Enables a playlist group
*
* \param p_playlist the playlist to enable from.
* \param i_group 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
;
vlc_mutex_lock
(
&
p_playlist
->
object_lock
);
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
]
->
input
.
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
;
val
.
b_bool
=
i
;
var_Set
(
p_playlist
,
"item-change"
,
val
);
}
}
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
return
0
;
var_SetInteger
(
p_playlist
,
"item-change"
,
p_item
->
input
.
i_id
);
return
VLC_SUCCESS
;
}
/**
...
...
@@ -582,11 +614,13 @@ int playlist_Move( playlist_t * p_playlist, int i_pos, int i_newpos )
{
p_playlist
->
i_index
=
i_newpos
;
}
else
if
(
i_pos
>
p_playlist
->
i_index
&&
i_newpos
<=
p_playlist
->
i_index
)
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
)
else
if
(
i_pos
<
p_playlist
->
i_index
&&
i_newpos
>=
p_playlist
->
i_index
)
{
p_playlist
->
i_index
--
;
}
...
...
src/playlist/item.c
View file @
f9d5e2ba
...
...
@@ -29,6 +29,8 @@
#include "vlc_playlist.h"
static
void
GuessType
(
input_item_t
*
p_item
);
/**
* Create a new item, without adding it to the playlist
*
...
...
@@ -43,23 +45,37 @@ playlist_item_t * __playlist_ItemNew( vlc_object_t *p_obj,
{
playlist_item_t
*
p_item
;
if
(
psz_uri
==
NULL
)
return
NULL
;
if
(
psz_uri
==
NULL
)
return
NULL
;
p_item
=
malloc
(
sizeof
(
playlist_item_t
)
);
if
(
p_item
==
NULL
)
return
NULL
;
memset
(
p_item
,
0
,
sizeof
(
playlist_item_t
)
);
vlc_input_item_Init
(
p_obj
,
&
p_item
->
input
);
p_item
->
input
.
i_duration
=
-
1
;
p_item
->
input
.
psz_uri
=
strdup
(
psz_uri
);
if
(
psz_name
!=
NULL
)
p_item
->
input
.
psz_name
=
strdup
(
psz_name
);
else
p_item
->
input
.
psz_name
=
strdup
(
psz_uri
);
p_item
->
b_enabled
=
VLC_TRUE
;
p_item
->
i_group
=
PLAYLIST_TYPE_MANUAL
;
p_item
->
i_nb_played
=
0
;
p_item
->
i_children
=
-
1
;
p_item
->
pp_children
=
NULL
;
p_item
->
i_flags
=
0
;
p_item
->
i_flags
|=
PLAYLIST_SKIP_FLAG
;
p_item
->
input
.
i_duration
=
-
1
;
p_item
->
input
.
ppsz_options
=
NULL
;
p_item
->
input
.
i_options
=
0
;
vlc_mutex_init
(
p_obj
,
&
p_item
->
input
.
lock
);
GuessType
(
&
p_item
->
input
);
playlist_ItemCreateCategory
(
p_item
,
_
(
"General"
)
);
return
p_item
;
}
...
...
@@ -71,136 +87,51 @@ playlist_item_t * __playlist_ItemNew( vlc_object_t *p_obj,
*/
void
playlist_ItemDelete
(
playlist_item_t
*
p_item
)
{
vlc_input_item_Clean
(
&
p_item
->
input
);
free
(
p_item
);
}
/**
* 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 The id of the playlist item
*/
int
playlist_AddItem
(
playlist_t
*
p_playlist
,
playlist_item_t
*
p_item
,
int
i_mode
,
int
i_pos
)
{
vlc_value_t
val
;
vlc_mutex_lock
(
&
p_item
->
input
.
lock
);
vlc_mutex_lock
(
&
p_playlist
->
object_lock
);
if
(
p_item
->
input
.
psz_name
)
free
(
p_item
->
input
.
psz_name
);
if
(
p_item
->
input
.
psz_uri
)
free
(
p_item
->
input
.
psz_uri
);
/*
* CHECK_INSERT : checks if the item is already enqued before
* enqueing it
*/
if
(
i_mode
&
PLAYLIST_CHECK_INSERT
)
/* Free the info categories */
if
(
p_item
->
input
.
i_categories
>
0
)
{
int
j
;
if
(
p_playlist
->
pp_items
)
{
for
(
j
=
0
;
j
<
p_playlist
->
i_size
;
j
++
)
{
if
(
!
strcmp
(
p_playlist
->
pp_items
[
j
]
->
input
.
psz_uri
,
p_item
->
input
.
psz_uri
)
)
{
if
(
p_item
->
input
.
psz_name
)
{
free
(
p_item
->
input
.
psz_name
);
}
if
(
p_item
->
input
.
psz_uri
)
{
free
(
p_item
->
input
.
psz_uri
);
}
free
(
p_item
);
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
return
-
1
;
}
}
}
i_mode
&=
~
PLAYLIST_CHECK_INSERT
;
i_mode
|=
PLAYLIST_APPEND
;
}
msg_Dbg
(
p_playlist
,
"adding playlist item `%s' ( %s )"
,
p_item
->
input
.
psz_name
,
p_item
->
input
.
psz_uri
);
p_item
->
i_id
=
++
p_playlist
->
i_last_id
;
int
i
,
j
;
/* Do a few boundary checks and allocate space for the item */
if
(
i_pos
==
PLAYLIST_END
)
{
if
(
i_mode
&
PLAYLIST_INSERT
)
for
(
i
=
0
;
i
<
p_item
->
input
.
i_categories
;
i
++
)
{
i_mode
&=
~
PLAYLIST_INSERT
;
i_mode
|=
PLAYLIST_APPEND
;
}
info_category_t
*
p_category
=
p_item
->
input
.
pp_categories
[
i
];
i_pos
=
p_playlist
->
i_size
-
1
;
}
for
(
j
=
0
;
j
<
p_category
->
i_infos
;
j
++
)
{
if
(
p_category
->
pp_infos
[
j
]
->
psz_name
)
{
free
(
p_category
->
pp_infos
[
j
]
->
psz_name
);
}
if
(
p_category
->
pp_infos
[
j
]
->
psz_value
)
{
free
(
p_category
->
pp_infos
[
j
]
->
psz_value
);
}
free
(
p_category
->
pp_infos
[
j
]
);
}
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
(
p_category
->
i_infos
)
free
(
p_category
->
pp_infos
);
if
(
p_category
->
psz_name
)
free
(
p_category
->
psz_name
);
free
(
p_category
);
}
if
(
i_pos
<
0
)
{
i_pos
=
0
;
}
else
if
(
i_pos
>
p_playlist
->
i_size
)
{
i_pos
=
p_playlist
->
i_size
;
}
INSERT_ELEM
(
p_playlist
->
pp_items
,
p_playlist
->
i_size
,
i_pos
,
p_item
);
p_playlist
->
i_enabled
++
;
if
(
p_playlist
->
i_index
>=
i_pos
)
{
p_playlist
->
i_index
++
;
}
}
else
{
/* i_mode == PLAYLIST_REPLACE and 0 <= i_pos < p_playlist->i_size */
if
(
p_playlist
->
pp_items
[
i_pos
]
->
input
.
psz_name
)
{
free
(
p_playlist
->
pp_items
[
i_pos
]
->
input
.
psz_name
);
}
if
(
p_playlist
->
pp_items
[
i_pos
]
->
input
.
psz_uri
)
{
free
(
p_playlist
->
pp_items
[
i_pos
]
->
input
.
psz_uri
);
}
/* XXX: what if the item is still in use? */
free
(
p_playlist
->
pp_items
[
i_pos
]
);
p_playlist
->
pp_items
[
i_pos
]
=
p_item
;
free
(
p_item
->
input
.
pp_categories
);
}
if
(
i_mode
&
PLAYLIST_GO
)
for
(
;
p_item
->
input
.
i_options
>
0
;
p_item
->
input
.
i_options
--
)
{
p_playlist
->
i_index
=
i_pos
;
if
(
p_playlist
->
p_input
)
{
input_StopThread
(
p_playlist
->
p_input
);
}
p_playlist
->
i_status
=
PLAYLIST_RUNNING
;
free
(
p_item
->
input
.
ppsz_options
[
p_item
->
input
.
i_options
-
1
]
);
if
(
p_item
->
input
.
i_options
==
1
)
free
(
p_item
->
input
.
ppsz_options
);
}
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
val
.
b_bool
=
VLC_TRUE
;
var_Set
(
p_playlist
,
"intf-change"
,
val
);
vlc_mutex_unlock
(
&
p_item
->
input
.
lock
);
vlc_mutex_destroy
(
&
p_item
->
input
.
lock
);
return
p_item
->
i_id
;
free
(
p_item
)
;
}
/**
...
...
@@ -221,3 +152,127 @@ int playlist_ItemAddOption( playlist_item_t *p_item, const char *psz_option )
return
VLC_SUCCESS
;
}
/**
* Add a parent to an item
*
* \param p_item the item
* \param i_view the view in which the parent is
* \param p_parent the parent to add
* \return nothing
*/
void
playlist_ItemAddParent
(
playlist_item_t
*
p_item
,
int
i_view
,
playlist_item_t
*
p_parent
)
{
vlc_bool_t
b_found
=
VLC_FALSE
;
int
i
;
for
(
i
=
0
;
i
<
p_item
->
i_parents
;
i
++
)
{
if
(
p_item
->
pp_parents
[
i
]
->
i_view
==
i_view
)
{
b_found
=
VLC_TRUE
;
break
;
}
}
if
(
b_found
==
VLC_FALSE
)
{
struct
item_parent_t
*
p_ip
=
(
struct
item_parent_t
*
)
malloc
(
sizeof
(
struct
item_parent_t
)
);
p_ip
->
i_view
=
i_view
;
p_ip
->
p_parent
=
p_parent
;
INSERT_ELEM
(
p_item
->
pp_parents
,
p_item
->
i_parents
,
p_item
->
i_parents
,
p_ip
);
}
}
/**********************************************************************
* playlist_item_t structure accessors
* These functions give access to the fields of the playlist_item_t
* structure
**********************************************************************/
/**
* Set the name of a playlist item
*
* \param p_item the item
* \param psz_name the new name
* \return VLC_SUCCESS on success, VLC_EGENERIC on failure
*/
int
playlist_ItemSetName
(
playlist_item_t
*
p_item
,
char
*
psz_name
)
{
if
(
psz_name
&&
p_item
)
{
p_item
->
input
.
psz_name
=
strdup
(
psz_name
);
return
VLC_SUCCESS
;
}
return
VLC_EGENERIC
;
}
/**
* Set the duration of a playlist item
* This function must be entered with the item lock
*
* \param p_item the item
* \param i_duration the new duration
* \return VLC_SUCCESS on success, VLC_EGENERIC on failure
*/
int
playlist_ItemSetDuration
(
playlist_item_t
*
p_item
,
mtime_t
i_duration
)
{
char
psz_buffer
[
MSTRTIME_MAX_SIZE
];
if
(
p_item
)
{
p_item
->
input
.
i_duration
=
i_duration
;
if
(
i_duration
!=
-
1
)
{
secstotimestr
(
psz_buffer
,
i_duration
/
1000000
);
}
else
{
memcpy
(
psz_buffer
,
"--:--:--"
,
sizeof
(
"--:--:--"
)
);
}
playlist_ItemAddInfo
(
p_item
,
_
(
"General"
)
,
_
(
"Duration"
),
"%s"
,
psz_buffer
);
return
VLC_SUCCESS
;
}
return
VLC_EGENERIC
;
}
static
void
GuessType
(
input_item_t
*
p_item
)
{
int
i
;
static
struct
{
char
*
psz_search
;
int
i_type
;
}
types_array
[]
=
{
{
"http"
,
ITEM_TYPE_NET
},
{
"dvd"
,
ITEM_TYPE_DISC
},
{
"cdda"
,
ITEM_TYPE_DISC
},
{
"mms"
,
ITEM_TYPE_NET
},
{
"rtsp"
,
ITEM_TYPE_NET
},
{
"udp"
,
ITEM_TYPE_NET
},
{
"vcd"
,
ITEM_TYPE_DISC
},
{
"v4l"
,
ITEM_TYPE_CARD
},
{
"dshow"
,
ITEM_TYPE_CARD
},
{
"pvr"
,
ITEM_TYPE_CARD
},
{
"dvb"
,
ITEM_TYPE_CARD
},
{
"qpsk"
,
ITEM_TYPE_CARD
},
{
NULL
,
0
}
};
for
(
i
=
0
;
types_array
[
i
].
psz_search
!=
NULL
;
i
++
)
{
if
(
!
strncmp
(
p_item
->
psz_uri
,
types_array
[
i
].
psz_search
,
strlen
(
types_array
[
i
].
psz_search
)
)
)
{
p_item
->
i_type
=
types_array
[
i
].
i_type
;
return
;
}
}
return
ITEM_TYPE_UNKNOWN
;
}
src/playlist/loadsave.c
View file @
f9d5e2ba
...
...
@@ -34,10 +34,11 @@
#define PLAYLIST_FILE_HEADER "# vlc playlist file version 0.5"
/**
* Import a certain playlist file into the playlist
* Import a certain playlist file into the library
* This file will get inserted as a new category
*
* XXX: TODO
* \param p_playlist the playlist to which the new items will be added
* \param psz_filename the name of the playlistfile to import
* \return VLC_SUCCESS on success
...
...
@@ -68,6 +69,40 @@ int playlist_Import( playlist_t * p_playlist, const char *psz_filename )
return
VLC_SUCCESS
;
}
/**
* Load a certain playlist file into the playlist
* This file will replace the contents of the "current" view
*
* \param p_playlist the playlist to which the new items will be added
* \param psz_filename the name of the playlistfile to import
* \return VLC_SUCCESS on success
*/
int
playlist_Load
(
playlist_t
*
p_playlist
,
const
char
*
psz_filename
)
{
playlist_item_t
*
p_item
;
char
*
psz_uri
;
int
i_id
;
msg_Dbg
(
p_playlist
,
"clearing playlist"
);
playlist_Clear
(
p_playlist
);
psz_uri
=
(
char
*
)
malloc
(
sizeof
(
char
)
*
strlen
(
psz_filename
)
+
17
);
sprintf
(
psz_uri
,
"file/playlist://%s"
,
psz_filename
);
i_id
=
playlist_Add
(
p_playlist
,
psz_uri
,
psz_uri
,
PLAYLIST_INSERT
,
PLAYLIST_END
);
vlc_mutex_lock
(
&
p_playlist
->
object_lock
);
p_item
=
playlist_ItemGetById
(
p_playlist
,
i_id
);
p_item
->
b_autodeletion
=
VLC_TRUE
;
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
playlist_Play
(
p_playlist
);
return
VLC_SUCCESS
;
}
/**
* Export a playlist to a certain type of playlistfile
*
...
...
src/playlist/playlist.c
View file @
f9d5e2ba
...
...
@@ -5,6 +5,7 @@
* $Id$
*
* Authors: Samuel Hocevar <sam@zoy.org>
* Clment Stenac <zorglub@videolan.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
...
...
@@ -31,14 +32,24 @@
#include "vlc_playlist.h"
#define PLAYLIST_FILE_HEADER_0_5 "# vlc playlist file version 0.5"
#define TITLE_CATEGORY N_( "By category" )
#define TITLE_SIMPLE N_( "Manually added" )
#define TITLE_ALL N_( "All items, unsorted" )
#define PLAYLIST_PROFILE 1
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static
void
RunThread
(
playlist_t
*
);
static
void
SkipItem
(
playlist_t
*
,
int
);
static
void
PlayItem
(
playlist_t
*
);
static
playlist_item_t
*
NextItem
(
playlist_t
*
);
static
void
PlayItem
(
playlist_t
*
,
playlist_item_t
*
);
static
int
ItemChange
(
vlc_object_t
*
,
const
char
*
,
vlc_value_t
,
vlc_value_t
,
void
*
);
int
playlist_vaControl
(
playlist_t
*
p_playlist
,
int
i_query
,
va_list
args
);
/**
* Create playlist
...
...
@@ -50,6 +61,7 @@ static void PlayItem ( playlist_t * );
playlist_t
*
__playlist_Create
(
vlc_object_t
*
p_parent
)
{
playlist_t
*
p_playlist
;
playlist_view_t
*
p_view
;
vlc_value_t
val
;
/* Allocate structure */
...
...
@@ -60,6 +72,7 @@ playlist_t * __playlist_Create ( vlc_object_t *p_parent )
return
NULL
;
}
/* These variables control updates */
var_Create
(
p_playlist
,
"intf-change"
,
VLC_VAR_BOOL
);
val
.
b_bool
=
VLC_TRUE
;
var_Set
(
p_playlist
,
"intf-change"
,
val
);
...
...
@@ -78,31 +91,51 @@ playlist_t * __playlist_Create ( vlc_object_t *p_parent )
val
.
b_bool
=
VLC_TRUE
;
var_Set
(
p_playlist
,
"intf-show"
,
val
);
/* Variables to control playback */
var_CreateGetBool
(
p_playlist
,
"play-and-stop"
);
var_CreateGetBool
(
p_playlist
,
"random"
);
var_CreateGetBool
(
p_playlist
,
"repeat"
);
var_CreateGetBool
(
p_playlist
,
"loop"
);
var_Create
(
p_playlist
,
"prevent-skip"
,
VLC_VAR_BOOL
);
val
.
b_bool
=
VLC_FALS
E
;
var_Set
(
p_playlist
,
"prevent-skip"
,
val
)
;
/* Initialise data structures */
p_playlist
->
b_go_next
=
VLC_TRU
E
;
p_playlist
->
p_input
=
NULL
;
var_Create
(
p_playlist
,
"play-and-stop"
,
VLC_VAR_BOOL
|
VLC_VAR_DOINHERIT
)
;
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
)
;
p_playlist
->
request_date
=
0
;
p_playlist
->
i_views
=
0
;
p_playlist
->
pp_views
=
NULL
;
p_playlist
->
p_input
=
NULL
;
p_playlist
->
i_status
=
PLAYLIST_STOPPED
;
p_playlist
->
i_index
=
-
1
;
p_playlist
->
i_size
=
0
;
p_playlist
->
pp_items
=
NULL
;
p_playlist
->
i_groups
=
0
;
p_playlist
->
pp_groups
=
NULL
;
p_playlist
->
i_last_group
=
0
;
playlist_ViewInsert
(
p_playlist
,
VIEW_CATEGORY
,
TITLE_CATEGORY
);
playlist_ViewInsert
(
p_playlist
,
VIEW_SIMPLE
,
TITLE_SIMPLE
);
playlist_ViewInsert
(
p_playlist
,
VIEW_ALL
,
TITLE_ALL
);
p_view
=
playlist_ViewFind
(
p_playlist
,
VIEW_CATEGORY
);
p_playlist
->
p_general
=
playlist_NodeCreate
(
p_playlist
,
VIEW_CATEGORY
,
_
(
"General"
),
p_view
->
p_root
);
/* Set startup status
* We set to simple view on startup for interfaces that don't do
* anything */
p_view
=
playlist_ViewFind
(
p_playlist
,
VIEW_SIMPLE
);
p_playlist
->
status
.
i_view
=
VIEW_SIMPLE
;
p_playlist
->
status
.
p_item
=
NULL
;
p_playlist
->
status
.
p_node
=
p_view
->
p_root
;
p_playlist
->
request
.
b_request
=
VLC_FALSE
;
p_playlist
->
status
.
i_status
=
PLAYLIST_STOPPED
;
p_playlist
->
i_last_id
=
0
;
p_playlist
->
i_sort
=
SORT_ID
;
p_playlist
->
i_order
=
ORDER_NORMAL
;
playlist_CreateGroup
(
p_playlist
,
_
(
"Normal"
)
);
/* Finally, launch the thread ! */
if
(
vlc_thread_create
(
p_playlist
,
"playlist"
,
RunThread
,
VLC_THREAD_PRIORITY_LOW
,
VLC_TRUE
)
)
{
...
...
@@ -125,6 +158,7 @@ playlist_t * __playlist_Create ( vlc_object_t *p_parent )
*/
void
playlist_Destroy
(
playlist_t
*
p_playlist
)
{
int
i
;
p_playlist
->
b_die
=
1
;
vlc_thread_join
(
p_playlist
);
...
...
@@ -134,20 +168,21 @@ void playlist_Destroy( playlist_t * p_playlist )
var_Destroy
(
p_playlist
,
"playlist-current"
);
var_Destroy
(
p_playlist
,
"intf-popmenu"
);
var_Destroy
(
p_playlist
,
"intf-show"
);
var_Destroy
(
p_playlist
,
"prevent-skip"
);
var_Destroy
(
p_playlist
,
"play-and-stop"
);
var_Destroy
(
p_playlist
,
"random"
);
var_Destroy
(
p_playlist
,
"repeat"
);
var_Destroy
(
p_playlist
,
"loop"
);
while
(
p_playlist
->
i_groups
>
0
)
{
playlist_DeleteGroup
(
p_playlist
,
p_playlist
->
pp_groups
[
0
]
->
i_id
);
}
playlist_Clear
(
p_playlist
);
while
(
p_playlist
->
i_size
>
0
)
for
(
i
=
p_playlist
->
i_views
-
1
;
i
>=
0
;
i
--
)
{
playlist_Delete
(
p_playlist
,
0
);
playlist_view_t
*
p_view
=
p_playlist
->
pp_views
[
i
];
if
(
p_view
->
psz_name
)
free
(
p_view
->
psz_name
);
playlist_ItemDelete
(
p_view
->
p_root
);
REMOVE_ELEM
(
p_playlist
->
pp_views
,
p_playlist
->
i_views
,
i
);
free
(
p_view
);
}
vlc_object_destroy
(
p_playlist
);
...
...
@@ -158,49 +193,100 @@ void playlist_Destroy( playlist_t * p_playlist )
* Do a playlist action.
*
* If there is something in the playlist then you can do playlist actions.
*
* Playlist lock must not be taken when calling this function
*
* \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
* \param i_query the command to do
* \param variable number of arguments
* \return VLC_SUCCESS or an error
*/
void
playlist_Command
(
playlist_t
*
p_playlist
,
playlist_command_t
i_command
,
int
i_arg
)
int
playlist_Control
(
playlist_t
*
p_playlist
,
int
i_query
,
...
)
{
vlc_value_t
val
;
va_list
args
;
int
i_result
;
va_start
(
args
,
i_query
);
i_result
=
playlist_vaControl
(
p_playlist
,
i_query
,
args
);
va_end
(
args
);
return
i_result
;
}
int
playlist_vaControl
(
playlist_t
*
p_playlist
,
int
i_query
,
va_list
args
)
{
vlc_mutex_lock
(
&
p_playlist
->
object_lock
);
playlist_view_t
*
p_view
;
vlc_value_t
val
;
#ifdef PLAYLIST_PROFILE
p_playlist
->
request_date
=
mdate
();
#endif
if
(
p_playlist
->
i_size
<=
0
)
{
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
return
;
return
VLC_EGENERIC
;
}
switch
(
i_
command
)
switch
(
i_
query
)
{
case
PLAYLIST_STOP
:
p_playlist
->
i_status
=
PLAYLIST_STOPPED
;
if
(
p_playlist
->
p_input
)
p_playlist
->
status
.
i_status
=
PLAYLIST_STOPPED
;
p_playlist
->
request
.
b_request
=
VLC_TRUE
;
break
;
case
PLAYLIST_ITEMPLAY
:
p_playlist
->
status
.
i_status
=
PLAYLIST_RUNNING
;
p_playlist
->
request
.
i_skip
=
0
;
p_playlist
->
request
.
b_request
=
VLC_TRUE
;
p_playlist
->
request
.
p_item
=
(
playlist_item_t
*
)
va_arg
(
args
,
playlist_item_t
*
);
p_playlist
->
request
.
i_view
=
p_playlist
->
status
.
i_view
;
p_view
=
playlist_ViewFind
(
p_playlist
,
p_playlist
->
status
.
i_view
);
p_playlist
->
request
.
p_node
=
p_view
->
p_root
;
break
;
case
PLAYLIST_VIEWPLAY
:
p_playlist
->
status
.
i_status
=
PLAYLIST_RUNNING
;
p_playlist
->
request
.
i_skip
=
0
;
p_playlist
->
request
.
b_request
=
VLC_TRUE
;
p_playlist
->
request
.
i_view
=
(
int
)
va_arg
(
args
,
int
);
p_playlist
->
request
.
p_node
=
(
playlist_item_t
*
)
va_arg
(
args
,
playlist_item_t
*
);
p_playlist
->
request
.
p_item
=
(
playlist_item_t
*
)
va_arg
(
args
,
playlist_item_t
*
);
/* If we select a node, play only it.
* If we select an item, continue */
if
(
p_playlist
->
request
.
p_item
==
NULL
||
!
p_playlist
->
request
.
p_node
->
i_flags
&
PLAYLIST_SKIP_FLAG
)
{
input_StopThread
(
p_playlist
->
p_input
);
val
.
i_int
=
p_playlist
->
i_index
;
/* Does not matter if we unlock here */
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
var_Set
(
p_playlist
,
"item-change"
,
val
);
vlc_mutex_lock
(
&
p_playlist
->
object_lock
);
p_playlist
->
b_go_next
=
VLC_FALSE
;
}
else
{
p_playlist
->
b_go_next
=
VLC_TRUE
;
}
break
;
case
PLAYLIST_PLAY
:
p_playlist
->
i_status
=
PLAYLIST_RUNNING
;
if
(
!
p_playlist
->
p_input
&&
p_playlist
->
i_enabled
!=
0
)
{
PlayItem
(
p_playlist
);
}
p_playlist
->
status
.
i_status
=
PLAYLIST_RUNNING
;
if
(
p_playlist
->
p_input
)
{
val
.
i_int
=
PLAYING_S
;
var_Set
(
p_playlist
->
p_input
,
"state"
,
val
);
break
;
}
/* FIXME : needed ? */
p_playlist
->
request
.
b_request
=
VLC_TRUE
;
p_playlist
->
request
.
i_view
=
p_playlist
->
status
.
i_view
;
p_playlist
->
request
.
p_node
=
p_playlist
->
status
.
p_node
;
p_playlist
->
request
.
p_item
=
p_playlist
->
status
.
p_item
;
p_playlist
->
request
.
i_skip
=
0
;
p_playlist
->
request
.
i_goto
=
-
1
;
break
;
case
PLAYLIST_PAUSE
:
...
...
@@ -210,7 +296,7 @@ void playlist_Command( playlist_t * p_playlist, playlist_command_t i_command,
if
(
val
.
i_int
==
PAUSE_S
)
{
p_playlist
->
i_status
=
PLAYLIST_RUNNING
;
p_playlist
->
status
.
i_status
=
PLAYLIST_RUNNING
;
if
(
p_playlist
->
p_input
)
{
val
.
i_int
=
PLAYING_S
;
...
...
@@ -219,7 +305,7 @@ void playlist_Command( playlist_t * p_playlist, playlist_command_t i_command,
}
else
{
p_playlist
->
i_status
=
PLAYLIST_PAUSED
;
p_playlist
->
status
.
i_status
=
PLAYLIST_PAUSED
;
if
(
p_playlist
->
p_input
)
{
val
.
i_int
=
PAUSE_S
;
...
...
@@ -229,48 +315,36 @@ void playlist_Command( playlist_t * p_playlist, playlist_command_t i_command,
break
;
case
PLAYLIST_SKIP
:
p_playlist
->
i_status
=
PLAYLIST_STOPPED
;
if
(
p_playlist
->
i_enabled
==
0
)
{
break
;
}
SkipItem
(
p_playlist
,
i_arg
);
if
(
p_playlist
->
p_input
)
if
(
p_playlist
->
status
.
i_view
>
-
1
)
{
input_StopThread
(
p_playlist
->
p_input
);
p_playlist
->
request
.
p_node
=
p_playlist
->
status
.
p_node
;
p_playlist
->
request
.
p_item
=
p_playlist
->
status
.
p_item
;
}
p_playlist
->
i_status
=
PLAYLIST_RUNNING
;
p_playlist
->
request
.
i_skip
=
(
int
)
va_arg
(
args
,
int
);
p_playlist
->
request
.
b_request
=
VLC_TRUE
;
break
;
case
PLAYLIST_GOTO
:
if
(
i_arg
>=
0
&&
i_arg
<
p_playlist
->
i_size
&&
p_playlist
->
i_enabled
!=
0
)
{
p_playlist
->
i_index
=
i_arg
;
if
(
p_playlist
->
p_input
)
{
input_StopThread
(
p_playlist
->
p_input
);
}
val
.
b_bool
=
VLC_TRUE
;
var_Set
(
p_playlist
,
"prevent-skip"
,
val
);
p_playlist
->
i_status
=
PLAYLIST_RUNNING
;
}
p_playlist
->
status
.
i_status
=
PLAYLIST_RUNNING
;
p_playlist
->
request
.
p_node
=
NULL
;
p_playlist
->
request
.
p_item
=
NULL
;
p_playlist
->
request
.
i_view
=
-
1
;
p_playlist
->
request
.
i_goto
=
(
int
)
va_arg
(
args
,
int
);
p_playlist
->
request
.
b_request
=
VLC_TRUE
;
break
;
default:
msg_Err
(
p_playlist
,
"unknown playlist command"
);
msg_Err
(
p_playlist
,
"unimplemented playlist query"
);
return
VLC_EBADVAR
;
break
;
}
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
#if 0
val.b_bool = VLC_TRUE;
var_Set( p_playlist, "intf-change", val );
#endif
return
;
return
VLC_SUCCESS
;
}
/* Destroy remaining objects */
static
mtime_t
ObjectGarbageCollector
(
playlist_t
*
p_playlist
,
int
i_type
,
mtime_t
destroy_date
)
{
...
...
@@ -316,7 +390,7 @@ static mtime_t ObjectGarbageCollector( playlist_t *p_playlist, int i_type,
static
void
RunThread
(
playlist_t
*
p_playlist
)
{
vlc_object_t
*
p_obj
;
vlc_value_t
val
;
playlist_item_t
*
p_item
;
mtime_t
i_vout_destroyed_date
=
0
;
mtime_t
i_sout_destroyed_date
=
0
;
...
...
@@ -330,6 +404,26 @@ static void RunThread ( playlist_t *p_playlist )
{
vlc_mutex_lock
(
&
p_playlist
->
object_lock
);
/* First, check if we have something to do */
/* FIXME : this can be called several times */
if
(
p_playlist
->
request
.
b_request
)
{
#ifdef PLAYLIST_PROFILE
msg_Dbg
(
p_playlist
,
"beginning processing of request, "
I64Fi
" us "
,
mdate
()
-
p_playlist
->
request_date
);
#endif
/* Stop the existing input */
if
(
p_playlist
->
p_input
)
{
input_StopThread
(
p_playlist
->
p_input
);
}
/* The code below will start the next input for us */
if
(
p_playlist
->
status
.
i_status
==
PLAYLIST_STOPPED
)
{
p_playlist
->
request
.
b_request
=
VLC_FALSE
;
}
}
/* If there is an input, check that it doesn't need to die. */
if
(
p_playlist
->
p_input
)
{
...
...
@@ -376,27 +470,34 @@ static void RunThread ( playlist_t *p_playlist )
else
if
(
p_playlist
->
p_input
->
b_error
||
p_playlist
->
p_input
->
b_eof
)
{
/* TODO FIXME XXX TODO FIXME XXX */
/* Check for autodeletion */
input_StopThread
(
p_playlist
->
p_input
);
if
(
p_playlist
->
pp_items
[
p_playlist
->
i_index
]
->
b_autodeletion
)
if
(
p_playlist
->
status
.
p_item
->
i_flags
&
PLAYLIST_DEL_FLAG
)
{
/* This ain't pretty but hey it works */
p_autodelete_item
=
p_playlist
->
pp_items
[
p_playlist
->
i_index
];
p_playlist
->
pp_items
[
p_playlist
->
i_index
]
=
p_autodelete_item
=
p_playlist
->
status
.
p_item
;
p_playlist
->
status
.
p_item
=
playlist_ItemNew
(
p_playlist
,
p_autodelete_item
->
input
.
psz_uri
,
0
);
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
p_playlist
->
i_status
=
PLAYLIST_STOPPED
;
playlist_Delete
(
p_playlist
,
p_playlist
->
i_index
);
p_playlist
->
i_status
=
PLAYLIST_RUNNING
;
playlist_Delete
(
p_playlist
,
p_playlist
->
status
.
p_item
->
input
.
i_id
);
p_playlist
->
request
.
i_skip
=
1
;
p_playlist
->
status
.
i_status
=
PLAYLIST_RUNNING
;
vlc_mutex_lock
(
&
p_playlist
->
object_lock
);
}
SkipItem
(
p_playlist
,
1
);
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
continue
;
else
{
/* Select the next playlist item */
input_StopThread
(
p_playlist
->
p_input
);
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
continue
;
}
}
else
if
(
p_playlist
->
p_input
->
i_state
!=
INIT_S
)
{
...
...
@@ -410,30 +511,25 @@ static void RunThread ( playlist_t *p_playlist )
vlc_mutex_lock
(
&
p_playlist
->
object_lock
);
}
}
else
if
(
p_playlist
->
i_status
!=
PLAYLIST_STOPPED
)
else
if
(
p_playlist
->
status
.
i_status
!=
PLAYLIST_STOPPED
)
{
/* Start another input. Let's check if that item has
* been forced. In that case, we override random (by not skipping)
* and play-and-stop */
vlc_bool_t
b_forced
;
var_Get
(
p_playlist
,
"prevent-skip"
,
&
val
);
b_forced
=
val
.
b_bool
;
if
(
val
.
b_bool
==
VLC_FALSE
)
{
SkipItem
(
p_playlist
,
0
);
}
/* Reset forced status */
val
.
b_bool
=
VLC_FALSE
;
var_Set
(
p_playlist
,
"prevent-skip"
,
val
);
/* Check for play-and-stop */
var_Get
(
p_playlist
,
"play-and-stop"
,
&
val
);
if
(
val
.
b_bool
==
VLC_FALSE
||
b_forced
==
VLC_TRUE
)
/* Start another input.
* Get the next item to play */
p_item
=
NextItem
(
p_playlist
);
/* We must stop */
if
(
p_item
==
NULL
)
{
PlayItem
(
p_playlist
);
p_playlist
->
status
.
i_status
=
PLAYLIST_STOPPED
;
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
continue
;
}
PlayItem
(
p_playlist
,
p_item
);
}
else
if
(
p_playlist
->
i_status
==
PLAYLIST_STOPPED
)
else
if
(
p_playlist
->
status
.
i_status
==
PLAYLIST_STOPPED
)
{
/* Collect garbage */
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
i_sout_destroyed_date
=
ObjectGarbageCollector
(
p_playlist
,
VLC_OBJECT_SOUT
,
mdate
()
);
...
...
@@ -443,9 +539,21 @@ static void RunThread ( playlist_t *p_playlist )
}
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
msleep
(
INTF_IDLE_SLEEP
);
msleep
(
INTF_IDLE_SLEEP
/
2
);
/* Stop sleeping earlier if we have work */
/* TODO : statistics about this */
if
(
p_playlist
->
request
.
b_request
&&
p_playlist
->
status
.
i_status
==
PLAYLIST_RUNNING
)
{
continue
;
}
msleep
(
INTF_IDLE_SLEEP
/
2
);
}
/* Playlist dying */
/* If there is an input, kill it */
while
(
1
)
{
...
...
@@ -516,45 +624,72 @@ static void RunThread ( playlist_t *p_playlist )
}
/*****************************************************************************
*
SkipItem: go to Xth playlist i
tem
*
NextI
tem
*****************************************************************************
* This function calculates the
position of the
next playlist item, depending
* on the playlist course mode (forward, backward, random...).
* This function calculates the next playlist item, depending
* on the playlist course mode (forward, backward, random
, view,
...).
*****************************************************************************/
static
void
SkipItem
(
playlist_t
*
p_playlist
,
int
i_arg
)
static
playlist_item_t
*
NextItem
(
playlist_t
*
p_playlist
)
{
int
i_oldindex
=
p_playlist
->
i_index
;
vlc_bool_t
b_random
,
b_repeat
,
b_loop
;
vlc_value_t
val
;
int
i_count
;
playlist_item_t
*
p_new
=
NULL
;
int
i_skip
,
i_goto
,
i
,
i_new
,
i_count
;
playlist_view_t
*
p_view
;
vlc_bool_t
b_loop
=
var_GetBool
(
p_playlist
,
"loop"
);
vlc_bool_t
b_random
=
var_GetBool
(
p_playlist
,
"random"
);
vlc_bool_t
b_repeat
=
var_GetBool
(
p_playlist
,
"repeat"
);
vlc_bool_t
b_playstop
=
var_GetBool
(
p_playlist
,
"play-and-stop"
);
#ifdef PLAYLIST_PROFILE
/* Calculate time needed */
int64_t
start
=
mdate
();
#endif
/* If the playlist is empty, there is no current item */
/* Handle quickly a few special cases */
/* No items to play */
if
(
p_playlist
->
i_size
==
0
)
{
p_playlist
->
i_index
=
-
1
;
return
;
msg_Info
(
p_playlist
,
"playlist is empty"
);
return
NULL
;
}
/* Nothing requested */
if
(
!
p_playlist
->
request
.
b_request
&&
p_playlist
->
status
.
p_item
==
NULL
)
{
msg_Warn
(
p_playlist
,
"nothing requested"
);
return
NULL
;
}
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
;
/* Repeat and play/stop */
if
(
!
p_playlist
->
request
.
b_request
&&
b_repeat
==
VLC_TRUE
)
{
msg_Dbg
(
p_playlist
,
"repeating item"
)
;
return
p_playlist
->
status
.
p_item
;
}
/* Increment */
if
(
b_random
)
if
(
!
p_playlist
->
request
.
b_request
&&
b_playstop
==
VLC_TRUE
)
{
msg_Dbg
(
p_playlist
,
"stopping (play and stop)"
);
return
NULL
;
}
/* TODO: improve this (only use current node) */
/* TODO: use the "shuffled view" internally ? */
/* Random case. This is an exception: if request, but request is skip +- 1
* we don't go to next item but select a new random one. */
if
(
b_random
&&
(
!
p_playlist
->
request
.
b_request
||
p_playlist
->
request
.
i_skip
==
1
||
p_playlist
->
request
.
i_skip
==
-
1
)
)
{
srand
(
(
unsigned
int
)
mdate
()
);
i_
count
=
0
;
while
(
i_count
<
p_playlist
->
i_size
)
i_
new
=
0
;
for
(
i_count
=
0
;
i_count
<
p_playlist
->
i_size
-
1
;
i_count
++
)
{
p_playlist
->
i_index
=
i_new
=
(
int
)((
float
)
p_playlist
->
i_size
*
rand
()
/
(
RAND_MAX
+
1
.
0
));
/* Check if the item has not already been played */
if
(
p_playlist
->
pp_items
[
p_playlist
->
i_index
]
->
i_nb_played
==
0
)
if
(
p_playlist
->
pp_items
[
i_new
]
->
i_nb_played
==
0
)
break
;
i_count
++
;
}
if
(
i_count
==
p_playlist
->
i_size
)
{
...
...
@@ -563,12 +698,152 @@ static void SkipItem( playlist_t *p_playlist, int i_arg )
{
p_playlist
->
pp_items
[
--
i_count
]
->
i_nb_played
=
0
;
}
if
(
!
b_loop
)
if
(
!
b_loop
)
{
return
NULL
;
}
}
p_playlist
->
request
.
i_skip
=
0
;
p_playlist
->
request
.
b_request
=
VLC_FALSE
;
return
p_playlist
->
pp_items
[
i_new
];
}
/* Start the real work */
if
(
p_playlist
->
request
.
b_request
)
{
msg_Dbg
(
p_playlist
,
"processing request"
);
/* We are not playing from a view */
if
(
p_playlist
->
request
.
i_view
==
-
1
)
{
/* Directly select the item, just like now */
i_skip
=
p_playlist
->
request
.
i_skip
;
i_goto
=
p_playlist
->
request
.
i_goto
;
if
(
p_playlist
->
i_index
==
-
1
)
p_playlist
->
i_index
=
0
;
p_new
=
p_playlist
->
pp_items
[
p_playlist
->
i_index
];
if
(
i_goto
>=
0
&&
i_goto
<
p_playlist
->
i_size
)
{
p_playlist
->
i_index
=
i_goto
;
p_new
=
p_playlist
->
pp_items
[
p_playlist
->
i_index
];
p_playlist
->
request
.
i_goto
=
-
1
;
}
if
(
i_skip
!=
0
)
{
if
(
p_playlist
->
i_index
+
i_skip
<
p_playlist
->
i_size
&&
p_playlist
->
i_index
+
i_skip
>=
0
)
{
p_playlist
->
i_index
+=
i_skip
;
p_new
=
p_playlist
->
pp_items
[
p_playlist
->
i_index
];
}
}
}
else
{
p_new
=
p_playlist
->
request
.
p_item
;
i_skip
=
p_playlist
->
request
.
i_skip
;
/* If we are asked for a node, take its first item */
if
(
p_playlist
->
request
.
p_item
==
NULL
&&
i_skip
==
0
)
{
i_skip
++
;
}
p_view
=
playlist_ViewFind
(
p_playlist
,
p_playlist
->
request
.
i_view
);
p_playlist
->
status
.
p_node
=
p_playlist
->
request
.
p_node
;
p_playlist
->
status
.
i_view
=
p_playlist
->
request
.
i_view
;
if
(
i_skip
>
0
)
{
for
(
i
=
i_skip
;
i
>
0
;
i
--
)
{
p_new
=
playlist_FindNextFromParent
(
p_playlist
,
p_playlist
->
request
.
i_view
,
p_view
->
p_root
,
p_playlist
->
request
.
p_node
,
p_new
);
if
(
p_new
==
NULL
)
break
;
}
}
else
if
(
i_skip
<
0
)
{
for
(
i
=
i_skip
;
i
<
0
;
i
++
)
{
p_new
=
playlist_FindPrevFromParent
(
p_playlist
,
p_playlist
->
request
.
i_view
,
p_view
->
p_root
,
p_playlist
->
request
.
p_node
,
p_new
);
if
(
p_new
==
NULL
)
break
;
}
}
}
/* Clear the request */
p_playlist
->
request
.
b_request
=
VLC_FALSE
;
}
/* "Automatic" item change ( next ) */
else
{
p_playlist
->
request_date
=
0
;
if
(
p_playlist
->
status
.
i_view
==
-
1
)
{
if
(
p_playlist
->
i_index
+
1
<
p_playlist
->
i_size
)
{
p_playlist
->
i_index
++
;
p_new
=
p_playlist
->
pp_items
[
p_playlist
->
i_index
];
}
else
{
p_playlist
->
i_status
=
PLAYLIST_STOPPED
;
msg_Dbg
(
p_playlist
,
"finished"
);
p_new
=
NULL
;
}
}
/* We are playing with a view */
else
{
playlist_view_t
*
p_view
=
playlist_ViewFind
(
p_playlist
,
p_playlist
->
status
.
i_view
);
p_new
=
playlist_FindNextFromParent
(
p_playlist
,
p_playlist
->
status
.
i_view
,
p_view
->
p_root
,
p_playlist
->
status
.
p_node
,
p_playlist
->
status
.
p_item
);
}
}
/* Reset index */
if
(
p_playlist
->
i_index
>=
0
&&
p_new
!=
NULL
&&
p_playlist
->
pp_items
[
p_playlist
->
i_index
]
!=
p_new
)
{
p_playlist
->
i_index
=
playlist_GetPositionById
(
p_playlist
,
p_new
->
input
.
i_id
);
}
#ifdef PLAYLIST_PROFILE
msg_Dbg
(
p_playlist
,
"next item found in "
I64Fi
" us
\n
"
,
mdate
()
-
start
);
#endif
if
(
p_new
==
NULL
)
{
msg_Info
(
p_playlist
,
"Nothing to play"
);
}
return
p_new
;
}
#if 0
static void SkipItem( playlist_t *p_playlist, int i_arg )
{
int i_oldindex = p_playlist->i_index;
vlc_bool_t b_random, b_repeat, b_loop;
vlc_value_t val;
int i_count;
/* Increment */
else if( !b_repeat )
{
p_playlist->i_index += i_arg;
...
...
@@ -602,38 +877,54 @@ static void SkipItem( playlist_t *p_playlist, int i_arg )
}
}
#endif
/*****************************************************************************
* PlayItem: play current playlist item
*****************************************************************************
* This function calculates the position of the next playlist item, depending
* on the playlist course mode (forward, backward, random...).
*****************************************************************************/
static
void
PlayItem
(
playlist_t
*
p_playlist
)
* PlayItem: start the input thread for an item
****************************************************************************/
static
void
PlayItem
(
playlist_t
*
p_playlist
,
playlist_item_t
*
p_item
)
{
playlist_item_t
*
p_item
;
vlc_value_t
val
;
if
(
p_playlist
->
i_index
==
-
1
)
{
if
(
p_playlist
->
i_size
==
0
||
p_playlist
->
i_enabled
==
0
)
{
return
;
}
SkipItem
(
p_playlist
,
1
);
}
if
(
p_playlist
->
i_enabled
==
0
)
{
return
;
}
int
i
;
msg_Dbg
(
p_playlist
,
"creating new input thread"
);
p_item
=
p_playlist
->
pp_items
[
p_playlist
->
i_index
];
p_item
->
i_nb_played
++
;
p_playlist
->
status
.
p_item
=
p_item
;
#ifdef PLAYLIST_PROFILE
if
(
p_playlist
->
request_date
!=
0
)
{
msg_Dbg
(
p_playlist
,
"request processed after "
I64Fi
" us"
,
mdate
()
-
p_playlist
->
request_date
);
}
#endif
p_playlist
->
p_input
=
input_CreateThread
(
p_playlist
,
&
p_item
->
input
);
val
.
i_int
=
p_playlist
->
i_index
;
var_AddCallback
(
p_playlist
->
p_input
,
"item-change"
,
ItemChange
,
p_playlist
);
val
.
i_int
=
p_item
->
input
.
i_id
;
/* unlock the playlist to set the var...mmm */
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
var_Set
(
p_playlist
,
"playlist-current"
,
val
);
vlc_mutex_lock
(
&
p_playlist
->
object_lock
);
}
/* Forward item change from input */
static
int
ItemChange
(
vlc_object_t
*
p_obj
,
const
char
*
psz_var
,
vlc_value_t
oldval
,
vlc_value_t
newval
,
void
*
param
)
{
playlist_t
*
p_playlist
=
(
playlist_t
*
)
param
;
//p_playlist->b_need_update = VLC_TRUE;
var_SetInteger
(
p_playlist
,
"item-change"
,
newval
.
i_int
);
/* Update view */
/* FIXME: Make that automatic */
playlist_ViewUpdate
(
p_playlist
,
VIEW_S_AUTHOR
);
return
VLC_SUCCESS
;
}
src/playlist/sort.c
View file @
f9d5e2ba
...
...
@@ -31,17 +31,22 @@
#include "vlc_playlist.h"
int
playlist_ItemArraySort
(
playlist_t
*
p_playlist
,
int
i_items
,
playlist_item_t
**
pp_items
,
int
i_mode
,
int
i_type
);
/**
* Sort the playlist
* Sort the playlist
.
* \param p_playlist the playlist
* \param i_mode: SORT_ID, SORT_TITLE, SORT_
GROUP, SORT_
AUTHOR, SORT_RANDOM
* \param i_mode: SORT_ID, SORT_TITLE, SORT_AUTHOR, SORT_RANDOM
* \param i_type: ORDER_NORMAL or ORDER_REVERSE (reversed order)
* \return VLC_SUCCESS on success
*/
int
playlist_Sort
(
playlist_t
*
p_playlist
,
int
i_mode
,
int
i_type
)
{
int
i
,
i_small
,
i_position
;
playlist_item_t
*
p_temp
;
int
i_id
=
-
1
;
vlc_value_t
val
;
val
.
b_bool
=
VLC_TRUE
;
...
...
@@ -49,76 +54,105 @@ int playlist_Sort( playlist_t * p_playlist , int i_mode, int i_type )
p_playlist
->
i_sort
=
i_mode
;
p_playlist
->
i_order
=
i_type
;
/* playlist with one or less items are allways sorted in all
manners, quit fast. */
if
(
p_playlist
->
i_size
<=
1
)
if
(
p_playlist
->
i_index
>=
0
)
{
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
i_id
=
p_playlist
->
pp_items
[
p_playlist
->
i_index
]
->
input
.
i_id
;
}
/* Notify the interfaces, is this necessary? */
var_Set
(
p_playlist
,
"intf-change"
,
val
);
playlist_ItemArraySort
(
p_playlist
,
p_playlist
->
i_size
,
p_playlist
->
pp_items
,
i_mode
,
i_type
);
return
VLC_SUCCESS
;
if
(
i_id
!=
-
1
)
{
p_playlist
->
i_index
=
playlist_GetPositionById
(
p_playlist
,
i_id
);
}
/* ensure we are in no-view mode */
p_playlist
->
status
.
i_view
=
-
1
;
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
/* Notify the interfaces */
var_Set
(
p_playlist
,
"intf-change"
,
val
);
return
VLC_SUCCESS
;
}
/**
* Sort a node.
* \param p_playlist the playlist
* \param p_node the node to sort
* \param i_mode: SORT_ID, SORT_TITLE, SORT_AUTHOR, SORT_RANDOM
* \param i_type: ORDER_NORMAL or ORDER_REVERSE (reversed order)
* \return VLC_SUCCESS on success
*/
int
playlist_NodeSort
(
playlist_t
*
p_playlist
,
playlist_item_t
*
p_node
,
int
i_mode
,
int
i_type
)
{
int
i_id
;
vlc_value_t
val
;
val
.
b_bool
=
VLC_TRUE
;
vlc_mutex_lock
(
&
p_playlist
->
object_lock
);
playlist_ItemArraySort
(
p_playlist
,
p_node
->
i_children
,
p_node
->
pp_children
,
i_mode
,
i_type
);
p_node
->
i_serial
++
;
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
/* Notify the interfaces */
var_Set
(
p_playlist
,
"intf-change"
,
val
);
return
VLC_SUCCESS
;
}
int
playlist_ItemArraySort
(
playlist_t
*
p_playlist
,
int
i_items
,
playlist_item_t
**
pp_items
,
int
i_mode
,
int
i_type
)
{
int
i
,
i_small
,
i_position
;
playlist_item_t
*
p_temp
;
vlc_value_t
val
;
val
.
b_bool
=
VLC_TRUE
;
if
(
i_mode
==
SORT_RANDOM
)
{
for
(
i_position
=
0
;
i_position
<
p_playlist
->
i_size
;
i_position
++
)
for
(
i_position
=
0
;
i_position
<
i_items
;
i_position
++
)
{
int
i_new
=
rand
()
%
(
p_playlist
->
i_size
-
1
);
/* Keep the correct current index */
if
(
i_new
==
p_playlist
->
i_index
)
p_playlist
->
i_index
=
i_position
;
else
if
(
i_position
==
p_playlist
->
i_index
)
p_playlist
->
i_index
=
i_new
;
int
i_new
=
rand
()
%
(
i_items
-
1
);
p_temp
=
p
_playlist
->
p
p_items
[
i_position
];
p
_playlist
->
pp_items
[
i_position
]
=
p_playlist
->
pp_items
[
i_new
];
p
_playlist
->
p
p_items
[
i_new
]
=
p_temp
;
p_temp
=
pp_items
[
i_position
];
p
p_items
[
i_position
]
=
pp_items
[
i_new
];
pp_items
[
i_new
]
=
p_temp
;
}
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
/* Notify the interfaces */
var_Set
(
p_playlist
,
"intf-change"
,
val
);
return
VLC_SUCCESS
;
}
for
(
i_position
=
0
;
i_position
<
p_playlist
->
i_size
-
1
;
i_position
++
)
for
(
i_position
=
0
;
i_position
<
i_items
-
1
;
i_position
++
)
{
i_small
=
i_position
;
for
(
i
=
i_position
+
1
;
i
<
p_playlist
->
i_size
;
i
++
)
for
(
i
=
i_position
+
1
;
i
<
i_items
;
i
++
)
{
int
i_test
=
0
;
if
(
i_mode
==
SORT_
ID
)
if
(
i_mode
==
SORT_
TITLE
)
{
i_test
=
p_playlist
->
pp_items
[
i
]
->
i_id
-
p_playlist
->
pp_items
[
i_small
]
->
i_id
;
}
else
if
(
i_mode
==
SORT_TITLE
)
{
i_test
=
strcasecmp
(
p_playlist
->
pp_items
[
i
]
->
input
.
psz_name
,
p_playlist
->
pp_items
[
i_small
]
->
input
.
psz_name
);
}
else
if
(
i_mode
==
SORT_GROUP
)
{
i_test
=
p_playlist
->
pp_items
[
i
]
->
i_group
-
p_playlist
->
pp_items
[
i_small
]
->
i_group
;
i_test
=
strcasecmp
(
pp_items
[
i
]
->
input
.
psz_name
,
pp_items
[
i_small
]
->
input
.
psz_name
);
}
else
if
(
i_mode
==
SORT_DURATION
)
{
i_test
=
p
_playlist
->
p
p_items
[
i
]
->
input
.
i_duration
-
p
_playlist
->
p
p_items
[
i_small
]
->
input
.
i_duration
;
i_test
=
pp_items
[
i
]
->
input
.
i_duration
-
pp_items
[
i_small
]
->
input
.
i_duration
;
}
else
if
(
i_mode
==
SORT_AUTHOR
)
{
i_test
=
strcasecmp
(
playlist_GetInfo
(
p_playlist
,
i
,
_
(
"General"
)
,
_
(
"Author"
)
),
playlist_GetInfo
(
p_playlist
,
i_small
,
_
(
"General"
)
,
_
(
"Author"
)
)
);
msg_Err
(
p_playlist
,
"META SORT not implemented"
);
}
if
(
(
i_type
==
ORDER_NORMAL
&&
i_test
<
0
)
||
...
...
@@ -127,20 +161,77 @@ int playlist_Sort( playlist_t * p_playlist , int i_mode, int i_type )
i_small
=
i
;
}
}
/* 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
;
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
;
p_temp
=
pp_items
[
i_position
];
pp_items
[
i_position
]
=
pp_items
[
i_small
];
pp_items
[
i_small
]
=
p_temp
;
}
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
return
VLC_SUCCESS
;
}
/* Notify the interfaces */
var_Set
(
p_playlist
,
"intf-change"
,
val
);
int
playlist_NodeGroup
(
playlist_t
*
p_playlist
,
int
i_view
,
playlist_item_t
*
p_root
,
playlist_item_t
**
pp_items
,
int
i_item
,
int
i_mode
,
int
i_type
)
{
char
*
psz_search
=
NULL
;
int
i_nodes
=
0
;
playlist_item_t
**
pp_nodes
=
NULL
;
playlist_item_t
*
p_node
;
vlc_bool_t
b_found
;
int
i
,
j
;
for
(
i
=
0
;
i
<
i_item
;
i
++
)
{
if
(
psz_search
)
free
(
psz_search
);
if
(
i_mode
==
SORT_TITLE
)
{
psz_search
=
strdup
(
pp_items
[
i
]
->
input
.
psz_name
);
}
else
if
(
i_mode
==
SORT_AUTHOR
)
{
psz_search
=
playlist_ItemGetInfo
(
pp_items
[
i
],
_
(
"Meta-information"
),
_
(
"Artist"
)
);
}
if
(
psz_search
&&
!
strcmp
(
psz_search
,
""
)
)
{
free
(
psz_search
);
psz_search
=
strdup
(
_
(
"Undefined"
)
);
}
b_found
=
VLC_FALSE
;
for
(
j
=
0
;
j
<
i_nodes
;
j
++
)
{
if
(
!
strcasecmp
(
psz_search
,
pp_nodes
[
j
]
->
input
.
psz_name
)
)
{
playlist_NodeAppend
(
p_playlist
,
i_view
,
pp_items
[
i
],
pp_nodes
[
j
]
);
b_found
=
VLC_TRUE
;
break
;
}
}
if
(
!
b_found
)
{
p_node
=
playlist_NodeCreate
(
p_playlist
,
i_view
,
psz_search
,
NULL
);
INSERT_ELEM
(
pp_nodes
,
i_nodes
,
i_nodes
,
p_node
);
playlist_NodeAppend
(
p_playlist
,
i_view
,
pp_items
[
i
],
p_node
);
}
}
/* Now, sort the nodes by name */
playlist_ItemArraySort
(
p_playlist
,
i_nodes
,
pp_nodes
,
SORT_TITLE
,
i_type
);
/* Now, sort each node and append it to the root node*/
for
(
i
=
0
;
i
<
i_nodes
;
i
++
)
{
playlist_ItemArraySort
(
p_playlist
,
pp_nodes
[
i
]
->
i_children
,
pp_nodes
[
i
]
->
pp_children
,
SORT_TITLE
,
i_type
);
playlist_NodeAppend
(
p_playlist
,
i_view
,
pp_nodes
[
i
],
p_root
);
}
return
VLC_SUCCESS
;
}
src/playlist/view.c
0 → 100644
View file @
f9d5e2ba
/*****************************************************************************
* view.c : Playlist views functions
*****************************************************************************
* Copyright (C) 1999-2004 VideoLAN
* $Id: item.c 7997 2004-06-18 11:35:45Z sigmunau $
*
* Authors: Clment Stenac <zorglub@videolan.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.
*
* 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>
#include <vlc/input.h>
#include "vlc_playlist.h"
/************************************************************************
* Local prototypes
************************************************************************/
/* TODO: inline */
playlist_item_t
*
playlist_FindDirectParent
(
playlist_t
*
p_playlist
,
playlist_item_t
*
,
int
);
playlist_item_t
*
playlist_RecursiveFindNext
(
playlist_t
*
p_playlist
,
int
i_view
,
playlist_item_t
*
p_root
,
playlist_item_t
*
p_item
,
playlist_item_t
*
p_parent
);
playlist_item_t
*
playlist_RecursiveFindPrev
(
playlist_t
*
p_playlist
,
int
i_view
,
playlist_item_t
*
p_root
,
playlist_item_t
*
p_item
,
playlist_item_t
*
p_parent
);
void
playlist_NodeDump
(
playlist_t
*
p_playlist
,
playlist_item_t
*
p_item
,
int
i_level
);
/**********************************************************************
* Exported View management functions
**********************************************************************/
/**
* Create a new view
*
* \param p_playlist a playlist object
* \param i_id the view identifier
* \return the new view or NULL on failure
*/
playlist_view_t
*
playlist_ViewCreate
(
playlist_t
*
p_playlist
,
int
i_id
,
char
*
psz_name
)
{
playlist_view_t
*
p_view
;
msg_Dbg
(
p_playlist
,
"Creating view %i"
,
i_id
);
p_view
=
malloc
(
sizeof
(
playlist_view_t
)
);
memset
(
p_view
,
0
,
sizeof
(
playlist_view_t
)
);
p_view
->
p_root
=
playlist_NodeCreate
(
p_playlist
,
i_id
,
NULL
,
NULL
);
p_view
->
i_id
=
i_id
;
p_view
->
psz_name
=
psz_name
?
strdup
(
psz_name
)
:
strdup
(
_
(
"Undefined"
)
);
return
p_view
;
}
/**
* Creates a new view and add it to the list
*
* \param p_playlist a playlist object
* \param i_id the view identifier
* \return VLC_SUCCESS or an error
*/
int
playlist_ViewInsert
(
playlist_t
*
p_playlist
,
int
i_id
,
char
*
psz_name
)
{
playlist_view_t
*
p_view
=
playlist_ViewCreate
(
p_playlist
,
i_id
,
psz_name
);
if
(
!
p_view
)
{
msg_Err
(
p_playlist
,
"Creation failed"
);
return
VLC_EGENERIC
;
}
vlc_mutex_lock
(
&
p_playlist
->
object_lock
);
INSERT_ELEM
(
p_playlist
->
pp_views
,
p_playlist
->
i_views
,
p_playlist
->
i_views
,
p_view
);
vlc_mutex_unlock
(
&
p_playlist
->
object_lock
);
}
/**
* Deletes a view
*
* \param p_view the view to delete
* \return nothing
*/
void
playlist_ViewDelete
(
playlist_t
*
p_playlist
,
playlist_view_t
*
p_view
)
{
//playlist_Delete( p_view->p_root );
REMOVE_ELEM
(
p_playlist
->
pp_views
,
p_playlist
->
i_views
,
0
);
}
/**
* Dumps the content of a view
*
* \param p_playlist the playlist
* \param p_view the view to dump
* \return nothing
*/
void
playlist_ViewDump
(
playlist_t
*
p_playlist
,
playlist_view_t
*
p_view
)
{
msg_Dbg
(
p_playlist
,
"Dumping view %i"
,
p_view
->
i_id
);
playlist_NodeDump
(
p_playlist
,
p_view
->
p_root
,
1
);
}
/**
* Counts the items of a view
*
* \param p_playlist the playlist
* \param p_view the view to count
* \return the number of items
*/
int
playlist_ViewItemCount
(
playlist_t
*
p_playlist
,
playlist_view_t
*
p_view
)
{
return
playlist_NodeChildrenCount
(
p_playlist
,
p_view
->
p_root
);
}
/**
* Updates a view. Only make sense for "sorted" and "ALL" views
*
* \param p_playlist the playlist
* \param i_view the view to update
* \return nothing
*/
int
playlist_ViewUpdate
(
playlist_t
*
p_playlist
,
int
i_view
)
{
playlist_view_t
*
p_view
=
playlist_ViewFind
(
p_playlist
,
i_view
);
if
(
p_view
==
NULL
)
{
return
VLC_EGENERIC
;
}
if
(
i_view
==
VIEW_ALL
)
{
p_view
->
p_root
->
i_children
=
p_playlist
->
i_size
;
p_view
->
p_root
->
pp_children
=
p_playlist
->
pp_items
;
}
/* Handle update of sorted views here */
if
(
i_view
==
VIEW_S_AUTHOR
)
{
playlist_ViewEmpty
(
p_playlist
,
i_view
,
VLC_FALSE
);
playlist_NodeGroup
(
p_playlist
,
i_view
,
p_view
->
p_root
,
p_playlist
->
pp_items
,
p_playlist
->
i_size
,
SORT_AUTHOR
,
ORDER_NORMAL
);
}
return
VLC_SUCCESS
;
}
/**
* Find a view
*
* \param p_playlist the playlist
* \param i_id the id to find
* \return the found view or NULL if not found
*/
playlist_view_t
*
playlist_ViewFind
(
playlist_t
*
p_playlist
,
int
i_id
)
{
int
i
;
for
(
i
=
0
;
i
<
p_playlist
->
i_views
;
i
++
)
{
if
(
p_playlist
->
pp_views
[
i
]
->
i_id
==
i_id
)
{
return
p_playlist
->
pp_views
[
i
];
}
}
return
NULL
;
}
int
playlist_ViewEmpty
(
playlist_t
*
p_playlist
,
int
i_view
,
vlc_bool_t
b_delete_items
)
{
playlist_view_t
*
p_view
=
playlist_ViewFind
(
p_playlist
,
i_view
);
if
(
p_view
==
NULL
)
{
return
VLC_EGENERIC
;
}
return
playlist_NodeEmpty
(
p_playlist
,
p_view
->
p_root
,
b_delete_items
);
}
/**********************************************************************
* Exported Nodes management functions
**********************************************************************/
/**
* Create a playlist node
*
* \param p_playlist the playlist
* \paam psz_name the name of the node
* \param p_parent the parent node to attach to or NULL if no attach
* \return the new node
*/
playlist_item_t
*
playlist_NodeCreate
(
playlist_t
*
p_playlist
,
int
i_view
,
char
*
psz_name
,
playlist_item_t
*
p_parent
)
{
/* Create the item */
playlist_item_t
*
p_item
=
(
playlist_item_t
*
)
malloc
(
sizeof
(
playlist_item_t
)
);
vlc_input_item_Init
(
VLC_OBJECT
(
p_playlist
),
&
p_item
->
input
);
if
(
p_item
==
NULL
)
{
return
NULL
;
}
if
(
psz_name
!=
NULL
)
{
p_item
->
input
.
psz_name
=
strdup
(
psz_name
);
}
else
{
p_item
->
input
.
psz_name
=
strdup
(
_
(
"Undefined"
)
);
}
p_item
->
input
.
psz_uri
=
NULL
;
p_item
->
b_enabled
=
VLC_TRUE
;
p_item
->
i_nb_played
=
0
;
p_item
->
i_flags
=
0
;
p_item
->
i_children
=
0
;
p_item
->
pp_children
=
NULL
;
p_item
->
input
.
i_duration
=
-
1
;
p_item
->
input
.
ppsz_options
=
NULL
;
p_item
->
input
.
i_options
=
0
;
p_item
->
input
.
i_categories
=
0
;
p_item
->
input
.
pp_categories
=
NULL
;
p_item
->
pp_parents
=
NULL
;
p_item
->
i_parents
=
0
;
p_item
->
i_flags
|=
PLAYLIST_SKIP_FLAG
;
/* Default behaviour */
vlc_mutex_init
(
p_playlist
,
&
p_item
->
input
.
lock
);
if
(
p_parent
!=
NULL
)
{
playlist_NodeAppend
(
p_playlist
,
i_view
,
p_item
,
p_parent
);
}
return
p_item
;
}
/**
* Remove all the children of a node
*
* \param p_playlist the playlist
* \param p_root the node
* \param b_delete_items do we have to delete the children items ?
* \return VLC_SUCCESS or an error
*/
int
playlist_NodeEmpty
(
playlist_t
*
p_playlist
,
playlist_item_t
*
p_root
,
vlc_bool_t
b_delete_items
)
{
int
i
;
if
(
p_root
->
i_children
==
-
1
)
{
return
VLC_EGENERIC
;
}
/* Delete the children */
for
(
i
=
p_root
->
i_children
-
1
;
i
>=
0
;
i
--
)
{
if
(
p_root
->
pp_children
[
i
]
->
i_children
>
-
1
)
{
playlist_NodeDelete
(
p_playlist
,
p_root
->
pp_children
[
i
],
b_delete_items
);
}
else
if
(
b_delete_items
)
{
/* Delete the item here */
}
}
return
VLC_SUCCESS
;
}
/**
* Remove all the children of a node and removes the node
*
* \param p_playlist the playlist
* \param p_root the node
* \param b_delete_items do we have to delete the children items ?
* \return VLC_SUCCESS or an error
*/
int
playlist_NodeDelete
(
playlist_t
*
p_playlist
,
playlist_item_t
*
p_root
,
vlc_bool_t
b_delete_items
)
{
int
i
;
if
(
p_root
->
i_children
==
-
1
)
{
return
VLC_EGENERIC
;
}
/* Delete the children */
for
(
i
=
p_root
->
i_children
-
1
;
i
>=
0
;
i
--
)
{
if
(
p_root
->
pp_children
[
i
]
->
i_children
>
-
1
)
{
playlist_NodeDelete
(
p_playlist
,
p_root
->
pp_children
[
i
],
b_delete_items
);
}
else
if
(
b_delete_items
)
{
/* Delete the item here */
}
}
/* Delete the node */
for
(
i
=
0
;
i
<
p_root
->
i_parents
;
i
++
)
{
playlist_NodeRemoveItem
(
p_playlist
,
p_root
,
p_root
->
pp_parents
[
i
]
->
p_parent
);
}
playlist_ItemDelete
(
p_root
);
return
VLC_SUCCESS
;
}
/**
* Adds an item to the childs of a node
*
* \param p_playlist the playlist
* \param i_view the view of the node ( needed for parent search )
* \param p_item the item to append
* \param p_parent the parent node
* \return VLC_SUCCESS or an error
*/
int
playlist_NodeAppend
(
playlist_t
*
p_playlist
,
int
i_view
,
playlist_item_t
*
p_item
,
playlist_item_t
*
p_parent
)
{
return
playlist_NodeInsert
(
p_playlist
,
i_view
,
p_item
,
p_parent
,
-
1
);
}
int
playlist_NodeInsert
(
playlist_t
*
p_playlist
,
int
i_view
,
playlist_item_t
*
p_item
,
playlist_item_t
*
p_parent
,
int
i_position
)
{
int
i
;
vlc_bool_t
b_found
=
VLC_FALSE
;
if
(
!
p_parent
||
p_parent
->
i_children
==
-
1
)
{
msg_Err
(
p_playlist
,
"invalid node"
);
}
if
(
i_position
==
-
1
)
i_position
=
p_parent
->
i_children
;
INSERT_ELEM
(
p_parent
->
pp_children
,
p_parent
->
i_children
,
i_position
,
p_item
);
/* Add the parent to the array */
for
(
i
=
0
;
i
<
p_item
->
i_parents
;
i
++
)
{
if
(
p_item
->
pp_parents
[
i
]
->
i_view
==
i_view
)
{
b_found
=
VLC_TRUE
;
break
;
}
}
if
(
b_found
==
VLC_FALSE
)
{
struct
item_parent_t
*
p_ip
=
(
struct
item_parent_t
*
)
malloc
(
sizeof
(
struct
item_parent_t
)
);
p_ip
->
i_view
=
i_view
;
p_ip
->
p_parent
=
p_parent
;
INSERT_ELEM
(
p_item
->
pp_parents
,
p_item
->
i_parents
,
p_item
->
i_parents
,
p_ip
);
}
/* Let the interface know this has been updated */
p_parent
->
i_serial
++
;
return
VLC_SUCCESS
;
}
/**
* Deletes an item from the children of a node
*
* \param p_playlist the playlist
* \param p_item the item to remove
* \param p_parent the parent node
* \return VLC_SUCCESS or an error
*/
int
playlist_NodeRemoveItem
(
playlist_t
*
p_playlist
,
playlist_item_t
*
p_item
,
playlist_item_t
*
p_parent
)
{
int
i
;
if
(
!
p_parent
||
p_parent
->
i_children
==
-
1
)
{
msg_Err
(
p_playlist
,
"invalid node"
);
}
for
(
i
=
0
;
i
<
p_parent
->
i_children
;
i
++
)
{
if
(
p_parent
->
pp_children
[
i
]
==
p_item
)
{
REMOVE_ELEM
(
p_parent
->
pp_children
,
p_parent
->
i_children
,
i
);
}
}
/* Let the interface know this has been updated */
p_parent
->
i_serial
++
;
return
VLC_SUCCESS
;
}
/**
* Count the children of a node
*
* \param p_playlist the playlist
* \param p_node the node
* \return the number of children
*/
int
playlist_NodeChildrenCount
(
playlist_t
*
p_playlist
,
playlist_item_t
*
p_node
)
{
int
i
;
int
i_nb
=
0
;
if
(
p_node
->
i_children
==
-
1
)
{
return
0
;
}
for
(
i
=
0
;
i
<
p_node
->
i_children
;
i
++
)
{
if
(
p_node
->
pp_children
[
i
]
->
i_children
==
-
1
)
{
i_nb
++
;
}
else
{
i_nb
+=
playlist_NodeChildrenCount
(
p_playlist
,
p_node
->
pp_children
[
i
]
);
}
}
return
i_nb
;
}
/**
* Search a child of a node by its name
*
* \param p_node the node
* \param psz_search the name of the child to search
* \return the child item or NULL if not found or error
*/
playlist_item_t
*
playlist_ChildSearchName
(
playlist_item_t
*
p_node
,
const
char
*
psz_search
)
{
int
i
;
if
(
p_node
->
i_children
<
0
)
{
return
NULL
;
}
for
(
i
=
0
;
i
<
p_node
->
i_children
;
i
++
)
{
if
(
!
strncmp
(
p_node
->
pp_children
[
i
]
->
input
.
psz_name
,
psz_search
,
strlen
(
p_node
->
pp_children
[
i
]
->
input
.
psz_name
)
)
)
{
return
p_node
->
pp_children
[
i
];
}
}
return
NULL
;
}
/**********************************************************************
* Tree functions
**********************************************************************/
/**
* Finds the next item to play
*
* \param p_playlist the playlist
* \param i_view the view
* \param p_root the root node
* \param p_node the node we are playing from
* \param p_item the item we were playing (NULL if none )
* \return the next item to play, or NULL if none found
*/
playlist_item_t
*
playlist_FindNextFromParent
(
playlist_t
*
p_playlist
,
int
i_view
,
/* FIXME: useless */
playlist_item_t
*
p_root
,
playlist_item_t
*
p_node
,
playlist_item_t
*
p_item
)
{
playlist_item_t
*
p_search
,
*
p_next
;
if
(
p_item
!=
NULL
)
{
msg_Dbg
(
p_playlist
,
"Finding next of %s within %s"
,
p_item
->
input
.
psz_name
,
p_node
->
input
.
psz_name
);
}
else
{
msg_Dbg
(
p_playlist
,
"Finding something to play within %s"
,
p_node
->
input
.
psz_name
);
}
if
(
!
p_node
||
p_node
->
i_children
==
-
1
)
{
msg_Err
(
p_playlist
,
"invalid arguments for FindNextFromParent"
);
return
NULL
;
}
/* Find the parent node of the item */
if
(
p_item
!=
NULL
)
{
p_search
=
playlist_FindDirectParent
(
p_playlist
,
p_item
,
i_view
);
if
(
p_search
==
NULL
)
{
msg_Err
(
p_playlist
,
"parent node not found"
);
return
NULL
;
}
}
else
{
p_search
=
p_node
;
}
/* Now, go up the tree until we find a suitable next item */
p_next
=
playlist_RecursiveFindNext
(
p_playlist
,
i_view
,
p_node
,
p_item
,
p_search
);
/* Not found, do we go past p_node ? */
if
(
p_next
==
NULL
)
{
if
(
p_playlist
->
b_go_next
)
{
p_next
=
playlist_RecursiveFindNext
(
p_playlist
,
i_view
,
p_root
,
p_item
,
p_search
);
if
(
p_next
==
NULL
)
{
return
NULL
;
}
/* OK, we could continue, so set our current node to the root */
p_playlist
->
status
.
p_node
=
p_root
;
}
else
{
return
NULL
;
}
}
return
p_next
;
}
/**
* Finds the previous item to play
*
* \param p_playlist the playlist
* \param i_view the view
* \param p_root the root node
* \param p_node the node we are playing from
* \param p_item the item we were playing (NULL if none )
* \return the next item to play, or NULL if none found
*/
playlist_item_t
*
playlist_FindPrevFromParent
(
playlist_t
*
p_playlist
,
int
i_view
,
playlist_item_t
*
p_root
,
playlist_item_t
*
p_node
,
playlist_item_t
*
p_item
)
{
playlist_item_t
*
p_search
,
*
p_next
;
if
(
p_item
!=
NULL
)
{
msg_Dbg
(
p_playlist
,
"Finding prev of %s within %s"
,
p_item
->
input
.
psz_name
,
p_node
->
input
.
psz_name
);
}
else
{
msg_Dbg
(
p_playlist
,
"Finding prev from %s"
,
p_node
->
input
.
psz_name
);
}
if
(
!
p_node
||
p_node
->
i_children
==
-
1
)
{
msg_Err
(
p_playlist
,
"invalid arguments for FindPrevFromParent"
);
return
NULL
;
}
/* Find the parent node of the item */
if
(
p_item
!=
NULL
)
{
p_search
=
playlist_FindDirectParent
(
p_playlist
,
p_item
,
i_view
);
if
(
p_search
==
NULL
)
{
msg_Err
(
p_playlist
,
"parent node not found"
);
return
NULL
;
}
}
else
{
p_search
=
p_node
;
}
/* Now, go up the tree until we find a suitable next item */
p_next
=
playlist_RecursiveFindPrev
(
p_playlist
,
i_view
,
p_node
,
p_item
,
p_search
);
if
(
p_next
==
NULL
)
{
if
(
p_playlist
->
b_go_next
)
{
p_next
=
playlist_RecursiveFindPrev
(
p_playlist
,
i_view
,
p_root
,
p_item
,
p_search
);
if
(
p_next
==
NULL
)
{
return
NULL
;
}
/* OK, we could continue, so set our current node to the root */
p_playlist
->
status
.
p_node
=
p_root
;
}
else
{
return
NULL
;
}
}
return
p_next
;
}
/************************************************************************
* Following functions are local
***********************************************************************/
/* Recursively search the tree for next item */
playlist_item_t
*
playlist_RecursiveFindNext
(
playlist_t
*
p_playlist
,
int
i_view
,
playlist_item_t
*
p_root
,
playlist_item_t
*
p_item
,
playlist_item_t
*
p_parent
)
{
int
i
;
playlist_item_t
*
p_parent_parent
;
for
(
i
=
0
;
i
<
p_parent
->
i_children
;
i
++
)
{
if
(
p_parent
->
pp_children
[
i
]
==
p_item
||
p_item
==
NULL
)
{
if
(
p_item
==
NULL
)
{
i
=
-
1
;
}
msg_Dbg
(
p_playlist
,
"Current item found, child %i of %s"
,
i
,
p_parent
->
input
.
psz_name
);
/* We found our item */
if
(
i
+
1
>=
p_parent
->
i_children
)
{
/* Too far... */
msg_Dbg
(
p_playlist
,
"Going up the tree,at parent of %s"
,
p_parent
->
input
.
psz_name
);
if
(
p_parent
==
p_root
)
{
/* Hmm, seems it's the end for you, guy ! */
return
NULL
;
}
/* Go up one level */
p_parent_parent
=
playlist_FindDirectParent
(
p_playlist
,
p_parent
,
i_view
);
if
(
p_parent_parent
==
NULL
)
{
msg_Warn
(
p_playlist
,
"Unable to find parent !"
);
return
NULL
;
}
return
playlist_RecursiveFindNext
(
p_playlist
,
i_view
,
p_root
,
p_parent
,
p_parent_parent
);
}
else
{
if
(
p_parent
->
pp_children
[
i
+
1
]
->
i_children
==
-
1
)
{
/* Cool, we have found a real item to play */
msg_Dbg
(
p_playlist
,
"Playing child %i of %s"
,
i
+
1
,
p_parent
->
input
.
psz_name
);
return
p_parent
->
pp_children
[
i
+
1
];
}
else
if
(
p_parent
->
pp_children
[
i
+
1
]
->
i_children
>
0
)
{
/* Select the first child of this node */
msg_Dbg
(
p_playlist
,
"%s is a node with children, "
"playing the first"
,
p_parent
->
pp_children
[
i
+
1
]
->
input
.
psz_name
);
if
(
p_parent
->
pp_children
[
i
+
1
]
->
pp_children
[
0
]
->
i_children
>=
0
)
{
/* first child is a node ! */
return
playlist_RecursiveFindNext
(
p_playlist
,
i_view
,
p_root
,
NULL
,
p_parent
->
pp_children
[
i
+
1
]
->
pp_children
[
0
]);
}
return
p_parent
->
pp_children
[
i
+
1
]
->
pp_children
[
0
];
}
else
{
/* This node has no child... We must continue */
msg_Dbg
(
p_playlist
,
"%s is a node with no children"
,
p_parent
->
pp_children
[
i
+
1
]
->
input
.
psz_name
);
p_item
=
p_parent
->
pp_children
[
i
+
1
];
}
}
}
}
/* Just in case :) */
return
NULL
;
}
/* Recursively search the tree for previous item */
playlist_item_t
*
playlist_RecursiveFindPrev
(
playlist_t
*
p_playlist
,
int
i_view
,
playlist_item_t
*
p_root
,
playlist_item_t
*
p_item
,
playlist_item_t
*
p_parent
)
{
int
i
;
playlist_item_t
*
p_parent_parent
;
for
(
i
=
p_parent
->
i_children
-
1
;
i
>=
0
;
i
--
)
{
if
(
p_parent
->
pp_children
[
i
]
==
p_item
||
p_item
==
NULL
)
{
if
(
p_item
==
NULL
)
{
i
=
-
1
;
}
msg_Dbg
(
p_playlist
,
"Current item found, child %i of %s"
,
i
,
p_parent
->
input
.
psz_name
);
/* We found our item */
if
(
i
<
1
)
{
/* Too far... */
msg_Dbg
(
p_playlist
,
"Going up the tree,at parent of %s"
,
p_parent
->
input
.
psz_name
);
if
(
p_parent
==
p_root
)
{
/* Hmm, seems it's the end for you, guy ! */
return
NULL
;
}
/* Go up one level */
p_parent_parent
=
playlist_FindDirectParent
(
p_playlist
,
p_parent
,
i_view
);
return
playlist_RecursiveFindPrev
(
p_playlist
,
i_view
,
p_root
,
p_parent
,
p_parent_parent
);
}
else
{
if
(
p_parent
->
pp_children
[
i
-
1
]
->
i_children
==
-
1
)
{
/* Cool, we have found a real item to play */
msg_Dbg
(
p_playlist
,
"Playing child %i of %s"
,
i
-
1
,
p_parent
->
input
.
psz_name
);
return
p_parent
->
pp_children
[
i
-
1
];
}
else
if
(
p_parent
->
pp_children
[
i
-
1
]
->
i_children
>
0
)
{
/* Select the last child of this node */
msg_Dbg
(
p_playlist
,
"%s is a node with children,"
" playing the last"
,
p_parent
->
pp_children
[
i
-
1
]
->
input
.
psz_name
);
if
(
p_parent
->
pp_children
[
i
-
1
]
->
pp_children
[
p_parent
->
pp_children
[
i
-
1
]
->
i_children
-
1
]
->
i_children
>=
0
)
{
/* Last child is a node */
return
playlist_RecursiveFindPrev
(
p_playlist
,
i_view
,
p_root
,
NULL
,
p_parent
->
pp_children
[
i
-
1
]
->
pp_children
[
p_parent
->
pp_children
[
i
-
1
]
->
i_children
-
1
]);
}
return
p_parent
->
pp_children
[
i
-
1
]
->
pp_children
[
p_parent
->
pp_children
[
i
-
1
]
->
i_children
-
1
];
}
else
{
/* This node has no child... We must continue */
msg_Dbg
(
p_playlist
,
"%s is a node with no children"
,
p_parent
->
pp_children
[
i
-
1
]
->
input
.
psz_name
);
p_item
=
p_parent
->
pp_children
[
i
-
1
];
}
}
}
}
return
NULL
;
}
/* This function returns the parent of an item in a view */
playlist_item_t
*
playlist_FindDirectParent
(
playlist_t
*
p_playlist
,
playlist_item_t
*
p_item
,
int
i_view
)
{
int
i
=
0
;
for
(
i
=
0
;
i
<
p_item
->
i_parents
;
i
++
)
{
if
(
p_item
->
pp_parents
[
i
]
->
i_view
==
i_view
)
{
return
p_item
->
pp_parents
[
i
]
->
p_parent
;
}
}
return
NULL
;
}
/* This function dumps a node */
void
playlist_NodeDump
(
playlist_t
*
p_playlist
,
playlist_item_t
*
p_item
,
int
i_level
)
{
char
str
[
512
];
int
i
;
if
(
i_level
==
1
)
{
msg_Dbg
(
p_playlist
,
"%s (%i)"
,
p_item
->
input
.
psz_name
,
p_item
->
i_children
);
}
if
(
p_item
->
i_children
==
-
1
)
{
return
;
}
for
(
i
=
0
;
i
<
p_item
->
i_children
;
i
++
)
{
memset
(
str
,
32
,
512
);
sprintf
(
str
+
2
*
i_level
,
"%s (%i)"
,
p_item
->
pp_children
[
i
]
->
input
.
psz_name
,
p_item
->
pp_children
[
i
]
->
i_children
);
msg_Dbg
(
p_playlist
,
"%s"
,
str
);
if
(
p_item
->
pp_children
[
i
]
->
i_children
>=
0
)
{
playlist_NodeDump
(
p_playlist
,
p_item
->
pp_children
[
i
],
i_level
+
1
);
}
}
return
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment