[{"id":1212,"web_url":"https://patchwork.libcamera.org/comment/1212/","msgid":"<20190402152329.GG4805@pendragon.ideasonboard.com>","date":"2019-04-02T15:23:29","subject":"Re: [libcamera-devel] [PATCH 2/4] cam: Add support to specify\n\tmultiple stream configurations with hints","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Niklas,\n\nThank you for the patch.\n\nOn Tue, Apr 02, 2019 at 02:54:04AM +0200, Niklas Söderlund wrote:\n> Extend the cam tool to allow configuring more then one stream. Add an\n\ns/then/than/\n\n> optional parameter to the --stream option to allow specifying a usage\n\ns/allow specifying/specify/\n\n> hint for the stream. The usage hint is passed to libcamera to allow it\n> to make better decisions on which stream to use.\n\nMaybe \"to give it control on which streams to use\" ?\n\n> \n> To allow multiple streams to work creation of requests needs to be\n\n\"To support multiple streams, creation ...\"\n\n> reworked to be limit the number of requests to match the stream with the\n\ns/to be limit/to limit/ ?\n\n> leasts number of buffers. This should be improved in the future as the\n\ns/leasts/least/\n\n> tool and the library evolves.\n\ns/evolves/evolve/\n\n> \n> Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> ---\n>  src/cam/main.cpp | 76 ++++++++++++++++++++++++++++++++++++++++--------\n>  1 file changed, 64 insertions(+), 12 deletions(-)\n> \n> diff --git a/src/cam/main.cpp b/src/cam/main.cpp\n> index d3f1f341d44e7f98..1bf28ca8eb8c6da7 100644\n> --- a/src/cam/main.cpp\n> +++ b/src/cam/main.cpp\n> @@ -7,6 +7,7 @@\n>  \n>  #include <iomanip>\n>  #include <iostream>\n> +#include <limits.h>\n>  #include <map>\n>  #include <signal.h>\n>  #include <string.h>\n> @@ -17,6 +18,8 @@\n>  #include \"event_loop.h\"\n>  #include \"options.h\"\n>  \n> +#define MIN(a, b) ((a) < (b) ? (a) : (b))\n> +\n\nThis is a bit dangerous as arguments are evaluated multiple times. The\nfollowing may help.\n\n#define MIN(a, b) ({\t\t\t\t\t\t\t\\\n\ttypeof(a) __a = (a);\t\t\t\t\t\t\\\n\ttypeof(b) __b = (b);\t\t\t\t\t\t\\\n\t__a < __b ? __a : __b;\t\t\t\t\t\t\\\n})\n\n>  using namespace libcamera;\n>  \n>  OptionsParser::Options options;\n> @@ -42,6 +45,9 @@ void signalHandler(int signal)\n>  static int parseOptions(int argc, char *argv[])\n>  {\n>  \tKeyValueParser streamKeyValue;\n> +\tstreamKeyValue.addOption(\"hint\", OptionString,\n> +\t\t\t\t \"Usage hint for the stream (viewfinder, video, still)\",\n> +\t\t\t\t ArgumentRequired);\n>  \tstreamKeyValue.addOption(\"width\", OptionInteger, \"Width in pixels\",\n>  \t\t\t\t ArgumentRequired);\n>  \tstreamKeyValue.addOption(\"height\", OptionInteger, \"Height in pixels\",\n> @@ -61,7 +67,7 @@ static int parseOptions(int argc, char *argv[])\n>  \t\t\t \"The default file name is 'frame-#.bin'.\",\n>  \t\t\t \"file\", ArgumentOptional, \"filename\");\n>  \tparser.addOption(OptStream, &streamKeyValue,\n> -\t\t\t \"Set configuration of the camera's streams\", \"stream\");\n> +\t\t\t \"Set configuration of the camera's streams\", \"stream\", true);\n>  \tparser.addOption(OptHelp, OptionNone, \"Display this help message\",\n>  \t\t\t \"help\");\n>  \tparser.addOption(OptList, OptionNone, \"List all cameras\", \"list\");\n> @@ -80,12 +86,48 @@ static int parseOptions(int argc, char *argv[])\n>  \n>  static int prepare_camera_config(std::map<Stream *, StreamConfiguration> *config)\n>  {\n> -\tstd::set<Stream *> streams = camera->streams();\n> -\t*config = camera->streamConfiguration({ Video() });\n> -\tStream *stream = config->begin()->first;\n> +\tstd::vector<StreamHint> hints;\n>  \n> -\tif (options.isSet(OptStream)) {\n> -\t\tKeyValueParser::Options conf = options[OptStream];\n> +\t/* If no configuration is provided assume a single video stream. */\n> +\tif (!options.isSet(OptStream)) {\n> +\t\t*config = camera->streamConfiguration({ Video() });\n> +\t\treturn 0;\n> +\t}\n> +\n\nYou could store a const reference to options[OptStream].toArray() in a\nlocal variable as you use it multiple times.\n\n> +\t/* Use hints and get a default configuration. */\n> +\tfor (auto const &value : options[OptStream].toArray()) {\n> +\t\tKeyValueParser::Options conf = value.toKeyValues();\n> +\n> +\t\tif (!conf.isSet(\"hint\"))\n> +\t\t\thints.push_back(Video());\n> +\t\telse if (conf[\"hint\"].toString() == \"viewfinder\")\n> +\t\t\thints.push_back(Viewfinder(conf[\"width\"],\n> +\t\t\t\t\t\t   conf[\"height\"]));\n> +\t\telse if (conf[\"hint\"].toString() == \"video\")\n> +\t\t\thints.push_back(Video());\n> +\t\telse if (conf[\"hint\"].toString() == \"still\")\n> +\t\t\thints.push_back(Still());\n> +\t\telse {\n> +\t\t\tstd::cerr << \"Unknown stream hint \"\n> +\t\t\t\t  << conf[\"hint\"].toString() << std::endl;\n> +\t\t\treturn -EINVAL;\n> +\t\t}\n\nShould we use braces for all statements, as in the kernel coding style ?\n\n> +\t}\n> +\n> +\t*config = camera->streamConfiguration(hints);\n> +\n> +\tif (config->size() != options[OptStream].toArray().size()) {\n> +\t\tstd::cerr << \"Failed to get default stream configuration\"\n> +\t\t\t  << std::endl;\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\t/* Apply configuration explicitly requested. */\n> +\tstd::map<Stream *, StreamConfiguration>::iterator it = config->begin();\n> +\tfor (auto const &value : options[OptStream].toArray()) {\n> +\t\tKeyValueParser::Options conf = value.toKeyValues();\n> +\t\tStream *stream = it->first;\n> +\t\tit++;\n>  \n>  \t\tif (conf.isSet(\"width\"))\n>  \t\t\t(*config)[stream].width = conf[\"width\"];\n> @@ -137,7 +179,6 @@ static void requestComplete(Request *request, const std::map<Stream *, Buffer *>\n>  static int capture()\n>  {\n>  \tstd::map<Stream *, StreamConfiguration> config;\n> -\tstd::vector<Request *> requests;\n>  \tint ret;\n>  \n>  \tret = prepare_camera_config(&config);\n> @@ -152,8 +193,6 @@ static int capture()\n>  \t\treturn ret;\n>  \t}\n>  \n> -\tStream *stream = config.begin()->first;\n> -\n>  \tret = camera->allocateBuffers();\n>  \tif (ret) {\n>  \t\tstd::cerr << \"Failed to allocate buffers\"\n> @@ -163,9 +202,18 @@ static int capture()\n>  \n>  \tcamera->requestCompleted.connect(requestComplete);\n>  \n> -\tBufferPool &pool = stream->bufferPool();\n> +\t/* Figure out which stream have least number of buffers. */\n\ns/have least/has the lower/\n\n> +\tunsigned int nbuffers = UINT_MAX;\n> +\tfor (auto const &it : config)\n> +\t\tnbuffers = MIN(nbuffers, it.first->bufferPool().count());\n>  \n> -\tfor (Buffer &buffer : pool.buffers()) {\n> +\t/*\n> +\t * TODO: make cam tool smarter to support still capture by for\n> +\t * example pushing a button. For now run all streams all the time.\n> +\t */\n> +\n> +\tstd::vector<Request *> requests;\n> +\tfor (unsigned int i = 0; i < nbuffers; i++) {\n>  \t\tRequest *request = camera->createRequest();\n>  \t\tif (!request) {\n>  \t\t\tstd::cerr << \"Can't create request\" << std::endl;\n> @@ -174,7 +222,11 @@ static int capture()\n>  \t\t}\n>  \n>  \t\tstd::map<Stream *, Buffer *> map;\n> -\t\tmap[stream] = &buffer;\n> +\t\tfor (auto const &it : config) {\n> +\t\t\tStream *stream = it.first;\n> +\t\t\tmap[stream] = &stream->bufferPool().buffers()[i];\n> +\t\t}\n> +\n>  \t\tret = request->setBuffers(map);\n>  \t\tif (ret < 0) {\n>  \t\t\tstd::cerr << \"Can't set buffers for request\" << std::endl;","headers":{"Return-Path":"<laurent.pinchart@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id F13FF600FB\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue,  2 Apr 2019 17:23:40 +0200 (CEST)","from pendragon.ideasonboard.com\n\t(dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi\n\t[IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 6FA002F9;\n\tTue,  2 Apr 2019 17:23:40 +0200 (CEST)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1554218620;\n\tbh=wPLWDbGjQzSMQlT0yinEyFIydECJhfjr07vRWtk0Xx0=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=T81kxwDR0wmPAQyDIP/siFe4tn6tC1nfZng9cpSsN+zyvEwaKURxWEphuPwmJCrG/\n\tuYmXlDKVAjR2qJ40MayKvLByQ39nYCYLcWrf/bGf7is3Sc7JRjEYeScDH7mqr4MtWk\n\tC9vz3YsoXJsytudXCqrr+1rS8c3DTKZU/c1ZfDDc=","Date":"Tue, 2 Apr 2019 18:23:29 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Niklas =?utf-8?q?S=C3=B6derlund?= <niklas.soderlund@ragnatech.se>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190402152329.GG4805@pendragon.ideasonboard.com>","References":"<20190402005406.25097-1-niklas.soderlund@ragnatech.se>\n\t<20190402005406.25097-3-niklas.soderlund@ragnatech.se>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20190402005406.25097-3-niklas.soderlund@ragnatech.se>","User-Agent":"Mutt/1.10.1 (2018-07-13)","Subject":"Re: [libcamera-devel] [PATCH 2/4] cam: Add support to specify\n\tmultiple stream configurations with hints","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":"Tue, 02 Apr 2019 15:23:41 -0000"}},{"id":1234,"web_url":"https://patchwork.libcamera.org/comment/1234/","msgid":"<20190403001733.GI23466@bigcity.dyn.berto.se>","date":"2019-04-03T00:17:33","subject":"Re: [libcamera-devel] [PATCH 2/4] cam: Add support to specify\n\tmultiple stream configurations with hints","submitter":{"id":5,"url":"https://patchwork.libcamera.org/api/people/5/","name":"Niklas Söderlund","email":"niklas.soderlund@ragnatech.se"},"content":"Hi Laurent,\n\nThanks for your feedback, special thanks for language support :-)\n\nOn 2019-04-02 18:23:29 +0300, Laurent Pinchart wrote:\n> Hi Niklas,\n> \n> Thank you for the patch.\n> \n> On Tue, Apr 02, 2019 at 02:54:04AM +0200, Niklas Söderlund wrote:\n> > Extend the cam tool to allow configuring more then one stream. Add an\n> \n> s/then/than/\n> \n> > optional parameter to the --stream option to allow specifying a usage\n> \n> s/allow specifying/specify/\n> \n> > hint for the stream. The usage hint is passed to libcamera to allow it\n> > to make better decisions on which stream to use.\n> \n> Maybe \"to give it control on which streams to use\" ?\n> \n> > \n> > To allow multiple streams to work creation of requests needs to be\n> \n> \"To support multiple streams, creation ...\"\n> \n> > reworked to be limit the number of requests to match the stream with the\n> \n> s/to be limit/to limit/ ?\n> \n> > leasts number of buffers. This should be improved in the future as the\n> \n> s/leasts/least/\n> \n> > tool and the library evolves.\n> \n> s/evolves/evolve/\n> \n> > \n> > Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> > ---\n> >  src/cam/main.cpp | 76 ++++++++++++++++++++++++++++++++++++++++--------\n> >  1 file changed, 64 insertions(+), 12 deletions(-)\n> > \n> > diff --git a/src/cam/main.cpp b/src/cam/main.cpp\n> > index d3f1f341d44e7f98..1bf28ca8eb8c6da7 100644\n> > --- a/src/cam/main.cpp\n> > +++ b/src/cam/main.cpp\n> > @@ -7,6 +7,7 @@\n> >  \n> >  #include <iomanip>\n> >  #include <iostream>\n> > +#include <limits.h>\n> >  #include <map>\n> >  #include <signal.h>\n> >  #include <string.h>\n> > @@ -17,6 +18,8 @@\n> >  #include \"event_loop.h\"\n> >  #include \"options.h\"\n> >  \n> > +#define MIN(a, b) ((a) < (b) ? (a) : (b))\n> > +\n> \n> This is a bit dangerous as arguments are evaluated multiple times. The\n> following may help.\n> \n> #define MIN(a, b) ({\t\t\t\t\t\t\t\\\n> \ttypeof(a) __a = (a);\t\t\t\t\t\t\\\n> \ttypeof(b) __b = (b);\t\t\t\t\t\t\\\n> \t__a < __b ? __a : __b;\t\t\t\t\t\t\\\n> })\n\nI thought the same, C++11 don't have typeof so this is not a solution.  \nThere is __typeof which is a G++ extension so it don't seem to be a good \nmatch. In the end I went for std::min() and avoided the macro issue al \ntogether.\n\n> \n> >  using namespace libcamera;\n> >  \n> >  OptionsParser::Options options;\n> > @@ -42,6 +45,9 @@ void signalHandler(int signal)\n> >  static int parseOptions(int argc, char *argv[])\n> >  {\n> >  \tKeyValueParser streamKeyValue;\n> > +\tstreamKeyValue.addOption(\"hint\", OptionString,\n> > +\t\t\t\t \"Usage hint for the stream (viewfinder, video, still)\",\n> > +\t\t\t\t ArgumentRequired);\n> >  \tstreamKeyValue.addOption(\"width\", OptionInteger, \"Width in pixels\",\n> >  \t\t\t\t ArgumentRequired);\n> >  \tstreamKeyValue.addOption(\"height\", OptionInteger, \"Height in pixels\",\n> > @@ -61,7 +67,7 @@ static int parseOptions(int argc, char *argv[])\n> >  \t\t\t \"The default file name is 'frame-#.bin'.\",\n> >  \t\t\t \"file\", ArgumentOptional, \"filename\");\n> >  \tparser.addOption(OptStream, &streamKeyValue,\n> > -\t\t\t \"Set configuration of the camera's streams\", \"stream\");\n> > +\t\t\t \"Set configuration of the camera's streams\", \"stream\", true);\n> >  \tparser.addOption(OptHelp, OptionNone, \"Display this help message\",\n> >  \t\t\t \"help\");\n> >  \tparser.addOption(OptList, OptionNone, \"List all cameras\", \"list\");\n> > @@ -80,12 +86,48 @@ static int parseOptions(int argc, char *argv[])\n> >  \n> >  static int prepare_camera_config(std::map<Stream *, StreamConfiguration> *config)\n> >  {\n> > -\tstd::set<Stream *> streams = camera->streams();\n> > -\t*config = camera->streamConfiguration({ Video() });\n> > -\tStream *stream = config->begin()->first;\n> > +\tstd::vector<StreamHint> hints;\n> >  \n> > -\tif (options.isSet(OptStream)) {\n> > -\t\tKeyValueParser::Options conf = options[OptStream];\n> > +\t/* If no configuration is provided assume a single video stream. */\n> > +\tif (!options.isSet(OptStream)) {\n> > +\t\t*config = camera->streamConfiguration({ Video() });\n> > +\t\treturn 0;\n> > +\t}\n> > +\n> \n> You could store a const reference to options[OptStream].toArray() in a\n> local variable as you use it multiple times.\n> \n> > +\t/* Use hints and get a default configuration. */\n> > +\tfor (auto const &value : options[OptStream].toArray()) {\n> > +\t\tKeyValueParser::Options conf = value.toKeyValues();\n> > +\n> > +\t\tif (!conf.isSet(\"hint\"))\n> > +\t\t\thints.push_back(Video());\n> > +\t\telse if (conf[\"hint\"].toString() == \"viewfinder\")\n> > +\t\t\thints.push_back(Viewfinder(conf[\"width\"],\n> > +\t\t\t\t\t\t   conf[\"height\"]));\n> > +\t\telse if (conf[\"hint\"].toString() == \"video\")\n> > +\t\t\thints.push_back(Video());\n> > +\t\telse if (conf[\"hint\"].toString() == \"still\")\n> > +\t\t\thints.push_back(Still());\n> > +\t\telse {\n> > +\t\t\tstd::cerr << \"Unknown stream hint \"\n> > +\t\t\t\t  << conf[\"hint\"].toString() << std::endl;\n> > +\t\t\treturn -EINVAL;\n> > +\t\t}\n> \n> Should we use braces for all statements, as in the kernel coding style ?\n\nYes we should.\n\n> \n> > +\t}\n> > +\n> > +\t*config = camera->streamConfiguration(hints);\n> > +\n> > +\tif (config->size() != options[OptStream].toArray().size()) {\n> > +\t\tstd::cerr << \"Failed to get default stream configuration\"\n> > +\t\t\t  << std::endl;\n> > +\t\treturn -EINVAL;\n> > +\t}\n> > +\n> > +\t/* Apply configuration explicitly requested. */\n> > +\tstd::map<Stream *, StreamConfiguration>::iterator it = config->begin();\n> > +\tfor (auto const &value : options[OptStream].toArray()) {\n> > +\t\tKeyValueParser::Options conf = value.toKeyValues();\n> > +\t\tStream *stream = it->first;\n> > +\t\tit++;\n> >  \n> >  \t\tif (conf.isSet(\"width\"))\n> >  \t\t\t(*config)[stream].width = conf[\"width\"];\n> > @@ -137,7 +179,6 @@ static void requestComplete(Request *request, const std::map<Stream *, Buffer *>\n> >  static int capture()\n> >  {\n> >  \tstd::map<Stream *, StreamConfiguration> config;\n> > -\tstd::vector<Request *> requests;\n> >  \tint ret;\n> >  \n> >  \tret = prepare_camera_config(&config);\n> > @@ -152,8 +193,6 @@ static int capture()\n> >  \t\treturn ret;\n> >  \t}\n> >  \n> > -\tStream *stream = config.begin()->first;\n> > -\n> >  \tret = camera->allocateBuffers();\n> >  \tif (ret) {\n> >  \t\tstd::cerr << \"Failed to allocate buffers\"\n> > @@ -163,9 +202,18 @@ static int capture()\n> >  \n> >  \tcamera->requestCompleted.connect(requestComplete);\n> >  \n> > -\tBufferPool &pool = stream->bufferPool();\n> > +\t/* Figure out which stream have least number of buffers. */\n> \n> s/have least/has the lower/\n> \n> > +\tunsigned int nbuffers = UINT_MAX;\n> > +\tfor (auto const &it : config)\n> > +\t\tnbuffers = MIN(nbuffers, it.first->bufferPool().count());\n> >  \n> > -\tfor (Buffer &buffer : pool.buffers()) {\n> > +\t/*\n> > +\t * TODO: make cam tool smarter to support still capture by for\n> > +\t * example pushing a button. For now run all streams all the time.\n> > +\t */\n> > +\n> > +\tstd::vector<Request *> requests;\n> > +\tfor (unsigned int i = 0; i < nbuffers; i++) {\n> >  \t\tRequest *request = camera->createRequest();\n> >  \t\tif (!request) {\n> >  \t\t\tstd::cerr << \"Can't create request\" << std::endl;\n> > @@ -174,7 +222,11 @@ static int capture()\n> >  \t\t}\n> >  \n> >  \t\tstd::map<Stream *, Buffer *> map;\n> > -\t\tmap[stream] = &buffer;\n> > +\t\tfor (auto const &it : config) {\n> > +\t\t\tStream *stream = it.first;\n> > +\t\t\tmap[stream] = &stream->bufferPool().buffers()[i];\n> > +\t\t}\n> > +\n> >  \t\tret = request->setBuffers(map);\n> >  \t\tif (ret < 0) {\n> >  \t\t\tstd::cerr << \"Can't set buffers for request\" << std::endl;\n> \n> -- \n> Regards,\n> \n> Laurent Pinchart","headers":{"Return-Path":"<niklas.soderlund@ragnatech.se>","Received":["from mail-lj1-x242.google.com (mail-lj1-x242.google.com\n\t[IPv6:2a00:1450:4864:20::242])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id CA4BF610B3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed,  3 Apr 2019 02:17:35 +0200 (CEST)","by mail-lj1-x242.google.com with SMTP id r24so13245088ljg.3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 02 Apr 2019 17:17:35 -0700 (PDT)","from localhost (89-233-230-99.cust.bredband2.com. [89.233.230.99])\n\tby smtp.gmail.com with ESMTPSA id\n\tf21sm1966237ljk.94.2019.04.02.17.17.33\n\t(version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256);\n\tTue, 02 Apr 2019 17:17:34 -0700 (PDT)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=ragnatech-se.20150623.gappssmtp.com; s=20150623;\n\th=date:from:to:cc:subject:message-id:references:mime-version\n\t:content-disposition:content-transfer-encoding:in-reply-to\n\t:user-agent; bh=cqC6b8cuqXTgMPXiIK1nRF0j6ke3KTBsEf0yNEWk4wA=;\n\tb=AkSVVsORrvGhHKeO/G079pSqG/89V92CelsNmr0gM9Sr15itBLVIqVP+B7/h7XEd4l\n\t761pwTamnjxn+uu/hImtu8fjDSuBmygtAlAApziGbWrA6/Ve8sKd9LSsuNXRxsGZNd4x\n\tU8IX9loZ2eDdmzVQJzwuf0zgH7Lflce4IdhvZ1+kf5/Dae1FvOJPOOu5+/A43z55QPDv\n\tTWk7CMDWKtZmLLqSbe3NUDCtEz1fTns8ylpEE7t2GQTRzvjpsh/iym+tyHTMDZLS8K6F\n\tkwb8NyOuG/WJfbkeaAG2Gdw9FCY2CFErejdnXUGt73O2oaWrfbzwNGnHNpiKlINVZQt6\n\tkDeg==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:date:from:to:cc:subject:message-id:references\n\t:mime-version:content-disposition:content-transfer-encoding\n\t:in-reply-to:user-agent;\n\tbh=cqC6b8cuqXTgMPXiIK1nRF0j6ke3KTBsEf0yNEWk4wA=;\n\tb=cTXDPdWVwhskBembmIYy0mivBnbkYCymxFMPb4xxUhjCl+xj93XrtPk7fFWrCe9dlL\n\tm0oW4BP8zLV7YDYCD0eVD0ZgXWPnClUHIxfNThQM1Mo1qYqLNqJzRzu+qzMNWgY+J2JI\n\t5fZ3RMcCBrWmM29FLiwptpOMQOBkw1avJS+JR6J1Ldnw107Aj0HQ55aMeP25yskb/E10\n\tg4JN0bp3TNkqvVPdbK3HE1ztIw26kFCK3BC79PFU00KMWRdGrvXFUBMIACMhM758mYti\n\tXb0TmHd8PtjEDtL7FygbOqVgVAdMAQsI1/RydJLwxNyv8h4ebmXzPKCJYO9niWxzKmsk\n\t60Tg==","X-Gm-Message-State":"APjAAAVYEl0VZhVUj3j0zwftd1U06XAZNCOgSRx/FYPxAH5BsukGl40V\n\txZrBoKRozcmJbEIXsjEcJrkAXacvmz0=","X-Google-Smtp-Source":"APXvYqzheQTlmWRvyUyKFZGWCQ/Pl5WnK/ZLgrPC8pfF46YOvbHxoEYOmcpbNgNpnPNSpp2zBtK3Sw==","X-Received":"by 2002:a2e:9655:: with SMTP id z21mr1834220ljh.60.1554250655183;\n\tTue, 02 Apr 2019 17:17:35 -0700 (PDT)","Date":"Wed, 3 Apr 2019 02:17:33 +0200","From":"Niklas =?iso-8859-1?q?S=F6derlund?= <niklas.soderlund@ragnatech.se>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190403001733.GI23466@bigcity.dyn.berto.se>","References":"<20190402005406.25097-1-niklas.soderlund@ragnatech.se>\n\t<20190402005406.25097-3-niklas.soderlund@ragnatech.se>\n\t<20190402152329.GG4805@pendragon.ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=iso-8859-1","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20190402152329.GG4805@pendragon.ideasonboard.com>","User-Agent":"Mutt/1.11.3 (2019-02-01)","Subject":"Re: [libcamera-devel] [PATCH 2/4] cam: Add support to specify\n\tmultiple stream configurations with hints","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":"Wed, 03 Apr 2019 00:17:36 -0000"}}]