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;
typedef struct input_thread_t input_thread_t;
typedef struct input_thread_sys_t input_thread_sys_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_sys_t access_sys_t;
typedef struct stream_t stream_t;
......
......@@ -119,6 +119,7 @@ typedef enum vlc_event_type_t {
/* Input item events */
vlc_InputItemMetaChanged,
vlc_InputItemSubItemAdded,
vlc_InputItemSubItemTreeAdded,
vlc_InputItemDurationChanged,
vlc_InputItemPreparsedChanged,
vlc_InputItemNameChanged,
......@@ -158,6 +159,10 @@ typedef struct vlc_event_t
{
input_item_t * p_new_child;
} 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
{
mtime_t new_duration;
......
......@@ -107,6 +107,14 @@ enum input_item_type_e
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_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
* 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_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
......@@ -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 )
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
******************/
......
......@@ -153,7 +153,6 @@ struct playlist_item_t
int i_id; /**< Playlist item specific id */
uint8_t i_flags; /**< Flags */
playlist_t *p_playlist; /**< Parent playlist */
bool b_input_item_observer;
};
#define PLAYLIST_SAVE_FLAG 0x0001 /**< Must it be saved */
......@@ -180,6 +179,11 @@ struct playlist_t
int i_current_index; /**< Index in current array */
/* 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_onelevel; /**< Root of onelevel tree */
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
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_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 *************************/
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 )
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_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_InputItemPreparsedChanged );
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 )
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 )
{
vlc_mutex_lock( &p_item->lock );
......@@ -962,3 +979,61 @@ static int GuessType( const input_item_t *p_item )
sizeof( tab[0] ), typecmp );
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
input_item_AddInfo
input_item_AddOption
input_item_AddSubItem
input_item_AddSubItem2
input_item_AddSubItemTree
input_item_CopyOptions
input_item_DelInfo
input_item_GetDuration
......@@ -203,6 +205,10 @@ input_item_IsPreparsed
input_item_MetaMatch
__input_item_NewExt
input_item_NewWithType
input_item_node_AppendItem
input_item_node_AppendNode
input_item_node_Create
input_item_node_Delete
input_item_SetDuration
input_item_SetMeta
input_item_SetName
......@@ -313,7 +319,6 @@ playlist_AddExt
playlist_AddInput
playlist_AskForArtEnqueue
playlist_AssertLocked
playlist_BothAddInput
playlist_ChildSearchName
playlist_Clear
playlist_Control
......
......@@ -105,54 +105,50 @@ playlist_t * playlist_Create( vlc_object_t *p_parent )
pl_priv(p_playlist)->b_auto_preparse =
var_InheritBool( p_parent, "auto-preparse" );
PL_LOCK; /* playlist_NodeCreate will check for it */
p_playlist->p_root_category = playlist_NodeCreate( p_playlist, NULL, NULL,
/* Create the root node */
PL_LOCK;
p_playlist->p_root = playlist_NodeCreate( p_playlist, NULL, NULL,
0, NULL );
p_playlist->p_root_onelevel = playlist_NodeCreate( p_playlist, NULL, NULL,
0, p_playlist->p_root_category->p_input );
PL_UNLOCK;
if( !p_playlist->p_root ) return NULL;
if( !p_playlist->p_root_category || !p_playlist->p_root_onelevel )
return NULL;
/* Create currently playing items node */
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;
p_playlist->p_local_category->i_flags |= PLAYLIST_RO_FLAG;
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;
if( !p_playlist->p_playing ) return NULL;
/* Create media library node */
const bool b_ml = var_InheritBool( p_parent, "media-library");
if( b_ml )
{
PL_LOCK; /* playlist_NodesPairCreate will check for it */
playlist_NodesPairCreate( p_playlist, _( "Media Library" ),
&p_playlist->p_ml_category,
&p_playlist->p_ml_onelevel, false );
PL_LOCK;
p_playlist->p_media_library = playlist_NodeCreate(
p_playlist, _( "Media Library" ), p_playlist->p_root,
PLAYLIST_RO_FLAG, NULL );
PL_UNLOCK;
if(!p_playlist->p_ml_category || !p_playlist->p_ml_onelevel)
return NULL;
p_playlist->p_ml_category->i_flags |= PLAYLIST_RO_FLAG;
p_playlist->p_ml_onelevel->i_flags |= PLAYLIST_RO_FLAG;
if(!p_playlist->p_media_library ) return NULL;
}
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 */
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)->status.i_status = PLAYLIST_STOPPED;
......
......@@ -33,90 +33,82 @@
static void AddItem( playlist_t *p_playlist, playlist_item_t *p_item,
playlist_item_t *p_node, int i_mode, int i_pos );
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 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;
p_child = p_event->u.input_item_subitem_added.p_new_child;
static void input_item_add_subitem_tree ( const vlc_event_t * p_event,
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;
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 &&
p_item_in_category == get_current_status_item( p_playlist ) &&
p_item_in_category->i_children == -1;
bool b_play = var_CreateGetBool( p_playlist, "playlist-autostart" ) &&
get_current_status_item( p_playlist ) == p_item;
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 */
if( p_item_in_category->i_children == -1 )
int pos = 0;
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,
p_item_in_category, pl_Locked );
p_item_in_category->p_input->i_type = ITEM_TYPE_PLAYLIST;
pos = i;
break;
}
}
int i_ret = playlist_BothAddInput( p_playlist, p_child,
p_item_in_category,
PLAYLIST_APPEND | PLAYLIST_SPREPARSE , PLAYLIST_END,
NULL, NULL, pl_Locked );
if( i_ret == VLC_SUCCESS && b_play )
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( b_stop )
{
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 );
if( !pl_priv(p_playlist)->b_tree ) b_flat = true;
break;
}
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)
*****************************************************************************/
......@@ -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 )
{
vlc_event_manager_t * p_em = &p_item->p_input->event_manager;
vlc_event_attach( p_em, vlc_InputItemSubItemAdded,
input_item_subitem_added, p_item );
vlc_event_attach( p_em, vlc_InputItemSubItemTreeAdded,
input_item_add_subitem_tree, p_item );
vlc_event_attach( p_em, vlc_InputItemDurationChanged,
input_item_changed, p_item );
vlc_event_attach( p_em, vlc_InputItemMetaChanged,
......@@ -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 )
{
vlc_event_manager_t * p_em = &p_item->p_input->event_manager;
vlc_event_detach( p_em, vlc_InputItemSubItemAdded,
input_item_subitem_added, p_item );
vlc_event_detach( p_em, vlc_InputItemSubItemTreeAdded,
input_item_add_subitem_tree, p_item );
vlc_event_detach( p_em, vlc_InputItemMetaChanged,
input_item_changed, p_item );
vlc_event_detach( p_em, vlc_InputItemDurationChanged,
......@@ -169,7 +161,7 @@ static void uninstall_input_item_observer( playlist_item_t * p_item )
* Playlist item creation
*****************************************************************************/
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 ) );
if( !p_item )
......@@ -187,10 +179,8 @@ playlist_item_t *playlist_ItemNewFromInput( playlist_t *p_playlist,
p_item->pp_children = NULL;
p_item->i_flags = 0;
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;
}
......@@ -218,8 +208,7 @@ int playlist_ItemRelease( playlist_item_t *p_item )
* Most of the modules does that.
*
* 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);
return VLC_SUCCESS;
}
......@@ -268,7 +257,7 @@ int playlist_DeleteFromInputInParent( playlist_t *p_playlist,
/**
* 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_input the input to delete
* \param b_locked TRUE if the playlist is locked
......@@ -277,15 +266,12 @@ int playlist_DeleteFromInputInParent( playlist_t *p_playlist,
int playlist_DeleteFromInput( playlist_t *p_playlist, input_item_t *p_input,
bool b_locked )
{
int i_ret1, i_ret2;
int i_ret;
PL_LOCK_IF( !b_locked );
i_ret1 = DeleteFromInput( p_playlist, p_input,
p_playlist->p_root_category, true );
i_ret2 = DeleteFromInput( p_playlist, p_input,
p_playlist->p_root_onelevel, true );
i_ret = DeleteFromInput( p_playlist, p_input,
p_playlist->p_root, true );
PL_UNLOCK_IF( !b_locked );
return ( i_ret1 == VLC_SUCCESS || i_ret2 == VLC_SUCCESS ) ?
VLC_SUCCESS : VLC_ENOITEM;
return ( i_ret == VLC_SUCCESS ? VLC_SUCCESS : VLC_ENOITEM );
}
/**
......@@ -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 )
{
PL_LOCK_IF( !b_locked );
playlist_NodeEmpty( p_playlist, p_playlist->p_local_category, true );
playlist_NodeEmpty( p_playlist, p_playlist->p_local_onelevel, true );
playlist_NodeEmpty( p_playlist, p_playlist->p_playing, true );
PL_UNLOCK_IF( !b_locked );
}
......@@ -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,
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( !pl_priv(p_playlist)->b_doing_ml )
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,
PL_LOCK_IF( !b_locked );
/* Add to ONELEVEL */
p_item_one = playlist_ItemNewFromInput( p_playlist, p_input, false );
if( p_item_one == NULL ) return VLC_ENOMEM;
AddItem( p_playlist, p_item_one,
b_playlist ? p_playlist->p_local_onelevel :
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 );
p_item = playlist_ItemNewFromInput( p_playlist, p_input );
if( p_item == NULL ) return VLC_ENOMEM;
AddItem( p_playlist, p_item,
b_playlist ? p_playlist->p_playing :
p_playlist->p_media_library , i_mode, i_pos );
GoAndPreparse( p_playlist, i_mode, p_item_cat, p_item_one );
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;
GoAndPreparse( p_playlist, i_mode, p_item );
PL_UNLOCK_IF( !b_locked );
return VLC_SUCCESS;
......@@ -524,7 +434,7 @@ playlist_item_t * playlist_NodeAddInput( playlist_t *p_playlist,
return NULL;
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;
AddItem( p_playlist, p_item, p_parent, i_mode, i_pos );
......@@ -533,6 +443,65 @@ playlist_item_t * playlist_NodeAddInput( playlist_t *p_playlist,
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
*****************************************************************************/
......@@ -552,87 +521,62 @@ static playlist_item_t *ItemToNode( playlist_t *p_playlist,
playlist_item_t *p_item,
bool b_locked )
{
PL_LOCK_IF( !b_locked );
playlist_item_t *p_item_in_category;
/* 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 )
*/
assert( p_item->p_parent );
PL_LOCK_IF( !b_locked );
bool b_flat = false;
playlist_item_t *p_up = p_item;
while( p_up->p_parent )