[vlc-devel] [vlc-commits] core: playlist: implement sorting
Steve Lhomme
robux4 at ycbcr.xyz
Wed Nov 21 09:40:27 CET 2018
On 20/11/2018 10:36, Thomas Guillem wrote:
> On Tue, Nov 20, 2018, at 04:16, Zhao Zhili wrote:
>> Hi Romain,
>>
>> Would you mind implementing a compatibility fallback for qsort_r()? It's
>> not available on Android.
>> error: implicit declaration of function 'qsort_r' is invalid in C99
>> [-Werror,-Wimplicit-function-declaration]
> We could fix that by putting the context in each elements. It's a quite ugly solution.
>
> One remark: shoud VLC 4.0 be built in C11 ?
AFAIK we already have this requirement, as well as C++11.
>
>> On 2018/11/15 下午11:23, Romain Vimont wrote:
>>> vlc | branch: master | Romain Vimont <rom1v at videolabs.io> | Tue Oct 16 15:51:02 2018 +0200| [a6832090ec73e28f71729be9d58af5c769f9a7a6] | committer: Thomas Guillem
>>>
>>> core: playlist: implement sorting
>>>
>>> Expose a function to sort the items in the playlist by a list of
>>> criteria. A criterion is composed of a key (title, duration, etc.) and
>>> an order (ascending or descending).
>>>
>>> Signed-off-by: Thomas Guillem <thomas at gllm.fr>
>>>
>>>> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=a6832090ec73e28f71729be9d58af5c769f9a7a6
>>> ---
>>>
>>> include/vlc_fixups.h | 4 +
>>> include/vlc_playlist.h | 40 +++++
>>> src/Makefile.am | 4 +-
>>> src/libvlccore.sym | 1 +
>>> src/playlist/sort.c | 404 +++++++++++++++++++++++++++++++++++++++++++++++++
>>> src/playlist/test.c | 108 +++++++++++++
>>> 6 files changed, 560 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/include/vlc_fixups.h b/include/vlc_fixups.h
>>> index caf1768f63..598521c510 100644
>>> --- a/include/vlc_fixups.h
>>> +++ b/include/vlc_fixups.h
>>> @@ -112,6 +112,10 @@ typedef struct
>>> # include <dirent.h>
>>> #endif
>>>
>>> +#ifdef _WIN32
>>> +# define qsort_r qsort_s
>>> +#endif
>>> +
>>> #ifdef __cplusplus
>>> # define VLC_NOTHROW throw ()
>>> extern "C" {
>>> diff --git a/include/vlc_playlist.h b/include/vlc_playlist.h
>>> index c9074912b3..9253bbb90d 100644
>>> --- a/include/vlc_playlist.h
>>> +++ b/include/vlc_playlist.h
>>> @@ -126,6 +126,33 @@ enum vlc_playlist_playback_order
>>> VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM,
>>> };
>>>
>>> +enum vlc_playlist_sort_key
>>> +{
>>> + VLC_PLAYLIST_SORT_KEY_TITLE,
>>> + VLC_PLAYLIST_SORT_KEY_DURATION,
>>> + VLC_PLAYLIST_SORT_KEY_ARTIST,
>>> + VLC_PLAYLIST_SORT_KEY_ALBUM,
>>> + VLC_PLAYLIST_SORT_KEY_ALBUM_ARTIST,
>>> + VLC_PLAYLIST_SORT_KEY_GENRE,
>>> + VLC_PLAYLIST_SORT_KEY_DATE,
>>> + VLC_PLAYLIST_SORT_KEY_TRACK_NUMBER,
>>> + VLC_PLAYLIST_SORT_KEY_DISC_NUMBER,
>>> + VLC_PLAYLIST_SORT_KEY_URL,
>>> + VLC_PLAYLIST_SORT_KEY_RATING,
>>> +};
>>> +
>>> +enum vlc_playlist_sort_order
>>> +{
>>> + VLC_PLAYLIST_SORT_ORDER_ASCENDING,
>>> + VLC_PLAYLIST_SORT_ORDER_DESCENDING,
>>> +};
>>> +
>>> +struct vlc_playlist_sort_criterion
>>> +{
>>> + enum vlc_playlist_sort_key key;
>>> + enum vlc_playlist_sort_order order;
>>> +};
>>> +
>>> /**
>>> * Playlist callbacks.
>>> *
>>> @@ -590,6 +617,19 @@ VLC_API void
>>> vlc_playlist_Shuffle(vlc_playlist_t *playlist);
>>>
>>> /**
>>> + * Sort the playlist by a list of criteria.
>>> + *
>>> + * \param playlist the playlist, locked
>>> + * \param criteria the sort criteria (in order)
>>> + * \param count the number of criteria
>>> + * \return VLC_SUCCESS on success, another value on error
>>> + */
>>> +VLC_API int
>>> +vlc_playlist_Sort(vlc_playlist_t *playlist,
>>> + const struct vlc_playlist_sort_criterion criteria[],
>>> + size_t count);
>>> +
>>> +/**
>>> * Return the index of a given item.
>>> *
>>> * \param playlist the playlist, locked
>>> diff --git a/src/Makefile.am b/src/Makefile.am
>>> index 58cc5a3319..d6bf427179 100644
>>> --- a/src/Makefile.am
>>> +++ b/src/Makefile.am
>>> @@ -245,6 +245,7 @@ libvlccore_la_SOURCES = \
>>> playlist/randomizer.h \
>>> playlist/request.c \
>>> playlist/shuffle.c \
>>> + playlist/sort.c \
>>> preparser/art.c \
>>> preparser/art.h \
>>> preparser/fetcher.c \
>>> @@ -595,7 +596,8 @@ test_playlist_SOURCES = playlist/test.c \
>>> playlist/preparse.c \
>>> playlist/randomizer.c \
>>> playlist/request.c \
>>> - playlist/shuffle.c
>>> + playlist/shuffle.c \
>>> + playlist/sort.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 52c8017a3a..3a88031d21 100644
>>> --- a/src/libvlccore.sym
>>> +++ b/src/libvlccore.sym
>>> @@ -926,6 +926,7 @@ vlc_playlist_RequestInsert
>>> vlc_playlist_RequestMove
>>> vlc_playlist_RequestRemove
>>> vlc_playlist_Shuffle
>>> +vlc_playlist_Sort
>>> vlc_playlist_IndexOf
>>> vlc_playlist_IndexOfMedia
>>> vlc_playlist_GetPlaybackRepeat
>>> diff --git a/src/playlist/sort.c b/src/playlist/sort.c
>>> new file mode 100644
>>> index 0000000000..b44f81a168
>>> --- /dev/null
>>> +++ b/src/playlist/sort.c
>>> @@ -0,0 +1,404 @@
>>> +/*****************************************************************************
>>> + * playlist/sort.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"
>>> +
>>> +/**
>>> + * Struct containing a copy of (parsed) media metadata, used for sorting
>>> + * without locking all the items.
>>> + */
>>> +struct vlc_playlist_item_meta {
>>> + vlc_playlist_item_t *item;
>>> + const char *title_or_name;
>>> + vlc_tick_t duration;
>>> + const char *artist;
>>> + const char *album;
>>> + const char *album_artist;
>>> + const char *genre;
>>> + const char *url;
>>> + int64_t date;
>>> + int64_t track_number;
>>> + int64_t disc_number;
>>> + int64_t rating;
>>> + bool has_date;
>>> + bool has_track_number;
>>> + bool has_disc_number;
>>> + bool has_rating;
>>> +};
>>> +
>>> +static int
>>> +vlc_playlist_item_meta_CopyString(const char **to, const char *from)
>>> +{
>>> + if (from)
>>> + {
>>> + *to = strdup(from);
>>> + if (unlikely(!*to))
>>> + return VLC_ENOMEM;
>>> + }
>>> + else
>>> + *to = NULL;
>>> + return VLC_SUCCESS;
>>> +}
>>> +
>>> +static int
>>> +vlc_playlist_item_meta_InitField(struct vlc_playlist_item_meta *meta,
>>> + enum vlc_playlist_sort_key key)
>>> +{
>>> + input_item_t *media = meta->item->media;
>>> + switch (key)
>>> + {
>>> + case VLC_PLAYLIST_SORT_KEY_TITLE:
>>> + {
>>> + const char *value = input_item_GetMetaLocked(media, vlc_meta_Title);
>>> + if (EMPTY_STR(value))
>>> + value = media->psz_name;
>>> + return vlc_playlist_item_meta_CopyString(&meta->title_or_name,
>>> + value);
>>> + }
>>> + case VLC_PLAYLIST_SORT_KEY_DURATION:
>>> + {
>>> + if (media->i_duration == INPUT_DURATION_INDEFINITE
>>> + || media->i_duration == INPUT_DURATION_UNSET)
>>> + meta->duration = 0;
>>> + else
>>> + meta->duration = media->i_duration;
>>> + return VLC_SUCCESS;
>>> + }
>>> + case VLC_PLAYLIST_SORT_KEY_ARTIST:
>>> + {
>>> + const char *value = input_item_GetMetaLocked(media,
>>> + vlc_meta_Artist);
>>> + return vlc_playlist_item_meta_CopyString(&meta->artist, value);
>>> + }
>>> + case VLC_PLAYLIST_SORT_KEY_ALBUM:
>>> + {
>>> + const char *value = input_item_GetMetaLocked(media, vlc_meta_Album);
>>> + return vlc_playlist_item_meta_CopyString(&meta->album, value);
>>> + }
>>> + case VLC_PLAYLIST_SORT_KEY_ALBUM_ARTIST:
>>> + {
>>> + const char *value = input_item_GetMetaLocked(media,
>>> + vlc_meta_AlbumArtist);
>>> + return vlc_playlist_item_meta_CopyString(&meta->album_artist,
>>> + value);
>>> + }
>>> + case VLC_PLAYLIST_SORT_KEY_GENRE:
>>> + {
>>> + const char *value = input_item_GetMetaLocked(media, vlc_meta_Genre);
>>> + return vlc_playlist_item_meta_CopyString(&meta->genre, value);
>>> + }
>>> + case VLC_PLAYLIST_SORT_KEY_DATE:
>>> + {
>>> + const char *str = input_item_GetMetaLocked(media, vlc_meta_Date);
>>> + meta->has_date = !EMPTY_STR(str);
>>> + if (meta->has_date)
>>> + meta->date = atoll(str);
>>> + return VLC_SUCCESS;
>>> + }
>>> + case VLC_PLAYLIST_SORT_KEY_TRACK_NUMBER:
>>> + {
>>> + const char *str = input_item_GetMetaLocked(media,
>>> + vlc_meta_TrackNumber);
>>> + meta->has_track_number = !EMPTY_STR(str);
>>> + if (meta->has_track_number)
>>> + meta->track_number = atoll(str);
>>> + return VLC_SUCCESS;
>>> + }
>>> + case VLC_PLAYLIST_SORT_KEY_DISC_NUMBER:
>>> + {
>>> + const char *str = input_item_GetMetaLocked(media,
>>> + vlc_meta_DiscNumber);
>>> + meta->has_disc_number = !EMPTY_STR(str);
>>> + if (meta->has_disc_number)
>>> + meta->disc_number = atoll(str);
>>> + return VLC_SUCCESS;
>>> + }
>>> + case VLC_PLAYLIST_SORT_KEY_URL:
>>> + {
>>> + const char *value = input_item_GetMetaLocked(media, vlc_meta_URL);
>>> + return vlc_playlist_item_meta_CopyString(&meta->url, value);
>>> + }
>>> + case VLC_PLAYLIST_SORT_KEY_RATING:
>>> + {
>>> + const char *str = input_item_GetMetaLocked(media, vlc_meta_Rating);
>>> + meta->has_rating = !EMPTY_STR(str);
>>> + if (meta->has_rating)
>>> + meta->rating = atoll(str);
>>> + return VLC_SUCCESS;
>>> + }
>>> + default:
>>> + assert(!"Unknown sort key");
>>> + vlc_assert_unreachable();
>>> + }
>>> +}
>>> +
>>> +static void
>>> +vlc_playlist_item_meta_DestroyFields(struct vlc_playlist_item_meta *meta)
>>> +{
>>> + free((void *) meta->title_or_name);
>>> + free((void *) meta->artist);
>>> + free((void *) meta->album);
>>> + free((void *) meta->album_artist);
>>> + free((void *) meta->genre);
>>> + free((void *) meta->url);
>>> +}
>>> +
>>> +static int
>>> +vlc_playlist_item_meta_InitFields(struct vlc_playlist_item_meta *meta,
>>> + const struct vlc_playlist_sort_criterion criteria[], size_t count)
>>> +{
>>> + for (size_t i = 0; i < count; ++i)
>>> + {
>>> + const struct vlc_playlist_sort_criterion *criterion = &criteria[i];
>>> + int ret = vlc_playlist_item_meta_InitField(meta, criterion->key);
>>> + if (unlikely(ret != VLC_SUCCESS))
>>> + {
>>> + vlc_playlist_item_meta_DestroyFields(meta);
>>> + return ret;
>>> + }
>>> + }
>>> + return VLC_SUCCESS;
>>> +}
>>> +
>>> +static struct vlc_playlist_item_meta *
>>> +vlc_playlist_item_meta_New(vlc_playlist_item_t *item,
>>> + const struct vlc_playlist_sort_criterion criteria[],
>>> + size_t count)
>>> +{
>>> + /* assume that NULL representation is all-zeros */
>>> + struct vlc_playlist_item_meta *meta = calloc(1, sizeof(*meta));
>>> + if (unlikely(!meta))
>>> + return NULL;
>>> +
>>> + meta->item = item;
>>> +
>>> + vlc_mutex_lock(&item->media->lock);
>>> + int ret = vlc_playlist_item_meta_InitFields(meta, criteria, count);
>>> + vlc_mutex_unlock(&item->media->lock);
>>> +
>>> + if (unlikely(ret != VLC_SUCCESS))
>>> + {
>>> + free(meta);
>>> + return NULL;
>>> + }
>>> +
>>> + return meta;
>>> +}
>>> +
>>> +static void
>>> +vlc_playlist_item_meta_Delete(struct vlc_playlist_item_meta *meta)
>>> +{
>>> + vlc_playlist_item_meta_DestroyFields(meta);
>>> + free(meta);
>>> +}
>>> +
>>> +static inline int
>>> +CompareStrings(const char *a, const char *b)
>>> +{
>>> + if (a && b)
>>> + return strcasecmp(a, b);
>>> + if (!a && !b)
>>> + return 0;
>>> + return a ? 1 : -1;
>>> +}
>>> +
>>> +static inline int
>>> +CompareIntegers(int64_t a, int64_t b)
>>> +{
>>> + if (a < b)
>>> + return -1;
>>> + if (a > b)
>>> + return 1;
>>> + return 0;
>>> +}
>>> +
>>> +static inline int
>>> +CompareOptionalIntegers(bool has_a, int64_t a, bool has_b, int64_t b)
>>> +{
>>> + if (has_a && has_b)
>>> + return CompareIntegers(a, b);
>>> +
>>> + if (!has_a && !has_b)
>>> + return 0;
>>> +
>>> + return a ? 1 : -1;
>>> +}
>>> +
>>> +static inline int
>>> +CompareMetaByKey(const struct vlc_playlist_item_meta *a,
>>> + const struct vlc_playlist_item_meta *b,
>>> + enum vlc_playlist_sort_key key)
>>> +{
>>> + switch (key)
>>> + {
>>> + case VLC_PLAYLIST_SORT_KEY_TITLE:
>>> + return CompareStrings(a->title_or_name, b->title_or_name);
>>> + case VLC_PLAYLIST_SORT_KEY_DURATION:
>>> + return CompareIntegers(a->duration, b->duration);
>>> + case VLC_PLAYLIST_SORT_KEY_ARTIST:
>>> + return CompareStrings(a->artist, b->artist);
>>> + case VLC_PLAYLIST_SORT_KEY_ALBUM:
>>> + return CompareStrings(a->album, b->album);
>>> + case VLC_PLAYLIST_SORT_KEY_ALBUM_ARTIST:
>>> + return CompareStrings(a->album_artist, b->album_artist);
>>> + case VLC_PLAYLIST_SORT_KEY_GENRE:
>>> + return CompareStrings(a->genre, b->genre);
>>> + case VLC_PLAYLIST_SORT_KEY_DATE:
>>> + return CompareOptionalIntegers(a->has_date, a->date,
>>> + b->has_date, b->date);
>>> + case VLC_PLAYLIST_SORT_KEY_TRACK_NUMBER:
>>> + return CompareOptionalIntegers(a->has_track_number, a->track_number,
>>> + b->has_track_number, b->track_number);
>>> + case VLC_PLAYLIST_SORT_KEY_DISC_NUMBER:
>>> + return CompareOptionalIntegers(a->has_disc_number, a->disc_number,
>>> + b->has_disc_number, b->disc_number);
>>> + case VLC_PLAYLIST_SORT_KEY_URL:
>>> + return CompareStrings(a->url, b->url);
>>> + case VLC_PLAYLIST_SORT_KEY_RATING:
>>> + return CompareOptionalIntegers(a->has_rating, a->rating,
>>> + b->has_rating, b->rating);
>>> + default:
>>> + assert(!"Unknown sort key");
>>> + vlc_assert_unreachable();
>>> + }
>>> +}
>>> +
>>> +/* context for qsort_r() */
>>> +struct sort_request
>>> +{
>>> + const struct vlc_playlist_sort_criterion *criteria;
>>> + size_t count;
>>> +};
>>> +
>>> +static int
>>> +compare_meta(const void *lhs, const void *rhs, void *userdata)
>>> +{
>>> + struct sort_request *req = userdata;
>>> + const struct vlc_playlist_item_meta *a =
>>> + *(const struct vlc_playlist_item_meta **) lhs;
>>> + const struct vlc_playlist_item_meta *b =
>>> + *(const struct vlc_playlist_item_meta **) rhs;
>>> +
>>> + for (size_t i = 0; i < req->count; ++i)
>>> + {
>>> + const struct vlc_playlist_sort_criterion *criterion = &req->criteria[i];
>>> + int ret = CompareMetaByKey(a, b, criterion->key);
>>> + if (ret)
>>> + {
>>> + if (criterion->order == VLC_PLAYLIST_SORT_ORDER_DESCENDING)
>>> + /* do not return -ret, it's undefined if ret == INT_MIN */
>>> + return ret > 0 ? -1 : 1;
>>> + return ret;
>>> + }
>>> + }
>>> + return 0;
>>> +}
>>> +
>>> +static void
>>> +vlc_playlist_DeleteMetaArray(struct vlc_playlist_item_meta *array[],
>>> + size_t count)
>>> +{
>>> + for (size_t i = 0; i < count; ++i)
>>> + vlc_playlist_item_meta_Delete(array[i]);
>>> + free(array);
>>> +}
>>> +
>>> +static struct vlc_playlist_item_meta **
>>> +vlc_playlist_NewMetaArray(vlc_playlist_t *playlist,
>>> + const struct vlc_playlist_sort_criterion criteria[], size_t count)
>>> +{
>>> + struct vlc_playlist_item_meta **array =
>>> + vlc_alloc(playlist->items.size, sizeof(*array));
>>> +
>>> + if (unlikely(!array))
>>> + return NULL;
>>> +
>>> + size_t i;
>>> + for (i = 0; i < playlist->items.size; ++i)
>>> + {
>>> + array[i] = vlc_playlist_item_meta_New(playlist->items.data[i],
>>> + criteria, count);
>>> + if (unlikely(!array[i]))
>>> + break;
>>> + }
>>> +
>>> + if (i < playlist->items.size)
>>> + {
>>> + /* allocation failure */
>>> + vlc_playlist_DeleteMetaArray(array, i);
>>> + return NULL;
>>> + }
>>> +
>>> + return array;
>>> +}
>>> +
>>> +int
>>> +vlc_playlist_Sort(vlc_playlist_t *playlist,
>>> + const struct vlc_playlist_sort_criterion criteria[],
>>> + size_t count)
>>> +{
>>> + assert(count > 0);
>>> + vlc_playlist_AssertLocked(playlist);
>>> +
>>> + vlc_playlist_item_t *current = playlist->current != -1
>>> + ? playlist->items.data[playlist->current]
>>> + : NULL;
>>> +
>>> + struct vlc_playlist_item_meta **array =
>>> + vlc_playlist_NewMetaArray(playlist, criteria, count);
>>> + if (unlikely(!array))
>>> + return VLC_ENOMEM;
>>> +
>>> + struct sort_request req = { criteria, count };
>>> +
>>> + qsort_r(array, playlist->items.size, sizeof(*array), compare_meta, &req);
>>> +
>>> + /* apply the sorting result to the playlist */
>>> + for (size_t i = 0; i < playlist->items.size; ++i)
>>> + playlist->items.data[i] = array[i]->item;
>>> +
>>> + vlc_playlist_DeleteMetaArray(array, playlist->items.size);
>>> +
>>> + 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);
>>> +
>>> + return VLC_SUCCESS;
>>> +}
>>> diff --git a/src/playlist/test.c b/src/playlist/test.c
>>> index 888e76efa9..5c3b75f3be 100644
>>> --- a/src/playlist/test.c
>>> +++ b/src/playlist/test.c
>>> @@ -2077,6 +2077,113 @@ test_shuffle(void)
>>> vlc_playlist_Delete(playlist);
>>> }
>>>
>>> +static void
>>> +test_sort(void)
>>> +{
>>> + vlc_playlist_t *playlist = vlc_playlist_New(NULL);
>>> + assert(playlist);
>>> +
>>> + input_item_t *media[10];
>>> + media[0] = CreateDummyMedia(4); media[0]->i_duration = 42;
>>> + media[1] = CreateDummyMedia(1); media[1]->i_duration = 5;
>>> + media[2] = CreateDummyMedia(6); media[2]->i_duration = 100;
>>> + media[3] = CreateDummyMedia(2); media[3]->i_duration = 1;
>>> + media[4] = CreateDummyMedia(1); media[4]->i_duration = 8;
>>> + media[5] = CreateDummyMedia(4); media[5]->i_duration = 23;
>>> + media[6] = CreateDummyMedia(3); media[6]->i_duration = 60;
>>> + media[7] = CreateDummyMedia(3); media[7]->i_duration = 40;
>>> + media[8] = CreateDummyMedia(0); media[8]->i_duration = 42;
>>> + media[9] = CreateDummyMedia(5); media[9]->i_duration = 42;
>>> +
>>> + /* 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 = 0;
>>> + playlist->has_prev = false;
>>> + playlist->has_next = true;
>>> +
>>> + struct vlc_playlist_sort_criterion criteria1[] = {
>>> + { VLC_PLAYLIST_SORT_KEY_TITLE, VLC_PLAYLIST_SORT_ORDER_ASCENDING },
>>> + { VLC_PLAYLIST_SORT_KEY_DURATION, VLC_PLAYLIST_SORT_ORDER_ASCENDING },
>>> + };
>>> + vlc_playlist_Sort(playlist, criteria1, 2);
>>> +
>>> + EXPECT_AT(0, 8);
>>> + EXPECT_AT(1, 1);
>>> + EXPECT_AT(2, 4);
>>> + EXPECT_AT(3, 3);
>>> + EXPECT_AT(4, 7);
>>> + EXPECT_AT(5, 6);
>>> + EXPECT_AT(6, 5);
>>> + EXPECT_AT(7, 0);
>>> + EXPECT_AT(8, 9);
>>> + EXPECT_AT(9, 2);
>>> +
>>> + ssize_t index = vlc_playlist_IndexOfMedia(playlist, media[0]);
>>> + assert(index == 7);
>>> + assert(playlist->current == 7);
>>> +
>>> + 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 == 7);
>>> + assert(ctx.vec_items_reset.data[0].state.has_prev);
>>> + assert(ctx.vec_items_reset.data[0].state.has_next);
>>> +
>>> + assert(ctx.vec_current_index_changed.size == 1);
>>> + assert(ctx.vec_current_index_changed.data[0].current == 7);
>>> +
>>> + assert(ctx.vec_has_prev_changed.size == 1);
>>> + assert(ctx.vec_has_prev_changed.data[0].has_prev);
>>> +
>>> + assert(ctx.vec_has_next_changed.size == 0);
>>> +
>>> + callback_ctx_reset(&ctx);
>>> +
>>> + struct vlc_playlist_sort_criterion criteria2[] = {
>>> + { VLC_PLAYLIST_SORT_KEY_DURATION, VLC_PLAYLIST_SORT_ORDER_DESCENDING },
>>> + { VLC_PLAYLIST_SORT_KEY_TITLE, VLC_PLAYLIST_SORT_ORDER_ASCENDING },
>>> + };
>>> +
>>> + vlc_playlist_Sort(playlist, criteria2, 2);
>>> +
>>> + EXPECT_AT(0, 2);
>>> + EXPECT_AT(1, 6);
>>> + EXPECT_AT(2, 8);
>>> + EXPECT_AT(3, 0);
>>> + EXPECT_AT(4, 9);
>>> + EXPECT_AT(5, 7);
>>> + EXPECT_AT(6, 5);
>>> + EXPECT_AT(7, 4);
>>> + EXPECT_AT(8, 1);
>>> + EXPECT_AT(9, 3);
>>> +
>>> + 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);
>>> +
>>> + callback_ctx_destroy(&ctx);
>>> + vlc_playlist_RemoveListener(playlist, listener);
>>> + DestroyMediaArray(media, 10);
>>> + vlc_playlist_Delete(playlist);
>>> +}
>>> +
>>> #undef EXPECT_AT
>>>
>>> int main(void)
>>> @@ -2109,5 +2216,6 @@ int main(void)
>>> test_request_goto_adapt();
>>> test_random();
>>> test_shuffle();
>>> + test_sort();
>>> return 0;
>>> }
>>>
>>> _______________________________________________
>>> vlc-commits mailing list
>>> vlc-commits at videolan.org
>>> https://mailman.videolan.org/listinfo/vlc-commits
>>
>>
>> _______________________________________________
>> vlc-devel mailing list
>> To unsubscribe or modify your subscription options:
>> https://mailman.videolan.org/listinfo/vlc-devel
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel
More information about the vlc-devel
mailing list