From c9601d407a7ca943e53fa49a5a5f69b868c6ed11 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 18 Nov 2014 22:52:06 +0200 Subject: Xilinx video library - Initial import Signed-off-by: Laurent Pinchart --- lib/xlnx-video.c | 388 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 388 insertions(+) create mode 100644 lib/xlnx-video.c (limited to 'lib/xlnx-video.c') diff --git a/lib/xlnx-video.c b/lib/xlnx-video.c new file mode 100644 index 0000000..61c9f7c --- /dev/null +++ b/lib/xlnx-video.c @@ -0,0 +1,388 @@ +/* + * Xilinx Video Library + * + * Copyright (C) 2014-2016 Ideas on board Oy + * + * Contact: Laurent Pinchart + * + * This library 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 library 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 General Public License for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "xlnx-priv.h" + +/** + * \mainpage + * + * The Xilinx video library offers a high-level API to enumerate video-related + * components in the system, assemble them in pipelines and stream video in and + * out of them. + * + * To use the library, an application must create a library context with a call + * to xlnx_video_create(). The function returns a context pointer that will be + * passed to all other library functions. Once a context isn't needed anymore it + * should be destroyed by a call to xlnx_video_destroy(). + * + * Multiple contexts can be created and managed separately. However, as contexts + * store information about all media devices present in the system, accessing + * the same media devices from multiple contexts isn't supported and leads to + * undefined behaviour. + * + * Right after creation contexts are not ready for use. They must be initialized + * by registering event handling operations with xlnx_video_set_event_handler(). + * Optionally logging can be initialized if desired with + * xlnx_video_set_log_level(). Finally, to complete initialization applications + * must call xlnx_video_setup() on the context. From that point onward the + * context can be used with other library functions. + */ + +/* ----------------------------------------------------------------------------- + * Components Discovery and Management + */ + +/** + * \brief Get a list of components in the system + * \param xv the library context + * \param type the desired component type + * \param [out] components array of returned components + * + * Store a list of components matching the requested \a type in the + * \a components array. + * + * The \a type parameter is a bitmask of components type. Components matching + * one of the types in the bitmask will be included in the list, all other + * components will be ignored. + * + * The \a components parameter points to an array of components pointer. + * The function allocates an array of component pointers, fills it with + * pointers to all components matching the requested \a type, and stores it in + * the \a components pointer. The components array is allocated using the C + * memory allocator and must be freed by the caller with a call to free(). + * + * The \a components array pointer can be NULL, in which case the function will + * not allocate any memory and will only return the number of matching + * components. + * + * If no component matches the requested \a type this function will not allocate + * any memory and will not touch the \a components parameter. + * + * Components must first be enumerated by a call to + * xlnx_video_component_enumerate() before calling this function. + * + * \return the total number of components matching the requested \a type found + * in the system and supported by the library (including the loaded plugins) on + * success, or a negative error code on failure. + */ +int xlnx_video_component_list(struct xlnx_video *xv, + enum xlnx_video_component_type type, + struct xlnx_video_component ***components) +{ + struct xlnx_video_component **comps; + struct xlnx_video_component *xvcomp; + unsigned int count; + + if (!xv->num_components) + return 0; + + count = 0; + list_for_each_entry(xvcomp, &xv->components, list) { + if (!(xvcomp->type & type)) + continue; + + count++; + } + + if (!count || !components) + return count; + + comps = calloc(count, sizeof(*comps)); + if (comps == NULL) + return -ENOMEM; + + count = 0; + list_for_each_entry(xvcomp, &xv->components, list) { + if (!(xvcomp->type & type)) + continue; + + comps[count++] = xvcomp; + } + + *components = comps; + return count; +} + +/** + * \brief Get the component name + * \param xvcomp the component + * + * \return the name of the component \a xvcomp. The name string is valid for the + * lifetime of the component. + */ +const char *xlnx_video_component_name(const struct xlnx_video_component *xvcomp) +{ + return xvcomp->name; +} + +/** + * \brief Get the component type + * \param xvcomp the component + * + * \return the type of the component \a xvcomp. + */ +enum xlnx_video_component_type +xlnx_video_component_type(const struct xlnx_video_component *xvcomp) +{ + return xvcomp->type; +} + +/* ----------------------------------------------------------------------------- + * Components Discovery + */ + +static int xlnx_video_component_scan_media(struct xlnx_video *xv, + struct media_device *media) +{ + struct xlnx_video_component *xvcomp; + + xvcomp = xlnx_video_plugin_scan(xv, media); + if (xvcomp) { + list_append(&xv->components, &xvcomp->list); + xv->num_components++; + } + + return 0; +} + +static int xlnx_video_component_scan(struct xlnx_video *xv) +{ + struct media_enumerate *media_enum; + struct media_device **devices; + unsigned int num_devices; + unsigned int i; + int ret; + + /* Start by scanning media controller devices. */ + media_enum = media_enumerate_new(); + if (!media_enum) + return -ENOMEM; + + ret = media_enumerate_scan(media_enum); + if (ret < 0) + goto done; + + num_devices = media_enumerate_get_devices_count(media_enum); + if (num_devices == 0) { + ret = -ENXIO; + goto done; + } + + devices = media_enumerate_get_devices(media_enum); + + for (i = 0; i < num_devices; ++i) { + ret = xlnx_video_component_scan_media(xv, devices[i]); + if (ret < 0) + goto done; + } + +done: + media_enumerate_unref(media_enum); + return ret; +} + +/** + * \brief Enumerate components in the system + * \param xv the library context + * + * This function enumerates all supported components in the system and cache + * them in the library context \a xv. It must be called once after initializing + * the context and before calling any other of the component-related functions. + * + * \return 0 on success or a negative error code otherwise. + */ +int xlnx_video_component_enumerate(struct xlnx_video *xv) +{ + int ret; + + ret = xlnx_video_component_scan(xv); + if (ret < 0) + return ret; + + return 0; +} + +/* ----------------------------------------------------------------------------- + * Initialization + */ + +/** + * \brief Create a working context for the library + * + * The Xilinx video library uses context objects to store internal data. + * Applications must call this function to create and initialize a context + * that can then be passed to other library functions. + * + * Multiple contexts can be created and managed separately. However, as contexts + * store information about all media devices present in the system, accessing + * the same media devices from multiple contexts isn't supported and leads to + * undefined behaviour. + * + * When a context isn't needed anymore applications must call the + * xlnx_video_destroy() function to destroy of it. + * + * \return a context pointer on success or NULL if an error occurs. + */ +struct xlnx_video *xlnx_video_create(void) +{ + struct xlnx_video *xv; + + xv = calloc(1, sizeof *xv); + if (!xv) + return NULL; + + list_init(&xv->components); + list_init(&xv->plugins); + + xv->log_level = XLNX_LOG_NONE; + + return xv; +} + +/** + * \brief Setup a library context to make it ready for use + * \param xv the library context + * + * After creating and initializing a library context \a xv, applications must + * call this function to finish context setup and make it ready for use. + * + * \return 0 on success or a negative error code otherwise. + */ +int xlnx_video_setup(struct xlnx_video *xv) +{ + int ret; + + ret = xlnx_video_plugin_init(xv); + if (ret < 0) + return ret; + + return 0; +} + +/** + * \brief Destroy a library context + * \param xv the library context + * + * Applications must call this function to destroy library contexts created + * by xlnx_video_create() when they're not needed anymore, and at the latest + * when the application exits. The context pointer \a xv becomes invalid when + * this function is called. + */ +void xlnx_video_destroy(struct xlnx_video *xv) +{ + xlnx_video_plugin_fini(xv); + free(xv); +} + +/** + * \brief Register event handler operations + * \param xv the library context + * \param ops the event handling operations + * \param handler the event handler private data + * + * The library requires the application to provide an implementation of a set of + * operations to handle event notifications on file descriptors. + * + * This function sets the event handler operations \a ops and private data + * pointer \a handler for the library context. It must be called after creating + * a context with xlnx_video_create() and before initializing it with + * xlnx_video_init(). + */ +void xlnx_video_set_event_handler(struct xlnx_video *xv, + const struct xlnx_video_event_operations *ops, + void *handler) +{ + xv->event_ops = ops; + xv->event_handler = handler; +} + +/** + * \brief Retrieve the event handler private data registered with the context + * \param xv the library context + * + * \return the event handler private data pointer registered with the library + * context by a previous call to xlnx_video_set_event_handler(). + */ +void *xlnx_video_get_event_handler_data(struct xlnx_video *xv) +{ + return xv->event_handler; +} + +/** + * \brief Log a library message + * \param xv the library context + * \param level the message log level + * \param fmt the message format + * \param ... the message arguments + * + * Log the message specified by \a format and \a ... arguments using the library + * logging infrastructure. The message will be logged only if its \a level is + * lower than or equal to the \a xv library context current log level, as set by + * xlnx_log_set_level(). Otherwise the message will be dropped silently. + */ +void xlnx_video_log_print(struct xlnx_video *xv, unsigned int level, + const char *func, const char *fmt, ...) +{ + struct timespec ts; + va_list ap; + + if (level == XLNX_LOG_NONE || level > xv->log_level) + return; + + clock_gettime(CLOCK_MONOTONIC, &ts); + + printf("[%lu.%06lu] %s: ", ts.tv_sec, ts.tv_nsec / 1000, func); + + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); +} + +/** + * \brief Set the library context log level + * \param xv the library context + * \param level the desired log level + * + * The Xilinx video library can print error, informational and debug messages + * to help debugging applications and library internals. Only messages whose log + * level is lower than or equal to the library context log level are printed, + * other messages are dropped silently + * + * This function sets the active log level for the context \a xv to \a level. + * The default log level is XLNX_LOG_NONE, which drops all log messages. + */ +void xlnx_video_set_log_level(struct xlnx_video *xv, enum xlnx_log_level level) +{ + xv->log_level = level; +} -- cgit v1.2.3