Commit defbc4a4 authored by Jakob Leben's avatar Jakob Leben

vlc core: single storage playlist

- Playlist items are stored only once. No category / onelevel separation
- Services Discovery nodes always stay a tree
- The playlist and Media Library are tree or flat depending on variable "playlist-tree".
  It means that if the setting variable says flat, the items that come from playlist
  demuxers are flattened into a single level list.
- The design demanded a different playlist demuxing system. Now playlist demuxers should
  construct a tree of items under an input_item_node_t root and send that using
  input_item_AddSubItemTree. Currently, the old scheme will be retained in modules, because
  there is still some listening to the old event in code (the libvlc media system for example)
parent 53d2132c
...@@ -212,6 +212,7 @@ typedef struct config_category_t config_category_t; ...@@ -212,6 +212,7 @@ typedef struct config_category_t config_category_t;
typedef struct input_thread_t input_thread_t; typedef struct input_thread_t input_thread_t;
typedef struct input_thread_sys_t input_thread_sys_t; typedef struct input_thread_sys_t input_thread_sys_t;
typedef struct input_item_t input_item_t; typedef struct input_item_t input_item_t;
typedef struct input_item_node_t input_item_node_t;
typedef struct access_t access_t; typedef struct access_t access_t;
typedef struct access_sys_t access_sys_t; typedef struct access_sys_t access_sys_t;
typedef struct stream_t stream_t; typedef struct stream_t stream_t;
......
...@@ -119,6 +119,7 @@ typedef enum vlc_event_type_t { ...@@ -119,6 +119,7 @@ typedef enum vlc_event_type_t {
/* Input item events */ /* Input item events */
vlc_InputItemMetaChanged, vlc_InputItemMetaChanged,
vlc_InputItemSubItemAdded, vlc_InputItemSubItemAdded,
vlc_InputItemSubItemTreeAdded,
vlc_InputItemDurationChanged, vlc_InputItemDurationChanged,
vlc_InputItemPreparsedChanged, vlc_InputItemPreparsedChanged,
vlc_InputItemNameChanged, vlc_InputItemNameChanged,
...@@ -158,6 +159,10 @@ typedef struct vlc_event_t ...@@ -158,6 +159,10 @@ typedef struct vlc_event_t
{ {
input_item_t * p_new_child; input_item_t * p_new_child;
} input_item_subitem_added; } input_item_subitem_added;
struct vlc_input_item_subitem_tree_added
{
input_item_node_t * p_root;
} input_item_subitem_tree_added;
struct vlc_input_item_duration_changed struct vlc_input_item_duration_changed
{ {
mtime_t new_duration; mtime_t new_duration;
......
...@@ -107,6 +107,14 @@ enum input_item_type_e ...@@ -107,6 +107,14 @@ enum input_item_type_e
ITEM_TYPE_NUMBER ITEM_TYPE_NUMBER
}; };
struct input_item_node_t
{
input_item_t * p_item;
int i_children;
input_item_node_t **pp_children;
input_item_node_t *p_parent;
};
VLC_EXPORT( void, input_item_CopyOptions, ( input_item_t *p_parent, input_item_t *p_child ) ); VLC_EXPORT( void, input_item_CopyOptions, ( input_item_t *p_parent, input_item_t *p_child ) );
VLC_EXPORT( void, input_item_SetName, ( input_item_t *p_item, const char *psz_name ) ); VLC_EXPORT( void, input_item_SetName, ( input_item_t *p_item, const char *psz_name ) );
...@@ -116,6 +124,11 @@ VLC_EXPORT( void, input_item_SetName, ( input_item_t *p_item, const char *psz_na ...@@ -116,6 +124,11 @@ VLC_EXPORT( void, input_item_SetName, ( input_item_t *p_item, const char *psz_na
* the input item children. */ * the input item children. */
VLC_EXPORT( void, input_item_AddSubItem, ( input_item_t *p_parent, input_item_t *p_child ) ); VLC_EXPORT( void, input_item_AddSubItem, ( input_item_t *p_parent, input_item_t *p_child ) );
VLC_EXPORT( void, input_item_AddSubItemTree, ( input_item_node_t *p_root ) );
/* Will send vlc_InputItemSubItemTreeAdded event, just as input_item_AddSubItemTree */
VLC_EXPORT( void, input_item_AddSubItem2, ( input_item_t *p_parent, input_item_t *p_child ) );
/** /**
* Option flags * Option flags
...@@ -215,6 +228,14 @@ VLC_EXPORT( input_item_t *, __input_item_NewExt, (vlc_object_t *, const char *ps ...@@ -215,6 +228,14 @@ VLC_EXPORT( input_item_t *, __input_item_NewExt, (vlc_object_t *, const char *ps
*/ */
#define input_item_New( a,b,c ) input_item_NewExt( a, b, c, 0, NULL, 0, -1 ) #define input_item_New( a,b,c ) input_item_NewExt( a, b, c, 0, NULL, 0, -1 )
VLC_EXPORT( input_item_node_t *, input_item_node_Create, ( input_item_t *p_input ) );
VLC_EXPORT( void, input_item_node_Delete, ( input_item_node_t *p_node ) );
VLC_EXPORT( input_item_node_t *, input_item_node_AppendItem, ( input_item_node_t *p_node, input_item_t *p_item ) );
VLC_EXPORT( void, input_item_node_AppendNode, ( input_item_node_t *p_node, input_item_node_t *p_item ) );
/****************** /******************
* Input stats * Input stats
******************/ ******************/
......
...@@ -153,7 +153,6 @@ struct playlist_item_t ...@@ -153,7 +153,6 @@ struct playlist_item_t
int i_id; /**< Playlist item specific id */ int i_id; /**< Playlist item specific id */
uint8_t i_flags; /**< Flags */ uint8_t i_flags; /**< Flags */
playlist_t *p_playlist; /**< Parent playlist */ playlist_t *p_playlist; /**< Parent playlist */
bool b_input_item_observer;
}; };
#define PLAYLIST_SAVE_FLAG 0x0001 /**< Must it be saved */ #define PLAYLIST_SAVE_FLAG 0x0001 /**< Must it be saved */
...@@ -180,6 +179,11 @@ struct playlist_t ...@@ -180,6 +179,11 @@ struct playlist_t
int i_current_index; /**< Index in current array */ int i_current_index; /**< Index in current array */
/* Predefined items */ /* Predefined items */
playlist_item_t * p_root;
playlist_item_t * p_playing;
playlist_item_t * p_media_library;
//Phony ones, point to those above;
playlist_item_t * p_root_category; /**< Root of category tree */ playlist_item_t * p_root_category; /**< Root of category tree */
playlist_item_t * p_root_onelevel; /**< Root of onelevel tree */ playlist_item_t * p_root_onelevel; /**< Root of onelevel tree */
playlist_item_t * p_local_category; /** < "Playlist" in CATEGORY view */ playlist_item_t * p_local_category; /** < "Playlist" in CATEGORY view */
...@@ -346,7 +350,6 @@ VLC_EXPORT( int, playlist_DeleteFromInput, ( playlist_t *, input_item_t *, bool ...@@ -346,7 +350,6 @@ VLC_EXPORT( int, playlist_DeleteFromInput, ( playlist_t *, input_item_t *, bool
VLC_EXPORT( int, playlist_Add, ( playlist_t *, const char *, const char *, int, int, bool, bool ) ); VLC_EXPORT( int, playlist_Add, ( playlist_t *, const char *, const char *, int, int, bool, bool ) );
VLC_EXPORT( int, playlist_AddExt, ( playlist_t *, const char *, const char *, int, int, mtime_t, int, const char *const *, unsigned, bool, bool ) ); VLC_EXPORT( int, playlist_AddExt, ( playlist_t *, const char *, const char *, int, int, mtime_t, int, const char *const *, unsigned, bool, bool ) );
VLC_EXPORT( int, playlist_AddInput, ( playlist_t *, input_item_t *, int, int, bool, bool ) ); VLC_EXPORT( int, playlist_AddInput, ( playlist_t *, input_item_t *, int, int, bool, bool ) );
VLC_EXPORT( int, playlist_BothAddInput, ( playlist_t *, input_item_t *,playlist_item_t *,int , int, int*, int*, bool ) );
/********************************** Item search *************************/ /********************************** Item search *************************/
VLC_EXPORT( playlist_item_t *, playlist_ItemGetById, (playlist_t *, int ) ); VLC_EXPORT( playlist_item_t *, playlist_ItemGetById, (playlist_t *, int ) );
......
...@@ -60,6 +60,7 @@ static inline void input_item_Init( vlc_object_t *p_o, input_item_t *p_i ) ...@@ -60,6 +60,7 @@ static inline void input_item_Init( vlc_object_t *p_o, input_item_t *p_i )
vlc_event_manager_init( p_em, p_i, p_o ); vlc_event_manager_init( p_em, p_i, p_o );
vlc_event_manager_register_event_type( p_em, vlc_InputItemMetaChanged ); vlc_event_manager_register_event_type( p_em, vlc_InputItemMetaChanged );
vlc_event_manager_register_event_type( p_em, vlc_InputItemSubItemAdded ); vlc_event_manager_register_event_type( p_em, vlc_InputItemSubItemAdded );
vlc_event_manager_register_event_type( p_em, vlc_InputItemSubItemTreeAdded );
vlc_event_manager_register_event_type( p_em, vlc_InputItemDurationChanged ); vlc_event_manager_register_event_type( p_em, vlc_InputItemDurationChanged );
vlc_event_manager_register_event_type( p_em, vlc_InputItemPreparsedChanged ); vlc_event_manager_register_event_type( p_em, vlc_InputItemPreparsedChanged );
vlc_event_manager_register_event_type( p_em, vlc_InputItemNameChanged ); vlc_event_manager_register_event_type( p_em, vlc_InputItemNameChanged );
...@@ -268,6 +269,22 @@ void input_item_AddSubItem( input_item_t *p_parent, input_item_t *p_child ) ...@@ -268,6 +269,22 @@ void input_item_AddSubItem( input_item_t *p_parent, input_item_t *p_child )
vlc_event_send( &p_parent->event_manager, &event ); vlc_event_send( &p_parent->event_manager, &event );
} }
void input_item_AddSubItemTree ( input_item_node_t *p_root )
{
vlc_event_t event;
event.type = vlc_InputItemSubItemTreeAdded;
event.u.input_item_subitem_tree_added.p_root = p_root;
vlc_event_send( &p_root->p_item->event_manager, &event );
}
void input_item_AddSubItem2 ( input_item_t *p_parent, input_item_t *p_child )
{
input_item_node_t *p_node = input_item_node_Create( p_parent );
input_item_node_AppendItem( p_node, p_child );
input_item_AddSubItemTree( p_node );
input_item_node_Delete( p_node );
}
bool input_item_HasErrorWhenReading( input_item_t *p_item ) bool input_item_HasErrorWhenReading( input_item_t *p_item )
{ {
vlc_mutex_lock( &p_item->lock ); vlc_mutex_lock( &p_item->lock );
...@@ -962,3 +979,61 @@ static int GuessType( const input_item_t *p_item ) ...@@ -962,3 +979,61 @@ static int GuessType( const input_item_t *p_item )
sizeof( tab[0] ), typecmp ); sizeof( tab[0] ), typecmp );
return e ? e->i_type : ITEM_TYPE_FILE; return e ? e->i_type : ITEM_TYPE_FILE;
} }
input_item_node_t *input_item_node_Create( input_item_t *p_input )
{
input_item_node_t* p_node = malloc( sizeof( input_item_node_t ) );
if( !p_node )
return NULL;
assert( p_input );
p_node->p_item = p_input;
vlc_gc_incref( p_input );
p_node->p_parent = NULL;
p_node->i_children = 0;
p_node->pp_children = NULL;
return p_node;
}
void input_item_node_Delete( input_item_node_t *p_node )
{
int i;
for( i = 0; i < p_node->i_children; i++ )
input_item_node_Delete( p_node->pp_children[i] );
if( p_node->p_parent )
{
for( i = 0; i < p_node->p_parent->i_children; i++ )
if( p_node->p_parent->pp_children[i] == p_node )
{
REMOVE_ELEM( p_node->p_parent->pp_children,
p_node->p_parent->i_children,
i );
break;
}
}
vlc_gc_decref( p_node->p_item );
free( p_node );
}
input_item_node_t *input_item_node_AppendItem( input_item_node_t *p_node, input_item_t *p_item )
{
input_item_node_t *p_new_child = input_item_node_Create( p_item );
if( !p_new_child ) return NULL;
input_item_node_AppendNode( p_node, p_new_child );
return p_new_child;
}
void input_item_node_AppendNode( input_item_node_t *p_parent, input_item_node_t *p_child )
{
assert( p_parent && p_child && p_child->p_parent == NULL );
INSERT_ELEM( p_parent->pp_children,
p_parent->i_children,
p_parent->i_children,
p_child );
p_child->p_parent = p_parent;
}
...@@ -189,6 +189,8 @@ input_GetItem ...@@ -189,6 +189,8 @@ input_GetItem
input_item_AddInfo input_item_AddInfo
input_item_AddOption input_item_AddOption
input_item_AddSubItem input_item_AddSubItem
input_item_AddSubItem2
input_item_AddSubItemTree
input_item_CopyOptions input_item_CopyOptions
input_item_DelInfo input_item_DelInfo
input_item_GetDuration input_item_GetDuration
...@@ -203,6 +205,10 @@ input_item_IsPreparsed ...@@ -203,6 +205,10 @@ input_item_IsPreparsed
input_item_MetaMatch input_item_MetaMatch
__input_item_NewExt __input_item_NewExt
input_item_NewWithType input_item_NewWithType
input_item_node_AppendItem
input_item_node_AppendNode
input_item_node_Create
input_item_node_Delete
input_item_SetDuration input_item_SetDuration
input_item_SetMeta input_item_SetMeta
input_item_SetName input_item_SetName
...@@ -313,7 +319,6 @@ playlist_AddExt ...@@ -313,7 +319,6 @@ playlist_AddExt
playlist_AddInput playlist_AddInput
playlist_AskForArtEnqueue playlist_AskForArtEnqueue
playlist_AssertLocked playlist_AssertLocked
playlist_BothAddInput
playlist_ChildSearchName playlist_ChildSearchName
playlist_Clear playlist_Clear
playlist_Control playlist_Control
......
...@@ -105,54 +105,50 @@ playlist_t * playlist_Create( vlc_object_t *p_parent ) ...@@ -105,54 +105,50 @@ playlist_t * playlist_Create( vlc_object_t *p_parent )
pl_priv(p_playlist)->b_auto_preparse = pl_priv(p_playlist)->b_auto_preparse =
var_InheritBool( p_parent, "auto-preparse" ); var_InheritBool( p_parent, "auto-preparse" );
PL_LOCK; /* playlist_NodeCreate will check for it */ /* Create the root node */
p_playlist->p_root_category = playlist_NodeCreate( p_playlist, NULL, NULL, PL_LOCK;
p_playlist->p_root = playlist_NodeCreate( p_playlist, NULL, NULL,
0, NULL ); 0, NULL );
p_playlist->p_root_onelevel = playlist_NodeCreate( p_playlist, NULL, NULL,
0, p_playlist->p_root_category->p_input );
PL_UNLOCK; PL_UNLOCK;
if( !p_playlist->p_root ) return NULL;
if( !p_playlist->p_root_category || !p_playlist->p_root_onelevel ) /* Create currently playing items node */
return NULL; PL_LOCK;
p_playlist->p_playing = playlist_NodeCreate(
p_playlist, _( "Playlist" ), p_playlist->p_root,
PLAYLIST_RO_FLAG, NULL );
/* Create playlist and media library */
PL_LOCK; /* playlist_NodesPairCreate will check for it */
playlist_NodesPairCreate( p_playlist, _( "Playlist" ),
&p_playlist->p_local_category,
&p_playlist->p_local_onelevel, false );
PL_UNLOCK; PL_UNLOCK;
p_playlist->p_local_category->i_flags |= PLAYLIST_RO_FLAG; if( !p_playlist->p_playing ) return NULL;
p_playlist->p_local_onelevel->i_flags |= PLAYLIST_RO_FLAG;
if( !p_playlist->p_local_category || !p_playlist->p_local_onelevel ||
!p_playlist->p_local_category->p_input ||
!p_playlist->p_local_onelevel->p_input )
return NULL;
/* Create media library node */
const bool b_ml = var_InheritBool( p_parent, "media-library"); const bool b_ml = var_InheritBool( p_parent, "media-library");
if( b_ml ) if( b_ml )
{ {
PL_LOCK; /* playlist_NodesPairCreate will check for it */ PL_LOCK;
playlist_NodesPairCreate( p_playlist, _( "Media Library" ), p_playlist->p_media_library = playlist_NodeCreate(
&p_playlist->p_ml_category, p_playlist, _( "Media Library" ), p_playlist->p_root,
&p_playlist->p_ml_onelevel, false ); PLAYLIST_RO_FLAG, NULL );
PL_UNLOCK; PL_UNLOCK;
if(!p_playlist->p_ml_category || !p_playlist->p_ml_onelevel) if(!p_playlist->p_media_library ) return NULL;
return NULL;
p_playlist->p_ml_category->i_flags |= PLAYLIST_RO_FLAG;
p_playlist->p_ml_onelevel->i_flags |= PLAYLIST_RO_FLAG;
} }
else else
{ {
p_playlist->p_ml_category = p_playlist->p_ml_onelevel = NULL; p_playlist->p_media_library = NULL;
} }
p_playlist->p_root_category = p_playlist->p_root;
p_playlist->p_root_onelevel = p_playlist->p_root;
p_playlist->p_local_category = p_playlist->p_playing;
p_playlist->p_local_onelevel = p_playlist->p_playing;
p_playlist->p_ml_category = p_playlist->p_media_library;
p_playlist->p_ml_onelevel = p_playlist->p_media_library;;
/* Initial status */ /* Initial status */
pl_priv(p_playlist)->status.p_item = NULL; pl_priv(p_playlist)->status.p_item = NULL;
pl_priv(p_playlist)->status.p_node = p_playlist->p_local_onelevel; pl_priv(p_playlist)->status.p_node = p_playlist->p_playing;
pl_priv(p_playlist)->request.b_request = false; pl_priv(p_playlist)->request.b_request = false;
pl_priv(p_playlist)->status.i_status = PLAYLIST_STOPPED; pl_priv(p_playlist)->status.i_status = PLAYLIST_STOPPED;
......
...@@ -33,90 +33,82 @@ ...@@ -33,90 +33,82 @@
static void AddItem( playlist_t *p_playlist, playlist_item_t *p_item, static void AddItem( playlist_t *p_playlist, playlist_item_t *p_item,
playlist_item_t *p_node, int i_mode, int i_pos ); playlist_item_t *p_node, int i_mode, int i_pos );
static void GoAndPreparse( playlist_t *p_playlist, int i_mode, static void GoAndPreparse( playlist_t *p_playlist, int i_mode,
playlist_item_t *, playlist_item_t * ); playlist_item_t * );
static void ChangeToNode( playlist_t *p_playlist, playlist_item_t *p_item ); static void ChangeToNode( playlist_t *p_playlist, playlist_item_t *p_item );
static playlist_item_t *ItemToNode( playlist_t *, playlist_item_t *, bool ); static playlist_item_t *ItemToNode( playlist_t *, playlist_item_t *, bool );
/***************************************************************************** /*****************************************************************************
* An input item has gained a subitem (Event Callback) * An input item has gained subitems (Event Callback)
*****************************************************************************/ *****************************************************************************/
static void input_item_subitem_added( const vlc_event_t * p_event,
void * user_data )
{
playlist_item_t *p_parent_playlist_item = user_data;
playlist_t * p_playlist = p_parent_playlist_item->p_playlist;
input_item_t * p_parent, * p_child;
playlist_item_t * p_child_in_category;
playlist_item_t * p_item_in_category;
bool b_play;
p_parent = p_event->p_obj; static void input_item_add_subitem_tree ( const vlc_event_t * p_event,
p_child = p_event->u.input_item_subitem_added.p_new_child; void * user_data )
{
input_item_t *p_input = p_event->p_obj;
playlist_t *p_playlist = (( playlist_item_t* ) user_data)->p_playlist;
input_item_node_t *p_new_root = p_event->u.input_item_subitem_tree_added.p_root;
PL_LOCK; PL_LOCK;
b_play = var_CreateGetBool( p_playlist, "playlist-autostart" );
/* This part is really hakish, but this playlist system isn't simple */
/* First check if we haven't already added the item as we are
* listening using the onelevel and the category representent
* (Because of the playlist design) */
p_child_in_category = playlist_ItemFindFromInputAndRoot(
p_playlist, p_child,
p_playlist->p_root_category,
false /* Only non-node */ );
if( !p_child_in_category )
{
/* Then, transform to a node if needed */
p_item_in_category = playlist_ItemFindFromInputAndRoot(
p_playlist, p_parent,
p_playlist->p_root_category,
false /* Only non-node */ );
if( !p_item_in_category )
{
/* Item may have been removed */
PL_UNLOCK;
return;
}
bool b_stop = p_item_in_category->i_flags & PLAYLIST_SUBITEM_STOP_FLAG; playlist_item_t *p_item =
playlist_ItemGetByInput( p_playlist, p_input );
assert( p_item != NULL );
playlist_item_t *p_parent = p_item->p_parent;
assert( p_parent != NULL );
b_play = b_play && bool b_play = var_CreateGetBool( p_playlist, "playlist-autostart" ) &&
p_item_in_category == get_current_status_item( p_playlist ) && get_current_status_item( p_playlist ) == p_item;
p_item_in_category->i_children == -1; bool b_stop = b_play && p_item->i_flags & PLAYLIST_SUBITEM_STOP_FLAG;
p_item->i_flags &= ~PLAYLIST_SUBITEM_STOP_FLAG;
/* If this item is already a node don't transform it */ int pos = 0;
if( p_item_in_category->i_children == -1 ) for( int i = 0; i < p_parent->i_children; i++ )
{
if( p_parent->pp_children[i] == p_item )
{ {
p_item_in_category = ItemToNode( p_playlist, pos = i;
p_item_in_category, pl_Locked ); break;
p_item_in_category->p_input->i_type = ITEM_TYPE_PLAYLIST;
} }
}
int i_ret = playlist_BothAddInput( p_playlist, p_child, bool b_flat = false;
p_item_in_category, playlist_item_t *p_up = p_item;
PLAYLIST_APPEND | PLAYLIST_SPREPARSE , PLAYLIST_END, while( p_up->p_parent )
NULL, NULL, pl_Locked ); {
if( p_up->p_parent == p_playlist->p_playing ||
if( i_ret == VLC_SUCCESS && b_play ) p_up->p_parent == p_playlist->p_media_library )
{ {
if( b_stop ) if( !pl_priv(p_playlist)->b_tree ) b_flat = true;
{ break;
p_item_in_category->i_flags &= ~PLAYLIST_SUBITEM_STOP_FLAG;
PL_UNLOCK;
playlist_Stop( p_playlist );
return;
}
playlist_Control( p_playlist, PLAYLIST_VIEWPLAY,
pl_Locked, p_item_in_category, NULL );
} }
p_up = p_up->p_parent;
}
if( b_flat )
{
playlist_DeleteItem( p_playlist, p_item, true );
p_item = playlist_InsertInputItemTree( p_playlist, p_parent,
p_new_root, pos, true );
} }
else
p_item = playlist_InsertInputItemTree( p_playlist, p_item,
p_new_root, 0, false );
PL_UNLOCK; if( b_stop )
{
PL_UNLOCK;
playlist_Stop( p_playlist );
return;
}
else if( b_play )
{
playlist_Control( p_playlist, PLAYLIST_VIEWPLAY,
pl_Locked, get_current_status_node( p_playlist ), p_item );
}
PL_UNLOCK;
} }
/***************************************************************************** /*****************************************************************************
* An input item's meta or duration has changed (Event Callback) * An input item's meta or duration has changed (Event Callback)
*****************************************************************************/ *****************************************************************************/
...@@ -134,8 +126,8 @@ static void input_item_changed( const vlc_event_t * p_event, ...@@ -134,8 +126,8 @@ static void input_item_changed( const vlc_event_t * p_event,
static void install_input_item_observer( playlist_item_t * p_item ) static void install_input_item_observer( playlist_item_t * p_item )
{ {
vlc_event_manager_t * p_em = &p_item->p_input->event_manager; vlc_event_manager_t * p_em = &p_item->p_input->event_manager;
vlc_event_attach( p_em, vlc_InputItemSubItemAdded, vlc_event_attach( p_em, vlc_InputItemSubItemTreeAdded,
input_item_subitem_added, p_item ); input_item_add_subitem_tree, p_item );
vlc_event_attach( p_em, vlc_InputItemDurationChanged, vlc_event_attach( p_em, vlc_InputItemDurationChanged,
input_item_changed, p_item ); input_item_changed, p_item );
vlc_event_attach( p_em, vlc_InputItemMetaChanged, vlc_event_attach( p_em, vlc_InputItemMetaChanged,
...@@ -151,8 +143,8 @@ static void install_input_item_observer( playlist_item_t * p_item ) ...@@ -151,8 +143,8 @@ static void install_input_item_observer( playlist_item_t * p_item )
static void uninstall_input_item_observer( playlist_item_t * p_item ) static void uninstall_input_item_observer( playlist_item_t * p_item )
{ {
vlc_event_manager_t * p_em = &p_item->p_input->event_manager; vlc_event_manager_t * p_em = &p_item->p_input->event_manager;
vlc_event_detach( p_em, vlc_InputItemSubItemAdded, vlc_event_detach( p_em, vlc_InputItemSubItemTreeAdded,
input_item_subitem_added, p_item ); input_item_add_subitem_tree, p_item );
vlc_event_detach( p_em, vlc_InputItemMetaChanged, vlc_event_detach( p_em, vlc_InputItemMetaChanged,
input_item_changed, p_item ); input_item_changed, p_item );
vlc_event_detach( p_em, vlc_InputItemDurationChanged, vlc_event_detach( p_em, vlc_InputItemDurationChanged,
...@@ -169,7 +161,7 @@ static void uninstall_input_item_observer( playlist_item_t * p_item ) ...@@ -169,7 +161,7 @@ static void uninstall_input_item_observer( playlist_item_t * p_item )
* Playlist item creation * Playlist item creation
*****************************************************************************/ *****************************************************************************/
playlist_item_t *playlist_ItemNewFromInput( playlist_t *p_playlist, playlist_item_t *playlist_ItemNewFromInput( playlist_t *p_playlist,
input_item_t *p_input, bool install_observer ) input_item_t *p_input )
{ {
playlist_item_t* p_item = malloc( sizeof( playlist_item_t ) ); playlist_item_t* p_item = malloc( sizeof( playlist_item_t ) );
if( !p_item ) if( !p_item )
...@@ -187,10 +179,8 @@ playlist_item_t *playlist_ItemNewFromInput( playlist_t *p_playlist, ...@@ -187,10 +179,8 @@ playlist_item_t *playlist_ItemNewFromInput( playlist_t *p_playlist,
p_item->pp_children = NULL; p_item->pp_children = NULL;
p_item->i_flags = 0; p_item->i_flags = 0;
p_item->p_playlist = p_playlist; p_item->p_playlist = p_playlist;
p_item->b_input_item_observer = install_observer;
if( install_observer ) install_input_item_observer( p_item );
install_input_item_observer( p_item );
return p_item; return p_item;
} }
...@@ -218,8 +208,7 @@ int playlist_ItemRelease( playlist_item_t *p_item ) ...@@ -218,8 +208,7 @@ int playlist_ItemRelease( playlist_item_t *p_item )
* Most of the modules does that. * Most of the modules does that.
* *
* Who wants to add proper memory management? */ * Who wants to add proper memory management? */
if( p_item->b_input_item_observer ) uninstall_input_item_observer( p_item );
uninstall_input_item_observer( p_item );
ARRAY_APPEND( pl_priv(p_playlist)->items_to_delete, p_item); ARRAY_APPEND( pl_priv(p_playlist)->items_to_delete, p_item);
return VLC_SUCCESS; return VLC_SUCCESS;
} }
...@@ -268,7 +257,7 @@ int playlist_DeleteFromInputInParent( playlist_t *p_playlist, ...@@ -268,7 +257,7 @@ int playlist_DeleteFromInputInParent( playlist_t *p_playlist,
/** /**
* Delete from input * Delete from input
* *
* Remove an input item from ONELEVEL and CATEGORY * Search anywhere in playlist for an an input item and delete it
* \param p_playlist playlist object * \param p_playlist playlist object
* \param p_input the input to delete * \param p_input the input to delete
* \param b_locked TRUE if the playlist is locked * \param b_locked TRUE if the playlist is locked
...@@ -277,15 +266,12 @@ int playlist_DeleteFromInputInParent( playlist_t *p_playlist, ...@@ -277,15 +266,12 @@ int playlist_DeleteFromInputInParent( playlist_t *p_playlist,
int playlist_DeleteFromInput( playlist_t *p_playlist, input_item_t *p_input, int playlist_DeleteFromInput( playlist_t *p_playlist, input_item_t *p_input,
bool b_locked ) bool b_locked )
{ {
int i_ret1, i_ret2; int i_ret;
PL_LOCK_IF( !b_locked ); PL_LOCK_IF( !b_locked );
i_ret1 = DeleteFromInput( p_playlist, p_input, i_ret = DeleteFromInput( p_playlist, p_input,
p_playlist->p_root_category, true ); p_playlist->p_root, true );
i_ret2 = DeleteFromInput( p_playlist, p_input,
p_playlist->p_root_onelevel, true );
PL_UNLOCK_IF( !b_locked ); PL_UNLOCK_IF( !b_locked );
return ( i_ret1 == VLC_SUCCESS || i_ret2 == VLC_SUCCESS ) ? return ( i_ret == VLC_SUCCESS ? VLC_SUCCESS : VLC_ENOITEM );
VLC_SUCCESS : VLC_ENOITEM;
} }
/** /**
...@@ -298,8 +284,7 @@ int playlist_DeleteFromInput( playlist_t *p_playlist, input_item_t *p_input, ...@@ -298,8 +284,7 @@ int playlist_DeleteFromInput( playlist_t *p_playlist, input_item_t *p_input,
void playlist_Clear( playlist_t * p_playlist, bool b_locked ) void playlist_Clear( playlist_t * p_playlist, bool b_locked )
{ {
PL_LOCK_IF( !b_locked ); PL_LOCK_IF( !b_locked );
playlist_NodeEmpty( p_playlist, p_playlist->p_local_category, true ); playlist_NodeEmpty( p_playlist, p_playlist->p_playing, true );
playlist_NodeEmpty( p_playlist, p_playlist->p_local_onelevel, true );
PL_UNLOCK_IF( !b_locked ); PL_UNLOCK_IF( !b_locked );
} }
...@@ -402,7 +387,7 @@ int playlist_AddInput( playlist_t* p_playlist, input_item_t *p_input, ...@@ -402,7 +387,7 @@ int playlist_AddInput( playlist_t* p_playlist, input_item_t *p_input,
int i_mode, int i_pos, bool b_playlist, int i_mode, int i_pos, bool b_playlist,
bool b_locked ) bool b_locked )
{ {
playlist_item_t *p_item_cat, *p_item_one; playlist_item_t *p_item;
if( p_playlist->b_die ) return VLC_EGENERIC; if( p_playlist->b_die ) return VLC_EGENERIC;
if( !pl_priv(p_playlist)->b_doing_ml ) if( !pl_priv(p_playlist)->b_doing_ml )
PL_DEBUG( "adding item `%s' ( %s )", p_input->psz_name, PL_DEBUG( "adding item `%s' ( %s )", p_input->psz_name,
...@@ -410,88 +395,13 @@ int playlist_AddInput( playlist_t* p_playlist, input_item_t *p_input, ...@@ -410,88 +395,13 @@ int playlist_AddInput( playlist_t* p_playlist, input_item_t *p_input,
PL_LOCK_IF( !b_locked ); PL_LOCK_IF( !b_locked );
/* Add to ONELEVEL */ p_item = playlist_ItemNewFromInput( p_playlist, p_input );
p_item_one = playlist_ItemNewFromInput( p_playlist, p_input, false ); if( p_item == NULL ) return VLC_ENOMEM;
if( p_item_one == NULL ) return VLC_ENOMEM; AddItem( p_playlist, p_item,
AddItem( p_playlist, p_item_one, b_playlist ? p_playlist->p_playing :
b_playlist ? p_playlist->p_local_onelevel : p_playlist->p_media_library , i_mode, i_pos );
p_playlist->p_ml_onelevel , i_mode, i_pos );
/* Add to CATEGORY */
p_item_cat = playlist_ItemNewFromInput( p_playlist, p_input, true );
if( p_item_cat == NULL ) return VLC_ENOMEM;
AddItem( p_playlist, p_item_cat,
b_playlist ? p_playlist->p_local_category :
p_playlist->p_ml_category , i_mode, i_pos );
GoAndPreparse( p_playlist, i_mode, p_item_cat, p_item_one ); GoAndPreparse( p_playlist, i_mode, p_item );
PL_UNLOCK_IF( !b_locked );
return VLC_SUCCESS;
}
/**
* Add input
*
* Add an input item to p_direct_parent in the category tree, and to the
* matching top category in onelevel
* \param p_playlist the playlist to add into
* \param p_input the input item to add
* \param p_direct_parent the parent item to add into
* \param i_mode the mode used when adding
* \param i_pos the position in the playlist where to add. If this is
* PLAYLIST_END the item will be added at the end of the playlist
* regardless of its size
* \param i_cat id of the items category
* \param i_one id of the item onelevel category
* \param b_locked TRUE if the playlist is locked
* \return VLC_SUCCESS if success, VLC_EGENERIC if fail, VLC_ENOMEM if OOM
*/
int playlist_BothAddInput( playlist_t *p_playlist,
input_item_t *p_input,
playlist_item_t *p_direct_parent,
int i_mode, int i_pos,
int *i_cat, int *i_one, bool b_locked )
{
playlist_item_t *p_item_cat, *p_item_one, *p_up;
int i_top;
assert( p_input );
if( !vlc_object_alive( p_playlist ) )
return VLC_EGENERIC;
PL_LOCK_IF( !b_locked );
/* Add to category */
p_item_cat = playlist_ItemNewFromInput( p_playlist, p_input, true );
if( p_item_cat == NULL ) return VLC_ENOMEM;
AddItem( p_playlist, p_item_cat, p_direct_parent, i_mode, i_pos );
/* Add to onelevel */
/** \todo make a faster case for ml import */
p_item_one = playlist_ItemNewFromInput( p_playlist, p_input, false );
if( p_item_one == NULL ) return VLC_ENOMEM;
p_up = p_direct_parent;
while( p_up->p_parent != p_playlist->p_root_category )
{
p_up = p_up->p_parent;
}
for( i_top = 0 ; i_top < p_playlist->p_root_onelevel->i_children; i_top++ )
{
if( p_playlist->p_root_onelevel->pp_children[i_top]->p_input ==
p_up->p_input )
{
AddItem( p_playlist, p_item_one,
p_playlist->p_root_onelevel->pp_children[i_top],
i_mode, i_pos );
break;
}
}
GoAndPreparse( p_playlist, i_mode, p_item_cat, p_item_one );
if( i_cat ) *i_cat = p_item_cat->i_id;
if( i_one ) *i_one = p_item_one->i_id;
PL_UNLOCK_IF( !b_locked ); PL_UNLOCK_IF( !b_locked );
return VLC_SUCCESS; return VLC_SUCCESS;
...@@ -524,7 +434,7 @@ playlist_item_t * playlist_NodeAddInput( playlist_t *p_playlist, ...@@ -524,7 +434,7 @@ playlist_item_t * playlist_NodeAddInput( playlist_t *p_playlist,
return NULL; return NULL;
PL_LOCK_IF( !b_locked ); PL_LOCK_IF( !b_locked );
p_item = playlist_ItemNewFromInput( p_playlist, p_input, true ); p_item = playlist_ItemNewFromInput( p_playlist, p_input );
if( p_item == NULL ) return NULL; if( p_item == NULL ) return NULL;
AddItem( p_playlist, p_item, p_parent, i_mode, i_pos ); AddItem( p_playlist, p_item, p_parent, i_mode, i_pos );
...@@ -533,6 +443,65 @@ playlist_item_t * playlist_NodeAddInput( playlist_t *p_playlist, ...@@ -533,6 +443,65 @@ playlist_item_t * playlist_NodeAddInput( playlist_t *p_playlist,
return p_item; return p_item;
} }
/**
* Insert a tree of input items into a given playlist node
*
* \param p_playlist the playlist to insert into
* \param p_parent the receiving playlist node (can be an item)
* \param p_node the root of input item tree,
only it's contents will be inserted
* \param i_pos the position in the playlist where to insert. If this is
* PLAYLIST_END the items will be added at the end of the playlist
* regardless of its size
* \param b_flat TRUE if the new tree contents should be flattened into a list
* \return the first new leaf inserted (in playing order)
*/
playlist_item_t *playlist_InsertInputItemTree (
playlist_t *p_playlist, playlist_item_t *p_parent,
input_item_node_t *p_node, int i_pos, bool b_flat )
{
playlist_item_t *p_first_leaf = NULL;
if( p_parent->i_children == -1 ) ChangeToNode( p_playlist, p_parent );
if( i_pos == PLAYLIST_END ) i_pos = p_parent->i_children;
for( int i = 0; i < p_node->i_children; i++, i_pos++ )
{
playlist_item_t *p_child = NULL;
if( b_flat ? p_node->pp_children[i]->i_children == 0 : 1 )
{
printf("creating a leaf: %i\n", i_pos);
p_child = playlist_NodeAddInput( p_playlist,
p_node->pp_children[i]->p_item,
p_parent,
PLAYLIST_INSERT, i_pos,
pl_Locked );
printf("leaf done\n");
}
if( p_node->pp_children[i]->i_children > 0 )
{
if( b_flat )
{
printf("flat -> subnode into parent\n");
p_child = playlist_InsertInputItemTree( p_playlist, p_parent,
p_node->pp_children[i], i_pos, true );
i_pos += p_node->i_children - 1; /* i_pos += 1 on loop */
}
else
{
printf("tree -> subnode on its own\n");
p_child = playlist_InsertInputItemTree( p_playlist, p_child,
p_node->pp_children[i], 0, false );
}
}
if( i == 0 ) p_first_leaf = p_child;
}
printf("leaving a node\n");
return p_first_leaf;
}
/***************************************************************************** /*****************************************************************************
* Playlist item misc operations * Playlist item misc operations
*****************************************************************************/ *****************************************************************************/
...@@ -552,87 +521,62 @@ static playlist_item_t *ItemToNode( playlist_t *p_playlist, ...@@ -552,87 +521,62 @@ static playlist_item_t *ItemToNode( playlist_t *p_playlist,
playlist_item_t *p_item, playlist_item_t *p_item,
bool b_locked ) bool b_locked )
{ {
PL_LOCK_IF( !b_locked );
playlist_item_t *p_item_in_category; assert( p_item->p_parent );
/* What we do
* Find the input in CATEGORY.
* - If we find it
* - change it to node
* - we'll return it at the end
* - If we are a direct child of onelevel root, change to node, else
* delete the input from ONELEVEL
* - If we don't find it, just change to node (we are probably in VLM)
* and return NULL
*
* If we were in ONELEVEL, we thus retrieve the node in CATEGORY (will be
* useful for later BothAddInput )
*/
PL_LOCK_IF( !b_locked ); bool b_flat = false;
playlist_item_t *p_up = p_item;
while( p_up->p_parent )
{
if( p_up->p_parent == p_playlist->p_playing ||
p_up->p_parent == p_playlist->p_media_library )
{
if( !pl_priv(p_playlist)->b_tree ) b_flat = true;
break;
}
p_up = p_up->p_parent;
}
/* Fast track the media library, no time to loose */ if( !b_flat )
if( p_item == p_playlist->p_ml_category ) { {
ChangeToNode( p_playlist, p_item );
if( p_up == p_playlist->p_root )
var_SetAddress( p_playlist, "item-change", p_item->p_input );
PL_UNLOCK_IF( !b_locked ); PL_UNLOCK_IF( !b_locked );
return p_item; return p_item;
} }
else
/** \todo First look if we don't already have it */
p_item_in_category = playlist_ItemFindFromInputAndRoot(
p_playlist, p_item->p_input,
p_playlist->p_root_category,
true );
if( p_item_in_category )
{ {
playlist_item_t *p_item_in_one = playlist_ItemFindFromInputAndRoot( playlist_item_t *p_status_item = get_current_status_item( p_playlist );
p_playlist, p_item->p_input, playlist_item_t *p_status_node = get_current_status_node( p_playlist );
p_playlist->p_root_onelevel, if( p_item == p_status_item )
true );
assert( p_item_in_one );
/* We already have it, and there is nothing more to do */
ChangeToNode( p_playlist, p_item_in_category );
/* Item in one is a root, change it to node */
if( p_item_in_one->p_parent == p_playlist->p_root_onelevel )
ChangeToNode( p_playlist, p_item_in_one );
else
{ {
playlist_item_t *p_status_item = get_current_status_item( p_playlist ); /* We're deleting the current playlist item. Update
playlist_item_t *p_status_node = get_current_status_node( p_playlist ); * the playlist object to point at the previous item
if( p_item_in_one == p_status_item ) * so the playlist won't be restarted */
playlist_item_t *p_prev_status_item = NULL;
int i = 0;
while( i < p_status_node->i_children &&
p_status_node->pp_children[i] != p_status_item )
{ {
/* We're deleting the current playlist item. Update p_prev_status_item = p_status_node->pp_children[i];
* the playlist object to point at the previous item i++;
* so the playlist won't be restarted */
playlist_item_t *p_prev_status_item = NULL;
int i = 0;
while( i < p_status_node->i_children &&
p_status_node->pp_children[i] != p_status_item )
{
p_prev_status_item = p_status_node->pp_children[i];
i++;
}
if( i == p_status_node->i_children )
p_prev_status_item = NULL;
if( p_prev_status_item )
set_current_status_item( p_playlist, p_prev_status_item );
} }
DeleteFromInput( p_playlist, p_item_in_one->p_input, if( i == p_status_node->i_children )
p_playlist->p_root_onelevel, false ); p_prev_status_item = NULL;
if( p_prev_status_item )
set_current_status_item( p_playlist, p_prev_status_item );
} }
DeleteFromInput( p_playlist, p_item->p_input,
p_playlist->p_root, false );
pl_priv(p_playlist)->b_reset_currently_playing = true; pl_priv(p_playlist)->b_reset_currently_playing = true;
vlc_cond_signal( &pl_priv(p_playlist)->signal ); vlc_cond_signal( &pl_priv(p_playlist)->signal );
var_SetAddress( p_playlist, "item-change", p_item_in_category->p_input );
var_SetAddress( p_playlist, "leaf-to-parent", p_item_in_category->p_input );
PL_UNLOCK_IF( !b_locked );
return p_item_in_category;
}
else
{
ChangeToNode( p_playlist, p_item );
PL_UNLOCK_IF( !b_locked ); PL_UNLOCK_IF( !b_locked );
return p_item; return p_item->p_parent;
} }
} }
...@@ -788,47 +732,31 @@ void playlist_SendAddNotify( playlist_t *p_playlist, int i_item_id, ...@@ -788,47 +732,31 @@ void playlist_SendAddNotify( playlist_t *p_playlist, int i_item_id,
/* Enqueue an item for preparsing, and play it, if needed */ /* Enqueue an item for preparsing, and play it, if needed */
static void GoAndPreparse( playlist_t *p_playlist, int i_mode, static void GoAndPreparse( playlist_t *p_playlist, int i_mode,
playlist_item_t *p_item_cat, playlist_item_t *p_item )
playlist_item_t *p_item_one )
{ {
PL_ASSERT_LOCKED; PL_ASSERT_LOCKED;
if( (i_mode & PLAYLIST_GO ) ) if( (i_mode & PLAYLIST_GO ) )
{ {
playlist_item_t *p_parent = p_item_one;
playlist_item_t *p_toplay = NULL;
while( p_parent )
{
if( p_parent == p_playlist->p_root_category )
{
p_toplay = p_item_cat; break;
}
else if( p_parent == p_playlist->p_root_onelevel )
{
p_toplay = p_item_one; break;
}
p_parent = p_parent->p_parent;
}
assert( p_toplay );
pl_priv(p_playlist)->request.b_request = true; pl_priv(p_playlist)->request.b_request = true;
pl_priv(p_playlist)->request.i_skip = 0; pl_priv(p_playlist)->request.i_skip = 0;
pl_priv(p_playlist)->request.p_item = p_toplay; pl_priv(p_playlist)->request.p_item = p_item;
if( pl_priv(p_playlist)->p_input ) if( pl_priv(p_playlist)->p_input )
input_Stop( pl_priv(p_playlist)->p_input, true ); input_Stop( pl_priv(p_playlist)->p_input, true );
pl_priv(p_playlist)->request.i_status = PLAYLIST_RUNNING; pl_priv(p_playlist)->request.i_status = PLAYLIST_RUNNING;
vlc_cond_signal( &pl_priv(p_playlist)->signal ); vlc_cond_signal( &pl_priv(p_playlist)->signal );
} }
/* Preparse if PREPARSE or SPREPARSE & not enough meta */ /* Preparse if PREPARSE or SPREPARSE & not enough meta */
char *psz_artist = input_item_GetArtist( p_item_cat->p_input ); char *psz_artist = input_item_GetArtist( p_item->p_input );
char *psz_album = input_item_GetAlbum( p_item_cat->p_input ); char *psz_album = input_item_GetAlbum( p_item->p_input );
if( pl_priv(p_playlist)->b_auto_preparse && if( pl_priv(p_playlist)->b_auto_preparse &&
(i_mode & PLAYLIST_PREPARSE || (i_mode & PLAYLIST_PREPARSE ||
( i_mode & PLAYLIST_SPREPARSE && ( i_mode & PLAYLIST_SPREPARSE &&
( EMPTY_STR( psz_artist ) || ( EMPTY_STR( psz_album ) ) ) ( EMPTY_STR( psz_artist ) || ( EMPTY_STR( psz_album ) ) )
) ) ) ) ) )
playlist_PreparseEnqueue( p_playlist, p_item_cat->p_input, pl_Locked ); playlist_PreparseEnqueue( p_playlist, p_item->p_input, pl_Locked );
/* If we already have it, signal it */ /* If we already have it, signal it */
else if( !EMPTY_STR( psz_artist ) && !EMPTY_STR( psz_album ) ) else if( !EMPTY_STR( psz_artist ) && !EMPTY_STR( psz_album ) )
input_item_SetPreparsed( p_item_cat->p_input, true ); input_item_SetPreparsed( p_item->p_input, true );
free( psz_artist ); free( psz_artist );
free( psz_album ); free( psz_album );
} }
......
...@@ -103,16 +103,17 @@ int playlist_Import( playlist_t *p_playlist, const char *psz_file ) ...@@ -103,16 +103,17 @@ int playlist_Import( playlist_t *p_playlist, const char *psz_file )
/***************************************************************************** /*****************************************************************************
* A subitem has been added to the Media Library (Event Callback) * A subitem has been added to the Media Library (Event Callback)
*****************************************************************************/ *****************************************************************************/
static void input_item_subitem_added( const vlc_event_t * p_event, static void input_item_subitem_tree_added( const vlc_event_t * p_event,
void * user_data ) void * user_data )
{ {
playlist_t *p_playlist = user_data; playlist_t *p_playlist = user_data;
input_item_t *p_item = p_event->u.input_item_subitem_added.p_new_child; input_item_node_t *p_root =
p_event->u.input_item_subitem_tree_added.p_root;
/* playlist_AddInput() can fail, but we have no way to report that .. PL_LOCK;
* Any way when it has failed, either the playlist is dying, either OOM */ playlist_InsertInputItemTree ( p_playlist, p_playlist->p_media_library,
playlist_AddInput( p_playlist, p_item, PLAYLIST_APPEND, PLAYLIST_END, p_root, 0, !pl_priv(p_playlist)->b_tree );
false, pl_Unlocked ); PL_UNLOCK;
} }
int playlist_MLLoad( playlist_t *p_playlist ) int playlist_MLLoad( playlist_t *p_playlist )
...@@ -156,7 +157,7 @@ int playlist_MLLoad( playlist_t *p_playlist ) ...@@ -156,7 +157,7 @@ int playlist_MLLoad( playlist_t *p_playlist )
return VLC_ENOMEM; return VLC_ENOMEM;
const char *const options[1] = { "meta-file", }; const char *const options[1] = { "meta-file", };
/* that option has to be cleaned in input_item_subitem_added() */ /* that option has to be cleaned in input_item_subitem_tree_added() */
/* vlc_gc_decref() in the same function */ /* vlc_gc_decref() in the same function */
p_input = input_item_NewExt( p_playlist, psz_uri, _("Media Library"), p_input = input_item_NewExt( p_playlist, psz_uri, _("Media Library"),
1, options, VLC_INPUT_OPTION_TRUSTED, -1 ); 1, options, VLC_INPUT_OPTION_TRUSTED, -1 );
...@@ -165,19 +166,13 @@ int playlist_MLLoad( playlist_t *p_playlist ) ...@@ -165,19 +166,13 @@ int playlist_MLLoad( playlist_t *p_playlist )
return VLC_EGENERIC; return VLC_EGENERIC;
PL_LOCK; PL_LOCK;
if( p_playlist->p_ml_onelevel->p_input ) if( p_playlist->p_media_library->p_input )
vlc_gc_decref( p_playlist->p_ml_onelevel->p_input ); vlc_gc_decref( p_playlist->p_media_library->p_input );
if( p_playlist->p_ml_category->p_input )
vlc_gc_decref( p_playlist->p_ml_category->p_input );
p_playlist->p_ml_onelevel->p_input = p_playlist->p_media_library->p_input = p_input;
p_playlist->p_ml_category->p_input = p_input;
/* We save the input at two different place, incref */
vlc_gc_incref( p_input );
vlc_gc_incref( p_input );
vlc_event_attach( &p_input->event_manager, vlc_InputItemSubItemAdded, vlc_event_attach( &p_input->event_manager, vlc_InputItemSubItemTreeAdded,
input_item_subitem_added, p_playlist ); input_item_subitem_tree_added, p_playlist );
pl_priv(p_playlist)->b_doing_ml = true; pl_priv(p_playlist)->b_doing_ml = true;
PL_UNLOCK; PL_UNLOCK;
...@@ -190,10 +185,9 @@ int playlist_MLLoad( playlist_t *p_playlist ) ...@@ -190,10 +185,9 @@ int playlist_MLLoad( playlist_t *p_playlist )
pl_priv(p_playlist)->b_doing_ml = false; pl_priv(p_playlist)->b_doing_ml = false;
PL_UNLOCK; PL_UNLOCK;
vlc_event_detach( &p_input->event_manager, vlc_InputItemSubItemAdded, vlc_event_detach( &p_input->event_manager, vlc_InputItemSubItemTreeAdded,
input_item_subitem_added, p_playlist ); input_item_subitem_tree_added, p_playlist );
vlc_gc_decref( p_input );
return VLC_SUCCESS; return VLC_SUCCESS;
} }
...@@ -220,7 +214,7 @@ int playlist_MLDump( playlist_t *p_playlist ) ...@@ -220,7 +214,7 @@ int playlist_MLDump( playlist_t *p_playlist )
strcat( psz_dirname, DIR_SEP "ml.xspf" ); strcat( psz_dirname, DIR_SEP "ml.xspf" );
stats_TimerStart( p_playlist, "ML Dump", STATS_TIMER_ML_DUMP ); stats_TimerStart( p_playlist, "ML Dump", STATS_TIMER_ML_DUMP );
playlist_Export( p_playlist, psz_dirname, p_playlist->p_ml_category, playlist_Export( p_playlist, psz_dirname, p_playlist->p_media_library,
"export-xspf" ); "export-xspf" );
stats_TimerStop( p_playlist, STATS_TIMER_ML_DUMP ); stats_TimerStop( p_playlist, STATS_TIMER_ML_DUMP );
......
...@@ -109,8 +109,7 @@ void pl_Deactivate (libvlc_int_t *); ...@@ -109,8 +109,7 @@ void pl_Deactivate (libvlc_int_t *);
/* */ /* */
playlist_item_t *playlist_ItemNewFromInput( playlist_t *p_playlist, playlist_item_t *playlist_ItemNewFromInput( playlist_t *p_playlist,
input_item_t *p_input, input_item_t *p_input );
bool install_observer );
/* Engine */ /* Engine */
playlist_item_t * get_current_status_item( playlist_t * p_playlist); playlist_item_t * get_current_status_item( playlist_t * p_playlist);
...@@ -132,6 +131,9 @@ void playlist_SendAddNotify( playlist_t *p_playlist, int i_item_id, ...@@ -132,6 +131,9 @@ void playlist_SendAddNotify( playlist_t *p_playlist, int i_item_id,
playlist_item_t * playlist_NodeAddInput( playlist_t *, input_item_t *, playlist_item_t * playlist_NodeAddInput( playlist_t *, input_item_t *,
playlist_item_t *,int , int, bool ); playlist_item_t *,int , int, bool );
playlist_item_t *playlist_InsertInputItemTree ( playlist_t *,
playlist_item_t *, input_item_node_t *, int, bool );
/* Tree walking */ /* Tree walking */
playlist_item_t *playlist_ItemFindFromInputAndRoot( playlist_t *p_playlist, playlist_item_t *playlist_ItemFindFromInputAndRoot( playlist_t *p_playlist,
input_item_t *p_input, playlist_item_t *p_root, input_item_t *p_input, playlist_item_t *p_root,
......
...@@ -90,8 +90,7 @@ char **vlc_sd_GetNames (vlc_object_t *obj, char ***pppsz_longnames) ...@@ -90,8 +90,7 @@ char **vlc_sd_GetNames (vlc_object_t *obj, char ***pppsz_longnames)
struct vlc_sd_internal_t struct vlc_sd_internal_t
{ {
/* the playlist items for category and onelevel */ /* the playlist items for category and onelevel */
playlist_item_t *p_cat; playlist_item_t *p_node;
playlist_item_t *p_one;
services_discovery_t *p_sd; /**< Loaded service discovery modules */ services_discovery_t *p_sd; /**< Loaded service discovery modules */
char *psz_name; char *psz_name;
}; };
...@@ -244,8 +243,7 @@ static void playlist_sd_item_added( const vlc_event_t * p_event, void * user_dat ...@@ -244,8 +243,7 @@ static void playlist_sd_item_added( const vlc_event_t * p_event, void * user_dat
PL_LOCK; PL_LOCK;
/* If p_parent is in root category (this is clearly a hack) and we have a cat */ /* If p_parent is in root category (this is clearly a hack) and we have a cat */
if( !EMPTY_STR(psz_cat) && if( !EMPTY_STR(psz_cat) )
p_parent->p_parent == p_playlist->p_root_category )
{ {
/* */ /* */
playlist_item_t * p_cat; playlist_item_t * p_cat;
...@@ -259,9 +257,9 @@ static void playlist_sd_item_added( const vlc_event_t * p_event, void * user_dat ...@@ -259,9 +257,9 @@ static void playlist_sd_item_added( const vlc_event_t * p_event, void * user_dat
p_parent = p_cat; p_parent = p_cat;
} }
playlist_BothAddInput( p_playlist, p_input, p_parent, playlist_NodeAddInput( p_playlist, p_input, p_parent,
PLAYLIST_APPEND, PLAYLIST_END, PLAYLIST_APPEND, PLAYLIST_END,
NULL, NULL, pl_Locked ); pl_Locked );
PL_UNLOCK; PL_UNLOCK;
} }
...@@ -299,22 +297,21 @@ int playlist_ServicesDiscoveryAdd( playlist_t *p_playlist, const char *psz_modul ...@@ -299,22 +297,21 @@ int playlist_ServicesDiscoveryAdd( playlist_t *p_playlist, const char *psz_modul
return VLC_ENOMEM; return VLC_ENOMEM;
} }
playlist_item_t * p_cat; playlist_item_t *p_node;
playlist_item_t * p_one;
PL_LOCK; PL_LOCK;
playlist_NodesPairCreate( p_playlist, module_get_name( m, true ), p_node = playlist_NodeCreate( p_playlist, module_get_name( m, true ),
&p_cat, &p_one, false ); p_playlist->p_root, 0, NULL );
PL_UNLOCK; PL_UNLOCK;
module_release( m ); module_release( m );
vlc_event_attach( services_discovery_EventManager( p_sd ), vlc_event_attach( services_discovery_EventManager( p_sd ),
vlc_ServicesDiscoveryItemAdded, vlc_ServicesDiscoveryItemAdded,
playlist_sd_item_added, p_cat ); playlist_sd_item_added, p_node );
vlc_event_attach( services_discovery_EventManager( p_sd ), vlc_event_attach( services_discovery_EventManager( p_sd ),
vlc_ServicesDiscoveryItemRemoved, vlc_ServicesDiscoveryItemRemoved,
playlist_sd_item_removed, p_cat ); playlist_sd_item_removed, p_node );
if( !vlc_sd_Start( p_sd, psz_module ) ) if( !vlc_sd_Start( p_sd, psz_module ) )
{ {
...@@ -324,10 +321,9 @@ int playlist_ServicesDiscoveryAdd( playlist_t *p_playlist, const char *psz_modul ...@@ -324,10 +321,9 @@ int playlist_ServicesDiscoveryAdd( playlist_t *p_playlist, const char *psz_modul
} }
/* We want tree-view for service directory */ /* We want tree-view for service directory */
p_one->p_input->b_prefers_tree = true; p_node->p_input->b_prefers_tree = true;
p_sds->p_sd = p_sd; p_sds->p_sd = p_sd;
p_sds->p_one = p_one; p_sds->p_node = p_node;
p_sds->p_cat = p_cat;
p_sds->psz_name = strdup( psz_module ); p_sds->psz_name = strdup( psz_module );
PL_LOCK; PL_LOCK;
...@@ -369,21 +365,16 @@ int playlist_ServicesDiscoveryRemove( playlist_t * p_playlist, ...@@ -369,21 +365,16 @@ int playlist_ServicesDiscoveryRemove( playlist_t * p_playlist,
vlc_event_detach( services_discovery_EventManager( p_sd ), vlc_event_detach( services_discovery_EventManager( p_sd ),
vlc_ServicesDiscoveryItemAdded, vlc_ServicesDiscoveryItemAdded,
playlist_sd_item_added, playlist_sd_item_added,
p_sds->p_cat ); p_sds->p_node );
vlc_event_detach( services_discovery_EventManager( p_sd ), vlc_event_detach( services_discovery_EventManager( p_sd ),
vlc_ServicesDiscoveryItemRemoved, vlc_ServicesDiscoveryItemRemoved,
playlist_sd_item_removed, playlist_sd_item_removed,
p_sds->p_cat ); p_sds->p_node );
/* Remove the sd playlist node if it exists */ /* Remove the sd playlist node if it exists */
PL_LOCK; PL_LOCK;
if( p_sds->p_cat != p_playlist->p_root_category && playlist_NodeDelete( p_playlist, p_sds->p_node, true, false );
p_sds->p_one != p_playlist->p_root_onelevel )
{
playlist_NodeDelete( p_playlist, p_sds->p_cat, true, false );
playlist_NodeDelete( p_playlist, p_sds->p_one, true, false );
}
PL_UNLOCK; PL_UNLOCK;
vlc_sd_Destroy( p_sd ); vlc_sd_Destroy( p_sd );
......
...@@ -69,7 +69,7 @@ playlist_item_t * playlist_NodeCreate( playlist_t *p_playlist, ...@@ -69,7 +69,7 @@ playlist_item_t * playlist_NodeCreate( playlist_t *p_playlist,
p_new_input = input_item_NewWithType( VLC_OBJECT(p_playlist), NULL, p_new_input = input_item_NewWithType( VLC_OBJECT(p_playlist), NULL,
psz_name, 0, NULL, 0, -1, ITEM_TYPE_NODE ); psz_name, 0, NULL, 0, -1, ITEM_TYPE_NODE );
p_item = playlist_ItemNewFromInput( p_playlist, p_item = playlist_ItemNewFromInput( p_playlist,
p_input ? p_input : p_new_input, p_input == NULL ); p_input ? p_input : p_new_input );
if( p_new_input ) if( p_new_input )
vlc_gc_decref( p_new_input ); vlc_gc_decref( p_new_input );
...@@ -266,69 +266,6 @@ playlist_item_t *playlist_ChildSearchName( playlist_item_t *p_node, ...@@ -266,69 +266,6 @@ playlist_item_t *playlist_ChildSearchName( playlist_item_t *p_node,
return NULL; return NULL;
} }
/**
* Create a pair of nodes in the category and onelevel trees.
* They share the same input item.
* \param p_playlist the playlist
* \param psz_name the name of the nodes
* \param pp_node_cat pointer to return the node in category tree
* \param pp_node_one pointer to return the node in onelevel tree
* \param b_for_sd For Services Discovery ? (make node read-only and unskipping)
*/
void playlist_NodesPairCreate( playlist_t *p_playlist, const char *psz_name,
playlist_item_t **pp_node_cat,
playlist_item_t **pp_node_one,
bool b_for_sd )
{
PL_ASSERT_LOCKED;
*pp_node_cat = playlist_NodeCreate( p_playlist, psz_name,
p_playlist->p_root_category, 0, NULL );
*pp_node_one = playlist_NodeCreate( p_playlist, psz_name,
p_playlist->p_root_onelevel, 0,
(*pp_node_cat)->p_input );
if( b_for_sd )
{
(*pp_node_cat)->i_flags |= PLAYLIST_RO_FLAG;
(*pp_node_cat)->i_flags |= PLAYLIST_SKIP_FLAG;
(*pp_node_one)->i_flags |= PLAYLIST_RO_FLAG;
(*pp_node_one)->i_flags |= PLAYLIST_SKIP_FLAG;
}
}
/**
* Get the node in the preferred tree from a node in one of category
* or onelevel tree.
*/
playlist_item_t * playlist_GetPreferredNode( playlist_t *p_playlist,
playlist_item_t *p_node )
{
PL_ASSERT_LOCKED;
int i;
if( p_node->p_parent == p_playlist->p_root_category )
{
if( pl_priv(p_playlist)->b_tree || p_node->p_input->b_prefers_tree )
return p_node;
for( i = 0 ; i< p_playlist->p_root_onelevel->i_children; i++ )
{
if( p_playlist->p_root_onelevel->pp_children[i]->p_input ==
p_node->p_input )
return p_playlist->p_root_onelevel->pp_children[i];
}
}
else if( p_node->p_parent == p_playlist->p_root_onelevel )
{
if( !pl_priv(p_playlist)->b_tree || !p_node->p_input->b_prefers_tree )
return p_node;
for( i = 0 ; i< p_playlist->p_root_category->i_children; i++ )
{
if( p_playlist->p_root_category->pp_children[i]->p_input ==
p_node->p_input )
return p_playlist->p_root_category->pp_children[i];
}
}
return NULL;
}
/********************************************************************** /**********************************************************************
* Tree walking functions * Tree walking functions
**********************************************************************/ **********************************************************************/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment