[vlc-devel] [RFC PATCHv2 1/6] add a new type of module: vlc_renderer

Thomas Guillem thomas at gllm.fr
Wed Mar 2 15:58:19 CET 2016


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 | 203 +++++++++++++++++++++++++++++++
 src/Makefile.am        |   2 +
 src/libvlccore.sym     |  13 ++
 src/misc/renderer.c    | 323 +++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 543 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..c084dcb
--- /dev/null
+++ b/include/vlc_renderer.h
@@ -0,0 +1,203 @@
+/*****************************************************************************
+ * 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
+
+/**
+ * @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;
+
+/** Renderer flags */
+typedef enum {
+    VLC_RENDERER_CAN_AUDIO  = 0x0001,  /**< Renderer can render audio */
+    VLC_RENDERER_CAN_VIDEO  = 0x0002,  /**< Renderer can render video */
+} vlc_renderer_flags;
+
+/**
+ * Create a new renderer item
+ *
+ * @param psz_module name of the module to use with this renderer, must be valid
+ * @param psz_host Host or IP of the item, must be valid
+ * @param i_port TCP/UDP port of the item, 0 for unknown port
+ * @param psz_name name of the item
+ * @param e_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_module, const char *psz_host,
+                      uint16_t i_port, const char *psz_name,
+                      vlc_renderer_flags e_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);
+
+/**
+ *  Returns true if the renderer item has the same parameters
+ */
+VLC_API bool
+vlc_renderer_item_equals(const vlc_renderer_item *p_item,
+                         const char *psz_module, const char *psz_host,
+                         uint16_t i_port, vlc_renderer_flags e_flags);
+/**
+ * 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_host(const vlc_renderer_item *p_item);
+
+/**
+ * Get the port of a renderer item
+ */
+VLC_API uint16_t
+vlc_renderer_item_port(const vlc_renderer_item *p_item);
+
+/**
+ * Get the flags of a renderer item
+ */
+VLC_API vlc_renderer_flags
+vlc_renderer_item_flags(const vlc_renderer_item *p_item);
+
+/**
+ * Get the VLC option used to run this renderer
+ */
+VLC_API const char *
+vlc_renderer_item_option(const vlc_renderer_item *p_item);
+
+/**
+ * @}
+ * @defgroup vlc_renderer_service VLC renderer functions
+ * @{
+ */
+
+/**
+ * Get the volume of the loaded renderer
+ *
+ * @param pf_volume a pointer to the volume (0.0 to 1.0)
+ * @return VLC_SUCCESS on success, VLC_ENOOBJ if no module is loaded, or an
+ * other VLC error code
+ */
+VLC_API int
+vlc_renderer_volume_get(vlc_renderer *p_renderer, float *pf_volume);
+
+/**
+ * Set the volume of the loaded renderer
+ *
+ * @param f_volume the volume (0.0 to 1.0)
+ * @return VLC_SUCCESS on success, VLC_ENOOBJ if no module is loaded, or an
+ * other VLC error code
+ */
+VLC_API int
+vlc_renderer_volume_set(vlc_renderer *p_renderer, float f_volume);
+
+/**
+ * Get the mute state of the loaded renderer
+ *
+ * @return VLC_SUCCESS on success, VLC_ENOOBJ if no module is loaded, or an
+ * other VLC error code
+ */
+VLC_API int
+vlc_renderer_mute_get(vlc_renderer *p_renderer, bool *b_mute);
+
+/**
+ * Get the mute state of the loaded renderer
+ *
+ * @return VLC_SUCCESS on success, VLC_ENOOBJ if no module is loaded, or an
+ * other VLC error code
+ */
+VLC_API int
+vlc_renderer_mute_set(vlc_renderer *p_renderer, bool b_mute);
+
+/**
+ * @}
+ * @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;
+
+    const vlc_renderer_item *p_item;
+
+    /**
+     * Called on vlc_renderer_set_input()
+     */
+    int     (*pf_set_input)(vlc_renderer *p_renderer, input_thread_t *p_input);
+    /**
+     * Called on vlc_renderer_volume_get()
+     */
+    int     (*pf_volume_get)(vlc_renderer *p_renderer, float *pf_volume);
+    /**
+     * Called on vlc_renderer_volume_set()
+     */
+    int     (*pf_volume_set)(vlc_renderer *p_renderer, float f_volume);
+    /**
+     * Called on vlc_renderer_mute_get()
+     */
+    int     (*pf_mute_get)(vlc_renderer *p_renderer, bool *pb_mute);
+    /**
+     * Called on vlc_renderer_mute_set()
+     */
+    int     (*pf_mute_set)(vlc_renderer *p_renderer, bool b_mute);
+};
+
+/** @} @} */
+
+/* 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)
+
+/* Returns true if the renderer is created from this string option */
+bool
+vlc_renderer_equals(const vlc_renderer *p_renderer, const char *psz_renderer);
+
+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..572e293 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -734,3 +734,16 @@ 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_item_equals
+vlc_renderer_item_name
+vlc_renderer_item_host
+vlc_renderer_item_port
+vlc_renderer_item_flags
+vlc_renderer_item_option
+vlc_renderer_volume_get
+vlc_renderer_volume_set
+vlc_renderer_mute_get
+vlc_renderer_mute_set
diff --git a/src/misc/renderer.c b/src/misc/renderer.c
new file mode 100644
index 0000000..f6ffbd9
--- /dev/null
+++ b/src/misc/renderer.c
@@ -0,0 +1,323 @@
+/*****************************************************************************
+ * 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_module;
+    char *psz_host;
+    uint16_t i_port;
+    vlc_renderer_flags e_flags;
+    char *psz_name;
+    char *psz_option;
+    atomic_uint refs;
+};
+
+struct renderer_priv
+{
+    vlc_renderer        s;
+    bool                b_has_input;
+    vlc_renderer_item * p_item;
+};
+
+vlc_renderer_item *
+vlc_renderer_item_new(const char *psz_module, const char *psz_host,
+                      uint16_t i_port, const char *psz_name,
+                      vlc_renderer_flags e_flags)
+{
+    assert(psz_module != NULL && psz_host != NULL);
+
+    vlc_renderer_item *p_item = calloc(1, sizeof(vlc_renderer_item));
+    if (p_item == NULL)
+        return NULL;
+
+    if (psz_name == NULL)
+        psz_name = "";
+    if ((p_item->psz_module = strdup(psz_module)) == NULL
+     || (p_item->psz_host = strdup(psz_host)) == NULL
+     || (p_item->psz_name = strdup(psz_name)) == NULL
+     || asprintf(&p_item->psz_option, "%s{host=%s,port=%u,name=%s,flags=%d}",
+                 psz_module, psz_host, i_port, psz_name, e_flags) == -1)
+    {
+        free(p_item->psz_module);
+        free(p_item->psz_host);
+        free(p_item->psz_name);
+        free(p_item);
+        return NULL;
+    }
+    p_item->i_port = i_port;
+    p_item->e_flags = e_flags;
+    atomic_init(&p_item->refs, 1);
+    return p_item;
+}
+
+static vlc_renderer_item *
+renderer_item_new_from_option(const char *psz_renderer)
+{
+    config_chain_t *p_cfg = NULL;
+    char *psz_module, *psz_host = NULL, *psz_name = NULL;
+    vlc_renderer_flags e_flags = 0;
+    uint16_t i_port = 0;
+    free(config_ChainCreate(&psz_module, &p_cfg, psz_renderer));
+
+    config_chain_t *p_read_cfg = p_cfg;
+    while (p_read_cfg != NULL)
+    {
+        if (!strcmp(p_cfg->psz_name, "host"))
+            psz_host = p_cfg->psz_value;
+        else if (!strcmp(p_cfg->psz_name, "name"))
+            psz_name = p_cfg->psz_value;
+        else if (!strcmp(p_cfg->psz_name, "port"))
+        {
+            int i_val = atoi(p_cfg->psz_value);
+            if (i_val >= 0 && i_val <= UINT16_MAX)
+                i_port = i_val;
+        }
+        else if (!strcmp(p_cfg->psz_name, "flags"))
+            e_flags = atoi(p_cfg->psz_value);
+        p_read_cfg = p_read_cfg->p_next;
+    }
+
+    vlc_renderer_item *p_item = NULL;
+    if (psz_module != NULL && psz_host != NULL)
+        p_item = vlc_renderer_item_new(psz_module, psz_host, i_port, psz_name,
+                                       e_flags);
+    free(psz_module);
+    config_ChainDestroy( p_cfg );
+
+    return p_item;
+}
+
+const char *
+vlc_renderer_item_name(const vlc_renderer_item *p_item)
+{
+    assert(p_item != NULL);
+
+    return p_item->psz_name != NULL ? p_item->psz_name : p_item->psz_module;
+}
+
+bool
+vlc_renderer_item_equals(const vlc_renderer_item *p_item,
+                         const char *psz_module, const char *psz_host,
+                         uint16_t i_port, vlc_renderer_flags e_flags)
+{
+    assert(p_item != NULL);
+    return (p_item->i_port == i_port || !p_item->i_port || !i_port)
+            && !strcmp(p_item->psz_host, psz_host)
+            && !strcmp(p_item->psz_module, psz_module)
+            && p_item->e_flags == e_flags;
+}
+
+const char *
+vlc_renderer_item_host(const vlc_renderer_item *p_item)
+{
+    assert(p_item != NULL);
+
+    return p_item->psz_host;
+}
+
+uint16_t
+vlc_renderer_item_port(const vlc_renderer_item *p_item)
+{
+    assert(p_item != NULL);
+
+    return p_item->i_port;
+}
+
+vlc_renderer_flags
+vlc_renderer_item_flags(const vlc_renderer_item *p_item)
+{
+    assert(p_item != NULL);
+
+    return p_item->e_flags;
+}
+
+const char *
+vlc_renderer_item_option(const vlc_renderer_item *p_item)
+{
+    assert(p_item != NULL);
+
+    return p_item->psz_option;
+}
+
+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_module);
+    free(p_item->psz_host);
+    free(p_item->psz_name);
+    free(p_item->psz_option);
+    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_renderer_item_release(p_priv->p_item);
+}
+
+#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;
+
+    p_priv->p_item = renderer_item_new_from_option(psz_renderer);
+    if (p_priv->p_item == NULL)
+    {
+        vlc_object_release(p_obj);
+        return NULL;
+    }
+    p_renderer->p_item = p_priv->p_item;
+
+    p_renderer->p_module = module_need(p_renderer, "renderer",
+                                       p_priv->p_item->psz_module, true);
+    if (p_renderer->p_module == NULL)
+    {
+        vlc_renderer_item_release(p_priv->p_item);
+        vlc_object_release(p_obj);
+        return NULL;
+    }
+    assert(p_renderer->pf_set_input);
+    vlc_object_set_destructor(p_renderer, renderer_destructor);
+
+    return p_renderer;
+}
+
+bool vlc_renderer_equals(const vlc_renderer *p_renderer,
+                         const char *psz_renderer)
+{
+    vlc_renderer_item *p_item = renderer_item_new_from_option(psz_renderer);
+    if (p_item == NULL)
+        return NULL;
+    else
+    {
+        bool b_ret = !strcmp(p_renderer->p_item->psz_option, p_item->psz_option);
+        vlc_renderer_item_release(p_item);
+        return b_ret;
+    }
+}
+
+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;
+}
+
+int
+vlc_renderer_volume_get(vlc_renderer *p_renderer, float *pf_volume)
+{
+    assert(p_renderer != NULL);
+
+    if (!pf_volume)
+        return VLC_EGENERIC;
+
+    if (p_renderer->pf_volume_get == NULL)
+        return VLC_ENOOBJ;
+
+    return p_renderer->pf_volume_get(p_renderer, pf_volume);
+}
+
+int
+vlc_renderer_volume_set(vlc_renderer *p_renderer, float f_volume)
+{
+    assert(p_renderer != NULL);
+
+    if (p_renderer->pf_volume_set == NULL)
+        return VLC_ENOOBJ;
+
+    return p_renderer->pf_volume_set(p_renderer, f_volume);
+}
+
+int
+vlc_renderer_mute_get(vlc_renderer *p_renderer, bool *pb_mute)
+{
+    assert(p_renderer != NULL && pb_mute != NULL);
+
+    if (p_renderer->pf_mute_get == NULL)
+        return VLC_ENOOBJ;
+
+    return p_renderer->pf_mute_get(p_renderer, pb_mute);
+}
+
+int
+vlc_renderer_mute_set(vlc_renderer *p_renderer, bool b_mute)
+{
+    assert(p_renderer != NULL);
+
+    if (p_renderer->pf_mute_set == NULL)
+        return VLC_ENOOBJ;
+
+    return p_renderer->pf_mute_set(p_renderer, b_mute);
+}
-- 
2.7.0



More information about the vlc-devel mailing list