[vlc-commits] core: playlist: handle random playback order
Romain Vimont
git at videolan.org
Thu Nov 15 16:23:37 CET 2018
vlc | branch: master | Romain Vimont <rom1v at videolabs.io> | 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 <thomas at gllm.fr>
> 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;
}
More information about the vlc-commits
mailing list