/* * 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; }