Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  media_tree.c   Sprache: C

 

/*****************************************************************************
 * media_tree.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_media_source.h>

#include <assert.h>
#include <vlc_common.h>
#include <vlc_arrays.h>
#include <vlc_atomic.h>
#include <vlc_input_item.h>
#include <vlc_threads.h>
#include <vlc_preparser.h>
#include "../libvlc.h"

struct vlc_media_tree_listener_id
{
    const struct vlc_media_tree_callbacks *cbs;
    void *userdata;
    struct vlc_list node; /**< node of media_tree_private_t.listeners */
};

typedef struct
{
    vlc_media_tree_t public_data;

    struct vlc_list listeners; /**< list of vlc_media_tree_listener_id.node */
    vlc_mutex_t lock;
    vlc_atomic_rc_t rc;
} media_tree_private_t;

#define mt_priv(mt) container_of(mt, media_tree_private_t, public_data)

vlc_media_tree_t *
vlc_media_tree_New(void)
{
    media_tree_private_t *priv = malloc(sizeof(*priv));
    if (unlikely(!priv))
        return NULL;

    vlc_mutex_init(&priv->lock);
    vlc_atomic_rc_init(&priv->rc);
    vlc_list_init(&priv->listeners);

    vlc_media_tree_t *tree = &priv->public_data;
    input_item_node_t *root = &tree->root;
    root->p_item = NULL;
    TAB_INIT(root->i_children, root->pp_children);

    return tree;
}

static inline void
vlc_media_tree_AssertLocked(vlc_media_tree_t *tree)
{
    media_tree_private_t *priv = mt_priv(tree);
    vlc_mutex_assert(&priv->lock);
}

#define vlc_media_tree_listener_foreach(listener, tree) \
    vlc_list_foreach(listener, &mt_priv(tree)->listeners, node)

#define vlc_media_tree_NotifyListener(tree, listener, event, ...) \
do { \
    if (listener->cbs->event) \
        listener->cbs->event(tree, ##__VA_ARGS__, listener->userdata); \
} while(0)

#define vlc_media_tree_Notify(tree, event, ...) \
do { \
    vlc_media_tree_AssertLocked(tree); \
    vlc_media_tree_listener_id *listener; \
    vlc_media_tree_listener_foreach(listener, tree) \
        vlc_media_tree_NotifyListener(tree, listener, event, ##__VA_ARGS__); \
} while (0)

static bool
vlc_media_tree_FindNodeByMedia(input_item_node_t *parent,
                               const input_item_t *media,
                               input_item_node_t **result,
                               input_item_node_t **result_parent)
{
    for (int i = 0; i < parent->i_children; ++i)
    {
        input_item_node_t *child = parent->pp_children[i];
        if (child->p_item == media)
        {
            *result = child;
            if (result_parent)
                *result_parent = parent;
            return true;
        }

        if (vlc_media_tree_FindNodeByMedia(child, media, result, result_parent))
            return true;
    }

    return false;
}

static void
vlc_media_tree_ClearChildren(input_item_node_t *root)
{
    for (int i = 0; i < root->i_children; ++i)
        input_item_node_Delete(root->pp_children[i]);

    free(root->pp_children);
    root->pp_children = NULL;
    root->i_children = 0;
}

static void
media_subtree_changed(vlc_preparser_req *req, input_item_node_t *node,
                      void *userdata)
{
    input_item_t *media = vlc_preparser_req_GetItem(req);
    vlc_media_tree_t *tree = userdata;

    vlc_media_tree_Lock(tree);
    input_item_node_t *subtree_root;
    /* TODO retrieve the node without traversing the tree */
    bool found = vlc_media_tree_FindNodeByMedia(&tree->root, media,
                                                &subtree_root, NULL);
    if (!found) {
        /* the node probably failed to be allocated */
        vlc_media_tree_Unlock(tree);
        return;
    }

    vlc_media_tree_ClearChildren(subtree_root);
    /* The nodes can be directly used, as the subtree callback is given
     * ownership of the input item node. */

    subtree_root->pp_children = node->pp_children;
    subtree_root->i_children = node->i_children;
    node->pp_children = NULL;
    node->i_children = 0;
    input_item_node_Delete(node);
    vlc_media_tree_Notify(tree, on_children_reset, subtree_root);
    vlc_media_tree_Unlock(tree);
}

static void
media_subtree_preparse_ended(vlc_preparser_req *req, int status, void *user_data)
{
    input_item_t *media = vlc_preparser_req_GetItem(req);
    vlc_media_tree_t *tree = user_data;

    vlc_media_tree_Lock(tree);
    input_item_node_t *subtree_root;
    /* TODO retrieve the node without traversing the tree */
    bool found = vlc_media_tree_FindNodeByMedia(&tree->root, media,
                                                &subtree_root, NULL);
    if (!found) {
        /* the node probably failed to be allocated */
        vlc_media_tree_Unlock(tree);
        return;
    }
    vlc_media_tree_Notify(tree, on_preparse_end, subtree_root, status);
    vlc_media_tree_Unlock(tree);
}

static inline void
vlc_media_tree_DestroyRootNode(vlc_media_tree_t *tree)
{
    vlc_media_tree_ClearChildren(&tree->root);
}

static void
vlc_media_tree_Delete(vlc_media_tree_t *tree)
{
    media_tree_private_t *priv = mt_priv(tree);
    vlc_media_tree_listener_id *listener;
    vlc_list_foreach(listener, &priv->listeners, node)
        free(listener);
    vlc_list_init(&priv->listeners); /* reset */
    vlc_media_tree_DestroyRootNode(tree);
    free(tree);
}

void
vlc_media_tree_Hold(vlc_media_tree_t *tree)
{
    media_tree_private_t *priv = mt_priv(tree);
    vlc_atomic_rc_inc(&priv->rc);
}

void
vlc_media_tree_Release(vlc_media_tree_t *tree)
{
    media_tree_private_t *priv = mt_priv(tree);
    if (vlc_atomic_rc_dec(&priv->rc))
        vlc_media_tree_Delete(tree);
}

void
vlc_media_tree_Lock(vlc_media_tree_t *tree)
{
    media_tree_private_t *priv = mt_priv(tree);
    vlc_mutex_lock(&priv->lock);
}

void
vlc_media_tree_Unlock(vlc_media_tree_t *tree)
{
    media_tree_private_t *priv = mt_priv(tree);
    vlc_mutex_unlock(&priv->lock);
}

static input_item_node_t *
vlc_media_tree_AddChild(input_item_node_t *parent, input_item_t *media)
{
    input_item_node_t *node = input_item_node_Create(media);
    if (unlikely(!node))
        return NULL;

    input_item_node_AppendNode(parent, node);

    return node;
}

static void
vlc_media_tree_NotifyCurrentState(vlc_media_tree_t *tree,
                                  vlc_media_tree_listener_id *listener)
{
    vlc_media_tree_NotifyListener(tree, listener, on_children_reset,
                                  &tree->root);
}

vlc_media_tree_listener_id *
vlc_media_tree_AddListener(vlc_media_tree_t *tree,
                           const struct vlc_media_tree_callbacks *cbs,
                           void *userdata, bool notify_current_state)
{
    vlc_media_tree_listener_id *listener = malloc(sizeof(*listener));
    if (unlikely(!listener))
        return NULL;
    listener->cbs = cbs;
    listener->userdata = userdata;

    media_tree_private_t *priv = mt_priv(tree);
    vlc_media_tree_Lock(tree);

    vlc_list_append(&listener->node, &priv->listeners);

    if (notify_current_state)
        vlc_media_tree_NotifyCurrentState(tree, listener);

    vlc_media_tree_Unlock(tree);
    return listener;
}

void
vlc_media_tree_RemoveListener(vlc_media_tree_t *tree,
                              vlc_media_tree_listener_id *listener)
{
    vlc_media_tree_Lock(tree);
    vlc_list_remove(&listener->node);
    vlc_media_tree_Unlock(tree);

    free(listener);
}

input_item_node_t *
vlc_media_tree_Add(vlc_media_tree_t *tree, input_item_node_t *parent,
                   input_item_t *media)
{
    vlc_media_tree_AssertLocked(tree);

    input_item_node_t *node = vlc_media_tree_AddChild(parent, media);
    if (unlikely(!node))
        return NULL;

    vlc_media_tree_Notify(tree, on_children_added, parent, &node, 1);

    return node;
}

bool
vlc_media_tree_Find(vlc_media_tree_t *tree, const input_item_t *media,
                    input_item_node_t **result,
                    input_item_node_t **result_parent)
{
    vlc_media_tree_AssertLocked(tree);

    /* quick & dirty depth-first O(n) implementation, with n the number of nodes
     * in the tree */

    return vlc_media_tree_FindNodeByMedia(&tree->root, media, result,
                                          result_parent);
}

bool
vlc_media_tree_Remove(vlc_media_tree_t *tree, input_item_t *media)
{
    vlc_media_tree_AssertLocked(tree);

    input_item_node_t *node;
    input_item_node_t *parent;
    if (!vlc_media_tree_FindNodeByMedia(&tree->root, media, &node, &parent))
        return false;

    input_item_node_RemoveNode(parent, node);
    vlc_media_tree_Notify(tree, on_children_removed, parent, &node, 1);
    input_item_node_Delete(node);
    return true;
}

static const struct vlc_preparser_cbs preparser_callbacks = {
    .on_ended = media_subtree_preparse_ended,
    .on_subtree_added = media_subtree_changed,
};

vlc_preparser_req *
vlc_media_tree_Preparse(vlc_media_tree_t *tree, vlc_preparser_t *parser,
                        input_item_t *media)
{
#ifdef TEST_MEDIA_SOURCE
    VLC_UNUSED(tree);
    VLC_UNUSED(parser);
    VLC_UNUSED(media);
    VLC_UNUSED(preparser_callbacks);
    return NULL;
#else
    vlc_preparser_req *req =
        vlc_preparser_req_NewParse(parser, media, VLC_PREPARSER_TYPE_PARSE |
                                   VLC_PREPARSER_OPTION_INTERACT |
                                   VLC_PREPARSER_OPTION_SUBITEMS,
                                   &preparser_callbacks, tree);
    if (req == NULL)
        return NULL;

    if (vlc_preparser_Submit(parser, req) != VLC_SUCCESS)
    {
        vlc_preparser_req_Release(req);
        return NULL;
    }

    return req;
#endif
}

Messung
CHZG
839610093

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104848
#Domains=416959