|
@@ -0,0 +1,154 @@
|
|
|
|
+# Idea synopsys
|
|
|
|
+
|
|
|
|
+Expose LibVLC API and plugins through a dynamically generated API, much
|
|
|
|
+alike how Wayland protocol is exposed with libwayland-client.
|
|
|
|
+
|
|
|
|
+# Motivation
|
|
|
|
+
|
|
|
|
+The libvlccore library is very flexible and has a lot of dynamic
|
|
|
|
+entrypoints that can be filled with features from different plugins.
|
|
|
|
+
|
|
|
|
+However, the libvlc API currently cannot be "modularised" into
|
|
|
|
+different plugins. Thus, every features brought by the plugin need
|
|
|
|
+their API to be exposed in static form as symbols.
|
|
|
|
+
|
|
|
|
+It means that:
|
|
|
|
+
|
|
|
|
+ - When libVLC exposes an API to use with the plugin, this plugin
|
|
|
|
+ becomes mandatory in libVLC builds, so it removes one of the main
|
|
|
|
+ interest of plugins from the user point of view.
|
|
|
|
+
|
|
|
|
+ - An API exposed by libVLC is meant to be stable, so as soon as the
|
|
|
|
+ API exists, VLC Core and libVLC layers are tied to it.
|
|
|
|
+
|
|
|
|
+ - It exposes a lot of symbols in libVLC, which are usually redundant
|
|
|
|
+ with what libvlccore can expose.
|
|
|
|
+
|
|
|
|
+Instead, the motivation here is to see libVLC through the concept of:
|
|
|
|
+
|
|
|
|
+ « Plugin as an API »
|
|
|
|
+
|
|
|
|
+The libvlc interface can be stretched to the minimal to setup libvlc
|
|
|
|
+and expose global interfaces. Then most of the code can just be inline
|
|
|
|
+structure and inline code to setup and use those structures from the
|
|
|
|
+plugins.
|
|
|
|
+
|
|
|
|
+In particular, it also allow different level of support without ever
|
|
|
|
+breaking the API/ABI at the link level.
|
|
|
|
+
|
|
|
|
+Many features at Videolabs for clients, or prototypes of API that need
|
|
|
|
+to be tested and iterated before going to the stable API support level
|
|
|
|
+are currently made available directly through libVLC symbols, which
|
|
|
|
+means forks, unfinished function that need to be stabilized and
|
|
|
|
+sometimes big crude hacks to make things work.
|
|
|
|
+
|
|
|
|
+By exposing this API at the plugin level, it's possible to expose
|
|
|
|
+the work-in-progress features and customers features without making
|
|
|
|
+transgressions on the public «supported» libVLC API, and most of the
|
|
|
|
+time expose those features as plugins in official release instead of
|
|
|
|
+libVLC builds.
|
|
|
|
+
|
|
|
|
+# Example client code
|
|
|
|
+
|
|
|
|
+```
|
|
|
|
+libvlc_instance *instance = libvlc_instance_New(argc, argv);
|
|
|
|
+
|
|
|
|
+libvlc_plugin_interactive_zoom *zoom = NULL;
|
|
|
|
+
|
|
|
|
+static void object_added(
|
|
|
|
+ libvlc_discoverer *discoverer,
|
|
|
|
+ libvlc_object *object
|
|
|
|
+) {
|
|
|
|
+ /* The libvlc_discoverer_attach_object must do some dark magic for
|
|
|
|
+ * the binding of protocol. In particular, it must return an object
|
|
|
|
+ * of type `libvlc_plugin_interactive_zoom *` (automatically casted
|
|
|
|
+ * from `void *` in C) that must be created by the probe proxy.
|
|
|
|
+ if (object->name == "vlc_filter_interactive_zoom")
|
|
|
|
+ zoom = libvlc_plugin_interactive_zoom_attach_object(
|
|
|
|
+ discoverer, object, INTERACTIVE_ZOOM_VERSION, NULL /*opaque*/
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ /* The code above is the type safe variant of
|
|
|
|
+ zoom = libvlc_discoverer_attach_object(
|
|
|
|
+ discoverer, object,
|
|
|
|
+ libvlc_plugin_interactive_zoom_interface,
|
|
|
|
+ INTERACTIVE_ZOOM_VERSION
|
|
|
|
+ */
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+libvlc_discovery_callbacks callbacks = {
|
|
|
|
+ .added = object_added,
|
|
|
|
+ .removed = object_removed,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+libvlc_discoverer *discoverer = libvlc_discoverer_new(instance);
|
|
|
|
+
|
|
|
|
+/* Enable some global features */
|
|
|
|
+libvlc_discoverer_add_option(/* ... */);
|
|
|
|
+libvlc_discoverer_add_option(/* ... */);
|
|
|
|
+libvlc_discoverer_add_option(/* ... */);
|
|
|
|
+
|
|
|
|
+/* Setup global objects */
|
|
|
|
+libvlc_discover(instance, &callbacks);
|
|
|
|
+
|
|
|
|
+/* global objects are attached to the libvlc discoverer */
|
|
|
|
+
|
|
|
|
+/* Interface callback for zoom */
|
|
|
|
+static int onZoomPerformed(zoom_params params) {
|
|
|
|
+ /* Check that we can use the interactive zoom API */
|
|
|
|
+ if (zoom == NULL)
|
|
|
|
+ return ENOTSUPPORTED;
|
|
|
|
+
|
|
|
|
+ libvlc_plugin_interactive_zoom_zoom(zoom, params.x, params.y);
|
|
|
|
+}
|
|
|
|
+```
|
|
|
|
+
|
|
|
|
+# Exemple server code
|
|
|
|
+
|
|
|
|
+```
|
|
|
|
+/* create a proxy interface object which must expose the interface */
|
|
|
|
+static void *create_proxy(
|
|
|
|
+ vlc_api_t *api,
|
|
|
|
+ const char *name,
|
|
|
|
+ unsigned version,
|
|
|
|
+ const void *listener;
|
|
|
|
+) {
|
|
|
|
+ VLC_UNUSED(name);
|
|
|
|
+
|
|
|
|
+ /* Generated:
|
|
|
|
+ * - libvlc_listener_plugin_interactive_zoom (events handling)
|
|
|
|
+ * - libvlc_plugin_interactive_zoom (requests pointer table)
|
|
|
|
+ **/
|
|
|
|
+ struct libvlc_wrapper_plugin_interactive_zoom {
|
|
|
|
+ libvlc_listener_plugin_interactive_zoom *listener;
|
|
|
|
+ libvlc_plugin_interactive_zoom interface;
|
|
|
|
+ };
|
|
|
|
+ libvlc_wrapper_plugin_interactive_zoom *zoom = malloc(sizeof *zoom);
|
|
|
|
+ if (!zoom) return NULL;
|
|
|
|
+
|
|
|
|
+ zoom->listener = listener;
|
|
|
|
+ zoom->interface = (struct libvlc_plugin_interactive_zoom) {
|
|
|
|
+ .zoom = DoZoom
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ return &zoom->interface;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* probe proxy exposing the API entrypoint and the creation
|
|
|
|
+ * function */
|
|
|
|
+static int OpenAPI(vlc_api_t *api)
|
|
|
|
+{
|
|
|
|
+ vlc_api_DefineGlobalObject(api,
|
|
|
|
+ "vlc_filter_interactive_zoom",
|
|
|
|
+ API_VERSION, &create_proxy)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+vlc_module_begin()
|
|
|
|
+ add_capability("api interface", API_VERSION)
|
|
|
|
+ set_callback(OpenAPI)
|
|
|
|
+
|
|
|
|
+ add_submodule()
|
|
|
|
+ add_capability("video filter", 0)
|
|
|
|
+ set_callbacks(Open, Close)
|
|
|
|
+vlc_module_end()
|
|
|
|
+```
|