Qt: add AV1 in profiles codecs
[vlc.git] / src / media_source / media_tree.c
blob6dd7055bccc98493e97ed0c2eaaa8ec87b49928e
1 /*****************************************************************************
2 * media_tree.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 "media_tree.h"
27 #include <assert.h>
28 #include <vlc_common.h>
29 #include <vlc_arrays.h>
30 #include <vlc_atomic.h>
31 #include <vlc_input_item.h>
32 #include <vlc_threads.h>
33 #include "libvlc.h"
35 struct vlc_media_tree_listener_id
37 const struct vlc_media_tree_callbacks *cbs;
38 void *userdata;
39 struct vlc_list node; /**< node of media_tree_private_t.listeners */
42 typedef struct
44 vlc_media_tree_t public_data;
46 struct vlc_list listeners; /**< list of vlc_media_tree_listener_id.node */
47 vlc_mutex_t lock;
48 vlc_atomic_rc_t rc;
49 } media_tree_private_t;
51 #define mt_priv(mt) container_of(mt, media_tree_private_t, public_data)
53 vlc_media_tree_t *
54 vlc_media_tree_New(void)
56 media_tree_private_t *priv = malloc(sizeof(*priv));
57 if (unlikely(!priv))
58 return NULL;
60 vlc_mutex_init(&priv->lock);
61 vlc_atomic_rc_init(&priv->rc);
62 vlc_list_init(&priv->listeners);
64 vlc_media_tree_t *tree = &priv->public_data;
65 input_item_node_t *root = &tree->root;
66 root->p_item = NULL;
67 TAB_INIT(root->i_children, root->pp_children);
69 return tree;
72 static inline void
73 vlc_media_tree_AssertLocked(vlc_media_tree_t *tree)
75 media_tree_private_t *priv = mt_priv(tree);
76 vlc_mutex_assert(&priv->lock);
79 #define vlc_media_tree_listener_foreach(listener, tree) \
80 vlc_list_foreach(listener, &mt_priv(tree)->listeners, node)
82 #define vlc_media_tree_NotifyListener(tree, listener, event, ...) \
83 do { \
84 if (listener->cbs->event) \
85 listener->cbs->event(tree, ##__VA_ARGS__, listener->userdata); \
86 } while(0)
88 #define vlc_media_tree_Notify(tree, event, ...) \
89 do { \
90 vlc_media_tree_AssertLocked(tree); \
91 vlc_media_tree_listener_id *listener; \
92 vlc_media_tree_listener_foreach(listener, tree) \
93 vlc_media_tree_NotifyListener(tree, listener, event, ##__VA_ARGS__); \
94 } while (0)
96 static bool
97 vlc_media_tree_FindNodeByMedia(input_item_node_t *parent,
98 const input_item_t *media,
99 input_item_node_t **result,
100 input_item_node_t **result_parent)
102 for (int i = 0; i < parent->i_children; ++i)
104 input_item_node_t *child = parent->pp_children[i];
105 if (child->p_item == media)
107 *result = child;
108 if (result_parent)
109 *result_parent = parent;
110 return true;
113 if (vlc_media_tree_FindNodeByMedia(child, media, result, result_parent))
114 return true;
117 return false;
120 static input_item_node_t *
121 vlc_media_tree_AddChild(input_item_node_t *parent, input_item_t *media);
123 static void
124 vlc_media_tree_AddSubtree(input_item_node_t *to, input_item_node_t *from)
126 for (int i = 0; i < from->i_children; ++i)
128 input_item_node_t *child = from->pp_children[i];
129 input_item_node_t *node = vlc_media_tree_AddChild(to, child->p_item);
130 if (unlikely(!node))
131 break; /* what could we do? */
133 vlc_media_tree_AddSubtree(node, child);
137 static void
138 media_subtree_changed(input_item_t *media, input_item_node_t *node,
139 void *userdata)
141 vlc_media_tree_t *tree = userdata;
143 vlc_media_tree_Lock(tree);
144 input_item_node_t *subtree_root;
145 /* TODO retrieve the node without traversing the tree */
146 bool found = vlc_media_tree_FindNodeByMedia(&tree->root, media,
147 &subtree_root, NULL);
148 if (!found) {
149 /* the node probably failed to be allocated */
150 vlc_media_tree_Unlock(tree);
151 return;
154 vlc_media_tree_AddSubtree(subtree_root, node);
155 vlc_media_tree_Notify(tree, on_children_reset, subtree_root);
156 vlc_media_tree_Unlock(tree);
159 static void
160 vlc_media_tree_DestroyRootNode(vlc_media_tree_t *tree)
162 input_item_node_t *root = &tree->root;
163 for (int i = 0; i < root->i_children; ++i)
164 input_item_node_Delete(root->pp_children[i]);
166 free(root->pp_children);
169 static void
170 vlc_media_tree_Delete(vlc_media_tree_t *tree)
172 media_tree_private_t *priv = mt_priv(tree);
173 vlc_media_tree_listener_id *listener;
174 vlc_list_foreach(listener, &priv->listeners, node)
175 free(listener);
176 vlc_list_init(&priv->listeners); /* reset */
177 vlc_media_tree_DestroyRootNode(tree);
178 vlc_mutex_destroy(&priv->lock);
179 free(tree);
182 void
183 vlc_media_tree_Hold(vlc_media_tree_t *tree)
185 media_tree_private_t *priv = mt_priv(tree);
186 vlc_atomic_rc_inc(&priv->rc);
189 void
190 vlc_media_tree_Release(vlc_media_tree_t *tree)
192 media_tree_private_t *priv = mt_priv(tree);
193 if (vlc_atomic_rc_dec(&priv->rc))
194 vlc_media_tree_Delete(tree);
197 void
198 vlc_media_tree_Lock(vlc_media_tree_t *tree)
200 media_tree_private_t *priv = mt_priv(tree);
201 vlc_mutex_lock(&priv->lock);
204 void
205 vlc_media_tree_Unlock(vlc_media_tree_t *tree)
207 media_tree_private_t *priv = mt_priv(tree);
208 vlc_mutex_unlock(&priv->lock);
211 static input_item_node_t *
212 vlc_media_tree_AddChild(input_item_node_t *parent, input_item_t *media)
214 input_item_node_t *node = input_item_node_Create(media);
215 if (unlikely(!node))
216 return NULL;
218 input_item_node_AppendNode(parent, node);
220 return node;
223 static void
224 vlc_media_tree_NotifyCurrentState(vlc_media_tree_t *tree,
225 vlc_media_tree_listener_id *listener)
227 vlc_media_tree_NotifyListener(tree, listener, on_children_reset,
228 &tree->root);
231 vlc_media_tree_listener_id *
232 vlc_media_tree_AddListener(vlc_media_tree_t *tree,
233 const struct vlc_media_tree_callbacks *cbs,
234 void *userdata, bool notify_current_state)
236 vlc_media_tree_listener_id *listener = malloc(sizeof(*listener));
237 if (unlikely(!listener))
238 return NULL;
239 listener->cbs = cbs;
240 listener->userdata = userdata;
242 media_tree_private_t *priv = mt_priv(tree);
243 vlc_media_tree_Lock(tree);
245 vlc_list_append(&listener->node, &priv->listeners);
247 if (notify_current_state)
248 vlc_media_tree_NotifyCurrentState(tree, listener);
250 vlc_media_tree_Unlock(tree);
251 return listener;
254 void
255 vlc_media_tree_RemoveListener(vlc_media_tree_t *tree,
256 vlc_media_tree_listener_id *listener)
258 vlc_media_tree_Lock(tree);
259 vlc_list_remove(&listener->node);
260 vlc_media_tree_Unlock(tree);
262 free(listener);
265 input_item_node_t *
266 vlc_media_tree_Add(vlc_media_tree_t *tree, input_item_node_t *parent,
267 input_item_t *media)
269 vlc_media_tree_AssertLocked(tree);
271 input_item_node_t *node = vlc_media_tree_AddChild(parent, media);
272 if (unlikely(!node))
273 return NULL;
275 vlc_media_tree_Notify(tree, on_children_added, parent, &node, 1);
277 return node;
280 bool
281 vlc_media_tree_Find(vlc_media_tree_t *tree, const input_item_t *media,
282 input_item_node_t **result,
283 input_item_node_t **result_parent)
285 vlc_media_tree_AssertLocked(tree);
287 /* quick & dirty depth-first O(n) implementation, with n the number of nodes
288 * in the tree */
289 return vlc_media_tree_FindNodeByMedia(&tree->root, media, result,
290 result_parent);
293 bool
294 vlc_media_tree_Remove(vlc_media_tree_t *tree, input_item_t *media)
296 vlc_media_tree_AssertLocked(tree);
298 input_item_node_t *node;
299 input_item_node_t *parent;
300 if (!vlc_media_tree_FindNodeByMedia(&tree->root, media, &node, &parent))
301 return false;
303 input_item_node_RemoveNode(parent, node);
304 vlc_media_tree_Notify(tree, on_children_removed, parent, &node, 1);
305 input_item_node_Delete(node);
306 return true;
309 static const input_preparser_callbacks_t input_preparser_callbacks = {
310 .on_subtree_added = media_subtree_changed,
313 void
314 vlc_media_tree_Preparse(vlc_media_tree_t *tree, libvlc_int_t *libvlc,
315 input_item_t *media)
317 #ifdef TEST_MEDIA_SOURCE
318 VLC_UNUSED(tree);
319 VLC_UNUSED(libvlc);
320 VLC_UNUSED(media);
321 VLC_UNUSED(input_preparser_callbacks);
322 #else
323 vlc_MetadataRequest(libvlc, media, META_REQUEST_OPTION_NONE,
324 &input_preparser_callbacks, tree, -1, NULL);
325 #endif