diff --git a/include/vlc_preparser_ipc.h b/include/vlc_preparser_ipc.h new file mode 100644 index 0000000000..a4b999c6d1 --- /dev/null +++ b/include/vlc_preparser_ipc.h @@ -0,0 +1,348 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/***************************************************************************** + * vlc_preparser_serializer.h: preparser serializer + ***************************************************************************** + * Copyright © 2025 Videolabs, VideoLAN and VLC authors + * + * Authors: Gabriel Lafond Thenaille + *****************************************************************************/ + +#ifndef VLC_PREPARSER_IPC_H +#define VLC_PREPARSER_IPC_H + +#include +#include +#include +#include +#include +#include + +/** + * @defgroup preparser_ipc Preparser IPC + * @ingroup preparser + * @{ + * @file + * VLC Preparser IPC API + * + * @defgroup preparser_msg preparser message api + * @ingroup preparser_ipc + * @{ + */ + +/** + * Request types + */ +enum vlc_preparser_msg_req_type { + /** + * Type of the request emitted by a `vlc_preparser_Push` call. + */ + VLC_PREPARSER_MSG_REQ_TYPE_PARSE, + /** + * Type of the request emitted by a `vlc_preparser_GenerateThumbnail` + * call. + */ + VLC_PREPARSER_MSG_REQ_TYPE_THUMBNAIL, + /** + * Type of the request emitted by a + * `vlc_preparser_GenerateThumbnailToFiles` call. + */ + VLC_PREPARSER_MSG_REQ_TYPE_THUMBNAIL_TO_FILES, +}; + +/** + * Preparser request. + */ +struct vlc_preparser_msg_req { + /** + * Type of the request. + */ + enum vlc_preparser_msg_req_type type; + + /** + * Used only by request of type `VLC_PREPARSER_MSG_REQ_TYPE_PARSE`. + */ + int options; + + /** + * Used by both type `VLC_PREPARSER_MSG_REQ_TYPE_THUMBNAIL` and + * `VLC_PREPARSER_MSG_REQ_TYPE_THUMBNAIL_TO_FILES`. + */ + struct vlc_thumbnailer_arg arg; + + /** + * Used only by request of type + * `VLC_PREPARSER_MSG_REQ_TYPE_THUMBNAIL_TO_FILES`. + */ + /* all `output_path` will be freed so they must be heap allocated or set to + * NULL before a `vlc_preparser_msg_Clean` call. */ + struct VLC_VECTOR(char *) outputs_path; + struct VLC_VECTOR(struct vlc_thumbnailer_output) outputs; + + /* `uri` will be freed so it must be heap allocated or set to + * NULL before a `vlc_preparser_msg_Clean` call. */ + char *uri; +}; + +/** + * Preparser Response + */ +struct vlc_preparser_msg_res { + /** + * Type of the response (As the response answering a request they share the + * same type). + */ + enum vlc_preparser_msg_req_type type; + + /** + * Used only by request of type `VLC_PREPARSER_MSG_REQ_TYPE_PARSE`. + */ + struct VLC_VECTOR(input_attachment_t *) attachments; + input_item_node_t *subtree; + + /** + * Used only by request of type `VLC_PREPARSER_MSG_REQ_TYPE_THUMBNAIL`. + */ + picture_t *pic; + + /** + * Used only by request of type + * `VLC_PREPARSER_MSG_REQ_TYPE_THUMBNAIL_TO_FILES`. + */ + struct VLC_VECTOR(bool) result; + + /** + * Used by all types of request. + */ + int status; + input_item_t *item; +}; + +/** + * Preparser message. + */ +struct vlc_preparser_msg { + /** + * Type of the message can be a request or a response. + */ + enum { + VLC_PREPARSER_MSG_TYPE_REQ, + VLC_PREPARSER_MSG_TYPE_RES, + } type; + + /** + * Type of the underling request or response. + */ + enum vlc_preparser_msg_req_type req_type; + union { + struct vlc_preparser_msg_req req; + struct vlc_preparser_msg_res res; + }; +}; + +/** + * Initialize a preparser message. + * + * @info All data specific to each request/response have to be initialized + * by hand. + * + * @param msg message to initialize. + * @param msg_type message type (request or response). + * @param req_type request/response type (see enum vlc_preparser_req_type + * for more information). + */ +VLC_API void +vlc_preparser_msg_Init(struct vlc_preparser_msg *msg, int msg_type, + enum vlc_preparser_msg_req_type req_type); + +/** + * Clean all memory used by a message. + * + * @info This function don't free the `msg` pointer. + * + * @param msg message to release. + */ +VLC_API void +vlc_preparser_msg_Clean(struct vlc_preparser_msg *msg); + +/** + * @} preparser_msg + * + * @defgroup preparser_serdes preparser serializer api + * @ingroup preparser_ipc + * + * @{ + */ +#define VLC_PREPARSER_MSG_SERDES_TYPE_DATA 0x1 +#define VLC_PREPARSER_MSG_SERDES_TYPE_ATTACHMENT 0x2 +#define VLC_PREPARSER_MSG_SERDES_TYPE_END_DATA 0x4 +#define VLC_PREPARSER_MSG_SERDES_TYPE_END_ATTACHMENT 0x8 + +struct vlc_preparser_msg_serdes_cbs { + /** + * Write callback. + * + * @param [in] data buffer to write. + * @param [in] size number of bytes to write. + * @param [in] userdata callback userdata. + * + * @return the number of bytes writen or an error code on failure. + */ + ssize_t (*write)(const void *data, size_t size, void *userdata); + + /** + * Read callback. + * + * @param [out] data buffer to read into. + * @param [in] size number of bytes to read. + * @param [in] userdata callback userdata. + * + * @return the number of bytes read or an error code on failure. + */ + ssize_t (*read)(void *data, size_t size, void *userdata); +}; + +struct vlc_preparser_msg_serdes; + +struct vlc_preparser_msg_serdes_operations { + /** + * Serialize `msg` and call the write callback with serialized data. + * + * @param [in] serdes serializer internal structure. + * @param [in] msg message to serialize. + * @param [in] userdata context for the write callbacks + * + * @return VLC_SUCCESS or an error code on failure. + */ + int (*serialize)(struct vlc_preparser_msg_serdes *serdes, + const struct vlc_preparser_msg *msg, + void *userdata); + + /** + * Deserialize `msg` and call the read callback to get data to deserialize. + * + * @param [in] serdes serializer internal structure. + * @param [out] msg message to deserialize. + * @param [in] userdata context for the read callbacks + * + * @return VLC_SUCCESS or an error code on failure. + */ + int (*deserialize)(struct vlc_preparser_msg_serdes *serdes, + struct vlc_preparser_msg *msg, + void *userdata); + + /** + * Close the serializer/deserialier and release all used memory. + * + * @param [in] serdes preparser msg serdes internal struture. + */ + void (*close)(struct vlc_preparser_msg_serdes *serdes); +}; + +/** + * Internal structure used by serializer. + */ +struct vlc_preparser_msg_serdes { + /** Operations */ + const struct vlc_preparser_msg_serdes_operations *ops; + + struct { + /** Callbacks */ + const struct vlc_preparser_msg_serdes_cbs *cbs; + /** Used by the serializer module. */ + void *sys; + } owner; +}; + +typedef int (*vlc_preparser_msg_serdes_module) + (struct vlc_preparser_msg_serdes *, bool); + +#define set_callback_preparser_msg_serdes(activate, priority) \ + {\ + vlc_preparser_msg_serdes_module open__ = activate;\ + (void)open__;\ + set_callback(activate)\ + }\ + set_capability("preparser msg serdes", priority) + +/** + * Call the serialize operation. + * + * @param [in] s + * @param [out] buf + * @param [in] msg + * + * @return size of the allocated buffer. + */ +static inline int +vlc_preparser_msg_serdes_Serialize(struct vlc_preparser_msg_serdes *serdes, + const struct vlc_preparser_msg *msg, + void *userdata) +{ + assert(serdes != NULL); + + if (serdes->ops != NULL && serdes->ops->serialize != NULL) { + return serdes->ops->serialize(serdes, msg, userdata); + } + return VLC_EGENERIC; +} + +/** + * Call the deserialize operation. + * + * @param [in] s + * @param [in] buf + * @param [in] size + * + * @return size of the allocated buffer. + */ +static inline int +vlc_preparser_msg_serdes_Deserialize(struct vlc_preparser_msg_serdes *serdes, + struct vlc_preparser_msg *msg, + void *userdata) +{ + assert(serdes!= NULL); + + if (serdes->ops != NULL && serdes->ops->deserialize != NULL) { + return serdes->ops->deserialize(serdes, msg, userdata); + } + return VLC_EGENERIC; +} + +/** + * Free the msg_serdes struct. + * + * @param [in] msg_serdes + */ +static inline void +vlc_preparser_msg_serdes_Delete(struct vlc_preparser_msg_serdes *serdes) +{ + assert(serdes != NULL); + + if (serdes->ops != NULL && serdes->ops->close != NULL) { + serdes->ops->close(serdes); + } + free(serdes); +} + +/** + * Create a vlc_preparser_msg_serdes object and load a preparser msg_serdes + * module. + * + * @param [in] obj vlc object + * @param [in] c serializer's callbacks + * @param [in] bin_data describe if the serializer and deserializer use + * binary data (intput_attachment_t or plane_t) + * + * @return a vlc_preparser_msg_serdes object or NULL on failure. + */ +VLC_API struct vlc_preparser_msg_serdes * +vlc_preparser_msg_serdes_Create(vlc_object_t *obj, + const struct vlc_preparser_msg_serdes_cbs *c, + bool bin_data); + +/** + * @} preparser_serdes + * @} preparser_ipc + */ + +#endif /* VLC_PREPARSER_IPC */ diff --git a/src/Makefile.am b/src/Makefile.am index a6e510e505..b2def548f0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -95,6 +95,7 @@ pluginsinclude_HEADERS.h = \ ../include/vlc_probe.h \ ../include/vlc_preparser.h \ ../include/vlc_process.h \ + ../include/vlc_preparser_ipc.h \ ../include/vlc_queue.h \ ../include/vlc_rand.h \ ../include/vlc_renderer_discovery.h \ @@ -273,6 +274,7 @@ libvlccore_la_SOURCES = \ preparser/art.h \ preparser/fetcher.c \ preparser/fetcher.h \ + preparser/ipc.c \ preparser/preparser.c \ input/item.c \ input/access.c \ diff --git a/src/libvlccore.sym b/src/libvlccore.sym index 8ae623db17..a8c24a3ac2 100644 --- a/src/libvlccore.sym +++ b/src/libvlccore.sym @@ -1070,3 +1070,6 @@ vlc_process_Spawn vlc_process_Terminate vlc_process_fd_Read vlc_process_fd_Write +vlc_preparser_msg_Init +vlc_preparser_msg_Clean +vlc_preparser_msg_serdes_Create diff --git a/src/meson.build b/src/meson.build index 700b839ed9..f2e54c257f 100644 --- a/src/meson.build +++ b/src/meson.build @@ -130,6 +130,7 @@ libvlccore_sources_base = files( 'preparser/art.h', 'preparser/fetcher.c', 'preparser/fetcher.h', + 'preparser/ipc.c', 'preparser/preparser.c', 'input/item.c', 'input/access.c', diff --git a/src/preparser/ipc.c b/src/preparser/ipc.c new file mode 100644 index 0000000000..8549e6b3b6 --- /dev/null +++ b/src/preparser/ipc.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/***************************************************************************** + * ipc.h: definition of vlc_preparser_ipc functions + ***************************************************************************** + * Copyright © 2025 Videolabs, VideoLAN and VLC authors + * + * Authors: Gabriel Lafond Thenaille + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_POLL_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct vlc_preparser_msg_serdes * +vlc_preparser_msg_serdes_Create(vlc_object_t *obj, + const struct vlc_preparser_msg_serdes_cbs *cbs, + bool bin_data) +{ + assert(cbs != NULL); + + struct vlc_preparser_msg_serdes *msg_serdes = malloc(sizeof(*msg_serdes)); + if (msg_serdes == NULL) { + return NULL; + } + msg_serdes->owner.cbs = cbs; + + module_t **mods = NULL; + size_t strict = 0; + ssize_t n = vlc_module_match("preparser msg serdes", "any", true, &mods, + &strict); + + for (ssize_t i = 0; i < n; i++) { + vlc_preparser_msg_serdes_module cb = vlc_module_map(obj->logger, + mods[i]); + if (cb == NULL) { + continue; + } + + int ret = cb(msg_serdes, bin_data); + if (ret == VLC_SUCCESS) { + free(mods); + return msg_serdes; + } + } + free(mods); + free(msg_serdes); + return NULL; +} + +/***************************************************************************** + * + *****************************************************************************/ + +void +vlc_preparser_msg_Init(struct vlc_preparser_msg *msg, int msg_type, + enum vlc_preparser_msg_req_type req_type) +{ + assert(msg != NULL); + assert(msg_type == VLC_PREPARSER_MSG_TYPE_REQ || + msg_type == VLC_PREPARSER_MSG_TYPE_RES); + assert(req_type == VLC_PREPARSER_MSG_REQ_TYPE_PARSE || + req_type == VLC_PREPARSER_MSG_REQ_TYPE_THUMBNAIL || + req_type == VLC_PREPARSER_MSG_REQ_TYPE_THUMBNAIL_TO_FILES); + + msg->type = msg_type; + msg->req_type = req_type; + if (msg->type == VLC_PREPARSER_MSG_TYPE_REQ) { + msg->req.type = req_type; + msg->req.options = 0; + msg->req.arg.seek.type = VLC_THUMBNAILER_SEEK_NONE; + msg->req.arg.seek.speed = VLC_THUMBNAILER_SEEK_PRECISE; + msg->req.arg.hw_dec = false; + vlc_vector_init(&msg->req.outputs); + vlc_vector_init(&msg->req.outputs_path); + msg->req.uri = NULL; + } else { + msg->res.type = req_type; + vlc_vector_init(&msg->res.attachments); + msg->res.subtree = NULL; + msg->res.pic = NULL; + vlc_vector_init(&msg->res.result); + msg->res.status = -1; + } +} + +void +vlc_preparser_msg_Clean(struct vlc_preparser_msg *msg) +{ + assert(msg != NULL); + + if (msg->type == VLC_PREPARSER_MSG_TYPE_REQ) { + vlc_vector_clear(&msg->req.outputs); + char *ptr = NULL; + vlc_vector_foreach(ptr, &msg->req.outputs_path) { + free(ptr); + } + vlc_vector_clear(&msg->req.outputs_path); + if (msg->req.uri != NULL) { + free(msg->req.uri); + msg->req.uri = NULL; + } + } else { + input_attachment_t *att = NULL; + vlc_vector_foreach(att, &msg->res.attachments) { + vlc_input_attachment_Release(att); + } + vlc_vector_clear(&msg->res.attachments); + if (msg->res.subtree != NULL) { + input_item_node_Delete(msg->res.subtree); + msg->res.subtree = NULL; + } + if (msg->res.pic != NULL) { + picture_Release(msg->res.pic); + msg->res.pic = NULL; + } + vlc_vector_clear(&msg->res.result); + if (msg->res.item != NULL) { + input_item_Release(msg->res.item); + msg->res.item = NULL; + } + } +}