vlc | branch: master | Romain Vimont <[email protected]> | Tue Oct 16 15:37:41 2018 +0200| [6b110b648d71504231b84788033e41f1627fb907] | committer: Thomas Guillem
core: playlist: implement shuffle Expose a function to shuffle the items in the playlist. Contrary to the random playback mode, the location of the items within the playlist changes. Signed-off-by: Thomas Guillem <[email protected]> > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=6b110b648d71504231b84788033e41f1627fb907 --- include/vlc_playlist.h | 8 +++++ src/Makefile.am | 4 ++- src/libvlccore.sym | 1 + src/playlist/shuffle.c | 74 ++++++++++++++++++++++++++++++++++++++++++++ src/playlist/test.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 170 insertions(+), 1 deletion(-) diff --git a/include/vlc_playlist.h b/include/vlc_playlist.h index 3659c2e2b4..c9074912b3 100644 --- a/include/vlc_playlist.h +++ b/include/vlc_playlist.h @@ -582,6 +582,14 @@ vlc_playlist_RequestRemove(vlc_playlist_t *playlist, ssize_t index_hint); /** + * Shuffle the playlist. + * + * \param playlist the playlist, locked + */ +VLC_API void +vlc_playlist_Shuffle(vlc_playlist_t *playlist); + +/** * Return the index of a given item. * * \param playlist the playlist, locked diff --git a/src/Makefile.am b/src/Makefile.am index cb47fb463e..58cc5a3319 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -244,6 +244,7 @@ libvlccore_la_SOURCES = \ playlist/randomizer.c \ playlist/randomizer.h \ playlist/request.c \ + playlist/shuffle.c \ preparser/art.c \ preparser/art.h \ preparser/fetcher.c \ @@ -593,7 +594,8 @@ test_playlist_SOURCES = playlist/test.c \ playlist/playlist.c \ playlist/preparse.c \ playlist/randomizer.c \ - playlist/request.c + playlist/request.c \ + playlist/shuffle.c test_playlist_CFLAGS = -DTEST_PLAYLIST test_randomizer_SOURCES = playlist/randomizer.c test_randomizer_CFLAGS = -DTEST_RANDOMIZER diff --git a/src/libvlccore.sym b/src/libvlccore.sym index d1d63a9550..52c8017a3a 100644 --- a/src/libvlccore.sym +++ b/src/libvlccore.sym @@ -925,6 +925,7 @@ vlc_playlist_Remove vlc_playlist_RequestInsert vlc_playlist_RequestMove vlc_playlist_RequestRemove +vlc_playlist_Shuffle vlc_playlist_IndexOf vlc_playlist_IndexOfMedia vlc_playlist_GetPlaybackRepeat diff --git a/src/playlist/shuffle.c b/src/playlist/shuffle.c new file mode 100644 index 0000000000..efc644ff58 --- /dev/null +++ b/src/playlist/shuffle.c @@ -0,0 +1,74 @@ +/***************************************************************************** + * playlist/shuffle.c + ***************************************************************************** + * Copyright (C) 2018 VLC authors and VideoLAN + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser 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. + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <vlc_common.h> +#include <vlc_rand.h> +#include "control.h" +#include "item.h" +#include "notify.h" +#include "playlist.h" + +void +vlc_playlist_Shuffle(vlc_playlist_t *playlist) +{ + vlc_playlist_AssertLocked(playlist); + if (playlist->items.size < 2) + /* we use size_t (unsigned), so the following loop would be incorrect */ + return; + + vlc_playlist_item_t *current = playlist->current != -1 + ? playlist->items.data[playlist->current] + : NULL; + + /* initialize separately instead of using vlc_lrand48() to avoid locking the + * mutex once for each item */ + unsigned short xsubi[3]; + vlc_rand_bytes(xsubi, sizeof(xsubi)); + + /* Fisher-Yates shuffle */ + for (size_t i = playlist->items.size - 1; i != 0; --i) + { + size_t selected = (size_t) (nrand48(xsubi) % (i + 1)); + + /* swap items i and selected */ + vlc_playlist_item_t *tmp = playlist->items.data[i]; + playlist->items.data[i] = playlist->items.data[selected]; + playlist->items.data[selected] = tmp; + } + + struct vlc_playlist_state state; + if (current) + { + /* the current position have changed after the shuffle */ + vlc_playlist_state_Save(playlist, &state); + playlist->current = vlc_playlist_IndexOf(playlist, current); + playlist->has_prev = vlc_playlist_ComputeHasPrev(playlist); + playlist->has_next = vlc_playlist_ComputeHasNext(playlist); + } + + vlc_playlist_Notify(playlist, on_items_reset, playlist->items.data, + playlist->items.size); + if (current) + vlc_playlist_state_NotifyChanges(playlist, &state); +} diff --git a/src/playlist/test.c b/src/playlist/test.c index 8bbcbe5c66..888e76efa9 100644 --- a/src/playlist/test.c +++ b/src/playlist/test.c @@ -1994,6 +1994,89 @@ test_random(void) vlc_playlist_Delete(playlist); } +static void +test_shuffle(void) +{ + vlc_playlist_t *playlist = vlc_playlist_New(NULL); + assert(playlist); + + input_item_t *media[10]; + CreateDummyMediaArray(media, 10); + + /* initial playlist with 10 items */ + int ret = vlc_playlist_Append(playlist, media, 10); + assert(ret == VLC_SUCCESS); + + struct vlc_playlist_callbacks cbs = { + .on_items_reset = callback_on_items_reset, + .on_current_index_changed = callback_on_current_index_changed, + .on_has_prev_changed = callback_on_has_prev_changed, + .on_has_next_changed = callback_on_has_next_changed, + }; + + struct callback_ctx ctx = CALLBACK_CTX_INITIALIZER; + vlc_playlist_listener_id *listener = + vlc_playlist_AddListener(playlist, &cbs, &ctx); + assert(listener); + + /* on_items_reset is called once during AddListener() */ + callback_ctx_reset(&ctx); + + playlist->current = 4; + playlist->has_prev = true; + playlist->has_next = true; + + vlc_playlist_Shuffle(playlist); + + ssize_t index = vlc_playlist_IndexOfMedia(playlist, media[4]); + assert(index != -1); + assert(index == playlist->current); + + assert(ctx.vec_items_reset.size == 1); + assert(ctx.vec_items_reset.data[0].count == 10); + assert(ctx.vec_items_reset.data[0].state.playlist_size == 10); + assert(ctx.vec_items_reset.data[0].state.current == index); + assert(ctx.vec_items_reset.data[0].state.has_prev == (index > 0)); + assert(ctx.vec_items_reset.data[0].state.has_next == (index < 9)); + + if (index == 4) + assert(ctx.vec_current_index_changed.size == 0); + else + { + assert(ctx.vec_current_index_changed.size == 1); + assert(ctx.vec_current_index_changed.data[0].current == index); + } + + if (index == 0) + { + assert(!playlist->has_prev); + assert(ctx.vec_has_prev_changed.size == 1); + assert(!ctx.vec_has_prev_changed.data[0].has_prev); + } + else + { + assert(playlist->has_prev); + assert(ctx.vec_has_prev_changed.size == 0); + } + + if (index == 9) + { + assert(!playlist->has_next); + assert(ctx.vec_has_next_changed.size == 1); + assert(!ctx.vec_has_next_changed.data[0].has_next); + } + else + { + assert(playlist->has_next); + assert(ctx.vec_has_next_changed.size == 0); + } + + callback_ctx_destroy(&ctx); + vlc_playlist_RemoveListener(playlist, listener); + DestroyMediaArray(media, 10); + vlc_playlist_Delete(playlist); +} + #undef EXPECT_AT int main(void) @@ -2025,5 +2108,6 @@ int main(void) test_request_goto_without_hint(); test_request_goto_adapt(); test_random(); + test_shuffle(); return 0; } _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
