Hi Jacek,
On Thu, Nov 24, 2016 at 05:14:40PM +0100, Jacek Anaszewski wrote:
> Hi Sakari,
>
> On 11/24/2016 04:11 PM, Sakari Ailus wrote:
> >Hi Jacek,
> >
> >Thank you for your continued work on the Exynos plugin patchset!
> >
> >I think we're pretty close to being able to merge the set, if you could
> >still bear with me awhile. :-)
>
> Your demanding reviewer I must admit. :-)
> Of course, I appreciate all your remarks, they're highly valuable.
>
> >On Wed, Oct 12, 2016 at 04:35:22PM +0200, Jacek Anaszewski wrote:
> >...
> >>diff --git a/lib/libv4l-exynos4-camera/Makefile.am
> >>b/lib/libv4l-exynos4-camera/Makefile.am
> >>new file mode 100644
> >>index 0000000..c38b7f6
> >>--- /dev/null
> >>+++ b/lib/libv4l-exynos4-camera/Makefile.am
> >>@@ -0,0 +1,19 @@
> >>+if WITH_V4L_PLUGINS
> >>+libv4l2plugin_LTLIBRARIES = libv4l-exynos4-camera.la
> >>+endif
> >>+
> >>+media-bus-format-names.h: ../../include/linux/media-bus-format.h
> >>+ sed -e '/#define MEDIA_BUS_FMT/ ! d; s/.*FMT_//; /FIXED/ d; s/\t.*//;
> >>s/.*/{ \"&\", MEDIA_BUS_FMT_& },/;' \
> >>+ < $< > $@
> >>+
> >>+media-bus-format-codes.h: ../../include/linux/media-bus-format.h
> >>+ sed -e '/#define MEDIA_BUS_FMT/ ! d; s/.*#define //; /FIXED/ d;
> >>s/\t.*//; s/.*/ &,/;' \
> >>+ < $< > $@
> >>+
> >>+BUILT_SOURCES = media-bus-format-names.h media-bus-format-codes.h
> >>+CLEANFILES = $(BUILT_SOURCES)
> >
> >It'd be nice to be able to use the same generated headers that now are under
> >utils/media-ctl, instead of copying the sed script here in verbatim. If the
> >script is changed or fixed in some way, the other location probably will
> >remain unchanged...
>
> The problem is that those headers are built after this plugin.
They could be moved to another directory from where they are now, and
explicitly built as a dependency. I don't know how to properly do that with
automake though.
I cc'd Gregor to the thread.
>
> >I wonder if there's a proper way to generate build time headers such as
> >these.
> >
> >Another less good alternative would be to put these into a separate Makefile
> >and include that Makefile where the headers are needed. But I don't like
> >that much either, it's a hack.
>
> In this case it seems to be the only feasible optimization.
I'm ok with that but still hope we could have something better. :-)
>
> >>+
> >>+nodist_libv4l_exynos4_camera_la_SOURCES = $(BUILT_SOURCES)
> >>+libv4l_exynos4_camera_la_SOURCES = libv4l-exynos4-camera.c
> >>../../utils/media-ctl/libmediactl.c ../../utils/media-ctl/libv4l2subdev.c
> >>../../utils/media-ctl/mediatext.c
> >>+libv4l_exynos4_camera_la_CFLAGS = -fvisibility=hidden -std=gnu99
> >>+libv4l_exynos4_camera_la_LDFLAGS = -avoid-version -module -shared
> >>-export-dynamic -lpthread
> >>diff --git a/lib/libv4l-exynos4-camera/libv4l-exynos4-camera.c
> >>b/lib/libv4l-exynos4-camera/libv4l-exynos4-camera.c
> >>new file mode 100644
> >>index 0000000..c219fe5
> >>--- /dev/null
> >>+++ b/lib/libv4l-exynos4-camera/libv4l-exynos4-camera.c
> >>@@ -0,0 +1,1325 @@
> >>+/*
> >>+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
> >>+ * http://www.samsung.com
> >>+ *
> >>+ * Author: Jacek Anaszewski <[email protected]>
> >>+ *
> >>+ * This program 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 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
> >>+ * Lesser General Public License for more details.
> >>+ */
> >>+
> >>+#include <config.h>
> >>+#include <errno.h>
> >>+#include <linux/types.h>
> >>+#include <stdbool.h>
> >>+#include <stdint.h>
> >>+#include <stdio.h>
> >>+#include <stdlib.h>
> >>+#include <string.h>
> >>+#include <sys/ioctl.h>
> >>+#include <sys/syscall.h>
> >>+#include <unistd.h>
> >>+
> >>+#include "../../utils/media-ctl/mediactl.h"
> >>+#include "../../utils/media-ctl/mediatext.h"
> >>+#include "../../utils/media-ctl/v4l2subdev.h"
> >>+#include "libv4l-plugin.h"
> >>+
> >>+#ifdef DEBUG
> >>+#define V4L2_EXYNOS4_DBG(format, ARG...)\
> >>+ printf("[%s:%d] [%s] " format " \n", __FILE__, __LINE__, __func__,
> >>##ARG)
> >>+#else
> >>+#define V4L2_EXYNOS4_DBG(format, ARG...)
> >>+#endif
> >>+
> >>+#define V4L2_EXYNOS4_ERR(format, ARG...)\
> >>+ fprintf(stderr, "Libv4l Exynos4 camera plugin: "format "\n", ##ARG)
> >>+
> >>+#define V4L2_EXYNOS4_LOG(format, ARG...)\
> >>+ fprintf(stdout, "Libv4l Exynos4 camera plugin: "format "\n", ##ARG)
> >>+
> >>+#define VIDIOC_CTRL(type) \
> >>+ ((type) == VIDIOC_S_CTRL ? "VIDIOC_S_CTRL" : \
> >>+ "VIDIOC_G_CTRL")
> >>+
> >>+#if HAVE_VISIBILITY
> >>+#define PLUGIN_PUBLIC __attribute__ ((visibility("default")))
> >>+#else
> >>+#define PLUGIN_PUBLIC
> >>+#endif
> >>+
> >>+#define SYS_IOCTL(fd, cmd, arg) \
> >>+ syscall(SYS_ioctl, (int)(fd), (unsigned long)(cmd), (void *)(arg))
> >>+
> >>+#define SIMPLE_CONVERT_IOCTL(fd, cmd, arg, __struc) ({ \
> >>+ int __ret; \
> >>+ struct __struc *req = arg; \
> >>+ uint32_t type = req->type; \
> >>+ req->type = convert_type(type); \
> >>+ __ret = SYS_IOCTL(fd, cmd, arg); \
> >>+ req->type = type; \
> >>+ __ret; \
> >>+ })
> >>+
> >>+#ifndef min
> >>+#define min(a, b) (((a) < (b)) ? (a) : (b))
> >>+#endif
> >>+
> >>+#ifndef max
> >>+#define max(a, b) (((a) > (b)) ? (a) : (b))
> >>+#endif
> >>+
> >>+#define EXYNOS4_FIMC_DRV "exynos4-fimc"
> >>+#define EXYNOS4_FIMC_LITE_DRV "exynos-fimc-lit"
> >>+#define EXYNOS4_FIMC_IS_ISP_DRV "exynos4-fimc-is"
> >>+#define EXYNOS4_CAPTURE_CONF "/var/lib/libv4l/exynos4_capture_conf"
> >
> >Is this something that should be configurable in ./configure?
>
> OK.
>
> >
> >>+#define EXYNOS4_FIMC_IS_ISP "FIMC-IS-ISP"
> >>+#define EXYNOS4_S5K6A3 "S5K6A3"
> >
> >Maybe this one as well. But it could come from a configuration file, too.
>
> Right, the sensor is independent of SoC.
>
> >
> >The problem at large is actually something else: how do you recognise the
> >hardware you're running on?
> >
> >You could find the sensor by walking the media graph.
> >
> >But if you need to know something very hardware specific it might not be
> >available through the generic interfaces, and you might need to know the
> >exact hardware you have.
> >
> >How do you know that you should load a particular plugin? I wonder if we
> >could add a small snippet of code to detect different kinds of systems, I
> >presume this is the plugin you want to load if the user has opened a video
> >node of the Exynos4 ISP; you could find through the Media controller.
>
> This code snippet in plugin_init() detects if we are on Exynos4 media
> device:
>
> ret = SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap);
> if (ret < 0) {
> V4L2_EXYNOS4_ERR("Failed to query video capabilities.");
> return NULL;
> }
>
> /* Check if this is Exynos4 media device */
> if (strcmp((char *) cap.driver, EXYNOS4_FIMC_DRV) &&
> strcmp((char *) cap.driver, EXYNOS4_FIMC_LITE_DRV) &&
> strcmp((char *) cap.driver, EXYNOS4_FIMC_IS_ISP_DRV)) {
> V4L2_EXYNOS4_ERR("Not an Exynos4 media device.");
> return NULL;
> }
>
> Additionally I check if this is capture and not m2m device:
>
> /* Check if video entity is of capture type, not m2m */
> if (!is_capture_entity(sink_entity_name)) {
> V4L2_EXYNOS4_ERR("Device not of capture type.");
> goto err_get_sink_entity;
> }
Ah, indeed. I presume it should work just fine then. Good.
The approach doesn't look too scalable still, but I don't think there's
a reason to worry about that now.
>
>
>
> >
> >That's certainly out of scope of the patchset, I just thought of binging up
> >the topics for discussion. :-)
> >
> >>+#define EXYNOS4_FIMC_LITE_PREFIX "FIMC-LITE."
> >>+#define EXYNOS4_FIMC_PREFIX "FIMC."
> >>+#define EXYNOS4_MAX_FMT_NEGO_NUM 50
> >>+#define EXYNOS4_MAX_PIPELINE_LEN 7
> >>+
> >>+struct media_device;
> >>+struct media_entity;
> >>+
> >>+/*
> >>+ * struct pipeline_entity - linked media device pipeline
> >>+ * @entity: linked entity
> >>+ * @sink_pad: inbound link pad of the entity
> >>+ * @src_pad: outbound link pad of the entity
> >>+ */
> >>+struct pipeline_entity {
> >>+ struct media_entity *entity;
> >>+ struct media_pad *sink_pad;
> >>+ struct media_pad *src_pad;
> >>+};
> >>+
> >>+/*
> >>+ * struct media_entity_to_cid - entity to control map
> >>+ * @entity: media entity
> >>+ * @sink_pad: inbound link pad of the entity
> >>+ * @src_pad: outbound link pad of the entity
> >>+ */
> >>+struct media_entity_to_cid {
> >>+ struct media_entity *entity;
> >>+ union {
> >>+ struct v4l2_queryctrl queryctrl;
> >>+ struct v4l2_query_ext_ctrl query_ext_ctrl;
> >>+ };
> >>+};
> >>+
> >>+/*
> >>+ * struct exynos4_camera_plugin - libv4l exynos4 camera plugin
> >>+ * @media: media device comprising the opened video device
> >>+ * @pipeline: video pipeline, element 0 is the source entity
> >>+ * @pipeline_len: length of the video pipeline
> >>+ */
> >>+struct exynos4_camera_plugin {
> >
> >static?
>
> Right.
>
> >>+ struct media_device *media;
> >>+ struct pipeline_entity pipeline[EXYNOS4_MAX_PIPELINE_LEN];
> >>+ unsigned int pipeline_len;
> >>+};
> >>+
> >>+/*
> >>-----------------------------------------------------------------------------
> >>+ * Pipeline operations
> >>+ */
> >>+
> >>+/**
> >>+ * @brief Discover video pipeline for given sink entity
> >>+ * @param plugin - this plugin.
> >>+ * @param entity - sink entity of the pipeline.
> >>+ *
> >>+ * Discover the video pipeline, by walking starting from the
> >>+ * sink entity upwards until a source entity is encountered.
> >>+ *
> >>+ * @return 0 if the sensor entity was detected,
> >>+ * or negative error code on failure.
> >>+ */
> >>+static int discover_pipeline_by_entity(struct exynos4_camera_plugin
> >>*plugin,
> >>+ struct media_entity *entity)
> >>+{
> >>+ struct pipeline_entity reverse_pipeline[EXYNOS4_MAX_PIPELINE_LEN];
> >>+ struct media_pad *src_pad;
> >>+ struct media_link *link = NULL, *backlinks[2];
> >>+ unsigned int num_backlinks, cur_pipe_pos = 0;
> >>+ int i, j;
> >>+ int ret;
> >>+
> >>+ if (entity == NULL)
> >>+ return -EINVAL;
> >>+
> >>+ for (;;) {
> >>+ /* Cache the recently discovered entity. */
> >>+ reverse_pipeline[cur_pipe_pos].entity = entity;
> >>+
> >>+ /* Cache the source pad used for linking the entity. */
> >>+ if (link)
> >>+ reverse_pipeline[cur_pipe_pos].src_pad = link->source;
> >>+
> >>+ ret = media_entity_get_backlinks(entity, backlinks,
> >>+ &num_backlinks);
> >>+ if (ret < 0)
> >>+ return ret;
> >>+
> >>+ /* Check if pipeline source entity has been reached. */
> >>+ if (num_backlinks > 2) {
> >>+ V4L2_EXYNOS4_DBG("Unexpected number of busy sink pads
> >>(%d)",
> >>+ num_backlinks);
> >>+ return -EINVAL;
> >>+ } else if (num_backlinks == 2) {
> >>+ /*
> >>+ * Allow two active pads only in case of
> >>+ * S5C73M3-OIF entity.
> >>+ */
> >>+ if (strcmp(media_entity_get_info(entity)->name,
> >>+ "S5C73M3-OIF")) {
> >>+ V4L2_EXYNOS4_DBG("Ambiguous media device
> >>topology: "
> >>+ "two busy sink pads");
> >>+ return -EINVAL;
> >>+ }
> >>+ /*
> >>+ * Two active links are allowed betwen S5C73M3-OIF and
> >>+ * S5C73M3 entities. In such a case route through the
> >>+ * pad with id == 0 has to be chosen.
> >>+ */
> >>+ link = NULL;
> >>+ for (i = 0; i < num_backlinks; i++)
> >>+ if (backlinks[i]->sink->index == 0)
> >>+ link = backlinks[i];
> >>+ if (link == NULL)
> >>+ return -EINVAL;
> >>+ } else if (num_backlinks == 1) {
> >>+ link = backlinks[0];
> >>+ } else {
> >>+ reverse_pipeline[cur_pipe_pos].sink_pad = NULL;
> >>+ break;
> >>+ }
> >>+
> >>+ /* Cache the sink pad used for linking the entity. */
> >>+ reverse_pipeline[cur_pipe_pos].sink_pad = link->sink;
> >>+
> >>+ V4L2_EXYNOS4_DBG("Discovered sink pad %d for the %s entity",
> >>+ reverse_pipeline[cur_pipe_pos].sink_pad->index,
> >>+ media_entity_get_info(entity)->name);
> >>+
> >>+ src_pad = media_entity_remote_source(link->sink);
> >>+ if (!src_pad)
> >>+ return -EINVAL;
> >>+
> >>+ entity = src_pad->entity;
> >>+ if (++cur_pipe_pos == EXYNOS4_MAX_PIPELINE_LEN)
> >>+ return -EINVAL;
> >>+ }
> >>+
> >>+ /*
> >>+ * Reorder discovered pipeline elements so that the sensor
> >>+ * entity was the pipeline head.
> >>+ */
> >>+ j = 0;
> >>+ for (i = cur_pipe_pos; i >= 0; i--)
> >
> >How about:
> >
> > for (i = cur_pipe_pos, j = 0; i >= 0; i--, j++)
> >
> >And you can avoid setting j to zero outside the loop plus incrementing j++
> >where it doesn't seem to fit too well.
>
> I was thinking about it, but finally decided that this arrangement
> will improve readability. Nothing prevents us to apply the
> optimizations you've just suggested though.
You could do that using a single loop variable, replacing j by cur_pipe_pos
- i. Up to you. :-)
>
> >>+ plugin->pipeline[j++] = reverse_pipeline[i];
> >>+
> >>+ plugin->pipeline_len = j;
> >>+
> >>+ return 0;
> >>+}
> >>+
--
Kind regards,
Sakari Ailus
e-mail: [email protected] XMPP: [email protected]
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html