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

Reply via email to