[vlc-devel] [PATCHv3 01/12] add a new type of module: vlc_renderer

Rémi Denis-Courmont remi at remlab.net
Wed Mar 30 20:15:38 CEST 2016


On Tuesday 29 March 2016 15:06:32 Thomas Guillem wrote:
> This new type of module will be used by renderers (chromecast, UPnP
> Renderer, miracast, airport, DIAL, ConeCast) to configure a VLC
> input_thread for rendering, like configuring a sout according to the
> renderer ip and capabilities.
> 
> This API is experimental and has been tested only for chromecast, it may
> move in the future when implementing others renderers.
> 
> Also-by: Steve Lhomme <robux4 at videolabs.io>
> ---
>  include/vlc_common.h   |   2 +
>  include/vlc_renderer.h | 130 ++++++++++++++++++++++++++++
>  src/Makefile.am        |   2 +
>  src/libvlccore.sym     |   7 ++
>  src/misc/renderer.c    | 223
> +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 364
> insertions(+)
>  create mode 100644 include/vlc_renderer.h
>  create mode 100644 src/misc/renderer.c
> 
> diff --git a/include/vlc_common.h b/include/vlc_common.h
> index 296439e..431fbb4 100644
> --- a/include/vlc_common.h
> +++ b/include/vlc_common.h
> @@ -208,6 +208,8 @@ typedef struct playlist_item_t playlist_item_t;
>  typedef struct services_discovery_t services_discovery_t;
>  typedef struct services_discovery_sys_t services_discovery_sys_t;
>  typedef struct playlist_add_t playlist_add_t;
> +typedef struct vlc_renderer_item vlc_renderer_item;
> +typedef struct vlc_renderer vlc_renderer;
> 
>  /* Modules */
>  typedef struct module_t module_t;
> diff --git a/include/vlc_renderer.h b/include/vlc_renderer.h
> new file mode 100644
> index 0000000..5c462d9
> --- /dev/null
> +++ b/include/vlc_renderer.h
> @@ -0,0 +1,130 @@
> +/**************************************************************************
> *** + * vlc_renderer.h: VLC renderer
> +
> ***************************************************************************
> ** + * Copyright (C) 2016 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. +
> ***************************************************************************
> **/ +
> +#ifndef VLC_RENDERER_H
> +#define VLC_RENDERER_H 1
> +
> +#include <vlc_url.h>
> +
> +/**
> + * @defgroup vlc_renderer VLC renderer
> + * @{
> + * @file
> + * This file declares VLC renderer structures and functions
> + * @defgroup vlc_renderer_item VLC renderer items
> + * @{
> + */
> +
> +typedef struct vlc_renderer_item vlc_renderer_item;
> +
> +#define VLC_RENDERER_CAN_AUDIO 0x0001
> +#define VLC_RENDERER_CAN_VIDEO 0x0002
> +
> +/**
> + * Create a new renderer item
> + *
> + * @param psz_name name of the item
> + * @param psz_uri uri of the renderer item, must contains a valid protocol
> and + * a valid host
> + * @param i_flags flags for the item
> + * @return a renderer item or NULL in case of error
> + */
> +VLC_API vlc_renderer_item *
> +vlc_renderer_item_new(const char *psz_name, const char *psz_uri,
> +                      int i_flags) VLC_USED;
> +
> +/**
> + * Hold a renderer item, i.e. creates a new reference
> + */
> +VLC_API vlc_renderer_item *
> +vlc_renderer_item_hold(vlc_renderer_item *p_item);
> +
> +/**
> + * Releases a renderer item, i.e. decrements its reference counter
> + */
> +VLC_API void
> +vlc_renderer_item_release(vlc_renderer_item *p_item);
> +
> +/**
> + * Get the name of a renderer item
> + */
> +VLC_API const char *
> +vlc_renderer_item_name(const vlc_renderer_item *p_item);
> +
> +/**
> + * Get the host of a renderer item
> + */
> +VLC_API const char *
> +vlc_renderer_item_uri(const vlc_renderer_item *p_item);
> +
> +/**
> + * Get the flags of a renderer item
> + */
> +VLC_API int
> +vlc_renderer_item_flags(const vlc_renderer_item *p_item);
> +
> +/**
> +  * Check if a renderer corresponds to this URI
> +  */
> +VLC_API
> +bool vlc_renderer_equals(vlc_renderer *p_renderer, const char *psz_uri);
> +
> +/**
> + * @}
> + * @defgroup vlc_renderer_module VLC renderer module
> + * @{
> + */
> +
> +typedef struct vlc_renderer vlc_renderer;
> +typedef struct vlc_renderer_sys vlc_renderer_sys;
> +struct vlc_renderer
> +{
> +    VLC_COMMON_MEMBERS
> +    /**
> +     */
> +    module_t            *p_module;
> +    vlc_renderer_sys    *p_sys;
> +
> +    vlc_url_t           target;
> +
> +    /**
> +     * Handle a new input thread.
> +     *
> +     * p_renderer->target is a valid url with a valid psz_protocol and
> valid +     * psz_host.
> +     *
> +     * @param p_input new input to handle, or NULL to stop the current one.
> +     */
> +    int     (*pf_set_input)(vlc_renderer *p_renderer, input_thread_t
> *p_input); +};
> +
> +/** @} @} */
> +
> +/* Internal API */
> +
> +/* Release with vlc_object_release */
> +vlc_renderer *
> +vlc_renderer_new(vlc_object_t *p_obj, const char *psz_renderer);
> +#define vlc_renderer_new(a, b) vlc_renderer_new(VLC_OBJECT(a), b)
> +
> +int
> +vlc_renderer_set_input(vlc_renderer *p_renderer, input_thread_t *p_input);
> +
> +#endif
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 5ee185f..4d5fd6c 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -82,6 +82,7 @@ pluginsinclude_HEADERS = \
>  	../include/vlc_services_discovery.h \
>  	../include/vlc_fingerprinter.h \
>  	../include/vlc_interrupt.h \
> +	../include/vlc_renderer.h \
>  	../include/vlc_sout.h \
>  	../include/vlc_spu.h \
>  	../include/vlc_stream.h \
> @@ -444,6 +445,7 @@ SOURCES_libvlc_common = \
>  	misc/interrupt.h \
>  	misc/interrupt.c \
>  	misc/keystore.c \
> +	misc/renderer.c \
>  	modules/modules.h \
>  	modules/modules.c \
>  	modules/bank.c \
> diff --git a/src/libvlccore.sym b/src/libvlccore.sym
> index 0d69d14..a6f292e 100644
> --- a/src/libvlccore.sym
> +++ b/src/libvlccore.sym
> @@ -734,3 +734,10 @@ addons_manager_Remove
>  addon_entry_New
>  addon_entry_Hold
>  addon_entry_Release
> +vlc_renderer_item_new
> +vlc_renderer_item_hold
> +vlc_renderer_item_release
> +vlc_renderer_equals
> +vlc_renderer_item_name
> +vlc_renderer_item_uri
> +vlc_renderer_item_flags
> diff --git a/src/misc/renderer.c b/src/misc/renderer.c
> new file mode 100644
> index 0000000..2a64f59
> --- /dev/null
> +++ b/src/misc/renderer.c
> @@ -0,0 +1,223 @@
> +/**************************************************************************
> *** + * renderer.c: Renderers
> +
> ***************************************************************************
> ** + * Copyright (C) 2016 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 <assert.h>
> +#include <stdint.h>
> +
> +#include <vlc_common.h>
> +#include <vlc_atomic.h>
> +#include <vlc_renderer.h>
> +#include <vlc_modules.h>
> +#include <libvlc.h>
> +#include "../lib/libvlc_internal.h"
> +
> +struct vlc_renderer_item
> +{
> +    char *psz_name;
> +    char *psz_uri;
> +    int i_flags;
> +    atomic_uint refs;
> +};
> +
> +struct renderer_priv
> +{
> +    vlc_renderer        s;
> +    bool                b_has_input;
> +};
> +
> +vlc_renderer_item *
> +vlc_renderer_item_new(const char *psz_name, const char *psz_uri, int
> i_flags) +{
> +    assert(psz_uri != NULL);
> +    vlc_renderer_item *p_item = NULL;
> +    vlc_url_t url;
> +    vlc_UrlParse(&url, psz_uri);
> +
> +    if (url.psz_protocol == NULL || url.psz_host == NULL)
> +        goto error;
> +
> +    p_item = calloc(1, sizeof(vlc_renderer_item));
> +    if (unlikely(p_item == NULL))
> +        goto error;
> +
> +    if (psz_name != NULL)
> +        p_item->psz_name = strdup(psz_name);
> +    else if (asprintf(&p_item->psz_name, "%s (%s)", url.psz_protocol,
> +                      url.psz_host) == -1)
> +        p_item->psz_name = NULL;
> +    if (p_item->psz_name == NULL)
> +        goto error;
> +
> +    if ((p_item->psz_uri = strdup(psz_uri)) == NULL)
> +    {
> +        free(p_item->psz_name);
> +        goto error;
> +    }
> +
> +    p_item->i_flags = i_flags;
> +    atomic_init(&p_item->refs, 1);
> +    vlc_UrlClean(&url);
> +    return p_item;
> +
> +error:
> +    vlc_UrlClean(&url);
> +    free(p_item);
> +    return NULL;
> +}
> +
> +const char *
> +vlc_renderer_item_name(const vlc_renderer_item *p_item)
> +{
> +    assert(p_item != NULL);
> +
> +    return p_item->psz_name;
> +}
> +
> +const char *
> +vlc_renderer_item_uri(const vlc_renderer_item *p_item)
> +{
> +    assert(p_item != NULL);
> +
> +    return p_item->psz_uri;
> +}
> +
> +int
> +vlc_renderer_item_flags(const vlc_renderer_item *p_item)
> +{
> +    assert(p_item != NULL);
> +
> +    return p_item->i_flags;
> +}
> +
> +vlc_renderer_item *
> +vlc_renderer_item_hold(vlc_renderer_item *p_item)
> +{
> +    assert(p_item != NULL);
> +
> +    atomic_fetch_add(&p_item->refs, 1);
> +    return p_item;
> +}
> +
> +void
> +vlc_renderer_item_release(vlc_renderer_item *p_item)
> +{
> +    assert(p_item != NULL);
> +
> +    if (atomic_fetch_sub(&p_item->refs, 1) != 1)
> +        return;
> +    free(p_item->psz_name);
> +    free(p_item->psz_uri);
> +    free(p_item);
> +}
> +
> +static inline struct renderer_priv *
> +renderer_priv(vlc_renderer *p_renderer)
> +{
> +    return (struct renderer_priv *)p_renderer;
> +}
> +
> +static void
> +renderer_destructor(vlc_object_t *p_obj)
> +{
> +    vlc_renderer *p_renderer = (vlc_renderer *)p_obj;
> +    struct renderer_priv *p_priv = renderer_priv(p_renderer);
> +
> +    if (p_priv->b_has_input)
> +        vlc_renderer_set_input(p_renderer, NULL);
> +
> +    module_unneed(p_renderer, p_renderer->p_module);
> +
> +    vlc_UrlClean(&p_renderer->target);
> +}
> +
> +#undef vlc_renderer_new
> +vlc_renderer *
> +vlc_renderer_new(vlc_object_t *p_obj, const char *psz_renderer)
> +{
> +    assert(p_obj != NULL && psz_renderer != NULL);
> +    struct renderer_priv *p_priv =
> +        vlc_custom_create(p_obj, sizeof (*p_priv), "renderer");
> +    if (p_priv == NULL)
> +        return NULL;
> +    vlc_renderer *p_renderer = &p_priv->s;
> +
> +    vlc_UrlParse(&p_renderer->target, psz_renderer);
> +    if (p_renderer->target.psz_protocol == NULL
> +     || p_renderer->target.psz_host == NULL)
> +    {
> +        vlc_object_release(p_renderer);
> +        return NULL;
> +    }
> +    p_renderer->p_module = module_need(p_renderer, "renderer",
> +                                       p_renderer->target.psz_protocol,
> true); +    if (p_renderer->p_module == NULL)
> +    {
> +        vlc_UrlClean(&p_renderer->target);
> +        vlc_object_release(p_renderer);
> +        return NULL;
> +    }
> +    assert(p_renderer->pf_set_input);
> +    vlc_object_set_destructor(p_renderer, renderer_destructor);
> +
> +    return p_renderer;
> +}
> +
> +int
> +vlc_renderer_set_input(vlc_renderer *p_renderer, input_thread_t *p_input)
> +{
> +    assert(p_renderer != NULL);
> +    struct renderer_priv *p_priv = renderer_priv(p_renderer);
> +
> +    int i_ret = p_renderer->pf_set_input(p_renderer, p_input);
> +    if (i_ret == VLC_SUCCESS)
> +        p_priv->b_has_input = p_input != NULL;
> +    else
> +        p_priv->b_has_input = false;
> +
> +    return i_ret;
> +}
> +
> +bool
> +vlc_renderer_equals(vlc_renderer *p_renderer, const char *psz_renderer)

Again: don´t do that. This function does not work and it never will.

> +{
> +    assert(p_renderer->target.psz_protocol != NULL
> +        && p_renderer->target.psz_host != NULL);
> +
> +    vlc_url_t url;
> +    vlc_UrlParse(&url, psz_renderer);
> +    if (url.psz_protocol == NULL || url.psz_host == NULL)
> +    {
> +        vlc_UrlClean(&url);
> +        return false;
> +    }
> +    const char *psz_option1 = p_renderer->target.psz_option != NULL
> +                            ? p_renderer->target.psz_option : "";
> +    const char *psz_option2 = url.psz_option != NULL ? url.psz_option : "";
> +    bool b_ret = !strcmp(p_renderer->target.psz_protocol,
> url.psz_protocol) +              && !strcmp(p_renderer->target.psz_host,
> url.psz_host) +              && !strcmp(psz_option1, psz_option2)
> +              && p_renderer->target.i_port == url.i_port;
> +    vlc_UrlClean(&url);
> +    return b_ret;
> +}

-- 
Rémi Denis-Courmont
http://www.remlab.net/



More information about the vlc-devel mailing list