From: Pierre d'Herbemont Date: Tue, 28 Aug 2007 23:25:54 +0000 (+0000) Subject: control/media_list_player.c: Add support for playing a hierarchical media_list. X-Git-Tag: 0.9.0-test0~6084 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;ds=sidebyside;h=1d2aca81f9ce226e86d286d19031b08a16db3c92;p=vlc control/media_list_player.c: Add support for playing a hierarchical media_list. --- diff --git a/src/control/media_list_path.h b/src/control/media_list_path.h new file mode 100644 index 0000000000..209b1eb0cd --- /dev/null +++ b/src/control/media_list_path.h @@ -0,0 +1,223 @@ +/***************************************************************************** + * media_list_path.h : Some inlined function that allows media_list_path + * manipulation. This is internal and used only by media_list_player. + ***************************************************************************** + * Copyright (C) 2005 the VideoLAN team + * $Id $ + * + * Authors: Pierre d'Herbemont + * + * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifndef _LIBVLC_MEDIA_LIST_PATH_H +#define _LIBVLC_MEDIA_LIST_PATH_H 1 + +/************************************************************************** + * path_empty (Media List Player Internal) + **************************************************************************/ +static inline libvlc_media_list_path_t libvlc_media_list_path_empty( void ) +{ + libvlc_media_list_path_t ret = malloc(sizeof(int)); + ret[0] = -1; + return ret; +} + +/************************************************************************** + * path_with_root_index (Media List Player Internal) + **************************************************************************/ +static inline libvlc_media_list_path_t libvlc_media_list_path_with_root_index( int index ) +{ + libvlc_media_list_path_t ret = malloc(sizeof(int)*2); + ret[0] = index; + ret[1] = -1; + return ret; +} + +/************************************************************************** + * path_deepness (Media List Player Internal) + **************************************************************************/ +static inline int libvlc_media_list_path_deepness( libvlc_media_list_path_t path ) +{ + int i; + for( i = 0; path[i] != -1; i++ ); + return i; +} + +/************************************************************************** + * path_append (Media List Player Internal) + **************************************************************************/ +static inline void libvlc_media_list_path_append( libvlc_media_list_path_t * p_path, int index ) +{ + int old_deepness = libvlc_media_list_path_deepness( *p_path ); + *p_path = realloc( *p_path, sizeof(int)*(old_deepness+2)); + *p_path[old_deepness] = index; + *p_path[old_deepness+1] = -1; +} + +/************************************************************************** + * path_copy_by_appending (Media List Player Internal) + **************************************************************************/ +static inline libvlc_media_list_path_t libvlc_media_list_path_copy_by_appending( libvlc_media_list_path_t path, int index ) +{ + libvlc_media_list_path_t ret; + int old_deepness = libvlc_media_list_path_deepness( path ); + ret = malloc( sizeof(int)*(old_deepness+2) ); + memcpy( ret, path, sizeof(int)*(old_deepness+2) ); + ret[old_deepness] = index; + ret[old_deepness+1] = -1; + return ret; +} + +/************************************************************************** + * path_copy (Media List Player Internal) + **************************************************************************/ +static inline libvlc_media_list_path_t libvlc_media_list_path_copy( libvlc_media_list_path_t path ) +{ + libvlc_media_list_path_t ret; + int deepness = libvlc_media_list_path_deepness( path ); + ret = malloc( sizeof(int)*(deepness+1) ); + memcpy( ret, path, sizeof(int)*(deepness+1) ); + return ret; +} + +/************************************************************************** + * get_path_rec (Media List Player Internal) + **************************************************************************/ +static libvlc_media_list_path_t +get_path_rec( libvlc_media_list_path_t path, libvlc_media_list_t * p_current_mlist, libvlc_media_descriptor_t * p_searched_md ) +{ + int i, count; + count = libvlc_media_list_count( p_current_mlist, NULL ); + for( i = 0; i < count; i++ ) + { + libvlc_media_descriptor_t * p_md = libvlc_media_list_item_at_index( p_current_mlist, i, NULL ); + + if( p_md == p_searched_md ) + return libvlc_media_list_path_copy_by_appending( path, i ); /* Found! */ + + libvlc_media_list_t * p_subitems = libvlc_media_descriptor_subitems( p_md, NULL ); + libvlc_media_descriptor_release( p_md ); + if( p_subitems ) + { + libvlc_media_list_path_t new_path = libvlc_media_list_path_copy_by_appending( path, i ); + libvlc_media_list_lock( p_subitems ); + libvlc_media_list_path_t ret = get_path_rec( new_path, p_subitems, p_searched_md ); + libvlc_media_list_unlock( p_subitems ); + free( new_path ); + libvlc_media_list_release( p_subitems ); + if( ret ) + return ret; /* Found in sublist! */ + } + } + return NULL; +} + +/************************************************************************** + * path_of_item (Media List Player Internal) + **************************************************************************/ +static inline libvlc_media_list_path_t libvlc_media_list_path_of_item( libvlc_media_list_t * p_mlist, libvlc_media_descriptor_t * p_md ) +{ + libvlc_media_list_path_t path = libvlc_media_list_path_empty(); + libvlc_media_list_path_t ret; + ret = get_path_rec( path, p_mlist, p_md ); + free( path ); + return ret; +} + +/************************************************************************** + * item_at_path (Media List Player Internal) + **************************************************************************/ +static libvlc_media_descriptor_t * +libvlc_media_list_item_at_path( libvlc_media_list_t * p_mlist, libvlc_media_list_path_t path ) +{ + libvlc_media_list_t * p_current_mlist = p_mlist; + libvlc_media_descriptor_t * p_md = NULL; + int i; + for( i = 0; path[i] != -1; i++ ) + { + p_md = libvlc_media_list_item_at_index( p_current_mlist, path[i], NULL ); + + if( p_current_mlist != p_mlist ) + libvlc_media_list_release( p_current_mlist ); + + if( path[i+1] == -1 ) + return p_md; + + p_current_mlist = libvlc_media_descriptor_subitems( p_md, NULL ); + libvlc_media_descriptor_release( p_md ); + + if( !p_current_mlist ) + return NULL; + + /* Fetch next one */ + } + /* Not found, shouldn't happen if the p_path is not empty */ + if( p_current_mlist != p_mlist ) + libvlc_media_list_release( p_current_mlist ); + return NULL; +} + +/************************************************************************** + * parentlist_at_path (Media List Player Internal) + **************************************************************************/ +static libvlc_media_list_t * +libvlc_media_list_parentlist_at_path( libvlc_media_list_t * p_mlist, libvlc_media_list_path_t path ) +{ + libvlc_media_list_t * p_current_mlist = p_mlist; + libvlc_media_descriptor_t * p_md = NULL; + int i; + for( i = 0; path[i] != -1; i++ ) + { + if( p_current_mlist != p_mlist ) + libvlc_media_list_release( p_current_mlist ); + + if( path[i+1] == -1 ) + return p_current_mlist; + + p_md = libvlc_media_list_item_at_index( p_current_mlist, path[i], NULL ); + + p_current_mlist = libvlc_media_descriptor_subitems( p_md, NULL ); + libvlc_media_descriptor_release( p_md ); + + if( !p_current_mlist ) + return NULL; + + /* Fetch next one */ + } + /* Not found, shouldn't happen if the p_path is not empty */ + if( p_current_mlist != p_mlist ) + libvlc_media_list_release( p_current_mlist ); + return NULL; +} + +/************************************************************************** + * sublist_at_path (Media List Player Internal) + **************************************************************************/ +static libvlc_media_list_t * +libvlc_media_list_sublist_at_path( libvlc_media_list_t * p_mlist, libvlc_media_list_path_t path ) +{ + libvlc_media_list_t * ret; + libvlc_media_descriptor_t * p_md = libvlc_media_list_item_at_path( p_mlist, path ); + if( !p_md ) + return NULL; + + ret = libvlc_media_descriptor_subitems( p_md, NULL ); + libvlc_media_descriptor_release( p_md ); + + return ret; +} + +#endif diff --git a/src/control/media_list_player.c b/src/control/media_list_player.c index 7fd708d99d..921d3f84f7 100644 --- a/src/control/media_list_player.c +++ b/src/control/media_list_player.c @@ -22,6 +22,7 @@ *****************************************************************************/ #include "libvlc_internal.h" #include +#include "media_list_path.h" /* * Private functions @@ -32,16 +33,52 @@ * * Simple next item fetcher. **************************************************************************/ -static int get_next_index( libvlc_media_list_player_t * p_mlp ) +static libvlc_media_list_path_t +get_next_path( libvlc_media_list_player_t * p_mlp ) { /* We are entered with libvlc_media_list_lock( p_mlp->p_list ) */ - - int next = p_mlp->i_current_playing_index + 1; + libvlc_media_list_path_t ret; + libvlc_media_list_t * p_parent_of_playing_item; + libvlc_media_list_t * p_sublist_of_playing_item; + p_sublist_of_playing_item = libvlc_media_list_sublist_at_path( + p_mlp->p_mlist, + p_mlp->current_playing_item_path ); + + /* If item just gained a sublist just play it */ + if( p_sublist_of_playing_item ) + { + libvlc_media_list_release( p_sublist_of_playing_item ); + return libvlc_media_list_path_copy_by_appending( p_mlp->current_playing_item_path, 0 ); + } - if( next >= libvlc_media_list_count( p_mlp->p_mlist, NULL ) ) - return -1; /* no more to play */ + /* Try to catch next element */ + p_parent_of_playing_item = libvlc_media_list_parentlist_at_path( + p_mlp->p_mlist, + p_mlp->current_playing_item_path ); - return next; + int deepness = libvlc_media_list_path_deepness( p_mlp->current_playing_item_path ); + if( deepness < 1 || !p_parent_of_playing_item ) + return NULL; + + ret = libvlc_media_list_path_copy( p_mlp->current_playing_item_path ); + + while( ret[deepness-1] >= libvlc_media_list_count( p_parent_of_playing_item, NULL ) ) + { + deepness--; + if( deepness <= 0 ) + { + free( ret ); + libvlc_media_list_release( p_parent_of_playing_item ); + return NULL; + } + ret[deepness] = -1; + ret[deepness-1]++; + p_parent_of_playing_item = libvlc_media_list_parentlist_at_path( + p_mlp->p_mlist, + ret ); + } + libvlc_media_list_release( p_parent_of_playing_item ); + return ret; } /************************************************************************** @@ -54,12 +91,12 @@ media_instance_reached_end( const libvlc_event_t * p_event, libvlc_media_list_player_t * p_mlp = p_user_data; libvlc_media_instance_t * p_mi = p_event->p_obj; libvlc_media_descriptor_t *p_md, * p_current_md; + p_md = libvlc_media_instance_get_media_descriptor( p_mi, NULL ); /* XXX: need if p_mlp->p_current_playing_index is beyond */ - p_current_md = libvlc_media_list_item_at_index( + p_current_md = libvlc_media_list_item_at_path( p_mlp->p_mlist, - p_mlp->i_current_playing_index, - NULL ); + p_mlp->current_playing_item_path ); if( p_md != p_current_md ) { msg_Warn( p_mlp->p_libvlc_instance->p_libvlc_int, @@ -83,10 +120,9 @@ mlist_item_deleted( const libvlc_event_t * p_event, void * p_user_data ) libvlc_media_list_player_t * p_mlp = p_user_data; libvlc_media_list_t * p_emitting_mlist = p_event->p_obj; /* XXX: need if p_mlp->p_current_playing_index is beyond */ - p_current_md = libvlc_media_list_item_at_index( + p_current_md = libvlc_media_list_item_at_path( p_mlp->p_mlist, - p_mlp->i_current_playing_index, - NULL ); + p_mlp->current_playing_item_path ); if( p_event->u.media_list_item_deleted.item == p_current_md && p_emitting_mlist == p_mlp->p_mlist ) @@ -146,37 +182,46 @@ static vlc_bool_t libvlc_media_list_player_is_playing( libvlc_media_list_player_t * p_mlp, libvlc_exception_t * p_e ) { - libvlc_exception_raise( p_e, "Unimplemented" ); - return 0; + //libvlc_exception_raise( p_e, "Unimplemented" ); + return 1; } /************************************************************************** - * Next (private) + * set_current_playing_item (private) * * Playlist lock should be held **************************************************************************/ static void -media_list_player_set_next( libvlc_media_list_player_t * p_mlp, int index, - libvlc_exception_t * p_e ) +set_current_playing_item( libvlc_media_list_player_t * p_mlp, + libvlc_media_list_path_t path, + libvlc_exception_t * p_e ) { libvlc_media_descriptor_t * p_md; - p_md = libvlc_media_list_item_at_index( p_mlp->p_mlist, index, p_e ); + p_md = libvlc_media_list_item_at_path( p_mlp->p_mlist, path ); if( !p_md ) { - libvlc_media_list_unlock( p_mlp->p_mlist ); if( !libvlc_exception_raised( p_e ) ) libvlc_exception_raise( p_e, "Can't obtain a media" ); return; } - + vlc_mutex_lock( &p_mlp->object_lock ); - p_mlp->i_current_playing_index = index; + free( p_mlp->current_playing_item_path ); + p_mlp->current_playing_item_path = path; /* We are not interested in getting media_descriptor stop event now */ uninstall_media_instance_observer( p_mlp ); - libvlc_media_instance_set_media_descriptor( p_mlp->p_mi, p_md, NULL ); + if( p_md->p_subitems && libvlc_media_list_count( p_md->p_subitems, NULL ) > 0 ) + { + libvlc_media_descriptor_t * p_submd; + p_submd = libvlc_media_list_item_at_index( p_md->p_subitems, 0, NULL ); + libvlc_media_instance_set_media_descriptor( p_mlp->p_mi, p_submd, NULL ); + libvlc_media_descriptor_release( p_submd ); + } + else + libvlc_media_instance_set_media_descriptor( p_mlp->p_mi, p_md, NULL ); // wait_playing_state(); /* If we want to be synchronous */ install_media_instance_observer( p_mlp ); @@ -201,7 +246,7 @@ libvlc_media_list_player_new( libvlc_instance_t * p_instance, (void)p_e; libvlc_media_list_player_t * p_mlp; p_mlp = malloc(sizeof(libvlc_media_list_player_t)); - p_mlp->i_current_playing_index = -1; + p_mlp->current_playing_item_path = NULL; p_mlp->p_mi = NULL; p_mlp->p_mlist = NULL; vlc_mutex_init( p_instance->p_libvlc_int, &p_mlp->object_lock ); @@ -221,7 +266,6 @@ libvlc_media_list_player_new( libvlc_instance_t * p_instance, **************************************************************************/ void libvlc_media_list_player_release( libvlc_media_list_player_t * p_mlp ) { - libvlc_event_manager_release( p_mlp->p_event_manager ); free(p_mlp); } @@ -259,7 +303,11 @@ void libvlc_media_list_player_set_media_list( vlc_mutex_lock( &p_mlp->object_lock ); if( libvlc_media_list_player_is_playing( p_mlp, p_e ) ) - libvlc_media_list_player_stop( p_mlp, p_e ); + { + libvlc_media_instance_stop( p_mlp->p_mi, p_e ); + /* Don't bother if there was an error. */ + libvlc_exception_clear( p_e ); + } if( p_mlp->p_mlist ) { @@ -280,7 +328,7 @@ void libvlc_media_list_player_set_media_list( void libvlc_media_list_player_play( libvlc_media_list_player_t * p_mlp, libvlc_exception_t * p_e ) { - if( p_mlp->i_current_playing_index < 0 ) + if( !p_mlp->current_playing_item_path ) { libvlc_media_list_player_next( p_mlp, p_e ); return; /* Will set to play */ @@ -291,15 +339,13 @@ void libvlc_media_list_player_play( libvlc_media_list_player_t * p_mlp, /************************************************************************** * Play item at index (Public) - * - * Playlist lock should be help **************************************************************************/ void libvlc_media_list_player_play_item_at_index( libvlc_media_list_player_t * p_mlp, int i_index, libvlc_exception_t * p_e ) { - media_list_player_set_next( p_mlp, i_index, p_e ); + set_current_playing_item( p_mlp, libvlc_media_list_path_with_root_index(i_index), p_e ); if( libvlc_exception_raised( p_e ) ) return; @@ -312,6 +358,27 @@ void libvlc_media_list_player_play_item_at_index( libvlc_media_instance_play( p_mlp->p_mi, p_e ); } +/************************************************************************** + * Play item (Public) + **************************************************************************/ +void libvlc_media_list_player_play_item( + libvlc_media_list_player_t * p_mlp, + libvlc_media_descriptor_t * p_md, + libvlc_exception_t * p_e ) +{ + libvlc_media_list_path_t path = libvlc_media_list_path_of_item( p_mlp->p_mlist, p_md ); + if( !path ) + { + libvlc_exception_raise( p_e, "No such item in media list" ); + return; + } + set_current_playing_item( p_mlp, path, p_e ); + + if( libvlc_exception_raised( p_e ) ) + return; + + libvlc_media_instance_play( p_mlp->p_mi, p_e ); +} /************************************************************************** * Stop (Public) @@ -322,7 +389,7 @@ void libvlc_media_list_player_stop( libvlc_media_list_player_t * p_mlp, libvlc_media_instance_stop( p_mlp->p_mi, p_e ); vlc_mutex_lock( &p_mlp->object_lock ); - p_mlp->i_current_playing_index = -1; + p_mlp->current_playing_item_path = NULL; vlc_mutex_unlock( &p_mlp->object_lock ); } @@ -332,13 +399,13 @@ void libvlc_media_list_player_stop( libvlc_media_list_player_t * p_mlp, void libvlc_media_list_player_next( libvlc_media_list_player_t * p_mlp, libvlc_exception_t * p_e ) { - int index; + libvlc_media_list_path_t path; libvlc_media_list_lock( p_mlp->p_mlist ); - index = get_next_index( p_mlp ); + path = get_next_path( p_mlp ); - if( index < 0 ) + if( !path ) { libvlc_media_list_unlock( p_mlp->p_mlist ); libvlc_exception_raise( p_e, "No more element to play" ); @@ -346,7 +413,7 @@ void libvlc_media_list_player_next( libvlc_media_list_player_t * p_mlp, return; } - media_list_player_set_next( p_mlp, index, p_e ); + set_current_playing_item( p_mlp, path, p_e ); libvlc_media_instance_play( p_mlp->p_mi, p_e ); @@ -357,4 +424,3 @@ void libvlc_media_list_player_next( libvlc_media_list_player_t * p_mlp, event.type = libvlc_MediaListPlayerNextItemSet; libvlc_event_send( p_mlp->p_event_manager, &event); } -