Browse Source

preparser: add serialization module capability

* Create a preparser IPC (preparser request and response) to send
   preparser requests to another process and receive the preparsed
   media in return.

 * Implement a de/serialization module capable of serializing and
   deserializing preparser messages (requests and responses).
update/opus-1.6.1
Gabriel Lafond-Thenaille 1 year ago
committed by Steve Lhomme
parent
commit
4d3651e483
  1. 348
      include/vlc_preparser_ipc.h
  2. 2
      src/Makefile.am
  3. 3
      src/libvlccore.sym
  4. 1
      src/meson.build
  5. 139
      src/preparser/ipc.c

348
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 <gabriel@videolabs.io>
*****************************************************************************/
#ifndef VLC_PREPARSER_IPC_H
#define VLC_PREPARSER_IPC_H
#include <vlc_common.h>
#include <vlc_vector.h>
#include <vlc_input.h>
#include <vlc_input_item.h>
#include <vlc_preparser.h>
#include <vlc_interrupt.h>
/**
* @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 */

2
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 \

3
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

1
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',

139
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 <gabriel@videolabs.io>
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#include <vlc_common.h>
#include <vlc_modules.h>
#include <vlc_preparser_ipc.h>
#include <vlc_input_item.h>
#include <vlc_list.h>
#include <vlc_vector.h>
#include <vlc_atomic.h>
#include <vlc_preparser.h>
#include <vlc_threads.h>
#include <vlc_memstream.h>
#include <vlc_poll.h>
#include <vlc_interrupt.h>
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;
}
}
}
Loading…
Cancel
Save