* [libv4l-mcplugin PATCH 1/3] Add files for media controller pipelines
2011-05-19 12:36 [libv4l-mcplugin PATCH 0/3] Media controller plugin for libv4l2 Yordan Kamenov
@ 2011-05-19 12:36 ` Yordan Kamenov
2011-05-19 12:36 ` [libv4l-mcplugin PATCH 2/3] Add files for v4l operations Yordan Kamenov
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Yordan Kamenov @ 2011-05-19 12:36 UTC (permalink / raw)
To: linux-media; +Cc: sakari.ailus, Yordan Kamenov
Add Makefile.
Add files for Media Controller pipelines initialization, configuration and
destruction.
Add file for list operations.
Add config file.
Signed-off-by: Yordan Kamenov <ykamenov@mm-sol.com>
---
Makefile | 30 ++
omap3-mc.conf | 82 +++++
paths.c | 959 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
paths.h | 64 ++++
sl_list.h | 65 ++++
5 files changed, 1200 insertions(+), 0 deletions(-)
create mode 100644 Makefile
create mode 100644 omap3-mc.conf
create mode 100644 paths.c
create mode 100644 paths.h
create mode 100644 sl_list.h
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..2b3b375
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,30 @@
+ARCH ?= arm
+KDIR ?= /usr/src/linux
+LIBV4LINCDIR ?= ../../v4l-utils/lib/include/
+LIBMEDIACTLDIR ?= /usr/local/lib
+CONF_INST_DIR := $(DESTDIR)/etc/libv4l2plugins
+PLUGIN_INST_DIR := $(DESTDIR)/usr/lib/libv4l/plugins
+
+KINC := -I$(KDIR)/include -I$(KDIR)/arch/$(ARCH)/include
+INC := -I$(LIBV4LINCDIR) $(KINC)
+CC := $(CROSS_COMPILE)gcc
+
+LDFLAGS += -L$(LIBMEDIACTLDIR) -lmediactl
+
+CFLAGS += -O2 -Wall -fpic -I. $(INC)
+OBJS = libv4l2plugin-omap3mc.o paths.o operations.o
+
+all: libv4l2plugin-omap3mc.so
+
+libv4l2plugin-omap3mc.so: $(OBJS)
+ $(CC) $(CFLAGS) -shared $(LDFLAGS) -o libv4l2plugin-omap3mc.so $(OBJS)
+clean:
+ rm -f $(OBJS) libv4l2plugin-omap3mc.so
+
+install: libv4l2plugin-omap3mc.so
+ test -z "$(CONF_INST_DIR)" || mkdir -p "$(CONF_INST_DIR)"
+ install -m 666 omap3-mc.conf "$(CONF_INST_DIR)"
+ test -z "$(PLUGIN_INST_DIR)" || mkdir -p "$(PLUGIN_INST_DIR)"
+ install -m 755 libv4l2plugin-omap3mc.so "$(PLUGIN_INST_DIR)"
+
+.PHONY: clean all
diff --git a/omap3-mc.conf b/omap3-mc.conf
new file mode 100644
index 0000000..3b7947c
--- /dev/null
+++ b/omap3-mc.conf
@@ -0,0 +1,82 @@
+# Configuration file for media controller plugin for libv4l
+#
+#
+# Format:
+#
+# [primary|secondary]_path
+# list of subdevice names
+# end
+#
+# [primary|secondary]_in_pixfmt
+# list of formats supported by input device
+# end
+#
+# [primary|secondary]_out_pixfmt
+# list of formats supported by output device
+# end
+#
+#
+#
+# Sensors:
+# jt8ev1, smiapp-001, smiapp-002, smiapp-003, smiapp-004, tcm8500md, vw6558
+#
+# Subdevices:
+# OMAP3 ISP CSI2a
+# OMAP3 ISP CSI2a output
+# OMAP3 ISP CCP2
+# OMAP3 ISP CCP2 input
+# OMAP3 ISP CCDC
+# OMAP3 ISP preview
+# OMAP3 ISP preview output
+# OMAP3 ISP resizer input
+# OMAP3 ISP resizer
+# OMAP3 ISP resizer output
+#
+#
+# Formats:
+# BAYER8_SBGGR, BAYER8_SGBRG, BAYER8_SGRBG, BAYER10_SGRBG, BAYER10_SRGGB,
+# BAYER10_SBGGR, BAYER10_SGBRG, BAYER10DPCM8_SGRBG, YUYV, UYVY
+#
+#
+
+
+
+primary_path
+ jt8ev1
+ OMAP3 ISP CSI2a
+ OMAP3 ISP CCDC
+ OMAP3 ISP preview
+ OMAP3 ISP resizer
+ OMAP3 ISP resizer output
+end
+
+primary_in_pixfmt
+ BAYER10DPCM8_SGRBG
+ BAYER10_SGRBG
+end
+
+primary_out_pixfmt
+ UYVY
+end
+
+
+
+secondary_path
+ vw6558
+ OMAP3 ISP CCP2
+ OMAP3 ISP CCDC
+ OMAP3 ISP preview
+ OMAP3 ISP resizer
+ OMAP3 ISP resizer output
+end
+
+secondary_in_pixfmt
+ BAYER10DPCM8_SGRBG
+ BAYER10_SGRBG
+end
+
+secondary_out_pixfmt
+ UYVY
+end
+
+
diff --git a/paths.c b/paths.c
new file mode 100644
index 0000000..bbc6cfd
--- /dev/null
+++ b/paths.c
@@ -0,0 +1,959 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation
+ *
+ * Contact: Yordan Kamenov <ykamenov@mm-sol.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ */
+
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stddef.h>
+#include <ctype.h>
+#include <string.h>
+
+#include <linux/v4l2-subdev.h>
+
+#include "sl_list.h"
+#include "paths.h"
+
+#define CONFIG_FILE "/etc/libv4l2plugins/omap3-mc.conf"
+
+#define LINESIZE (256)
+#define CHOMP(x) \
+ do { \
+ char *p; \
+ int sz; \
+ p = (x); \
+ sz = strlen(p); \
+ p += sz - 1; \
+ if (sz) \
+ while (isspace(*p)) *p-- = 0; \
+ } while (0)
+
+/* Sections in configuration file */
+enum mc_plugin_config_sections {
+ CONFIG_SECTION_NONE,
+ CONFIG_SECTION_PRIMARY_PATH,
+ CONFIG_SECTION_PRIMARY_IN_PIXFMT,
+ CONFIG_SECTION_PRIMARY_OUT_PIXFMT,
+ CONFIG_SECTION_SECONDARY_PATH,
+ CONFIG_SECTION_SECONDARY_IN_PIXFMT,
+ CONFIG_SECTION_SECONDARY_OUT_PIXFMT
+};
+
+struct capture_pipeline pipe_sensor_yuv_path;
+
+int pixel_mc_plugin_to_subdev(enum mc_plugin_pixelformat pixfmt)
+{
+ switch (pixfmt) {
+ case MC_PLUGIN_PIX_FMT_BAYER10_SGRBG:
+ return V4L2_MBUS_FMT_SGRBG10_1X10;
+
+ case MC_PLUGIN_PIX_FMT_BAYER10DPCM8_SGRBG:
+ return V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8;
+
+ case MC_PLUGIN_PIX_FMT_YUYV:
+ return V4L2_MBUS_FMT_YUYV8_1X16;
+
+ case MC_PLUGIN_PIX_FMT_UYVY:
+ return V4L2_MBUS_FMT_UYVY8_1X16;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+enum mc_plugin_pixelformat pixel_subdev_to_mc_plugin(int pixfmt)
+{
+ switch (pixfmt) {
+ case V4L2_MBUS_FMT_SGRBG10_1X10:
+ return MC_PLUGIN_PIX_FMT_BAYER10_SGRBG;
+
+ case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
+ return MC_PLUGIN_PIX_FMT_BAYER10DPCM8_SGRBG;
+
+ case V4L2_MBUS_FMT_YUYV8_1X16:
+ return MC_PLUGIN_PIX_FMT_YUYV;
+
+ case V4L2_MBUS_FMT_UYVY8_1X16:
+ return MC_PLUGIN_PIX_FMT_UYVY;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int pixel_mc_plugin_to_v4l(enum mc_plugin_pixelformat pixfmt)
+{
+ switch (pixfmt) {
+ case MC_PLUGIN_PIX_FMT_BAYER10_SGRBG:
+ return V4L2_PIX_FMT_SGRBG10;
+
+#ifdef V4L2_PIX_FMT_SGRBG10DPCM8
+ case MC_PLUGIN_PIX_FMT_BAYER10DPCM8_SGRBG:
+ return V4L2_PIX_FMT_SGRBG10DPCM8;
+#endif
+
+ case MC_PLUGIN_PIX_FMT_YUYV:
+ return V4L2_PIX_FMT_YUYV;
+
+ case MC_PLUGIN_PIX_FMT_UYVY:
+ return V4L2_PIX_FMT_UYVY;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+enum mc_plugin_pixelformat pixel_v4l_to_mc_plugin(int pixfmt)
+{
+ switch (pixfmt) {
+ case V4L2_PIX_FMT_SGRBG10:
+ return MC_PLUGIN_PIX_FMT_BAYER10_SGRBG;
+
+#ifdef V4L2_PIX_FMT_SGRBG10DPCM8
+ case V4L2_PIX_FMT_SGRBG10DPCM8:
+ return MC_PLUGIN_PIX_FMT_BAYER10DPCM8_SGRBG;
+#endif
+
+ case V4L2_PIX_FMT_YUYV:
+ return MC_PLUGIN_PIX_FMT_YUYV;
+
+ case V4L2_PIX_FMT_UYVY:
+ return MC_PLUGIN_PIX_FMT_UYVY;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+enum mc_plugin_pixelformat pixel_str_to_mc_plugin(char *strpix)
+{
+ if (strcmp(strpix, "BAYER8_SBGGR") == 0)
+ return MC_PLUGIN_PIX_FMT_BAYER8_SBGGR;
+ if (strcmp(strpix, "BAYER8_SGBRG") == 0)
+ return MC_PLUGIN_PIX_FMT_BAYER8_SGBRG;
+ if (strcmp(strpix, "BAYER8_SGRBG") == 0)
+ return MC_PLUGIN_PIX_FMT_BAYER8_SGRBG;
+ if (strcmp(strpix, "BAYER10_SGRBG") == 0)
+ return MC_PLUGIN_PIX_FMT_BAYER10_SGRBG;
+ if (strcmp(strpix, "BAYER10_SRGGB") == 0)
+ return MC_PLUGIN_PIX_FMT_BAYER10_SRGGB;
+ if (strcmp(strpix, "BAYER10_SBGGR") == 0)
+ return MC_PLUGIN_PIX_FMT_BAYER10_SBGGR;
+ if (strcmp(strpix, "BAYER10_SGBRG") == 0)
+ return MC_PLUGIN_PIX_FMT_BAYER10_SGBRG;
+ if (strcmp(strpix, "BAYER10DPCM8_SGRBG") == 0)
+ return MC_PLUGIN_PIX_FMT_BAYER10DPCM8_SGRBG;
+ if (strcmp(strpix, "YUYV") == 0)
+ return MC_PLUGIN_PIX_FMT_YUYV;
+ if (strcmp(strpix, "UYVY") == 0)
+ return MC_PLUGIN_PIX_FMT_UYVY;
+
+ return MC_PLUGIN_PIX_FMT_INVALID;
+}
+
+const struct capture_pipeline *pipe_sensor_yuv(int primary)
+{
+ FILE *fp = NULL;
+ char buffer[LINESIZE], *begin;
+ int i = 0;
+ enum mc_plugin_config_sections conf_section = CONFIG_SECTION_NONE;
+
+ fp = fopen(CONFIG_FILE, "r");
+ if (!fp) {
+ MC_PLUGIN_PRINTF ("Opening file %s failed", CONFIG_FILE);
+ return NULL;
+ }
+
+ while (fgets(buffer, LINESIZE, fp)) {
+ /* skip initial whitespace */
+ begin = buffer + strspn(buffer, "\r\t ");
+
+ /* skip comments and empty lines */
+ if (*begin == '#')
+ continue;
+ if (*begin == '\n')
+ continue;
+
+ /* Remove LF */
+ CHOMP(begin);
+
+ /* Check if we enter a config section */
+ if (conf_section == CONFIG_SECTION_NONE) {
+ if (strcmp(begin, "primary_path") == 0)
+ conf_section = CONFIG_SECTION_PRIMARY_PATH;
+ else if (strcmp(begin, "primary_in_pixfmt") == 0)
+ conf_section = CONFIG_SECTION_PRIMARY_IN_PIXFMT;
+ else if (strcmp(begin, "primary_out_pixfmt") == 0)
+ conf_section = CONFIG_SECTION_PRIMARY_OUT_PIXFMT;
+ else if (strcmp(begin, "secondary_path") == 0)
+ conf_section = CONFIG_SECTION_SECONDARY_PATH;
+ else if (strcmp(begin, "secondary_in_pixfmt") == 0)
+ conf_section = CONFIG_SECTION_SECONDARY_IN_PIXFMT;
+ else if (strcmp(begin, "secondary_out_pixfmt") == 0)
+ conf_section = CONFIG_SECTION_SECONDARY_OUT_PIXFMT;
+
+ i = 0;
+ continue;
+ }
+
+ /* Check if we exit a config section */
+ if (strcmp(begin, "end") == 0) {
+ conf_section = CONFIG_SECTION_NONE;
+ continue;
+ }
+
+ if ((i + 1) > PIPELINE_MAX_ELEMENTS ||
+ strlen(begin) >= SUBDEVICE_MAX_NAME_LEN) {
+
+ fclose(fp);
+ return NULL;
+ }
+
+ switch (conf_section) {
+ case CONFIG_SECTION_PRIMARY_PATH:
+ if (!primary)
+ break;
+ strcpy(pipe_sensor_yuv_path.path[i], begin);
+ strcpy(pipe_sensor_yuv_path.path[i+1], "");
+ i++;
+ break;
+ case CONFIG_SECTION_PRIMARY_IN_PIXFMT:
+ if (!primary)
+ break;
+ pipe_sensor_yuv_path.in_pixfmt[i] = pixel_str_to_mc_plugin(begin);
+ pipe_sensor_yuv_path.in_pixfmt[i+1] = MC_PLUGIN_PIX_FMT_INVALID;
+ i++;
+ break;
+ case CONFIG_SECTION_PRIMARY_OUT_PIXFMT:
+ if (!primary)
+ break;
+ pipe_sensor_yuv_path.out_pixfmt[i] = pixel_str_to_mc_plugin(begin);
+ pipe_sensor_yuv_path.out_pixfmt[i+1] = MC_PLUGIN_PIX_FMT_INVALID;
+ i++;
+ break;
+ case CONFIG_SECTION_SECONDARY_PATH:
+ if (primary)
+ break;
+ strcpy(pipe_sensor_yuv_path.path[i], begin);
+ strcpy(pipe_sensor_yuv_path.path[i+1], "");
+ i++;
+ break;
+ case CONFIG_SECTION_SECONDARY_IN_PIXFMT:
+ if (primary)
+ break;
+ pipe_sensor_yuv_path.in_pixfmt[i] = pixel_str_to_mc_plugin(begin);
+ pipe_sensor_yuv_path.in_pixfmt[i+1] = MC_PLUGIN_PIX_FMT_INVALID;
+ i++;
+ break;
+ case CONFIG_SECTION_SECONDARY_OUT_PIXFMT:
+ if (primary)
+ break;
+ pipe_sensor_yuv_path.out_pixfmt[i] = pixel_str_to_mc_plugin(begin);
+ pipe_sensor_yuv_path.out_pixfmt[i+1] = MC_PLUGIN_PIX_FMT_INVALID;
+ i++;
+ break;
+ case CONFIG_SECTION_NONE:
+ break;
+ }
+
+ }
+
+ fclose(fp);
+
+ return &pipe_sensor_yuv_path;
+}
+
+struct media_link *media_find_link(struct media_device *media,
+ struct media_entity *source,
+ struct media_entity *sink)
+{
+ unsigned int l;
+
+ for (l = 0; l < source->num_links; l++) {
+ struct media_link *link = &source->links[l];
+
+ if (link->source->entity == source &&
+ link->sink->entity == sink)
+ return link;
+ }
+
+ return NULL;
+}
+
+struct ipipe_descriptor *path_allocate(struct media_device *media,
+ const struct capture_pipeline *pipe)
+{
+ struct ipipe_descriptor *image_path;
+ struct sub_module *sub;
+ struct media_entity *entity;
+ const char *entity_name;
+ int i;
+
+ if (!media || !pipe) {
+ MC_PLUGIN_PRINTF("NULL pointer\n");
+ return NULL;
+ }
+
+ image_path = malloc(sizeof(*image_path));
+ if (!image_path) {
+ perror("image path");
+ return NULL;
+ }
+
+ image_path->pipe = pipe;
+ INIT_LIST_HEAD(&image_path->container);
+
+ for (i = 0; ; i++) {
+ entity_name = (char *)pipe->path[i];
+ if (strlen(entity_name) == 0)
+ break;
+
+ entity = media_get_entity_by_name(media, entity_name, strlen(entity_name));
+ if (!entity) {
+ MC_PLUGIN_PRINTF("Can't find entity [%s]\n", entity_name);
+ continue;
+ }
+
+ sub = submodule_alloc();
+ if (sub) {
+ sub->entity = entity;
+ list_add_tail(&sub->list, &image_path->container);
+ }
+ }
+
+ return image_path;
+}
+
+struct sub_module *submodule_alloc()
+{
+ struct sub_module *sb = NULL;
+
+ sb = malloc(sizeof (*sb));
+ if (!sb) {
+ MC_PLUGIN_PRINTF("Can not allocate module\n");
+ return sb;
+ }
+
+ sb->entity = NULL;
+ INIT_LIST_HEAD(&sb->list);
+
+ return sb;
+}
+
+void submodule_free(struct sub_module *sb)
+{
+ free(sb);
+ sb = NULL;
+}
+
+struct sub_module *path_destination_submodule(struct ipipe_descriptor *path)
+{
+ struct sub_module *next, *last;
+
+ if (NULL == path) {
+ MC_PLUGIN_PRINTF("Wrong argument: NULL pointer\n");
+ return NULL;
+ }
+
+ last = NULL;
+ list_for_each_entry(next, &path->container, list)
+ last = next;
+
+ return last;
+}
+
+int path_power_on(struct ipipe_descriptor *path, int fd)
+{
+ struct sub_module *sub_mod, *next_sub_mod;
+ int last_sm, err = 0;
+
+ if (NULL == path) {
+ MC_PLUGIN_PRINTF("Wrong argument: NULL pointer\n");
+ return -1;
+ }
+
+ list_for_each_entry(sub_mod, &path->container, list) {
+ next_sub_mod = list_entry(sub_mod->list.next, typeof(*sub_mod), list);
+ last_sm = &next_sub_mod->list == &path->container;
+ err += submodule_open(sub_mod, fd, last_sm);
+ }
+
+ return err;
+}
+
+int submodule_open(struct sub_module *sb, int fd, int last_sm)
+{
+ int err = 0;
+
+ if (!sb) {
+ MC_PLUGIN_PRINTF("Wrong argument: NULL pointer\n");
+ return -1;
+ }
+
+ if (sb->entity->fd < 0)
+ sb->entity->fd = SYS_OPEN(sb->entity->devname, O_RDWR, 0);
+
+ if (sb->entity->fd < 0)
+ err = -1;
+
+ if (last_sm && err != -1) {
+ int dr;
+ dr = dup2(sb->entity->fd, fd);
+ close(sb->entity->fd);
+ sb->entity->fd = fd;
+ }
+
+ return err;
+}
+
+int path_connect_entities(struct media_device *media,
+ struct ipipe_descriptor *path)
+{
+ struct media_entity *source, *sink;
+ struct media_link *link;
+ const char *sink_name, *source_name;
+ int i, err = 0;
+
+ if (!media || !path) {
+ MC_PLUGIN_PRINTF("Wrong argument: NULL pointer\n");
+ return -1;
+ }
+
+ source_name = (char *)path->pipe->path[0];
+ sink_name = (char *)path->pipe->path[1];
+ i = 1;
+
+ while (strlen(source_name) != 0) {
+
+ sink_name = (char *)path->pipe->path[i];
+ if (strlen(sink_name) == 0)
+ break;
+
+ source = media_get_entity_by_name(media, source_name, strlen(source_name));
+ sink = media_get_entity_by_name(media, sink_name, strlen(sink_name));
+
+ if ((NULL == sink) || (NULL == source)) {
+ MC_PLUGIN_PRINTF("Error finding entities\n");
+ err = -1;
+ break;
+ }
+
+ link = media_find_link(media, source, sink);
+
+ /* Do not explicitly setup immutable links */
+ if (!(link->flags & MEDIA_LINK_FLAG_IMMUTABLE)) {
+ err = media_setup_link(media, link->source, link->sink,
+ MEDIA_LINK_FLAG_ACTIVE);
+ } else {
+ if (!(link->flags & MEDIA_LINK_FLAG_ACTIVE)) {
+ MC_PLUGIN_PRINTF("Immutable link is not activated\n");
+ err = -1;
+ }
+ }
+
+ if (err < 0) {
+ MC_PLUGIN_PRINTF("Fail to connect %s->%s\n", source_name, sink_name);
+ break;
+ }
+
+ source_name = sink_name;
+ i++;
+ }
+
+ return err;
+}
+
+void path_power_off(struct ipipe_descriptor *path)
+{
+ struct sub_module *sub_mod, *next_sub_mod;
+ int last_sm;
+
+ if (NULL == path) {
+ MC_PLUGIN_PRINTF("Wrong argument: NULL pointer\n");
+ return;
+ }
+
+ list_for_each_entry(sub_mod, &path->container, list) {
+ next_sub_mod = list_entry(sub_mod->list.next, typeof(*sub_mod), list);
+ last_sm = &next_sub_mod->list == &path->container;
+ submodule_power_off(sub_mod, last_sm);
+ }
+
+}
+
+int submodule_power_off(struct sub_module *sb, int last_sm)
+{
+ if (!sb) {
+ MC_PLUGIN_PRINTF("Wrong argument: NULL pointer\n");
+ return -1;
+ }
+
+ if (sb->entity->fd > 0 && !last_sm)
+ SYS_CLOSE(sb->entity->fd);
+
+ sb->entity->fd = -1;
+
+ return 0;
+}
+
+int path_disconnect_entities(struct media_device *media,
+ struct ipipe_descriptor *path)
+{
+ struct media_entity *source, *sink;
+ struct media_link *link;
+ const char *sink_name, *source_name;
+ int i, err = 0;
+
+ if (!media || !path) {
+ MC_PLUGIN_PRINTF("Wrong argument: NULL pointer\n");
+ return -1;
+ }
+
+ source_name = (char *)path->pipe->path[0];
+ sink_name = (char *)path->pipe->path[1];
+ i = 1;
+
+ while (strlen(source_name) != 0) {
+
+ sink_name = (char *)path->pipe->path[i];
+ if (strlen(sink_name) == 0)
+ break;
+
+ source = media_get_entity_by_name(media, source_name, strlen(source_name));
+ sink = media_get_entity_by_name(media, sink_name, strlen(sink_name));
+
+ if ((NULL == sink) || (NULL == source)) {
+ MC_PLUGIN_PRINTF("Error finding entities\n");
+ err = -1;
+ break;
+ }
+
+ link = media_find_link(media, source, sink);
+
+ /* Do not explicitly setup immutable links */
+ if (!(link->flags & MEDIA_LINK_FLAG_IMMUTABLE))
+ err = media_setup_link(media, link->source, link->sink,
+ (link->flags & ~MEDIA_LINK_FLAG_ACTIVE));
+
+ source_name = sink_name;
+ i++;
+ }
+
+ return err;
+}
+
+int path_enum_src_framesizes(struct omap3mcplugin *plugin,
+ enum mc_plugin_pixelformat *pixfmt,
+ struct v4l2_rect *res, int max_rect)
+{
+ struct media_entity *source, *sink;
+ const char *sink_name, *source_name;
+ struct media_link *link;
+ int ret = -1;
+ struct v4l2_subdev_frame_size_enum size;
+
+ if (!plugin || !pixfmt || !res) {
+ MC_PLUGIN_PRINTF("NULL pointer");
+ return -1;
+ }
+
+ source_name = (char *)plugin->path->pipe->path[0];
+ sink_name = (char *)plugin->path->pipe->path[1];
+
+ source = media_get_entity_by_name(plugin->media, source_name, strlen(source_name));
+ sink = media_get_entity_by_name(plugin->media, sink_name, strlen(sink_name));
+
+ if ((NULL == sink) || (NULL == source)) {
+ MC_PLUGIN_PRINTF("Error finding entities\n");
+ errno = EBADF;
+ return -1;
+ }
+
+ link = media_find_link(plugin->media, source, sink);
+
+ if (NULL == link) {
+ MC_PLUGIN_PRINTF("No link present between source and sink\n");
+ errno = EBADF;
+ return -1;
+ }
+
+ memset(&size, 0, sizeof(size));
+
+ size.index = 0;
+ size.code = pixel_mc_plugin_to_subdev(*pixfmt);
+ size.pad = link->source->index;
+
+ while (0 == SYS_IOCTL(source->fd, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &size)) {
+ /* NOTE : min_width min_height and max_width max_height */
+ /* are equal for now so take just one of them */
+ ret = 0;
+ res[size.index].width = size.max_width;
+ res[size.index].height = size.max_height;
+
+ ++size.index;
+ if (size.index >= max_rect)
+ break;
+
+ }
+
+ return ret;
+}
+
+int path_set_resolution(struct omap3mcplugin *plugin,
+ struct v4l2_rect *src_res,
+ enum mc_plugin_pixelformat *src_pix,
+ struct v4l2_rect *dst_res,
+ enum mc_plugin_pixelformat *dst_pix)
+{
+ struct media_link *link = NULL;
+ struct sub_module *pos, *source = NULL, *sink = NULL;
+ struct v4l2_rect res;
+ struct v4l2_format format;
+ struct v4l2_subdev_format subdev_fmt;
+ enum mc_plugin_pixelformat source_pix, sink_pix;
+ int first_submodule, err = -1;
+
+ if (!plugin || !src_res || !src_pix ||
+ !dst_res || !dst_pix) {
+
+ MC_PLUGIN_PRINTF("NULL pointer\n");
+ return -1;
+ }
+
+ if (!src_res->width || !src_res->height || MC_PLUGIN_PIX_FMT_INVALID == *src_pix ||
+ !dst_res->width || !dst_res->height || MC_PLUGIN_PIX_FMT_INVALID == *dst_pix) {
+
+ MC_PLUGIN_PRINTF("Wrong input argumets\n");
+ return -1;
+ }
+
+ source_pix = *src_pix;
+ sink_pix = *src_pix;
+ res = *src_res;
+
+ first_submodule = 1;
+ list_for_each_entry(pos, &plugin->path->container, list) {
+
+ /* If first submodule just set source pixel format and resolution */
+ if (NULL == source) {
+ source = pos;
+ continue;
+ }
+
+ /* If we reach last submodule apply destination resolution */
+ if (media_entity_type(pos->entity) == MEDIA_ENTITY_TYPE_NODE && sink) {
+ res = *dst_res;
+
+ memset (&format, 0x0, sizeof (struct v4l2_format));
+ format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ err = SYS_IOCTL(pos->entity->fd, VIDIOC_G_FMT, &format);
+ if (err < 0) {
+ perror("VIDIOC_G_FMT:");
+ break;
+ }
+
+ format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ format.fmt.pix.width = dst_res->width;
+ format.fmt.pix.height = dst_res->height;
+ format.fmt.pix.pixelformat = pixel_mc_plugin_to_v4l(*dst_pix);
+ format.fmt.pix.field = V4L2_FIELD_ANY;
+
+ err = SYS_IOCTL(pos->entity->fd, VIDIOC_S_FMT, &format);
+ if (err < 0) {
+ perror("VIDIOC_S_FMT:");
+ break;
+ }
+ }
+
+ sink = pos;
+
+ link = media_find_link(plugin->media, source->entity, sink->entity);
+
+ if (link == NULL) {
+ MC_PLUGIN_PRINTF("No link present between source and sink\n");
+ err = -1;
+ break;
+ }
+
+ if (!(link->flags & MEDIA_LINK_FLAG_ACTIVE)) {
+ MC_PLUGIN_PRINTF("This link is not active\n");
+ err = -1;
+ break;
+ }
+
+ /* Set source format */
+ memset(&subdev_fmt, 0, sizeof(subdev_fmt));
+ subdev_fmt.format.code = pixel_mc_plugin_to_subdev(source_pix);
+ subdev_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ subdev_fmt.format.width = res.width;
+ subdev_fmt.format.height = res.height;
+ subdev_fmt.pad = link->source->index;
+
+ err = SYS_IOCTL(source->entity->fd, VIDIOC_SUBDEV_S_FMT, &subdev_fmt);
+ if (err < 0) {
+ perror("Error set source format:");
+ break;
+ } else {
+ res.width = subdev_fmt.format.width;
+ res.height = subdev_fmt.format.height;
+ source_pix = pixel_subdev_to_mc_plugin(subdev_fmt.format.code);
+ }
+
+ if (media_entity_type(pos->entity) == MEDIA_ENTITY_TYPE_NODE && sink)
+ break;
+
+ /* Set sink format */
+ memset(&subdev_fmt, 0, sizeof(subdev_fmt));
+ subdev_fmt.format.code = pixel_mc_plugin_to_subdev(sink_pix);
+ subdev_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ subdev_fmt.format.width = res.width;
+ subdev_fmt.format.height = res.height;
+ subdev_fmt.pad = link->sink->index;
+
+ err = SYS_IOCTL(sink->entity->fd, VIDIOC_SUBDEV_S_FMT, &subdev_fmt);
+ if (err < 0) {
+ perror("Error set sink format:");
+ break;
+ } else {
+ res.width = subdev_fmt.format.width;
+ res.height = subdev_fmt.format.height;
+ sink_pix = pixel_subdev_to_mc_plugin(subdev_fmt.format.code);
+ }
+
+ /* Sink pix is not supported modify source pixelformat also */
+ if (source_pix != sink_pix) {
+ source_pix = sink_pix;
+
+ memset(&subdev_fmt, 0, sizeof(subdev_fmt));
+ subdev_fmt.format.code = pixel_mc_plugin_to_subdev(source_pix);
+ subdev_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ subdev_fmt.format.width = res.width;
+ subdev_fmt.format.height = res.height;
+ subdev_fmt.pad = link->source->index;
+
+ err = SYS_IOCTL(source->entity->fd, VIDIOC_SUBDEV_S_FMT, &subdev_fmt);
+ if (err < 0) {
+ perror("Error set source format:");
+ break;
+ } else {
+ res.width = subdev_fmt.format.width;
+ res.height = subdev_fmt.format.height;
+ source_pix = pixel_subdev_to_mc_plugin(subdev_fmt.format.code);
+ }
+
+ err += (source_pix == sink_pix) ? 0 : -1;
+ }
+
+ if (err < 0) {
+ fprintf(stderr, "Error set source format for second time %s\n", source->entity->info.name);
+ break;
+ }
+
+ /* Store correct source pixel format and resolution */
+ if (first_submodule) {
+ *src_pix = source_pix;
+ *src_res = res;
+ first_submodule = 0;
+ }
+
+ /* Try to set destination pixel fmt */
+ source_pix = sink_pix = *dst_pix;
+ /* Continue with next element */
+ source = sink;
+ }
+
+ /* Set Destination resolution and pixel format */
+ if (0 == err) {
+ *dst_pix = sink_pix;
+ *dst_res = res;
+ }
+
+ return err;
+}
+
+int path_try_resolution(struct omap3mcplugin *plugin,
+ struct v4l2_rect *src_res,
+ enum mc_plugin_pixelformat *src_pix,
+ struct v4l2_rect *dst_res,
+ enum mc_plugin_pixelformat *dst_pix)
+{
+ struct media_link *link = NULL;
+ struct sub_module *pos, *source = NULL, *sink = NULL;
+ struct v4l2_rect res;
+ struct v4l2_subdev_format subdev_fmt;
+ enum mc_plugin_pixelformat source_pix, sink_pix;
+ int first_submodule, err = -1;
+
+ if (!plugin || !src_res || !src_pix ||
+ !dst_res || !dst_pix) {
+
+ MC_PLUGIN_PRINTF("NULL pointer\n"
+ " plugin=%p\n"
+ " src_res=%p, src_pix=%p\n"
+ " dst_res=%p, dst_pix=%p\n",
+ plugin,
+ src_res, src_pix,
+ dst_res, dst_pix);
+
+ return -1;
+ }
+
+ if (!src_res->width || !src_res->height || MC_PLUGIN_PIX_FMT_INVALID == *src_pix ||
+ !dst_res->width || !dst_res->height || MC_PLUGIN_PIX_FMT_INVALID == *dst_pix) {
+
+ MC_PLUGIN_PRINTF("Wrong input argumets\n"
+ " Source format: Width = %d, Height = %d, Format = %d\n"
+ " Destination format: Width = %d, Height = %d, Format = %d\n",
+ src_res->width, src_res->height, *src_pix,
+ dst_res->width, dst_res->height, *dst_pix);
+ return -1;
+ }
+
+ source_pix = *src_pix;
+ sink_pix = *src_pix;
+ res = *src_res;
+
+ first_submodule = 1;
+ list_for_each_entry(pos, &plugin->path->container, list) {
+
+ /* If first submodule just set source pixel format and resolution */
+ if (NULL == source) {
+ source = pos;
+ continue;
+ }
+
+ /* If we reach last submodule apply destination resolution */
+ if (media_entity_type(pos->entity) == MEDIA_ENTITY_TYPE_NODE && sink)
+ res = *dst_res;
+
+ sink = pos;
+
+ link = media_find_link(plugin->media, source->entity, sink->entity);
+
+ if (NULL == link) {
+ MC_PLUGIN_PRINTF("No link present between source and sink\n");
+ err = -1;
+ break;
+ }
+
+ if (!(link->flags & MEDIA_LINK_FLAG_ACTIVE)) {
+ MC_PLUGIN_PRINTF("This link is not active\n");
+ err = -1;
+ break;
+ }
+
+ /* Set source format */
+ memset(&subdev_fmt, 0, sizeof(subdev_fmt));
+ subdev_fmt.format.code = pixel_mc_plugin_to_subdev(source_pix);
+ subdev_fmt.which = V4L2_SUBDEV_FORMAT_TRY;
+ subdev_fmt.format.width = res.width;
+ subdev_fmt.format.height = res.height;
+ subdev_fmt.pad = link->source->index;
+
+ err = SYS_IOCTL(source->entity->fd, VIDIOC_SUBDEV_S_FMT, &subdev_fmt);
+ if (err < 0) {
+ perror("Error try source format:");
+ break;
+ } else {
+ res.width = subdev_fmt.format.width;
+ res.height = subdev_fmt.format.height;
+ source_pix = pixel_subdev_to_mc_plugin(subdev_fmt.format.code);
+ }
+
+ if (media_entity_type(pos->entity) == MEDIA_ENTITY_TYPE_NODE && sink)
+ break;
+
+ /* Set sink format */
+ memset(&subdev_fmt, 0, sizeof(subdev_fmt));
+ subdev_fmt.format.code = pixel_mc_plugin_to_subdev(sink_pix);
+ subdev_fmt.which = V4L2_SUBDEV_FORMAT_TRY;
+ subdev_fmt.format.width = res.width;
+ subdev_fmt.format.height = res.height;
+ subdev_fmt.pad = link->sink->index;
+
+ err = SYS_IOCTL(sink->entity->fd, VIDIOC_SUBDEV_S_FMT, &subdev_fmt);
+ if (err < 0) {
+ MC_PLUGIN_PRINTF("Error try sink format\n");
+ break;
+ } else {
+ res.width = subdev_fmt.format.width;
+ res.height = subdev_fmt.format.height;
+ sink_pix = pixel_subdev_to_mc_plugin(subdev_fmt.format.code);
+ }
+
+ /* Sink pix is not supported modify source pixelformat also */
+ if (source_pix != sink_pix) {
+ source_pix = sink_pix;
+
+ memset(&subdev_fmt, 0, sizeof(subdev_fmt));
+ subdev_fmt.format.code = pixel_mc_plugin_to_subdev(source_pix);
+ subdev_fmt.which = V4L2_SUBDEV_FORMAT_TRY;
+ subdev_fmt.format.width = res.width;
+ subdev_fmt.format.height = res.height;
+ subdev_fmt.pad = link->source->index;
+
+ err = SYS_IOCTL(source->entity->fd, VIDIOC_SUBDEV_S_FMT, &subdev_fmt);
+ if (err < 0) {
+ perror("Error try source format:");
+ break;
+ } else {
+ res.width = subdev_fmt.format.width;
+ res.height = subdev_fmt.format.height;
+ source_pix = pixel_subdev_to_mc_plugin(subdev_fmt.format.code);
+ }
+
+ err += (source_pix == sink_pix) ? 0 : -1;
+ }
+
+ if (err < 0) {
+ fprintf(stderr, "Error try source format for second time %s\n", source->entity->info.name);
+ break;
+ }
+
+ /* Store correct source pixel format and resolution */
+ if (first_submodule) {
+ *src_pix = source_pix;
+ *src_res = res;
+ first_submodule = 0;
+ }
+
+ /* Try to set destination pixel fmt */
+ source_pix = sink_pix = *dst_pix;
+ /* Continue with next element */
+ source = sink;
+ }
+
+ /* Set Destination resolution and pixel format */
+ if (0 == err) {
+ *dst_pix = sink_pix;
+ *dst_res = res;
+ }
+
+ return err;
+}
diff --git a/paths.h b/paths.h
new file mode 100644
index 0000000..58d2409
--- /dev/null
+++ b/paths.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation
+ *
+ * Contact: Yordan Kamenov <ykamenov@mm-sol.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ */
+
+#ifndef __PATHS_H__
+#define __PATHS_H__
+
+#include <linux/videodev2.h>
+#include <mediactl/media.h>
+
+#include "libv4l2plugin-omap3mc.h"
+
+struct media_link *media_find_link(struct media_device *media,
+ struct media_entity *source,
+ struct media_entity *sink);
+int pixel_mc_plugin_to_subdev(enum mc_plugin_pixelformat pixfmt);
+enum mc_plugin_pixelformat pixel_subdev_to_mc_plugin(int pixfmt);
+int pixel_mc_plugin_to_v4l(enum mc_plugin_pixelformat pixfmt);
+enum mc_plugin_pixelformat pixel_v4l_to_mc_plugin(int pixfmt);
+const struct capture_pipeline *pipe_sensor_yuv(int primary);
+struct ipipe_descriptor *path_allocate(struct media_device *media,
+ const struct capture_pipeline *pipe);
+struct sub_module *submodule_alloc();
+void submodule_free(struct sub_module *sb);
+struct sub_module *path_destination_submodule(struct ipipe_descriptor *path);
+int path_power_on(struct ipipe_descriptor *path, int fd);
+int submodule_open(struct sub_module *sb, int fd, int last_sb);
+int path_connect_entities(struct media_device *media,
+ struct ipipe_descriptor *path);
+void path_power_off(struct ipipe_descriptor *path);
+int submodule_power_off(struct sub_module *sb, int last_sb);
+int path_disconnect_entities(struct media_device *media,
+ struct ipipe_descriptor *path);
+int path_enum_src_framesizes(struct omap3mcplugin *plugin,
+ enum mc_plugin_pixelformat *pixfmt,
+ struct v4l2_rect *res, int max_rect);
+int path_set_resolution(struct omap3mcplugin *plugin,
+ struct v4l2_rect *src_res,
+ enum mc_plugin_pixelformat *src_pix,
+ struct v4l2_rect *dst_res,
+ enum mc_plugin_pixelformat *dst_pix);
+int path_try_resolution(struct omap3mcplugin *plugin,
+ struct v4l2_rect *src_res,
+ enum mc_plugin_pixelformat *src_pix,
+ struct v4l2_rect *dst_res,
+ enum mc_plugin_pixelformat *dst_pix);
+
+
+#endif /* __PATHS_H__ */
diff --git a/sl_list.h b/sl_list.h
new file mode 100644
index 0000000..e48b984
--- /dev/null
+++ b/sl_list.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation
+ *
+ * Contact: Yordan Kamenov <ykamenov@mm-sol.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ */
+
+#ifndef __SINGLE_LINKED_LIST_H__
+#define __SINGLE_LINKED_LIST_H__
+
+/* Simple single linked list implementation. */
+
+struct list_head {
+ struct list_head *next;
+};
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+ list->next = list;
+}
+
+/* Insert new node after known node */
+static inline void list_add_after(struct list_head *new,
+ struct list_head *prev)
+{
+ new->next = prev->next;
+ prev->next = new;
+}
+
+/* Insert new node at the end of the list */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ struct list_head *element = head;
+
+ while (element->next != head)
+ element = element->next;
+
+ list_add_after(new, element);
+}
+
+ /* Get the struct for this entry */
+#define list_entry(ptr, type, member)({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ ((type *)(void *)( (char *)__mptr - offsetof(type,member) ));})
+
+
+/* Iterate over the list */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+#endif
--
1.7.3.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [libv4l-mcplugin PATCH 2/3] Add files for v4l operations
2011-05-19 12:36 [libv4l-mcplugin PATCH 0/3] Media controller plugin for libv4l2 Yordan Kamenov
2011-05-19 12:36 ` [libv4l-mcplugin PATCH 1/3] Add files for media controller pipelines Yordan Kamenov
@ 2011-05-19 12:36 ` Yordan Kamenov
2011-05-19 12:36 ` [libv4l-mcplugin PATCH 3/3] Add libv4l2 media controller plugin interface files Yordan Kamenov
2011-05-20 7:11 ` [libv4l-mcplugin PATCH 0/3] Media controller plugin for libv4l2 Hans de Goede
3 siblings, 0 replies; 6+ messages in thread
From: Yordan Kamenov @ 2011-05-19 12:36 UTC (permalink / raw)
To: linux-media; +Cc: sakari.ailus, Yordan Kamenov
Add files with implementation of v4l ioctls.
Signed-off-by: Yordan Kamenov <ykamenov@mm-sol.com>
---
operations.c | 611 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
operations.h | 44 +++++
2 files changed, 655 insertions(+), 0 deletions(-)
create mode 100644 operations.c
create mode 100644 operations.h
diff --git a/operations.c b/operations.c
new file mode 100644
index 0000000..307785f
--- /dev/null
+++ b/operations.c
@@ -0,0 +1,611 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation
+ *
+ * Contact: Yordan Kamenov <ykamenov@mm-sol.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ */
+
+#include <stdarg.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <stddef.h>
+
+#include <linux/v4l2-subdev.h>
+
+#include "sl_list.h"
+#include "operations.h"
+#include "paths.h"
+
+#define CHECK_DST_SUBMODULE(dst_sm, error_msg) {\
+ if ((dst_sm) == NULL) {\
+ MC_PLUGIN_PRINTF(error_msg);\
+ errno = EBADF;\
+ return -1;\
+ }\
+}
+
+int mc_vidioc_streamon(struct omap3mcplugin *plugin, unsigned long int request, ...)
+{
+ int ret = -1;
+ enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ struct sub_module *dst_sub_module = NULL;
+
+ if (plugin->path)
+ dst_sub_module = path_destination_submodule(plugin->path);
+
+ CHECK_DST_SUBMODULE(dst_sub_module, "streamon failed\n");
+
+ ret = SYS_IOCTL(dst_sub_module->entity->fd, VIDIOC_STREAMON, &type);
+ if (ret) {
+ int saved_err = errno;
+ MC_PLUGIN_PRINTF("streamon: %s\n", strerror(errno));
+ errno = saved_err;
+ }
+
+ return ret;
+}
+
+int mc_vidioc_streamoff(struct omap3mcplugin *plugin, unsigned long int request, ...)
+{
+ int ret = -1;
+ enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ struct sub_module *dst_sub_module = NULL;
+
+ if (plugin->path)
+ dst_sub_module = path_destination_submodule(plugin->path);
+
+ CHECK_DST_SUBMODULE(dst_sub_module, "streamoff failed\n");
+
+ ret = SYS_IOCTL(dst_sub_module->entity->fd, VIDIOC_STREAMOFF, &type);
+ if (ret) {
+ int saved_err = errno;
+ MC_PLUGIN_PRINTF("streamoff: %s\n", strerror(errno));
+ errno = saved_err;
+ }
+
+ return ret;
+}
+
+int mc_vidioc_s_fmt(struct omap3mcplugin *plugin, unsigned long int request, ...)
+{
+ int pix_count, res_count, found = 0, ret = -1;
+ enum mc_plugin_pixelformat src_pixfmt, dst_pixfmt, temp_pixfmt;
+ struct v4l2_rect src_res, dst_res;
+ const int max_rect = 10;
+ struct v4l2_rect res[max_rect];
+ struct v4l2_format *arg;
+ va_list ap;
+ enum mc_plugin_pixelformat pixfmt;
+
+ va_start(ap, request);
+ arg = va_arg(ap, struct v4l2_format *);
+ va_end(ap);
+
+ pixfmt = pixel_v4l_to_mc_plugin(arg->fmt.pix.pixelformat);
+
+ /* Check if destionation format is supported from pipeline */
+ for (pix_count = 0;
+ MC_PLUGIN_PIX_FMT_INVALID != plugin->path->pipe->out_pixfmt[pix_count];
+ pix_count++)
+ if (pixfmt == plugin->path->pipe->out_pixfmt[pix_count]) {
+ dst_pixfmt = pixfmt;
+ ret = 0;
+ break;
+ }
+
+ if (ret < 0) {
+ MC_PLUGIN_PRINTF("Destination format not supported\n");
+ errno = EINVAL;
+ return ret;
+ }
+
+ for (pix_count = 0;
+ MC_PLUGIN_PIX_FMT_INVALID != plugin->path->pipe->in_pixfmt[pix_count];
+ pix_count++) {
+
+ memset(res, 0x0, sizeof(res));
+ src_pixfmt = plugin->path->pipe->in_pixfmt[pix_count];
+ temp_pixfmt = src_pixfmt;
+
+ ret = path_enum_src_framesizes(plugin, &src_pixfmt, res, max_rect);
+
+ /* Find Best capture resolution */
+ for (res_count = 0; res_count < max_rect; res_count++) {
+
+ src_res = res[res_count];
+ dst_res.width = arg->fmt.pix.width;
+ dst_res.height = arg->fmt.pix.height;
+
+ /* If width and height are not valid we reach end of resolutions */
+ if (0 == res[res_count].width && 0 == res[res_count].height)
+ break;
+
+ ret = path_set_resolution(plugin, &src_res, &src_pixfmt,
+ &dst_res, &dst_pixfmt);
+ if (ret < 0) {
+ MC_PLUGIN_PRINTF("Set Resolution fail!\n");
+ break;
+ }
+
+ if (dst_res.width == arg->fmt.pix.width &&
+ dst_res.height == arg->fmt.pix.height &&
+ temp_pixfmt == src_pixfmt) {
+ /* Capture resolution found */
+ found = 1;
+ break;
+ }
+ }
+
+ if (1 == found)
+ break;
+ }
+
+ return ret;
+}
+
+int mc_vidioc_g_fmt(struct omap3mcplugin *plugin, unsigned long int request, ...)
+{
+ int ret = -1;
+ struct v4l2_format *arg;
+ va_list ap;
+ struct sub_module *dst_sub_module = NULL;
+
+ va_start(ap, request);
+ arg = va_arg(ap, struct v4l2_format *);
+ va_end(ap);
+
+ if (plugin->path)
+ dst_sub_module = path_destination_submodule(plugin->path);
+
+ CHECK_DST_SUBMODULE(dst_sub_module, "get format failed\n");
+
+ ret = SYS_IOCTL(dst_sub_module->entity->fd, VIDIOC_G_FMT, arg);
+ if (ret) {
+ int saved_err = errno;
+ MC_PLUGIN_PRINTF("get format: %s\n", strerror(errno));
+ errno = saved_err;
+ }
+
+ return ret;
+}
+
+int mc_vidioc_try_fmt(struct omap3mcplugin *plugin, unsigned long int request, ...)
+{
+ int pix_count, res_count, found = 0, ret = -1;
+ enum mc_plugin_pixelformat src_pixfmt, dst_pixfmt, temp_pixfmt;
+ struct v4l2_rect src_res, dst_res;
+ const int max_rect = 10;
+ struct v4l2_rect res[max_rect];
+ struct v4l2_format *arg;
+ va_list ap;
+
+ va_start(ap, request);
+ arg = va_arg(ap, struct v4l2_format *);
+ va_end(ap);
+
+ enum mc_plugin_pixelformat pixfmt = pixel_v4l_to_mc_plugin(arg->fmt.pix.pixelformat);
+
+ /* Check if destionation format is supported from pipeline */
+ for (pix_count = 0;
+ MC_PLUGIN_PIX_FMT_INVALID != plugin->path->pipe->out_pixfmt[pix_count];
+ pix_count++)
+ if (pixfmt == plugin->path->pipe->out_pixfmt[pix_count]) {
+ dst_pixfmt = pixfmt;
+ ret = 0;
+ break;
+ }
+
+ if (ret < 0) {
+ MC_PLUGIN_PRINTF("Destination format not supported\n");
+ errno = EINVAL;
+ return ret;
+ }
+
+ for (pix_count = 0;
+ MC_PLUGIN_PIX_FMT_INVALID != plugin->path->pipe->in_pixfmt[pix_count];
+ pix_count++) {
+
+ memset(res, 0x0, sizeof(res));
+ src_pixfmt = plugin->path->pipe->in_pixfmt[pix_count];
+ temp_pixfmt = src_pixfmt;
+
+ ret = path_enum_src_framesizes(plugin, &src_pixfmt, res, max_rect);
+
+ /* Find Best capture resolution */
+ for (res_count = 0; res_count < max_rect; res_count++) {
+
+ src_res = res[res_count];
+ dst_res.width = arg->fmt.pix.width;
+ dst_res.height = arg->fmt.pix.height;
+
+ /* If width and height are not valid we reach end of resolutions */
+ if (0 == res[res_count].width && 0 == res[res_count].height)
+ break;
+
+ ret = path_try_resolution(plugin, &src_res, &src_pixfmt,
+ &dst_res, &dst_pixfmt);
+ if (ret < 0) {
+ MC_PLUGIN_PRINTF("Set Resolution fail!\n");
+ break;
+ }
+
+ if (dst_res.width == arg->fmt.pix.width &&
+ dst_res.height == arg->fmt.pix.height &&
+ temp_pixfmt == src_pixfmt) {
+ /* Capture resolution found */
+ found = 1;
+ break;
+ }
+ }
+
+ if (1 == found)
+ break;
+ }
+
+ return ret;
+}
+
+int mc_vidioc_s_crop(struct omap3mcplugin *plugin, unsigned long int request, ...)
+{
+ int ret = -1;
+ struct v4l2_subdev_crop s_crop;
+ struct v4l2_crop *arg;
+ va_list ap;
+
+ va_start(ap, request);
+ arg = va_arg(ap, struct v4l2_crop *);
+ va_end(ap);
+
+ memset (&s_crop, 0, sizeof (s_crop));
+ s_crop.pad = 0; /* It has only one sink pad */
+ s_crop.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ s_crop.rect.top = arg->c.top;
+ s_crop.rect.left = arg->c.left;
+ s_crop.rect.width = arg->c.width;
+ s_crop.rect.height = arg->c.height;
+
+ ret = SYS_IOCTL(plugin->fd, VIDIOC_SUBDEV_S_CROP, &s_crop);
+ if (ret < 0) {
+ MC_PLUGIN_PRINTF("set crop: %s\n", strerror(errno));
+ } else {
+ arg->c.top = s_crop.rect.top;
+ arg->c.left = s_crop.rect.left;
+ arg->c.width = s_crop.rect.width;
+ arg->c.height = s_crop.rect.height;
+ }
+
+ return ret;
+}
+
+int mc_vidioc_g_crop(struct omap3mcplugin *plugin, unsigned long int request, ...)
+{
+ int ret = -1;
+ struct v4l2_subdev_crop g_crop;
+ struct v4l2_crop *arg;
+ va_list ap;
+
+ va_start(ap, request);
+ arg = va_arg(ap, struct v4l2_crop *);
+ va_end(ap);
+
+ memset (&g_crop, 0, sizeof (g_crop));
+ g_crop.pad = 0; /* It has only one sink pad */
+ g_crop.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+
+ ret = SYS_IOCTL(plugin->fd, VIDIOC_SUBDEV_G_CROP, &g_crop);
+ if (ret < 0) {
+ MC_PLUGIN_PRINTF("get crop: %s\n", strerror(errno));
+ } else {
+ arg->c.top = g_crop.rect.top;
+ arg->c.left = g_crop.rect.left;
+ arg->c.width = g_crop.rect.width;
+ arg->c.height = g_crop.rect.height;
+ }
+
+ return ret;
+}
+
+int mc_vidioc_queryctrl(struct omap3mcplugin *plugin, unsigned long int request, ...)
+{
+ int ret = -1;
+ struct sub_module *sub_mod;
+ struct v4l2_queryctrl *arg;
+ va_list ap;
+
+ va_start(ap, request);
+ arg = va_arg(ap, struct v4l2_queryctrl *);
+ va_end(ap);
+
+ list_for_each_entry(sub_mod, &plugin->path->container, list) {
+ ret = SYS_IOCTL(sub_mod->entity->fd, VIDIOC_QUERYCTRL, arg);
+ if (ret == 0)
+ break;
+ }
+
+ return ret;
+}
+
+int mc_vidioc_g_ctrl(struct omap3mcplugin *plugin, unsigned long int request, ...)
+{
+ int ret = -1;
+ struct sub_module *sub_mod;
+ struct v4l2_control *arg;
+ va_list ap;
+
+ va_start(ap, request);
+ arg = va_arg(ap, struct v4l2_control *);
+ va_end(ap);
+
+ list_for_each_entry(sub_mod, &plugin->path->container, list) {
+ ret = SYS_IOCTL(sub_mod->entity->fd, VIDIOC_G_CTRL, arg);
+ if (ret == 0)
+ break;
+ }
+
+ return ret;
+}
+
+int mc_vidioc_s_ctrl(struct omap3mcplugin *plugin, unsigned long int request, ...)
+{
+ int ret = -1;
+ struct sub_module *sub_mod;
+ struct v4l2_control *arg;
+ va_list ap;
+
+ va_start(ap, request);
+ arg = va_arg(ap, struct v4l2_control *);
+ va_end(ap);
+
+ list_for_each_entry(sub_mod, &plugin->path->container, list) {
+ ret = SYS_IOCTL(sub_mod->entity->fd, VIDIOC_S_CTRL, arg);
+ if (ret == 0)
+ break;
+ }
+
+ return ret;
+}
+
+int mc_vidioc_querycap(struct omap3mcplugin *plugin, unsigned long int request, ...)
+{
+ int ret = -1;
+ struct v4l2_capability *arg;
+ va_list ap;
+
+ va_start(ap, request);
+ arg = va_arg(ap, struct v4l2_capability *);
+ va_end(ap);
+
+ ret = SYS_IOCTL(plugin->fd, VIDIOC_QUERYCAP, arg);
+ if (ret) {
+ int saved_err = errno;
+ MC_PLUGIN_PRINTF("query capabilities: %s\n", strerror(errno));
+ errno = saved_err;
+ }
+
+ return ret;
+}
+
+int mc_vidioc_enum_fmt(struct omap3mcplugin *plugin, unsigned long int request, ...)
+{
+ int ret = -1;
+ struct v4l2_fmtdesc *arg;
+ va_list ap;
+ struct v4l2_subdev_mbus_code_enum mbus_format;
+ struct sub_module *dst_sub_module = NULL;
+
+ va_start(ap, request);
+ arg = va_arg(ap, struct v4l2_fmtdesc *);
+ va_end(ap);
+
+ mbus_format.pad = 0;
+ mbus_format.index = arg->index;
+
+ if (plugin->path)
+ dst_sub_module = path_destination_submodule(plugin->path);
+
+ CHECK_DST_SUBMODULE(dst_sub_module, "enum fmt failed\n");
+
+ ret = SYS_IOCTL(dst_sub_module->entity->fd, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &mbus_format);
+ if (ret == 0) {
+ arg->flags = 0;
+ arg->pixelformat = pixel_mc_plugin_to_v4l(mbus_format.code);
+ }
+
+ return ret;
+}
+
+int mc_vidioc_enum_framesizes(struct omap3mcplugin *plugin, unsigned long int request, ...)
+{
+ int ret = -1;
+ struct v4l2_frmsizeenum *arg;
+ va_list ap;
+ struct sub_module *dst_sub_module = NULL;
+
+ va_start(ap, request);
+ arg = va_arg(ap, struct v4l2_frmsizeenum *);
+ va_end(ap);
+
+
+ if (plugin->path)
+ dst_sub_module = path_destination_submodule(plugin->path);
+
+ CHECK_DST_SUBMODULE(dst_sub_module, "enum framesizes\n");
+
+ ret = SYS_IOCTL(dst_sub_module->entity->fd, VIDIOC_ENUM_FRAMESIZES, arg);
+ if (ret) {
+ int saved_err = errno;
+ MC_PLUGIN_PRINTF("enum framesizes: %s\n", strerror(errno));
+ errno = saved_err;
+ }
+
+ return ret;
+}
+
+int mc_vidioc_enum_frameintervals(struct omap3mcplugin *plugin, unsigned long int request, ...)
+{
+ int ret = -1;
+ struct media_entity *source, *sink;
+ struct media_link *link;
+ struct v4l2_subdev_frame_interval_enum e_interval;
+ const char *sink_name, *source_name;
+ struct v4l2_frmivalenum *arg;
+ va_list ap;
+
+ va_start(ap, request);
+ arg = va_arg(ap, struct v4l2_frmivalenum *);
+ va_end(ap);
+
+ source_name = plugin->path->pipe->path[0];
+ sink_name = plugin->path->pipe->path[1];
+
+ source = media_get_entity_by_name(plugin->media, source_name, strlen(source_name));
+ sink = media_get_entity_by_name(plugin->media, sink_name, strlen(sink_name));
+
+ if ((NULL == sink) || (NULL == source)) {
+ MC_PLUGIN_PRINTF("Error finding entities\n");
+ errno = EBADF;
+ return -1;
+ }
+
+ link = media_find_link(plugin->media, source, sink);
+
+ if (NULL == link) {
+ MC_PLUGIN_PRINTF("No link present between source and sink\n");
+ errno = EBADF;
+ return -1;
+ }
+
+ e_interval.index = arg->index;
+ e_interval.code = arg->pixel_format;
+ e_interval.width = arg->width;
+ e_interval.height = arg->height;
+ e_interval.pad = link->source->index;
+
+ ret = SYS_IOCTL(source->fd, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &e_interval);
+ if (ret == 0) {
+ arg->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ arg->discrete.numerator = e_interval.interval.numerator;
+ arg->discrete.denominator = e_interval.interval.denominator;
+ }
+
+ return ret;
+}
+
+int mc_vidioc_reqbufs(struct omap3mcplugin *plugin, unsigned long int request, ...)
+{
+ int ret = -1;
+ struct v4l2_requestbuffers *arg;
+ va_list ap;
+ struct sub_module *dst_sub_module = NULL;
+
+ va_start(ap, request);
+ arg = va_arg(ap, struct v4l2_requestbuffers *);
+ va_end(ap);
+
+ if (plugin->path)
+ dst_sub_module = path_destination_submodule(plugin->path);
+
+ CHECK_DST_SUBMODULE(dst_sub_module, "request buffer failed\n");
+
+ ret = SYS_IOCTL(dst_sub_module->entity->fd, VIDIOC_REQBUFS, arg);
+ if (ret) {
+ int saved_err = errno;
+ MC_PLUGIN_PRINTF("request buffer: %s\n", strerror(errno));
+ errno = saved_err;
+ }
+
+ return ret;
+}
+
+int mc_vidioc_querybuf(struct omap3mcplugin *plugin, unsigned long int request, ...)
+{
+ int ret = -1;
+ struct v4l2_buffer *arg;
+ va_list ap;
+ struct sub_module *dst_sub_module = NULL;
+
+ va_start(ap, request);
+ arg = va_arg(ap, struct v4l2_buffer *);
+ va_end(ap);
+
+ if (plugin->path)
+ dst_sub_module = path_destination_submodule(plugin->path);
+
+ CHECK_DST_SUBMODULE(dst_sub_module, "query failed\n");
+
+ ret = SYS_IOCTL(dst_sub_module->entity->fd, VIDIOC_QUERYBUF, arg);
+ if (ret) {
+ int saved_err = errno;
+ MC_PLUGIN_PRINTF("query buffer: %s\n", strerror(errno));
+ errno = saved_err;
+ }
+
+ return ret;
+}
+
+int mc_vidioc_qbuf(struct omap3mcplugin *plugin, unsigned long int request, ...)
+{
+ int ret = -1;
+ struct v4l2_buffer *arg;
+ va_list ap;
+ struct sub_module *dst_sub_module = NULL;
+
+ va_start(ap, request);
+ arg = va_arg(ap, struct v4l2_buffer *);
+ va_end(ap);
+
+ if (plugin->path)
+ dst_sub_module = path_destination_submodule(plugin->path);
+
+ CHECK_DST_SUBMODULE(dst_sub_module, "queue buffer failed\n");
+
+ ret = SYS_IOCTL(dst_sub_module->entity->fd, VIDIOC_QBUF, arg);
+ if (ret) {
+ int saved_err = errno;
+ MC_PLUGIN_PRINTF("queue buffer: %s\n", strerror(errno));
+ errno = saved_err;
+ }
+
+ return ret;
+}
+
+int mc_vidioc_dqbuf(struct omap3mcplugin *plugin, unsigned long int request, ...)
+{
+ int ret = -1;
+ struct v4l2_buffer *arg;
+ va_list ap;
+ struct sub_module *dst_sub_module = NULL;
+
+ va_start(ap, request);
+ arg = va_arg(ap, struct v4l2_buffer *);
+ va_end(ap);
+
+ if (plugin->path)
+ dst_sub_module = path_destination_submodule(plugin->path);
+
+ CHECK_DST_SUBMODULE(dst_sub_module, "dequeue failed\n");
+
+ ret = SYS_IOCTL(dst_sub_module->entity->fd, VIDIOC_DQBUF, arg);
+ if (ret) {
+ int saved_err = errno;
+ MC_PLUGIN_PRINTF("dequeue buffer: %s\n", strerror(errno));
+ errno = saved_err;
+ }
+
+ return ret;
+}
diff --git a/operations.h b/operations.h
new file mode 100644
index 0000000..62129c0
--- /dev/null
+++ b/operations.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation
+ *
+ * Contact: Yordan Kamenov <ykamenov@mm-sol.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ */
+
+#ifndef __OPERATIONS_H__
+#define __OPERATIONS_H__
+
+#include "libv4l2plugin-omap3mc.h"
+
+int mc_vidioc_streamon(struct omap3mcplugin *plugin, unsigned long int request, ...);
+int mc_vidioc_streamoff(struct omap3mcplugin *plugin, unsigned long int request, ...);
+int mc_vidioc_s_fmt(struct omap3mcplugin *plugin, unsigned long int request, ...);
+int mc_vidioc_g_fmt(struct omap3mcplugin *plugin, unsigned long int request, ...);
+int mc_vidioc_try_fmt(struct omap3mcplugin *plugin, unsigned long int request, ...);
+int mc_vidioc_s_crop(struct omap3mcplugin *plugin, unsigned long int request, ...);
+int mc_vidioc_g_crop(struct omap3mcplugin *plugin, unsigned long int request, ...);
+int mc_vidioc_queryctrl(struct omap3mcplugin *plugin, unsigned long int request, ...);
+int mc_vidioc_g_ctrl(struct omap3mcplugin *plugin, unsigned long int request, ...);
+int mc_vidioc_s_ctrl(struct omap3mcplugin *plugin, unsigned long int request, ...);
+int mc_vidioc_querycap(struct omap3mcplugin *plugin, unsigned long int request, ...);
+int mc_vidioc_enum_fmt(struct omap3mcplugin *plugin, unsigned long int request, ...);
+int mc_vidioc_enum_framesizes(struct omap3mcplugin *plugin, unsigned long int request, ...);
+int mc_vidioc_enum_frameintervals(struct omap3mcplugin *plugin, unsigned long int request, ...);
+int mc_vidioc_reqbufs(struct omap3mcplugin *plugin, unsigned long int request, ...);
+int mc_vidioc_querybuf(struct omap3mcplugin *plugin, unsigned long int request, ...);
+int mc_vidioc_qbuf(struct omap3mcplugin *plugin, unsigned long int request, ...);
+int mc_vidioc_dqbuf(struct omap3mcplugin *plugin, unsigned long int request, ...);
+
+#endif /* __OPERATIONS_H__ */
--
1.7.3.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [libv4l-mcplugin PATCH 3/3] Add libv4l2 media controller plugin interface files
2011-05-19 12:36 [libv4l-mcplugin PATCH 0/3] Media controller plugin for libv4l2 Yordan Kamenov
2011-05-19 12:36 ` [libv4l-mcplugin PATCH 1/3] Add files for media controller pipelines Yordan Kamenov
2011-05-19 12:36 ` [libv4l-mcplugin PATCH 2/3] Add files for v4l operations Yordan Kamenov
@ 2011-05-19 12:36 ` Yordan Kamenov
2011-05-20 7:11 ` [libv4l-mcplugin PATCH 0/3] Media controller plugin for libv4l2 Hans de Goede
3 siblings, 0 replies; 6+ messages in thread
From: Yordan Kamenov @ 2011-05-19 12:36 UTC (permalink / raw)
To: linux-media; +Cc: sakari.ailus, Yordan Kamenov
Add interface functions init(), close() and ioctl(), called by libv4l2.
Signed-off-by: Yordan Kamenov <ykamenov@mm-sol.com>
---
libv4l2plugin-omap3mc.c | 241 +++++++++++++++++++++++++++++++++++++++++++++++
libv4l2plugin-omap3mc.h | 91 ++++++++++++++++++
2 files changed, 332 insertions(+), 0 deletions(-)
create mode 100644 libv4l2plugin-omap3mc.c
create mode 100644 libv4l2plugin-omap3mc.h
diff --git a/libv4l2plugin-omap3mc.c b/libv4l2plugin-omap3mc.c
new file mode 100644
index 0000000..e5b5ef0
--- /dev/null
+++ b/libv4l2plugin-omap3mc.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation
+ *
+ * Contact: Yordan Kamenov <ykamenov@mm-sol.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ */
+
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <glob.h>
+#include <linux/videodev2.h>
+#include <mediactl/media.h>
+
+#include "libv4l2-plugin.h"
+#include "libv4l2plugin-omap3mc.h"
+#include "paths.h"
+#include "operations.h"
+
+#if __GNUC__ >= 4
+#define PLUGIN_PUBLIC __attribute__ ((visibility("default")))
+#define PLUGIN_HIDDEN __attribute__ ((visibility("hidden")))
+#else
+#define PLUGIN_PUBLIC
+#define PLUGIN_HIDDEN
+#endif
+
+/* Check if /dev/media0 is already open*/
+int media_in_use()
+{
+ int glob_ret, file, ret = 0;
+ glob_t globbuf;
+ ssize_t link_len;
+ char file_name[16];
+
+ glob_ret = glob("/proc/self/fd/*", 0, NULL, &globbuf);
+
+ if (glob_ret == GLOB_NOSPACE)
+ return ret;
+
+ if (glob_ret == GLOB_ABORTED || glob_ret == GLOB_NOMATCH)
+ goto leave;
+
+ for (file = 0; file < globbuf.gl_pathc; file++) {
+ link_len = readlink(globbuf.gl_pathv[file],
+ file_name, strlen(MEDIA_DEVICE));
+ if (link_len == strlen(MEDIA_DEVICE))
+ file_name[link_len] = '\0';
+ else
+ continue;
+
+ if (!strncmp(file_name, MEDIA_DEVICE, strlen(MEDIA_DEVICE))) {
+ ret = 1;
+ break;
+ }
+ }
+
+leave:
+ globfree(&globbuf);
+
+ return ret;
+}
+
+PLUGIN_HIDDEN void * omap3mc_init(int fd)
+{
+ int ret = -1, primary;
+ struct omap3mcplugin *plugin;
+ const struct capture_pipeline *pipe = NULL;
+ struct sub_module *dst_sub_module = NULL;
+ char link_path[20];
+ ssize_t link_len;
+ char file[VIDEO_NODE_LENGTH + 1];
+
+ /* Get filename from fd */
+ sprintf(link_path, "/proc/self/fd/%d", fd);
+ link_len = readlink(link_path, file, VIDEO_NODE_LENGTH);
+ if (link_len == VIDEO_NODE_LENGTH)
+ link_path[link_len] = '\0';
+ else
+ return NULL;
+
+ /* FIXME: What we do if the application is aware of video nodes
+ and tries to open() real /dev/video0 (CSI2 capture) */
+ if (strncmp(file, VIDEO_PRIMARY, strlen(VIDEO_PRIMARY)) == 0)
+ primary = 1;
+ else if (strncmp(file, VIDEO_SECONDARY, strlen(VIDEO_SECONDARY)) == 0)
+ primary = 0;
+ else
+ return NULL;
+
+ if (media_in_use())
+ return NULL;
+
+ plugin = calloc(1, sizeof(*plugin));
+ if (plugin == NULL)
+ return NULL;
+
+ plugin->media = media_open(MEDIA_DEVICE, 1);
+ if (plugin->media == NULL) {
+ free(plugin);
+ return NULL;
+ }
+
+ pipe = pipe_sensor_yuv(primary);
+
+ if (pipe)
+ plugin->path = path_allocate(plugin->media, pipe);
+
+ if (plugin->path)
+ dst_sub_module = path_destination_submodule(plugin->path);
+
+ if (dst_sub_module)
+ ret = path_power_on(plugin->path, fd);
+
+ if (ret == 0)
+ ret = path_connect_entities(plugin->media, plugin->path);
+
+ plugin->fd = dst_sub_module->entity->fd;
+
+ if (ret != 0) {
+ path_disconnect_entities(plugin->media, plugin->path);
+ path_power_off(plugin->path);
+
+ media_close(plugin->media);
+ free(plugin);
+ plugin = NULL;
+ }
+
+ return plugin;
+}
+
+PLUGIN_HIDDEN void omap3mc_close(void *dev_ops_priv)
+{
+ struct omap3mcplugin *plugin;
+
+ if (dev_ops_priv == NULL)
+ return;
+
+ plugin = (struct omap3mcplugin *)dev_ops_priv;
+
+ path_disconnect_entities(plugin->media, plugin->path);
+ path_power_off(plugin->path);
+
+ media_close(plugin->media);
+
+ free(plugin);
+}
+
+PLUGIN_HIDDEN int omap3mc_ioctl(void *dev_ops_priv, int fd,
+ unsigned long int request, void *arg)
+{
+ int ret = -1;
+ struct omap3mcplugin *plugin;
+
+ plugin = (struct omap3mcplugin *)dev_ops_priv;
+
+ switch (request) {
+ case VIDIOC_STREAMON:
+ ret = mc_vidioc_streamon(plugin, request, arg);
+ break;
+ case VIDIOC_STREAMOFF:
+ ret = mc_vidioc_streamoff(plugin, request, arg);
+ break;
+ case VIDIOC_S_FMT:
+ ret = mc_vidioc_s_fmt(plugin, request, arg);
+ break;
+ case VIDIOC_G_FMT:
+ ret = mc_vidioc_g_fmt(plugin, request, arg);
+ break;
+ case VIDIOC_TRY_FMT:
+ ret = mc_vidioc_try_fmt(plugin, request, arg);
+ break;
+ case VIDIOC_S_CROP:
+ ret = mc_vidioc_s_crop(plugin, request, arg);
+ break;
+ case VIDIOC_G_CROP:
+ ret = mc_vidioc_g_crop(plugin, request, arg);
+ break;
+ case VIDIOC_QUERYCTRL:
+ ret = mc_vidioc_queryctrl(plugin, request, arg);
+ break;
+ case VIDIOC_G_CTRL:
+ ret = mc_vidioc_g_ctrl(plugin, request, arg);
+ break;
+ case VIDIOC_S_CTRL:
+ ret = mc_vidioc_s_ctrl(plugin, request, arg);
+ break;
+ case VIDIOC_QUERYCAP:
+ ret = mc_vidioc_querycap(plugin, request, arg);
+ break;
+ case VIDIOC_ENUM_FMT:
+ ret = mc_vidioc_enum_fmt(plugin, request, arg);
+ break;
+ case VIDIOC_ENUM_FRAMESIZES:
+ ret = mc_vidioc_enum_framesizes(plugin, request, arg);
+ break;
+ case VIDIOC_ENUM_FRAMEINTERVALS:
+ ret = mc_vidioc_enum_frameintervals(plugin, request, arg);
+ break;
+ case VIDIOC_REQBUFS:
+ ret = mc_vidioc_reqbufs(plugin, request, arg);
+ break;
+ case VIDIOC_QUERYBUF:
+ ret = mc_vidioc_querybuf(plugin, request, arg);
+ break;
+ case VIDIOC_QBUF:
+ ret = mc_vidioc_qbuf(plugin, request, arg);
+ break;
+ case VIDIOC_DQBUF:
+ ret = mc_vidioc_dqbuf(plugin, request, arg);
+ break;
+ default:
+ errno = EINVAL;
+ ret = -1;
+ break;
+ }
+
+ return ret;
+}
+
+PLUGIN_PUBLIC const struct libv4l2_dev_ops libv4l2_plugin = {
+ .init = &omap3mc_init,
+ .close = &omap3mc_close,
+ .ioctl = &omap3mc_ioctl,
+ .read = NULL
+};
diff --git a/libv4l2plugin-omap3mc.h b/libv4l2plugin-omap3mc.h
new file mode 100644
index 0000000..430df96
--- /dev/null
+++ b/libv4l2plugin-omap3mc.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation
+ *
+ * Contact: Yordan Kamenov <ykamenov@mm-sol.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ */
+
+#ifndef __LIBV4L2PLUGIN_OMAP3MC_H__
+#define __LIBV4L2PLUGIN_OMAP3MC_H__
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <mediactl/media.h>
+
+#include "sl_list.h"
+
+#define SYS_OPEN(file, oflag, mode) \
+ syscall(SYS_open, (const char *)(file), (int)(oflag), (mode_t)(mode))
+#define SYS_CLOSE(fd) \
+ syscall(SYS_close, (int)(fd))
+#define SYS_IOCTL(fd, cmd, arg) \
+ syscall(SYS_ioctl, (int)(fd), (unsigned long)(cmd), (void *)(arg))
+
+
+#define VIDEO_PRIMARY "/dev/video0"
+#define VIDEO_SECONDARY "/dev/video1"
+#define VIDEO_NODE_LENGTH 11
+#define MEDIA_DEVICE "/dev/media0"
+
+#define PIPELINE_MAX_ELEMENTS 32
+#define SUBDEVICE_MAX_NAME_LEN 32
+#define PIXELFMT_MAX_ELEMENTS 10
+
+#define MC_PLUGIN_VERBOSE
+#ifdef MC_PLUGIN_VERBOSE
+#define MC_PLUGIN_PRINTF(str,args...) \
+ printf("%s():%d: " str, __FUNCTION__,__LINE__,##args)
+#endif
+
+
+
+/* pixel formats */
+enum mc_plugin_pixelformat {
+ MC_PLUGIN_PIX_FMT_INVALID = 0,
+ MC_PLUGIN_PIX_FMT_BAYER8_SBGGR,
+ MC_PLUGIN_PIX_FMT_BAYER8_SGBRG,
+ MC_PLUGIN_PIX_FMT_BAYER8_SGRBG,
+ MC_PLUGIN_PIX_FMT_BAYER10_SGRBG,
+ MC_PLUGIN_PIX_FMT_BAYER10_SRGGB,
+ MC_PLUGIN_PIX_FMT_BAYER10_SBGGR,
+ MC_PLUGIN_PIX_FMT_BAYER10_SGBRG,
+ MC_PLUGIN_PIX_FMT_BAYER10DPCM8_SGRBG,
+ MC_PLUGIN_PIX_FMT_YUYV,
+ MC_PLUGIN_PIX_FMT_UYVY
+};
+
+struct capture_pipeline {
+ char path[PIPELINE_MAX_ELEMENTS][SUBDEVICE_MAX_NAME_LEN];
+ enum mc_plugin_pixelformat in_pixfmt[PIXELFMT_MAX_ELEMENTS];
+ enum mc_plugin_pixelformat out_pixfmt[PIXELFMT_MAX_ELEMENTS];
+};
+
+struct ipipe_descriptor {
+ const struct capture_pipeline *pipe;
+ struct list_head container;
+};
+struct sub_module {
+ struct media_entity *entity;
+ struct list_head list;
+};
+
+
+struct omap3mcplugin {
+ struct media_device *media;
+ struct ipipe_descriptor *path;
+ int fd;
+};
+
+#endif /* __LIBV4L2PLUGIN_OMAP3MC_H__ */
--
1.7.3.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [libv4l-mcplugin PATCH 0/3] Media controller plugin for libv4l2
2011-05-19 12:36 [libv4l-mcplugin PATCH 0/3] Media controller plugin for libv4l2 Yordan Kamenov
` (2 preceding siblings ...)
2011-05-19 12:36 ` [libv4l-mcplugin PATCH 3/3] Add libv4l2 media controller plugin interface files Yordan Kamenov
@ 2011-05-20 7:11 ` Hans de Goede
2011-05-20 8:42 ` Yordan Kamenov
3 siblings, 1 reply; 6+ messages in thread
From: Hans de Goede @ 2011-05-20 7:11 UTC (permalink / raw)
To: Yordan Kamenov; +Cc: linux-media, sakari.ailus
Hi,
So judging from the directory layout, this is supposed to be a separate
project, and not part of v4l-utils / libv4l, right?
WRT my merging plans for libv4l. I've recently done some much needed
work to better support high-res usb cameras. I plan to do a 0.8.4 release
with that work included real soon. Once that is done I'll change the version
in the Make.rules to 0.9.0-test and merge the plugin. Then we'll have
some 0.9.x releases followed by some 0.9.9x release (all testing releases)
followed by a 0.10.0 which should be the first stable release with plugin
support.
Regards,
Hans
On 05/19/2011 02:36 PM, Yordan Kamenov wrote:
> Hi,
>
> This is the Media Controller plugin for libv4l. It uses libv4l2 plugin support
> which is accepted by Hans De Goede, but not yet included in mainline libv4l2:
> http://www.spinics.net/lists/linux-media/msg32017.html
>
> The plugin allows a traditional v4l2 applications to work with Media Controller
> framework. The plugin is loaded when application opens /dev/video0 and it
> configures the media controller and then all ioctl's by the applicatin are
> handled by the plugin.
>
> The plugin implements init, close and ioctl callbacks. The init callback
> checks it's input file descriptor and if it coresponds to /dev/video0, then
> the media controller is initialized and appropriate pipeline is created.
> The close callback deinitializes the pipeline, and closes the media device.
> The ioctl callback is responsible to handle ioctl calls from application by
> using the media controller pipeline.
>
> The plugin uses media-ctl library for media controller operations:
> http://git.ideasonboard.org/?p=media-ctl.git;a=summary
>
> The plugin is divided in three separate patches:
> * Media Controller pipelines initialization, configuration and destruction
> * v4l operations - uses some functionality from the first one
> * Plugin interface operations (init, close and ioctl) - uses functionality
> from first two
>
>
>
> Yordan Kamenov (3):
> Add files for media controller pipelines
> Add files for v4l operations
> Add libv4l2 media controller plugin interface files
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [libv4l-mcplugin PATCH 0/3] Media controller plugin for libv4l2
2011-05-20 7:11 ` [libv4l-mcplugin PATCH 0/3] Media controller plugin for libv4l2 Hans de Goede
@ 2011-05-20 8:42 ` Yordan Kamenov
0 siblings, 0 replies; 6+ messages in thread
From: Yordan Kamenov @ 2011-05-20 8:42 UTC (permalink / raw)
To: Hans de Goede; +Cc: linux-media, sakari.ailus
Hans de Goede wrote:
> Hi,
Hi Hans,
>
> So judging from the directory layout, this is supposed to be a separate
> project, and not part of v4l-utils / libv4l, right?
>
It is separate now, but I guess that at some point it would be good to have
'plugins' directory containing some generic plugins as part of libv4l.
Regards
Yordan
> WRT my merging plans for libv4l. I've recently done some much needed
> work to better support high-res usb cameras. I plan to do a 0.8.4 release
> with that work included real soon. Once that is done I'll change the
> version
> in the Make.rules to 0.9.0-test and merge the plugin. Then we'll have
> some 0.9.x releases followed by some 0.9.9x release (all testing
> releases)
> followed by a 0.10.0 which should be the first stable release with plugin
> support.
>
> Regards,
>
> Hans
>
>
> On 05/19/2011 02:36 PM, Yordan Kamenov wrote:
>> Hi,
>>
>> This is the Media Controller plugin for libv4l. It uses libv4l2
>> plugin support
>> which is accepted by Hans De Goede, but not yet included in mainline
>> libv4l2:
>> http://www.spinics.net/lists/linux-media/msg32017.html
>>
>> The plugin allows a traditional v4l2 applications to work with Media
>> Controller
>> framework. The plugin is loaded when application opens /dev/video0
>> and it
>> configures the media controller and then all ioctl's by the
>> applicatin are
>> handled by the plugin.
>>
>> The plugin implements init, close and ioctl callbacks. The init callback
>> checks it's input file descriptor and if it coresponds to
>> /dev/video0, then
>> the media controller is initialized and appropriate pipeline is created.
>> The close callback deinitializes the pipeline, and closes the media
>> device.
>> The ioctl callback is responsible to handle ioctl calls from
>> application by
>> using the media controller pipeline.
>>
>> The plugin uses media-ctl library for media controller operations:
>> http://git.ideasonboard.org/?p=media-ctl.git;a=summary
>>
>> The plugin is divided in three separate patches:
>> * Media Controller pipelines initialization, configuration and
>> destruction
>> * v4l operations - uses some functionality from the first one
>> * Plugin interface operations (init, close and ioctl) - uses
>> functionality
>> from first two
>>
>>
>>
>> Yordan Kamenov (3):
>> Add files for media controller pipelines
>> Add files for v4l operations
>> Add libv4l2 media controller plugin interface files
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe
>> linux-media" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 6+ messages in thread