lib: media_track: add new members
[vlc.git] / src / playlist / content.c
blob7fba8cf3883b250f8cb0fdf6c30be4a4fcc7355e
1 /*****************************************************************************
2 * playlist/content.c
3 *****************************************************************************
4 * Copyright (C) 2018 VLC authors and VideoLAN
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
25 #include "content.h"
27 #include "control.h"
28 #include "item.h"
29 #include "notify.h"
30 #include "playlist.h"
31 #include "preparse.h"
33 void
34 vlc_playlist_ClearItems(vlc_playlist_t *playlist)
36 vlc_playlist_item_t *item;
37 vlc_vector_foreach(item, &playlist->items)
38 vlc_playlist_item_Release(item);
39 vlc_vector_clear(&playlist->items);
42 static void
43 vlc_playlist_ItemsReset(vlc_playlist_t *playlist)
45 if (playlist->order == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM)
46 randomizer_Clear(&playlist->randomizer);
48 struct vlc_playlist_state state;
49 vlc_playlist_state_Save(playlist, &state);
51 playlist->current = -1;
52 playlist->has_prev = vlc_playlist_ComputeHasPrev(playlist);
53 playlist->has_next = vlc_playlist_ComputeHasNext(playlist);
55 vlc_playlist_Notify(playlist, on_items_reset, playlist->items.data,
56 playlist->items.size);
57 vlc_playlist_state_NotifyChanges(playlist, &state);
60 static void
61 vlc_playlist_ItemsInserted(vlc_playlist_t *playlist, size_t index, size_t count)
63 if (playlist->order == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM)
64 randomizer_Add(&playlist->randomizer,
65 &playlist->items.data[index], count);
67 struct vlc_playlist_state state;
68 vlc_playlist_state_Save(playlist, &state);
70 if (playlist->current >= (ssize_t) index)
71 playlist->current += count;
72 playlist->has_prev = vlc_playlist_ComputeHasPrev(playlist);
73 playlist->has_next = vlc_playlist_ComputeHasNext(playlist);
75 vlc_playlist_item_t **items = &playlist->items.data[index];
76 vlc_playlist_Notify(playlist, on_items_added, index, items, count);
77 vlc_playlist_state_NotifyChanges(playlist, &state);
79 for (size_t i = index; i < index + count; ++i)
81 vlc_playlist_item_t *item = playlist->items.data[i];
82 vlc_playlist_AutoPreparse(playlist, item->media);
86 static void
87 vlc_playlist_ItemsMoved(vlc_playlist_t *playlist, size_t index, size_t count,
88 size_t target)
90 struct vlc_playlist_state state;
91 vlc_playlist_state_Save(playlist, &state);
93 if (playlist->current != -1) {
94 size_t current = (size_t) playlist->current;
95 if (index < target)
97 if (current >= index && current < index + count)
98 /* current item belongs to the moved block */
99 playlist->current += target - index;
100 else if (current >= index + count && current < target + count)
101 /* current item was shifted backwards to the moved block */
102 playlist->current -= count;
103 /* else the current item does not move */
105 else
107 if (current >= index && current < index + count)
108 /* current item belongs to the moved block */
109 playlist->current -= index - target;
110 else if (current >= target && current < index)
111 /* current item was shifted forward to the moved block */
112 playlist->current += count;
113 /* else the current item does not move */
117 playlist->has_prev = vlc_playlist_ComputeHasPrev(playlist);
118 playlist->has_next = vlc_playlist_ComputeHasNext(playlist);
120 vlc_playlist_Notify(playlist, on_items_moved, index, count, target);
121 vlc_playlist_state_NotifyChanges(playlist, &state);
124 static void
125 vlc_playlist_ItemsRemoving(vlc_playlist_t *playlist, size_t index, size_t count)
127 if (playlist->order == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM)
128 randomizer_Remove(&playlist->randomizer,
129 &playlist->items.data[index], count);
132 /* return whether the current media has changed */
133 static bool
134 vlc_playlist_ItemsRemoved(vlc_playlist_t *playlist, size_t index, size_t count)
136 struct vlc_playlist_state state;
137 vlc_playlist_state_Save(playlist, &state);
139 bool current_media_changed = false;
140 if (playlist->current != -1) {
141 size_t current = (size_t) playlist->current;
142 if (current >= index && current < index + count) {
143 /* current item has been removed */
144 if (index + count < playlist->items.size) {
145 /* select the first item after the removed block */
146 playlist->current = index;
147 } else {
148 /* no more items */
149 playlist->current = -1;
151 current_media_changed = true;
152 } else if (current >= index + count) {
153 playlist->current -= count;
156 playlist->has_prev = vlc_playlist_ComputeHasPrev(playlist);
157 playlist->has_next = vlc_playlist_ComputeHasNext(playlist);
159 vlc_playlist_Notify(playlist, on_items_removed, index, count);
160 vlc_playlist_state_NotifyChanges(playlist, &state);
162 return current_media_changed;
165 static void
166 vlc_playlist_ItemReplaced(vlc_playlist_t *playlist, size_t index)
168 struct vlc_playlist_state state;
169 vlc_playlist_state_Save(playlist, &state);
171 playlist->has_prev = vlc_playlist_ComputeHasPrev(playlist);
172 playlist->has_next = vlc_playlist_ComputeHasNext(playlist);
174 vlc_playlist_Notify(playlist, on_items_updated, index,
175 &playlist->items.data[index], 1);
176 vlc_playlist_state_NotifyChanges(playlist, &state);
178 vlc_playlist_AutoPreparse(playlist, playlist->items.data[index]->media);
181 size_t
182 vlc_playlist_Count(vlc_playlist_t *playlist)
184 vlc_playlist_AssertLocked(playlist);
185 return playlist->items.size;
188 vlc_playlist_item_t *
189 vlc_playlist_Get(vlc_playlist_t *playlist, size_t index)
191 vlc_playlist_AssertLocked(playlist);
192 return playlist->items.data[index];
195 ssize_t
196 vlc_playlist_IndexOf(vlc_playlist_t *playlist, const vlc_playlist_item_t *item)
198 vlc_playlist_AssertLocked(playlist);
200 ssize_t index;
201 vlc_vector_index_of(&playlist->items, item, &index);
202 return index;
205 ssize_t
206 vlc_playlist_IndexOfMedia(vlc_playlist_t *playlist, const input_item_t *media)
208 vlc_playlist_AssertLocked(playlist);
210 playlist_item_vector_t *items = &playlist->items;
211 for (size_t i = 0; i < items->size; ++i)
212 if (items->data[i]->media == media)
213 return i;
214 return -1;
217 ssize_t
218 vlc_playlist_IndexOfId(vlc_playlist_t *playlist, uint64_t id)
220 vlc_playlist_AssertLocked(playlist);
222 playlist_item_vector_t *items = &playlist->items;
223 for (size_t i = 0; i < items->size; ++i)
224 if (items->data[i]->id == id)
225 return i;
226 return -1;
229 void
230 vlc_playlist_Clear(vlc_playlist_t *playlist)
232 vlc_playlist_AssertLocked(playlist);
234 int ret = vlc_player_SetCurrentMedia(playlist->player, NULL);
235 VLC_UNUSED(ret); /* what could we do? */
237 vlc_playlist_ClearItems(playlist);
238 vlc_playlist_ItemsReset(playlist);
241 static int
242 vlc_playlist_MediaToItems(vlc_playlist_t *playlist, input_item_t *const media[],
243 size_t count, vlc_playlist_item_t *items[])
245 vlc_playlist_AssertLocked(playlist);
246 size_t i;
247 for (i = 0; i < count; ++i)
249 uint64_t id = playlist->idgen++;
250 items[i] = vlc_playlist_item_New(media[i], id);
251 if (unlikely(!items[i]))
252 break;
254 if (i < count)
256 /* allocation failure, release partial items */
257 while (i)
258 vlc_playlist_item_Release(items[--i]);
259 return VLC_ENOMEM;
261 return VLC_SUCCESS;
265 vlc_playlist_Insert(vlc_playlist_t *playlist, size_t index,
266 input_item_t *const media[], size_t count)
268 vlc_playlist_AssertLocked(playlist);
269 assert(index <= playlist->items.size);
271 /* make space in the vector */
272 if (!vlc_vector_insert_hole(&playlist->items, index, count))
273 return VLC_ENOMEM;
275 /* create playlist items in place */
276 int ret = vlc_playlist_MediaToItems(playlist, media, count,
277 &playlist->items.data[index]);
278 if (ret != VLC_SUCCESS)
280 /* we were optimistic, it failed, restore the vector state */
281 vlc_vector_remove_slice(&playlist->items, index, count);
282 return ret;
285 vlc_playlist_ItemsInserted(playlist, index, count);
286 vlc_player_InvalidateNextMedia(playlist->player);
288 return VLC_SUCCESS;
291 void
292 vlc_playlist_Move(vlc_playlist_t *playlist, size_t index, size_t count,
293 size_t target)
295 vlc_playlist_AssertLocked(playlist);
296 assert(index + count <= playlist->items.size);
297 assert(target + count <= playlist->items.size);
299 vlc_vector_move_slice(&playlist->items, index, count, target);
301 vlc_playlist_ItemsMoved(playlist, index, count, target);
302 vlc_player_InvalidateNextMedia(playlist->player);
305 void
306 vlc_playlist_Remove(vlc_playlist_t *playlist, size_t index, size_t count)
308 vlc_playlist_AssertLocked(playlist);
309 assert(index < playlist->items.size);
311 vlc_playlist_ItemsRemoving(playlist, index, count);
313 for (size_t i = 0; i < count; ++i)
314 vlc_playlist_item_Release(playlist->items.data[index + i]);
316 vlc_vector_remove_slice(&playlist->items, index, count);
318 bool current_media_changed = vlc_playlist_ItemsRemoved(playlist, index,
319 count);
320 if (current_media_changed)
321 vlc_playlist_SetCurrentMedia(playlist, playlist->current);
322 else
323 vlc_player_InvalidateNextMedia(playlist->player);
326 static int
327 vlc_playlist_Replace(vlc_playlist_t *playlist, size_t index,
328 input_item_t *media)
330 vlc_playlist_AssertLocked(playlist);
331 assert(index < playlist->items.size);
333 uint64_t id = playlist->idgen++;
334 vlc_playlist_item_t *item = vlc_playlist_item_New(media, id);
335 if (!item)
336 return VLC_ENOMEM;
338 if (playlist->order == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM)
340 randomizer_Remove(&playlist->randomizer,
341 &playlist->items.data[index], 1);
342 randomizer_Add(&playlist->randomizer, &item, 1);
345 vlc_playlist_item_Release(playlist->items.data[index]);
346 playlist->items.data[index] = item;
348 vlc_playlist_ItemReplaced(playlist, index);
349 return VLC_SUCCESS;
353 vlc_playlist_Expand(vlc_playlist_t *playlist, size_t index,
354 input_item_t *const media[], size_t count)
356 vlc_playlist_AssertLocked(playlist);
357 assert(index < playlist->items.size);
359 if (count == 0)
360 vlc_playlist_RemoveOne(playlist, index);
361 else
363 int ret = vlc_playlist_Replace(playlist, index, media[0]);
364 if (ret != VLC_SUCCESS)
365 return ret;
367 if (count > 1)
369 /* make space in the vector */
370 if (!vlc_vector_insert_hole(&playlist->items, index + 1, count - 1))
371 return VLC_ENOMEM;
373 /* create playlist items in place */
374 ret = vlc_playlist_MediaToItems(playlist, &media[1], count - 1,
375 &playlist->items.data[index + 1]);
376 if (ret != VLC_SUCCESS)
378 /* we were optimistic, it failed, restore the vector state */
379 vlc_vector_remove_slice(&playlist->items, index + 1, count - 1);
380 return ret;
382 vlc_playlist_ItemsInserted(playlist, index + 1, count - 1);
385 if ((ssize_t) index == playlist->current)
386 vlc_playlist_SetCurrentMedia(playlist, playlist->current);
387 else
388 vlc_player_InvalidateNextMedia(playlist->player);
391 return VLC_SUCCESS;