{"id":825,"url":"https://patchwork.libcamera.org/api/1.1/patches/825/?format=json","web_url":"https://patchwork.libcamera.org/patch/825/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/1.1/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20190401101410.4984-3-jacopo@jmondi.org>","date":"2019-04-01T10:14:10","name":"[libcamera-devel,RFC,2/2] libcamera: Modify streamConfiguration()","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"19b8cfe61ea6e26ba69416b5e9fc6a3ad87cc2a8","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/1.1/people/3/?format=json","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"delegate":{"id":15,"url":"https://patchwork.libcamera.org/api/1.1/users/15/?format=json","username":"jmondi","first_name":"Jacopo","last_name":"Mondi","email":"jacopo@jmondi.org"},"mbox":"https://patchwork.libcamera.org/patch/825/mbox/","series":[{"id":225,"url":"https://patchwork.libcamera.org/api/1.1/series/225/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=225","date":"2019-04-01T10:14:08","name":"libcamera: Implement stream properties","version":1,"mbox":"https://patchwork.libcamera.org/series/225/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/825/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/825/checks/","tags":{},"headers":{"Return-Path":"<jacopo@jmondi.org>","Received":["from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net\n\t[217.70.183.201])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id BD4C1600F9\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon,  1 Apr 2019 12:13:38 +0200 (CEST)","from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101])\n\t(Authenticated sender: jacopo@jmondi.org)\n\tby relay8-d.mail.gandi.net (Postfix) with ESMTPSA id 497F61BF214;\n\tMon,  1 Apr 2019 10:13:38 +0000 (UTC)"],"X-Originating-IP":"2.224.242.101","From":"Jacopo Mondi <jacopo@jmondi.org>","To":"libcamera-devel@lists.libcamera.org","Date":"Mon,  1 Apr 2019 12:14:10 +0200","Message-Id":"<20190401101410.4984-3-jacopo@jmondi.org>","X-Mailer":"git-send-email 2.21.0","In-Reply-To":"<20190401101410.4984-1-jacopo@jmondi.org>","References":"<20190401101410.4984-1-jacopo@jmondi.org>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","Subject":"[libcamera-devel] [RFC 2/2] libcamera: Modify streamConfiguration()","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Mon, 01 Apr 2019 10:13:39 -0000"},"content":"Modify streamConfiguration() along the whole library stack:\n- streamConfiguration receives a list of required stream configurations\n- the camera, with support of the pipeline handler, associates one\nstream to each requested configuration\n- application modifies the received configuration and provide it to\nconfigureStreams()\n\nImplement stream matching in the IPU3 pipeline handler and modify the\ncamera application use the new API and capture from output and\nviewfinder with different resolutions.\n\nSigned-off-by: Jacopo Mondi <jacopo@jmondi.org>\n---\n include/libcamera/camera.h               |  2 +-\n src/cam/main.cpp                         | 48 +++++++-------\n src/libcamera/camera.cpp                 | 30 ++++-----\n src/libcamera/include/pipeline_handler.h |  3 +-\n src/libcamera/pipeline/ipu3/ipu3.cpp     | 82 ++++++++++++++++--------\n src/libcamera/pipeline/uvcvideo.cpp      |  4 +-\n src/libcamera/pipeline/vimc.cpp          |  4 +-\n src/libcamera/pipeline_handler.cpp       | 23 ++++---\n 8 files changed, 118 insertions(+), 78 deletions(-)","diff":"diff --git a/include/libcamera/camera.h b/include/libcamera/camera.h\nindex bfd574a25070..01e0188468c1 100644\n--- a/include/libcamera/camera.h\n+++ b/include/libcamera/camera.h\n@@ -44,7 +44,7 @@ public:\n \n \tconst std::set<Stream *> &streams() const;\n \tstd::map<Stream *, StreamConfiguration>\n-\tstreamConfiguration(std::set<Stream *> &streams);\n+\tstreamConfiguration(std::list<StreamConfiguration> &configs);\n \tint configureStreams(std::map<Stream *, StreamConfiguration> &config);\n \n \tint allocateBuffers();\ndiff --git a/src/cam/main.cpp b/src/cam/main.cpp\nindex 4608c2bc6f3c..fd94629e0726 100644\n--- a/src/cam/main.cpp\n+++ b/src/cam/main.cpp\n@@ -5,6 +5,7 @@\n  * main.cpp - cam - The libcamera swiss army knife\n  */\n \n+#include <list>\n #include <iomanip>\n #include <iostream>\n #include <map>\n@@ -90,39 +91,42 @@ static int configureStreams(Camera *camera, std::set<Stream *> &streams,\n \t\t\t    std::map<Stream *, StreamConfiguration> &config)\n {\n \tKeyValueParser::Options format = options[OptFormat];\n-\tauto it = streams.begin();\n-\tStream *output = *it;\n-\tStream *viewfinder = *(++it);\n-\n-\tstd::map<Stream *, StreamConfiguration> defaultConfig =\n-\t\tcamera->streamConfiguration(streams);\n+\tstd::list<StreamConfiguration> streamConfs;\n \n+\tStreamConfiguration outputConfig = {};\n \tif (options.isSet(OptFormat)) {\n \t\tif (format.isSet(\"width\"))\n-\t\t\tdefaultConfig[output].width = format[\"width\"];\n+\t\t\toutputConfig.width = format[\"width\"];\n \n \t\tif (format.isSet(\"height\"))\n-\t\t\tdefaultConfig[output].height = format[\"height\"];\n+\t\t\toutputConfig.height = format[\"height\"];\n \n \t\t/* TODO: Translate 4CC string to ID. */\n \t\tif (format.isSet(\"pixelformat\"))\n-\t\t\tdefaultConfig[output].pixelFormat = format[\"pixelformat\"];\n+\t\t\toutputConfig.pixelFormat = format[\"pixelformat\"];\n \t}\n+\toutputConfig.hints.push_front(STILL_CAPTURE);\n+\tstreamConfs.push_back(outputConfig);\n \n-\t/* Configure the secondary output stream. */\n-\tdefaultConfig[viewfinder].width = 640;\n-\tdefaultConfig[viewfinder].height = 480;\n+\tStreamConfiguration vfConfig = {};\n+\tvfConfig.hints.push_front(VIEWFINDER);\n+\tstreamConfs.push_back(vfConfig);\n \n-\t/*\n-\t * HACK: Select which stream to capture: use output if required,\n-\t * use viewfinder if required or if no option has been specified\n-\t * from the command line.\n-\t */\n-\tif (options.isSet(OptOutput))\n-\t\tconfig[output] = defaultConfig[output];\n-\tif (options.isSet(OptViefinder) ||\n-\t    (!options.isSet(OptViefinder) && !options.isSet(OptOutput)))\n-\t\tconfig[viewfinder] = defaultConfig[viewfinder];\n+\tconfig = camera->streamConfiguration(streamConfs);\n+\tif (config.empty()) {\n+\t\tstd::cout << \"Cannot configure the requested streams\"\n+\t\t\t  << std::endl;\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tfor (auto &map : config) {\n+\t\tStreamConfiguration *c = &map.second;\n+\n+\t\tif (c->supports(VIEWFINDER)) {\n+\t\t\tc->width = 640;\n+\t\t\tc->height = 480;\n+\t\t}\n+\t}\n \n \treturn camera->configureStreams(config);\n }\ndiff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp\nindex 99eb0e6876f0..f2ae3d3e2d9a 100644\n--- a/src/libcamera/camera.cpp\n+++ b/src/libcamera/camera.cpp\n@@ -346,32 +346,30 @@ const std::set<Stream *> &Camera::streams() const\n \n /**\n  * \\brief Retrieve a group of stream configurations\n- * \\param[in] streams A map of stream IDs and configurations to setup\n+ * \\param[in] configs A set of requested stream configurations\n  *\n- * Retrieve the camera's configuration for a specified group of streams. The\n- * caller can specifies which of the camera's streams to retrieve configuration\n- * from by populating \\a streams.\n- *\n- * The easiest way to populate the array of streams to fetch configuration from\n- * is to first retrieve the camera's full array of stream with streams() and\n- * then potentially trim it down to only contain the streams the caller\n- * are interested in.\n+ * Retrieve a list of streams and associated default configurations in the\n+ * camera. The caller specifies the properties a stream shall satisfy by\n+ * populating \\a config and the camera associates each supplied configuration\n+ * with a stream that matches the requested properties. The requested\n+ * per-stream configuration might be modified by the camera to report the\n+ * stream default parameters. The callers of this function are free to adjust\n+ * the default paramters and provide such configuration to the\n+ * configureStreams() method.\n  *\n  * \\return A map of successfully retrieved stream IDs and configurations or an\n  * empty list on error.\n  */\n std::map<Stream *, StreamConfiguration>\n-Camera::streamConfiguration(std::set<Stream *> &streams)\n+Camera::streamConfiguration(std::list<StreamConfiguration> &configs)\n {\n-\tif (disconnected_ || !streams.size())\n+\tif (disconnected_ || !configs.size())\n \t\treturn std::map<Stream *, StreamConfiguration>{};\n \n-\tfor (Stream *stream : streams) {\n-\t\tif (streams_.find(stream) == streams_.end())\n-\t\t\treturn std::map<Stream *, StreamConfiguration>{};\n-\t}\n+\tif (configs.size() > streams_.size())\n+\t\treturn std::map<Stream *, StreamConfiguration>{};\n \n-\treturn pipe_->streamConfiguration(this, streams);\n+\treturn pipe_->streamConfiguration(this, configs);\n }\n \n /**\ndiff --git a/src/libcamera/include/pipeline_handler.h b/src/libcamera/include/pipeline_handler.h\nindex 6cdadcbdc3ea..ff9f265fe880 100644\n--- a/src/libcamera/include/pipeline_handler.h\n+++ b/src/libcamera/include/pipeline_handler.h\n@@ -56,7 +56,8 @@ public:\n \tvirtual bool match(DeviceEnumerator *enumerator) = 0;\n \n \tvirtual std::map<Stream *, StreamConfiguration>\n-\tstreamConfiguration(Camera *camera, std::set<Stream *> &streams) = 0;\n+\tstreamConfiguration(Camera *camera,\n+\t\t\t    std::list<StreamConfiguration> &config) = 0;\n \tvirtual int configureStreams(Camera *camera,\n \t\t\t\t     std::map<Stream *, StreamConfiguration> &config) = 0;\n \ndiff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp\nindex 46479944a4da..52583b2beefd 100644\n--- a/src/libcamera/pipeline/ipu3/ipu3.cpp\n+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp\n@@ -197,7 +197,7 @@ public:\n \n \tstd::map<Stream *, StreamConfiguration>\n \tstreamConfiguration(Camera *camera,\n-\t\t\t    std::set<Stream *> &streams) override;\n+\t\t\t    std::list<StreamConfiguration> &confs) override;\n \tint configureStreams(Camera *camera,\n \t\t\t     std::map<Stream *, StreamConfiguration> &config) override;\n \n@@ -318,36 +318,66 @@ PipelineHandlerIPU3::~PipelineHandlerIPU3()\n \n std::map<Stream *, StreamConfiguration>\n PipelineHandlerIPU3::streamConfiguration(Camera *camera,\n-\t\t\t\t\t std::set<Stream *> &streams)\n+\t\t\t\t\t std::list<StreamConfiguration> &confs)\n {\n-\tstd::map<Stream *, StreamConfiguration> configs;\n+\tstd::map<Stream *, StreamConfiguration> configs = {};\n \tIPU3CameraData *data = cameraData(camera);\n-\tStreamConfiguration config = {};\n+\n+\tstd::list<Stream *> availableStreams;\n+\tavailableStreams.push_front(&data->outStream_);\n+\tavailableStreams.push_front(&data->vfStream_);\n \n \t/*\n-\t * FIXME: Soraka: the maximum resolution reported by both sensors\n-\t * (2592x1944 for ov5670 and 4224x3136 for ov13858) are returned as\n-\t * default configurations but they're not correctly processed by the\n-\t * ImgU. Resolutions up tp 2560x1920 have been validated.\n-\t *\n-\t * \\todo Clarify ImgU alignement requirements.\n+\t * Try to match all the requested stream configurations with all\n+\t * the streams available in the camera.\n \t */\n-\tconfig.width = 2560;\n-\tconfig.height = 1920;\n-\tconfig.pixelFormat = V4L2_PIX_FMT_NV12;\n-\tconfig.bufferCount = IPU3_BUFFER_COUNT;\n-\n-\tconfigs[&data->outStream_] = config;\n-\tLOG(IPU3, Debug)\n-\t\t<< \"Stream 'output' format set to \" << config.width << \"x\"\n-\t\t<< config.height << \"-0x\" << std::hex << std::setfill('0')\n-\t\t<< std::setw(8) << config.pixelFormat;\n-\n-\tconfigs[&data->vfStream_] = config;\n-\tLOG(IPU3, Debug)\n-\t\t<< \"Stream 'viewfinder' format set to \" << config.width << \"x\"\n-\t\t<< config.height << \"-0x\" << std::hex << std::setfill('0')\n-\t\t<< std::setw(8) << config.pixelFormat;\n+\tfor (auto it = confs.begin(); it != confs.end(); ++it) {\n+\t\tStreamConfiguration &conf = *it;\n+\t\tauto sit = availableStreams.begin();\n+\n+\t\twhile (sit != availableStreams.end()) {\n+\t\t\tIPU3StreamProperties *props = &data->streamProps_[*sit];\n+\n+\t\t\tif (!props->match(conf)) {\n+\t\t\t\t++sit;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\n+\t\t\t/*\n+\t\t\t * FIXME: Soraka: the maximum resolution reported by\n+\t\t\t * both sensors (2592x1944 for ov5670 and 4224x3136 for\n+\t\t\t * ov13858) are returned as default configurations but\n+\t\t\t * they're not correctly processed by the ImgU.\n+\t\t\t * Resolutions up tp 2560x1920 have been validated.\n+\t\t\t *\n+\t\t\t * \\todo Clarify ImgU alignement requirements.\n+\t\t\t */\n+\t\t\tconf.width = 2560;\n+\t\t\tconf.height = 1920;\n+\t\t\tconf.pixelFormat = V4L2_PIX_FMT_NV12;\n+\t\t\tconf.bufferCount = IPU3_BUFFER_COUNT;\n+\t\t\tconfigs[*sit] = conf;\n+\n+\t\t\tLOG(IPU3, Debug)\n+\t\t\t\t<< \"Stream \" << props->name()\n+\t\t\t\t<< \" format set to \" << conf.width << \"x\"\n+\t\t\t\t<< conf.height << \"-0x\" << std::hex\n+\t\t\t\t<< std::setfill('0') << std::setw(8)\n+\t\t\t\t<< conf.pixelFormat;\n+\n+\t\t\t/*\n+\t\t\t * Once the stream has been assigned, remove it\n+\t\t\t * from the list of available ones.\n+\t\t\t */\n+\t\t\tavailableStreams.erase(sit);\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (sit == availableStreams.end()) {\n+\t\t\tLOG(IPU3, Error)\n+\t\t\t\t<< \"Cannot satisfy the requested configuration\";\n+\t\t\treturn std::map<Stream *, StreamConfiguration> {};\n+\t\t}\n+\t}\n \n \treturn configs;\n }\ndiff --git a/src/libcamera/pipeline/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo.cpp\nindex d571b8b4ea83..a88784b28189 100644\n--- a/src/libcamera/pipeline/uvcvideo.cpp\n+++ b/src/libcamera/pipeline/uvcvideo.cpp\n@@ -28,7 +28,7 @@ public:\n \n \tstd::map<Stream *, StreamConfiguration>\n \tstreamConfiguration(Camera *camera,\n-\t\t\t    std::set<Stream *> &streams) override;\n+\t\t\t    std::list<StreamConfiguration> &confs) override;\n \tint configureStreams(Camera *camera,\n \t\t\t     std::map<Stream *, StreamConfiguration> &config) override;\n \n@@ -86,7 +86,7 @@ PipelineHandlerUVC::~PipelineHandlerUVC()\n \n std::map<Stream *, StreamConfiguration>\n PipelineHandlerUVC::streamConfiguration(Camera *camera,\n-\t\t\t\t\tstd::set<Stream *> &streams)\n+\t\t\t\t\tstd::list<StreamConfiguration> &confs)\n {\n \tUVCCameraData *data = cameraData(camera);\n \ndiff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp\nindex e83416effad8..e36a58e70f8c 100644\n--- a/src/libcamera/pipeline/vimc.cpp\n+++ b/src/libcamera/pipeline/vimc.cpp\n@@ -28,7 +28,7 @@ public:\n \n \tstd::map<Stream *, StreamConfiguration>\n \tstreamConfiguration(Camera *camera,\n-\t\t\t    std::set<Stream *> &streams) override;\n+\t\t\t    std::list<StreamConfiguration> &confs) override;\n \tint configureStreams(Camera *camera,\n \t\t\t     std::map<Stream *, StreamConfiguration> &config) override;\n \n@@ -86,7 +86,7 @@ PipelineHandlerVimc::~PipelineHandlerVimc()\n \n std::map<Stream *, StreamConfiguration>\n PipelineHandlerVimc::streamConfiguration(Camera *camera,\n-\t\t\t\t\t std::set<Stream *> &streams)\n+\t\t\t\t\t std::list<StreamConfiguration> &confs)\n {\n \tVimcCameraData *data = cameraData(camera);\n \tstd::map<Stream *, StreamConfiguration> configs;\ndiff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp\nindex 82070d364c03..2dc78d7f0b5e 100644\n--- a/src/libcamera/pipeline_handler.cpp\n+++ b/src/libcamera/pipeline_handler.cpp\n@@ -183,18 +183,25 @@ PipelineHandler::~PipelineHandler()\n \n /**\n  * \\fn PipelineHandler::streamConfiguration()\n- * \\brief Retrieve a group of stream configurations for a specified camera\n+ * \\brief Retrieve the streams matching a configurations for a specified camera\n  * \\param[in] camera The camera to fetch default configuration from\n- * \\param[in] streams An array of streams to fetch information about\n+ * \\param[in] config The list of requested stream configurations\n  *\n- * Retrieve the species camera's default configuration for a specified group of\n- * streams. The caller shall populate the \\a streams array with the streams it\n- * wish to fetch the configuration from. The map of streams and configuration\n- * returned can then be examined by the caller to learn about the defualt\n- * parameters for the specified streams.\n+ * For each provided stream configuration request, retrieve a stream in the\n+ * camera that satisfies it and return it with an associated default\n+ * configuration.\n+ *\n+ * The caller shall populate the \\a config array with the stream configurations\n+ * it wishes to have satisfied, specifying the requested sizes, formats and the\n+ * stream's intended usage. The pipeline handler retrieves a stream that matches\n+ * the characteristics reported in the configuration and associates it a default\n+ * configuration in the returned map.\n+ *\n+ * The returned map can then be examined by the caller to learn about the\n+ * defualt parameters for the returned streams.\n  *\n  * The intended companion to this is \\a configureStreams() which can be used to\n- * change the group of streams parameters.\n+ * change each stream parameters and have them applied in the Camera.\n  *\n  * \\return A map of successfully retrieved streams and configurations or an\n  * empty map on error.\n","prefixes":["libcamera-devel","RFC","2/2"]}