vlc | branch: master | Romain Vimont <[email protected]> | Tue Oct 16 15:27:35 2018 +0200| [3e5e863ca67c47c8ec7317bcae5e2be985af8c04] | committer: Thomas Guillem
core: playlist: handle random playback order Use the randomizer in the playlist to implement random playback order. Signed-off-by: Thomas Guillem <[email protected]> > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=3e5e863ca67c47c8ec7317bcae5e2be985af8c04 --- src/Makefile.am | 1 + src/playlist/content.c | 17 ++++++ src/playlist/control.c | 68 +++++++++++++++++++---- src/playlist/playlist.c | 2 + src/playlist/playlist.h | 2 + src/playlist/test.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 220 insertions(+), 12 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index eefeab25cd..cb47fb463e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -592,6 +592,7 @@ test_playlist_SOURCES = playlist/test.c \ playlist/player.c \ playlist/playlist.c \ playlist/preparse.c \ + playlist/randomizer.c \ playlist/request.c test_playlist_CFLAGS = -DTEST_PLAYLIST test_randomizer_SOURCES = playlist/randomizer.c diff --git a/src/playlist/content.c b/src/playlist/content.c index cf9f53aa79..86de05ccf9 100644 --- a/src/playlist/content.c +++ b/src/playlist/content.c @@ -41,6 +41,9 @@ vlc_playlist_ClearItems(vlc_playlist_t *playlist) static void vlc_playlist_ItemsReset(vlc_playlist_t *playlist) { + if (playlist->order == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM) + randomizer_Clear(&playlist->randomizer); + struct vlc_playlist_state state; vlc_playlist_state_Save(playlist, &state); @@ -57,6 +60,10 @@ vlc_playlist_ItemsReset(vlc_playlist_t *playlist) void vlc_playlist_ItemsInserted(vlc_playlist_t *playlist, size_t index, size_t count) { + if (playlist->order == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM) + randomizer_Add(&playlist->randomizer, + &playlist->items.data[index], count); + struct vlc_playlist_state state; vlc_playlist_state_Save(playlist, &state); @@ -113,6 +120,14 @@ vlc_playlist_ItemsMoved(vlc_playlist_t *playlist, size_t index, size_t count, } static void +vlc_playlist_ItemsRemoving(vlc_playlist_t *playlist, size_t index, size_t count) +{ + if (playlist->order == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM) + randomizer_Remove(&playlist->randomizer, + &playlist->items.data[index], count); +} + +static void vlc_playlist_ItemsRemoved(vlc_playlist_t *playlist, size_t index, size_t count) { struct vlc_playlist_state state; @@ -262,6 +277,8 @@ vlc_playlist_Remove(vlc_playlist_t *playlist, size_t index, size_t count) vlc_playlist_AssertLocked(playlist); assert(index < playlist->items.size); + vlc_playlist_ItemsRemoving(playlist, index, count); + for (size_t i = 0; i < count; ++i) vlc_playlist_item_Release(playlist->items.data[index + i]); diff --git a/src/playlist/control.c b/src/playlist/control.c index f921e0d933..99c975bf64 100644 --- a/src/playlist/control.c +++ b/src/playlist/control.c @@ -31,6 +31,20 @@ static void vlc_playlist_PlaybackOrderChanged(vlc_playlist_t *playlist) { + if (playlist->order == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM) + { + /* randomizer is expected to be empty at this point */ + assert(randomizer_Count(&playlist->randomizer) == 0); + randomizer_Add(&playlist->randomizer, playlist->items.data, + playlist->items.size); + + bool loop = playlist->repeat == VLC_PLAYLIST_PLAYBACK_REPEAT_ALL; + randomizer_SetLoop(&playlist->randomizer, loop); + } + else + /* we don't use the randomizer anymore */ + randomizer_Clear(&playlist->randomizer); + struct vlc_playlist_state state; vlc_playlist_state_Save(playlist, &state); @@ -44,6 +58,12 @@ vlc_playlist_PlaybackOrderChanged(vlc_playlist_t *playlist) static void vlc_playlist_PlaybackRepeatChanged(vlc_playlist_t *playlist) { + if (playlist->order == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM) + { + bool loop = playlist->repeat == VLC_PLAYLIST_PLAYBACK_REPEAT_ALL; + randomizer_SetLoop(&playlist->randomizer, loop); + } + struct vlc_playlist_state state; vlc_playlist_state_Save(playlist, &state); @@ -166,33 +186,35 @@ vlc_playlist_NormalOrderGetNextIndex(vlc_playlist_t *playlist) static inline bool vlc_playlist_RandomOrderHasPrev(vlc_playlist_t *playlist) { - VLC_UNUSED(playlist); - /* TODO */ - return false; + return randomizer_HasPrev(&playlist->randomizer); } static inline size_t vlc_playlist_RandomOrderGetPrevIndex(vlc_playlist_t *playlist) { - VLC_UNUSED(playlist); - /* TODO */ - return -0; + vlc_playlist_item_t *prev = randomizer_PeekPrev(&playlist->randomizer); + assert(prev); + ssize_t index = vlc_playlist_IndexOf(playlist, prev); + assert(index != -1); + return (size_t) index; } static inline bool vlc_playlist_RandomOrderHasNext(vlc_playlist_t *playlist) { - VLC_UNUSED(playlist); - /* TODO */ - return false; + if (playlist->repeat == VLC_PLAYLIST_PLAYBACK_REPEAT_ALL) + return playlist->items.size > 0; + return randomizer_HasNext(&playlist->randomizer); } static inline size_t vlc_playlist_RandomOrderGetNextIndex(vlc_playlist_t *playlist) { - VLC_UNUSED(playlist); - /* TODO */ - return 0; + vlc_playlist_item_t *next = randomizer_PeekNext(&playlist->randomizer); + assert(next); + ssize_t index = vlc_playlist_IndexOf(playlist, next); + assert(index != -1); + return (size_t) index; } static size_t @@ -304,6 +326,14 @@ vlc_playlist_Prev(vlc_playlist_t *playlist) if (ret != VLC_SUCCESS) return ret; + if (playlist->order == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM) + { + /* mark the item as selected in the randomizer */ + vlc_playlist_item_t *selected = randomizer_Prev(&playlist->randomizer); + assert(selected == playlist->items.data[index]); + VLC_UNUSED(selected); + } + vlc_playlist_SetCurrentIndex(playlist, index); return VLC_SUCCESS; } @@ -323,6 +353,14 @@ vlc_playlist_Next(vlc_playlist_t *playlist) if (ret != VLC_SUCCESS) return ret; + if (playlist->order == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM) + { + /* mark the item as selected in the randomizer */ + vlc_playlist_item_t *selected = randomizer_Next(&playlist->randomizer); + assert(selected == playlist->items.data[index]); + VLC_UNUSED(selected); + } + vlc_playlist_SetCurrentIndex(playlist, index); return VLC_SUCCESS; } @@ -337,6 +375,12 @@ vlc_playlist_GoTo(vlc_playlist_t *playlist, ssize_t index) if (ret != VLC_SUCCESS) return ret; + if (index != -1 && playlist->order == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM) + { + vlc_playlist_item_t *item = playlist->items.data[index]; + randomizer_Select(&playlist->randomizer, item); + } + vlc_playlist_SetCurrentIndex(playlist, index); return VLC_SUCCESS; } diff --git a/src/playlist/playlist.c b/src/playlist/playlist.c index 0fbac27d73..618433c9e3 100644 --- a/src/playlist/playlist.c +++ b/src/playlist/playlist.c @@ -45,6 +45,7 @@ vlc_playlist_New(vlc_object_t *parent) } vlc_vector_init(&playlist->items); + randomizer_Init(&playlist->randomizer); playlist->current = -1; playlist->has_prev = false; playlist->has_next = false; @@ -61,6 +62,7 @@ vlc_playlist_Delete(vlc_playlist_t *playlist) assert(vlc_list_is_empty(&playlist->listeners)); vlc_playlist_PlayerDestroy(playlist); + randomizer_Destroy(&playlist->randomizer); vlc_playlist_ClearItems(playlist); free(playlist); } diff --git a/src/playlist/playlist.h b/src/playlist/playlist.h index adbcf506ed..7af25b65bd 100644 --- a/src/playlist/playlist.h +++ b/src/playlist/playlist.h @@ -25,6 +25,7 @@ #include <vlc_playlist.h> #include <vlc_vector.h> #include "../input/player.h" +#include "randomizer.h" typedef struct input_item_t input_item_t; @@ -48,6 +49,7 @@ struct vlc_playlist /* all remaining fields are protected by the lock of the player */ struct vlc_player_listener_id *player_listener; playlist_item_vector_t items; + struct randomizer randomizer; ssize_t current; bool has_prev; bool has_next; diff --git a/src/playlist/test.c b/src/playlist/test.c index a41d007e2c..8bbcbe5c66 100644 --- a/src/playlist/test.c +++ b/src/playlist/test.c @@ -1853,6 +1853,147 @@ test_request_goto_adapt(void) vlc_playlist_Delete(playlist); } +/* this only tests that the randomizer is correctly managed by the playlist, + * for further tests on randomization properties, see randomizer tests. */ +static void +test_random(void) +{ + vlc_playlist_t *playlist = vlc_playlist_New(NULL); + assert(playlist); + + input_item_t *media[6]; + CreateDummyMediaArray(media, 6); + + /* initial playlist with 5 items (1 is not added immediately) */ + int ret = vlc_playlist_Append(playlist, media, 5); + assert(ret == VLC_SUCCESS); + + struct vlc_playlist_callbacks cbs = { + .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); + + assert(!vlc_playlist_HasPrev(playlist)); + assert(vlc_playlist_HasNext(playlist)); + + for (int i = 0; i < 3; ++i) + { + assert(vlc_playlist_HasNext(playlist)); + ret = vlc_playlist_Next(playlist); + assert(ret == VLC_SUCCESS); + } + + assert(vlc_playlist_HasPrev(playlist)); + vlc_playlist_SetPlaybackOrder(playlist, VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM); + + /* in random order, previous uses the history of randomly selected items */ + assert(!vlc_playlist_HasPrev(playlist)); + + bool selected[5] = {}; + for (int i = 0; i < 5; ++i) + { + assert(vlc_playlist_HasNext(playlist)); + ret = vlc_playlist_Next(playlist); + assert(ret == VLC_SUCCESS); + ssize_t index = vlc_playlist_GetCurrentIndex(playlist); + assert(index != -1); + assert(!selected[index]); /* not selected twice */ + selected[index] = true; + } + + assert(!vlc_playlist_HasNext(playlist)); + + /* add a new item, it must be taken into account */ + ret = vlc_playlist_AppendOne(playlist, media[5]); + assert(ret == VLC_SUCCESS); + assert(vlc_playlist_HasNext(playlist)); + + ret = vlc_playlist_Next(playlist); + assert(ret == VLC_SUCCESS); + + assert(vlc_playlist_GetCurrentIndex(playlist) == 5); + assert(!vlc_playlist_HasNext(playlist)); + + vlc_playlist_RemoveOne(playlist, 5); + + /* enable repeat */ + vlc_playlist_SetPlaybackRepeat(playlist, VLC_PLAYLIST_PLAYBACK_REPEAT_ALL); + + /* now there are more items */ + assert(vlc_playlist_HasNext(playlist)); + + /* once again */ + memset(selected, 0, sizeof(selected)); + for (int i = 0; i < 5; ++i) + { + assert(vlc_playlist_HasNext(playlist)); + ret = vlc_playlist_Next(playlist); + assert(ret == VLC_SUCCESS); + ssize_t index = vlc_playlist_GetCurrentIndex(playlist); + assert(index != -1); + assert(!selected[index]); /* not selected twice */ + selected[index] = true; + } + + /* there are always more items */ + assert(vlc_playlist_HasNext(playlist)); + + /* move to the middle of the random array */ + for (int i = 0; i < 3; ++i) + { + assert(vlc_playlist_HasNext(playlist)); + ret = vlc_playlist_Next(playlist); + assert(ret == VLC_SUCCESS); + } + + memset(selected, 0, sizeof(selected)); + int actual[5]; /* store the selected items (by their index) */ + + ssize_t current = vlc_playlist_GetCurrentIndex(playlist); + assert(current != -1); + actual[4] = current; + + for (int i = 3; i >= 0; --i) + { + assert(vlc_playlist_HasPrev(playlist)); + ret = vlc_playlist_Prev(playlist); + assert(ret == VLC_SUCCESS); + ssize_t index = vlc_playlist_GetCurrentIndex(playlist); + assert(index != -1); + actual[i] = index; + assert(!selected[index]); /* not selected twice */ + selected[index] = true; + } + + /* no more previous, the history may only contain each item once */ + assert(!vlc_playlist_HasPrev(playlist)); + + /* we should get the same items in the reverse order going forward */ + for (int i = 1; i < 5; ++i) + { + assert(vlc_playlist_HasNext(playlist)); + ret = vlc_playlist_Next(playlist); + assert(ret == VLC_SUCCESS); + ssize_t index = vlc_playlist_GetCurrentIndex(playlist); + assert(index != -1); + assert(index == actual[i]); + } + + /* there are always more items */ + assert(vlc_playlist_HasNext(playlist)); + + callback_ctx_destroy(&ctx); + vlc_playlist_RemoveListener(playlist, listener); + DestroyMediaArray(media, 6); + vlc_playlist_Delete(playlist); +} + #undef EXPECT_AT int main(void) @@ -1883,5 +2024,6 @@ int main(void) test_request_goto_with_matching_hint(); test_request_goto_without_hint(); test_request_goto_adapt(); + test_random(); return 0; } _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
