summaryrefslogtreecommitdiff
path: root/lib/xlnx-video.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/xlnx-video.c')
-rw-r--r--lib/xlnx-video.c388
1 files changed, 388 insertions, 0 deletions
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 <laurent.pinchart@ideasonboard.com>
+ *
+ * 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 <errno.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <media-enumerate.h>
+#include <mediactl.h>
+
+#include <xlnx-list.h>
+#include <xlnx-plugin.h>
+#include <xlnx-tools.h>
+#include <xlnx-video.h>
+
+#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;
+}