[{"id":672,"web_url":"https://patchwork.libcamera.org/comment/672/","msgid":"<7b9a3502-1848-8c37-33f3-03e1aa4db519@ideasonboard.com>","date":"2019-01-29T09:29:37","subject":"Re: [libcamera-devel] [PATCH 6/6] cam: add --format option to\n\tconfigure a stream","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Hi Niklas,\n\nOn 28/01/2019 00:41, Niklas Söderlund wrote:\n> Add a option to configure the first stream of a camera from an argument\n> with options and parse the width, height and pixel format from that\n> list.\n> \n> The pixel format is still specified as a integer which should correspond\n> to the kernels FOURCC identifiers. Going forward this should be turned\n> into a string representation and the cam parser should translate between\n> the two.\n> \n> Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> ---\n>  src/cam/main.cpp | 104 +++++++++++++++++++++++++++++++++++++++++------\n>  1 file changed, 92 insertions(+), 12 deletions(-)\n> \n> diff --git a/src/cam/main.cpp b/src/cam/main.cpp\n> index bde47a8f17983912..4b4ce9aa29c80bd1 100644\n> --- a/src/cam/main.cpp\n> +++ b/src/cam/main.cpp\n> @@ -20,7 +20,8 @@ using namespace libcamera;\n>  OptionsParser::Options options;\n>  \n>  enum {\n> -\tOptCamera = 'c',\n> +\tOptCamera = 'C',\n> +\tOptFormat = 'f',\n>  \tOptHelp = 'h',\n>  \tOptList = 'l',\n>  };\n> @@ -35,10 +36,20 @@ void signalHandler(int signal)\n>  \n>  static int parseOptions(int argc, char *argv[])\n>  {\n> +\tKeyValueParser formatKeyValue;\n> +\tformatKeyValue.addOption(\"width\", \"Set width in pixels\",\n> +\t\t\t\t ArgumentRequired, \"w\");\n> +\tformatKeyValue.addOption(\"height\", \"Set height in pixels\",\n> +\t\t\t\t ArgumentRequired, \"h\");\n> +\tformatKeyValue.addOption(\"pixelformat\", \"Set pixel format\",\n> +\t\t\t\t ArgumentRequired, \"pf\");\n\nHrm - can a short-option have two letters? (if so, should it?)\n\n> +\n>  \tOptionsParser parser;\n>  \n>  \tparser.addOption(OptCamera, \"Specify which camera to operate on\",\n>  \t\t\t \"camera\", ArgumentRequired, \"camera\");\n> +\tparser.addOption(OptFormat, \"Set format of the cameras first stream\",\n> +\t\t\t formatKeyValue, \"format\");\n>  \tparser.addOption(OptHelp, \"Display this help message\", \"help\");\n>  \tparser.addOption(OptList, \"List all cameras\", \"list\");\n>  \n> @@ -54,6 +65,42 @@ static int parseOptions(int argc, char *argv[])\n>  \treturn 0;\n>  }\n>  \n> +int str2uint(std::string str, unsigned int *dest)\n> +{\n> +\tif (!dest || str == \"\" || !sscanf(str.c_str(), \"%d\", dest))\n> +\t\treturn -EINVAL;\n> +\treturn 0;\n> +}\n> +\n> +bool configureStreams(Camera *camera, std::vector<Stream> &streams)\n> +{\n> +\tif (!options.isKeyValue(OptFormat))\n> +\t\treturn false;\n> +\n> +\tKeyValueParser::Options format = options.keyValues(OptFormat);\n> +\n> +\tstd::map<unsigned int, StreamConfiguration> config = camera->streamConfiguration(streams);\n> +\tunsigned int id = streams.front().id();\n> +\n> +\tif (format.isSet(\"width\"))\n> +\t\tif (str2uint(format[\"width\"], &config[id].width))\n> +\t\t\treturn false;\n> +\n> +\tif (format.isSet(\"height\"))\n> +\t\tif (str2uint(format[\"height\"], &config[id].height))\n> +\t\t\treturn false;\n> +\n> +\t/* TODO: Translate 4CC string to ID. */\n> +\tif (format.isSet(\"pixelformat\"))\n> +\t\tif (str2uint(format[\"pixelformat\"], &config[id].pixelFormat))\n> +\t\t\treturn false;\n> +\n> +\tif (camera->configureStreams(config))\n> +\t\treturn false;\n> +\n> +\treturn true;\n> +}\n> +\n>  int main(int argc, char **argv)\n>  {\n>  \tint ret;\n> @@ -63,6 +110,8 @@ int main(int argc, char **argv)\n>  \t\treturn EXIT_FAILURE;\n>  \n>  \tCameraManager *cm = CameraManager::instance();\n> +\tstd::shared_ptr<Camera> camera;\n> +\tstd::vector<Stream> streams;\n>  \n>  \tret = cm->start();\n>  \tif (ret) {\n> @@ -71,31 +120,62 @@ int main(int argc, char **argv)\n>  \t\treturn EXIT_FAILURE;\n>  \t}\n>  \n> +\tloop = new EventLoop(cm->eventDispatcher());\n> +\n> +\tstruct sigaction sa = {};\n> +\tsa.sa_handler = &signalHandler;\n> +\tsigaction(SIGINT, &sa, nullptr);\n> +\n>  \tif (options.isSet(OptList)) {\n>  \t\tstd::cout << \"Available cameras:\" << std::endl;\n> -\t\tfor (const std::shared_ptr<Camera> &camera : cm->cameras())\n> -\t\t\tstd::cout << \"- \" << camera->name() << std::endl;\n> +\t\tfor (const std::shared_ptr<Camera> &cam : cm->cameras())\n> +\t\t\tstd::cout << \"- \" << cam->name() << std::endl;\n>  \t}\n>  \n>  \tif (options.isSet(OptCamera)) {\n> -\t\tstd::shared_ptr<Camera> cam = cm->get(options[OptCamera]);\n> -\n> -\t\tif (cam) {\n> -\t\t\tstd::cout << \"Using camera \" << cam->name() << std::endl;\n> -\t\t} else {\n> +\t\tcamera = cm->get(options[OptCamera]);\n> +\t\tif (!camera) {\n>  \t\t\tstd::cout << \"Camera \" << options[OptCamera]\n>  \t\t\t\t  << \" not found\" << std::endl;\n> +\t\t\tgoto out;\n> +\t\t}\n> +\n> +\t\tstreams = camera->streams();\n> +\t\tif (streams.size() != 1) {\n> +\t\t\tstd::cout << \"Camera have \" << streams.size()\n\nCamera 'has' N streams...\n\n> +\t\t\t\t  << \" streams, I only know how to work with 1\"\n> +\t\t\t\t  << std::endl;\n> +\t\t\tgoto out;\n> +\t\t}\n> +\n> +\t\tif (camera->acquire()) {\n> +\t\t\tstd::cout << \"Failed to acquire camera\" << std::endl;\n> +\t\t\tgoto out;\n>  \t\t}\n> +\n> +\t\tstd::cout << \"Using camera \" << camera->name() << std::endl;\n>  \t}\n>  \n> -\tloop = new EventLoop(cm->eventDispatcher());\n> +\tif (options.isSet(OptFormat)) {\n> +\t\tif (!camera) {\n> +\t\t\tstd::cout << \"Can't configure stream, no camera selected\" << std::endl;\n> +\t\t\tgoto out_camera;\n> +\t\t}\n>  \n> -\tstruct sigaction sa = {};\n> -\tsa.sa_handler = &signalHandler;\n> -\tsigaction(SIGINT, &sa, nullptr);\n> +\t\tif (!configureStreams(camera.get(), streams)) {\n> +\t\t\tstd::cout << \"Failed to configure camera\" << std::endl;\n> +\t\t\tgoto out_camera;\n> +\t\t}\n> +\t}\n>  \n>  \tret = loop->exec();\n>  \n> +out_camera:\n> +\tif (camera) {\n> +\t\tcamera->release();\n> +\t\tcamera.reset();\n\nUhm ... first a pointer call '->' then a direct member call ? '.' ?\n\n\n> +\t}\n> +out:\n>  \tdelete loop;\n>  \n>  \tcm->stop();\n>","headers":{"Return-Path":"<kieran.bingham@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 E94BC60B2D\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 29 Jan 2019 10:29:40 +0100 (CET)","from [192.168.0.21]\n\t(cpc89242-aztw30-2-0-cust488.18-1.cable.virginm.net [86.31.129.233])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 5E16D85;\n\tTue, 29 Jan 2019 10:29:40 +0100 (CET)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1548754180;\n\tbh=ws+fux/ejGoU1AnlkJebuxMvasbNYQQwDyJsoWRgZYs=;\n\th=Reply-To:Subject:To:References:From:Date:In-Reply-To:From;\n\tb=U3v86GaelCf+SXGfYqIQWt08/uzZez+L61eQbiego51sIsixBV+TYhgFYLFoYICC6\n\tvDYSao/Asah7Xf8Vr/9PDr7kKcATIfLGZ0w8JEgBL3ywjGswlDhC9PGsnrWRjmtXWm\n\tAu7f+LAQEkyIi0NtkS0aL7KgTzySGwKezp5R1Sbk=","Reply-To":"kieran.bingham@ideasonboard.com","To":"=?utf-8?q?Niklas_S=C3=B6derlund?= <niklas.soderlund@ragnatech.se>,\n\tlibcamera-devel@lists.libcamera.org","References":"<20190128004109.25860-1-niklas.soderlund@ragnatech.se>\n\t<20190128004109.25860-7-niklas.soderlund@ragnatech.se>","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Openpgp":"preference=signencrypt","Autocrypt":"addr=kieran.bingham@ideasonboard.com; keydata=\n\t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\n\tsbsRB8KNNvVXBOVNwko86rQqF9drZuw=","Organization":"Ideas on Board","Message-ID":"<7b9a3502-1848-8c37-33f3-03e1aa4db519@ideasonboard.com>","Date":"Tue, 29 Jan 2019 09:29:37 +0000","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101\n\tThunderbird/60.2.1","MIME-Version":"1.0","In-Reply-To":"<20190128004109.25860-7-niklas.soderlund@ragnatech.se>","Content-Type":"text/plain; charset=utf-8","Content-Language":"en-GB","Content-Transfer-Encoding":"8bit","Subject":"Re: [libcamera-devel] [PATCH 6/6] cam: add --format option to\n\tconfigure a stream","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, 29 Jan 2019 09:29:41 -0000"}},{"id":685,"web_url":"https://patchwork.libcamera.org/comment/685/","msgid":"<20190129133426.GF19527@bigcity.dyn.berto.se>","date":"2019-01-29T13:34:26","subject":"Re: [libcamera-devel] [PATCH 6/6] cam: add --format option to\n\tconfigure a stream","submitter":{"id":5,"url":"https://patchwork.libcamera.org/api/people/5/","name":"Niklas Söderlund","email":"niklas.soderlund@ragnatech.se"},"content":"Hi Kieran,\n\nThanks for your comment.\n\nOn 2019-01-29 09:29:37 +0000, Kieran Bingham wrote:\n> Hi Niklas,\n> \n> On 28/01/2019 00:41, Niklas Söderlund wrote:\n> > Add a option to configure the first stream of a camera from an argument\n> > with options and parse the width, height and pixel format from that\n> > list.\n> > \n> > The pixel format is still specified as a integer which should correspond\n> > to the kernels FOURCC identifiers. Going forward this should be turned\n> > into a string representation and the cam parser should translate between\n> > the two.\n> > \n> > Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> > ---\n> >  src/cam/main.cpp | 104 +++++++++++++++++++++++++++++++++++++++++------\n> >  1 file changed, 92 insertions(+), 12 deletions(-)\n> > \n> > diff --git a/src/cam/main.cpp b/src/cam/main.cpp\n> > index bde47a8f17983912..4b4ce9aa29c80bd1 100644\n> > --- a/src/cam/main.cpp\n> > +++ b/src/cam/main.cpp\n> > @@ -20,7 +20,8 @@ using namespace libcamera;\n> >  OptionsParser::Options options;\n> >  \n> >  enum {\n> > -\tOptCamera = 'c',\n> > +\tOptCamera = 'C',\n> > +\tOptFormat = 'f',\n> >  \tOptHelp = 'h',\n> >  \tOptList = 'l',\n> >  };\n> > @@ -35,10 +36,20 @@ void signalHandler(int signal)\n> >  \n> >  static int parseOptions(int argc, char *argv[])\n> >  {\n> > +\tKeyValueParser formatKeyValue;\n> > +\tformatKeyValue.addOption(\"width\", \"Set width in pixels\",\n> > +\t\t\t\t ArgumentRequired, \"w\");\n> > +\tformatKeyValue.addOption(\"height\", \"Set height in pixels\",\n> > +\t\t\t\t ArgumentRequired, \"h\");\n> > +\tformatKeyValue.addOption(\"pixelformat\", \"Set pixel format\",\n> > +\t\t\t\t ArgumentRequired, \"pf\");\n> \n> Hrm - can a short-option have two letters? (if so, should it?)\n\nThis is not a shot-option :-) It is a descriptive name for the parameter \nonly used for printing the usage. The usage printing for the whole \n--format options:\n\n  -f, --format key=value[,key=value,...]        Set format of the cameras first stream\n                                                height=h                Set height in pixels\n                                                pixelformat=pf          Set pixel format\n                                                width=w                 Set width in pixels\n\nAnd one would use it as --format width=800,pixelformat=42\n\n> \n> > +\n> >  \tOptionsParser parser;\n> >  \n> >  \tparser.addOption(OptCamera, \"Specify which camera to operate on\",\n> >  \t\t\t \"camera\", ArgumentRequired, \"camera\");\n> > +\tparser.addOption(OptFormat, \"Set format of the cameras first stream\",\n> > +\t\t\t formatKeyValue, \"format\");\n> >  \tparser.addOption(OptHelp, \"Display this help message\", \"help\");\n> >  \tparser.addOption(OptList, \"List all cameras\", \"list\");\n> >  \n> > @@ -54,6 +65,42 @@ static int parseOptions(int argc, char *argv[])\n> >  \treturn 0;\n> >  }\n> >  \n> > +int str2uint(std::string str, unsigned int *dest)\n> > +{\n> > +\tif (!dest || str == \"\" || !sscanf(str.c_str(), \"%d\", dest))\n> > +\t\treturn -EINVAL;\n> > +\treturn 0;\n> > +}\n> > +\n> > +bool configureStreams(Camera *camera, std::vector<Stream> &streams)\n> > +{\n> > +\tif (!options.isKeyValue(OptFormat))\n> > +\t\treturn false;\n> > +\n> > +\tKeyValueParser::Options format = options.keyValues(OptFormat);\n> > +\n> > +\tstd::map<unsigned int, StreamConfiguration> config = camera->streamConfiguration(streams);\n> > +\tunsigned int id = streams.front().id();\n> > +\n> > +\tif (format.isSet(\"width\"))\n> > +\t\tif (str2uint(format[\"width\"], &config[id].width))\n> > +\t\t\treturn false;\n> > +\n> > +\tif (format.isSet(\"height\"))\n> > +\t\tif (str2uint(format[\"height\"], &config[id].height))\n> > +\t\t\treturn false;\n> > +\n> > +\t/* TODO: Translate 4CC string to ID. */\n> > +\tif (format.isSet(\"pixelformat\"))\n> > +\t\tif (str2uint(format[\"pixelformat\"], &config[id].pixelFormat))\n> > +\t\t\treturn false;\n> > +\n> > +\tif (camera->configureStreams(config))\n> > +\t\treturn false;\n> > +\n> > +\treturn true;\n> > +}\n> > +\n> >  int main(int argc, char **argv)\n> >  {\n> >  \tint ret;\n> > @@ -63,6 +110,8 @@ int main(int argc, char **argv)\n> >  \t\treturn EXIT_FAILURE;\n> >  \n> >  \tCameraManager *cm = CameraManager::instance();\n> > +\tstd::shared_ptr<Camera> camera;\n> > +\tstd::vector<Stream> streams;\n> >  \n> >  \tret = cm->start();\n> >  \tif (ret) {\n> > @@ -71,31 +120,62 @@ int main(int argc, char **argv)\n> >  \t\treturn EXIT_FAILURE;\n> >  \t}\n> >  \n> > +\tloop = new EventLoop(cm->eventDispatcher());\n> > +\n> > +\tstruct sigaction sa = {};\n> > +\tsa.sa_handler = &signalHandler;\n> > +\tsigaction(SIGINT, &sa, nullptr);\n> > +\n> >  \tif (options.isSet(OptList)) {\n> >  \t\tstd::cout << \"Available cameras:\" << std::endl;\n> > -\t\tfor (const std::shared_ptr<Camera> &camera : cm->cameras())\n> > -\t\t\tstd::cout << \"- \" << camera->name() << std::endl;\n> > +\t\tfor (const std::shared_ptr<Camera> &cam : cm->cameras())\n> > +\t\t\tstd::cout << \"- \" << cam->name() << std::endl;\n> >  \t}\n> >  \n> >  \tif (options.isSet(OptCamera)) {\n> > -\t\tstd::shared_ptr<Camera> cam = cm->get(options[OptCamera]);\n> > -\n> > -\t\tif (cam) {\n> > -\t\t\tstd::cout << \"Using camera \" << cam->name() << std::endl;\n> > -\t\t} else {\n> > +\t\tcamera = cm->get(options[OptCamera]);\n> > +\t\tif (!camera) {\n> >  \t\t\tstd::cout << \"Camera \" << options[OptCamera]\n> >  \t\t\t\t  << \" not found\" << std::endl;\n> > +\t\t\tgoto out;\n> > +\t\t}\n> > +\n> > +\t\tstreams = camera->streams();\n> > +\t\tif (streams.size() != 1) {\n> > +\t\t\tstd::cout << \"Camera have \" << streams.size()\n> \n> Camera 'has' N streams...\n\nThanks :-)\n\n> \n> > +\t\t\t\t  << \" streams, I only know how to work with 1\"\n> > +\t\t\t\t  << std::endl;\n> > +\t\t\tgoto out;\n> > +\t\t}\n> > +\n> > +\t\tif (camera->acquire()) {\n> > +\t\t\tstd::cout << \"Failed to acquire camera\" << std::endl;\n> > +\t\t\tgoto out;\n> >  \t\t}\n> > +\n> > +\t\tstd::cout << \"Using camera \" << camera->name() << std::endl;\n> >  \t}\n> >  \n> > -\tloop = new EventLoop(cm->eventDispatcher());\n> > +\tif (options.isSet(OptFormat)) {\n> > +\t\tif (!camera) {\n> > +\t\t\tstd::cout << \"Can't configure stream, no camera selected\" << std::endl;\n> > +\t\t\tgoto out_camera;\n> > +\t\t}\n> >  \n> > -\tstruct sigaction sa = {};\n> > -\tsa.sa_handler = &signalHandler;\n> > -\tsigaction(SIGINT, &sa, nullptr);\n> > +\t\tif (!configureStreams(camera.get(), streams)) {\n> > +\t\t\tstd::cout << \"Failed to configure camera\" << std::endl;\n> > +\t\t\tgoto out_camera;\n> > +\t\t}\n> > +\t}\n> >  \n> >  \tret = loop->exec();\n> >  \n> > +out_camera:\n> > +\tif (camera) {\n> > +\t\tcamera->release();\n> > +\t\tcamera.reset();\n> \n> Uhm ... first a pointer call '->' then a direct member call ? '.' ?\n\ncamera is a shard_ptr<Camera*> so the ->release() access the Camera \npointers that the shard_ptr<> holds while .reset() clears the \nshard_ptr<> of the reference to the Camera hence reducing the refcount \nby one and potentialy deleting the Camera object. \n\n> \n> \n> > +\t}\n> > +out:\n> >  \tdelete loop;\n> >  \n> >  \tcm->stop();\n> > \n> \n> -- \n> Regards\n> --\n> Kieran","headers":{"Return-Path":"<niklas.soderlund@ragnatech.se>","Received":["from mail-lj1-x235.google.com (mail-lj1-x235.google.com\n\t[IPv6:2a00:1450:4864:20::235])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 43AD960DB6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 29 Jan 2019 14:34:29 +0100 (CET)","by mail-lj1-x235.google.com with SMTP id c19-v6so17485569lja.5\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 29 Jan 2019 05:34:29 -0800 (PST)","from localhost (89-233-230-99.cust.bredband2.com. [89.233.230.99])\n\tby smtp.gmail.com with ESMTPSA id\n\td15-v6sm3547816lja.38.2019.01.29.05.34.27\n\t(version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256);\n\tTue, 29 Jan 2019 05:34:27 -0800 (PST)"],"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=wYVC7Id8HCkjoN9bQBT32VW/4lng3wJhVfA3wXq0Ff8=;\n\tb=MJDCf5FqzBXNzeFVMacEPZjqoJx7DIzllMQp+iATJnf4tKEOzDLgthOwNON+97Gyeh\n\tRibHyTaW7BXRH7mcWQjQlmKCe1ex1YOoHZMjTybLhlI3b9jVWzFPVgrSTG3U+B9VP3e7\n\tDYWamFb8xFn+lAydUJprU3+O59hfRuEq/uCWXyi4TpYaNzCYkoW/zbnOEK33nKlhRf0W\n\tJbTWSCQHM4tAK4E0zFyJgUd5eLjteSBjOe0lgnL6K1FRKKPInwMqyEqrqebdZTCNKzp3\n\t8hNgRP71Y8vPEYJPGMS480BB//Cy3//WQVNOou5S98MiwzVu77vYZ3mtSggo38/hSC9K\n\tVYUg==","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=wYVC7Id8HCkjoN9bQBT32VW/4lng3wJhVfA3wXq0Ff8=;\n\tb=AGwR86w57YDf7DuJycuVf8BsFgLXYgkzW04CqIND4SiB0qlSjJoMeTOhg46HdggSlj\n\tuQLL+At11KLxTurhdC/qIF29X/TxD+FwqsgdYFiE3z/Yi3jY5vePSGef43i8G09tvqiY\n\throWW+OvJ7qzco6MRmxRO/pROVyvpxkkhEmH/EzNL2vW/RHa+Uo/M5Rd1uI54PI9lLgI\n\t/No4W6Fq6bknf4lbTmPtSgYA9nvyL6Lthwu6Lr661rpr7KI9T5xZ/AU0ANs48x/BMMDj\n\tEc08AT0x4/KSKn/4MSTu+roxArfj314EetYKqr0TfpIpSOAJOw1Lvv+y1CLdBRawEuyi\n\tcLtg==","X-Gm-Message-State":"AJcUukeHHPVKEXBsgg7hsv7+P2pnezrsNfuCz1CjO+5DmaFOMvLlFt+H\n\tK0XnlCXdJBZY3CQvhoENlIGj3w==","X-Google-Smtp-Source":"ALg8bN6ncIw+YuLOQLThEuap3+j9jjLNS+Og3rM8AQPauAEIfXeRvBR0u5IEx7z3oXCay2tI29/Bow==","X-Received":"by 2002:a2e:b1ca:: with SMTP id\n\te10-v6mr20985673lja.16.1548768868468; \n\tTue, 29 Jan 2019 05:34:28 -0800 (PST)","Date":"Tue, 29 Jan 2019 14:34:26 +0100","From":"Niklas =?iso-8859-1?q?S=F6derlund?= <niklas.soderlund@ragnatech.se>","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190129133426.GF19527@bigcity.dyn.berto.se>","References":"<20190128004109.25860-1-niklas.soderlund@ragnatech.se>\n\t<20190128004109.25860-7-niklas.soderlund@ragnatech.se>\n\t<7b9a3502-1848-8c37-33f3-03e1aa4db519@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=iso-8859-1","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<7b9a3502-1848-8c37-33f3-03e1aa4db519@ideasonboard.com>","User-Agent":"Mutt/1.10.1 (2018-07-13)","Subject":"Re: [libcamera-devel] [PATCH 6/6] cam: add --format option to\n\tconfigure a stream","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, 29 Jan 2019 13:34:29 -0000"}},{"id":686,"web_url":"https://patchwork.libcamera.org/comment/686/","msgid":"<5091d61e-cce4-9aeb-6357-e3b5c387f5e3@ideasonboard.com>","date":"2019-01-29T13:39:59","subject":"Re: [libcamera-devel] [PATCH 6/6] cam: add --format option to\n\tconfigure a stream","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Hi Niklas,\n\nOn 29/01/2019 13:34, Niklas Söderlund wrote:\n> Hi Kieran,\n> \n> Thanks for your comment.\n> \n> On 2019-01-29 09:29:37 +0000, Kieran Bingham wrote:\n>> Hi Niklas,\n>>\n>> On 28/01/2019 00:41, Niklas Söderlund wrote:\n>>> Add a option to configure the first stream of a camera from an argument\n>>> with options and parse the width, height and pixel format from that\n>>> list.\n>>>\n>>> The pixel format is still specified as a integer which should correspond\n>>> to the kernels FOURCC identifiers. Going forward this should be turned\n>>> into a string representation and the cam parser should translate between\n>>> the two.\n>>>\n>>> Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n>>> ---\n>>>  src/cam/main.cpp | 104 +++++++++++++++++++++++++++++++++++++++++------\n>>>  1 file changed, 92 insertions(+), 12 deletions(-)\n>>>\n>>> diff --git a/src/cam/main.cpp b/src/cam/main.cpp\n>>> index bde47a8f17983912..4b4ce9aa29c80bd1 100644\n>>> --- a/src/cam/main.cpp\n>>> +++ b/src/cam/main.cpp\n>>> @@ -20,7 +20,8 @@ using namespace libcamera;\n>>>  OptionsParser::Options options;\n>>>  \n>>>  enum {\n>>> -\tOptCamera = 'c',\n>>> +\tOptCamera = 'C',\n>>> +\tOptFormat = 'f',\n>>>  \tOptHelp = 'h',\n>>>  \tOptList = 'l',\n>>>  };\n>>> @@ -35,10 +36,20 @@ void signalHandler(int signal)\n>>>  \n>>>  static int parseOptions(int argc, char *argv[])\n>>>  {\n>>> +\tKeyValueParser formatKeyValue;\n>>> +\tformatKeyValue.addOption(\"width\", \"Set width in pixels\",\n>>> +\t\t\t\t ArgumentRequired, \"w\");\n>>> +\tformatKeyValue.addOption(\"height\", \"Set height in pixels\",\n>>> +\t\t\t\t ArgumentRequired, \"h\");\n>>> +\tformatKeyValue.addOption(\"pixelformat\", \"Set pixel format\",\n>>> +\t\t\t\t ArgumentRequired, \"pf\");\n>>\n>> Hrm - can a short-option have two letters? (if so, should it?)\n> \n> This is not a shot-option :-) It is a descriptive name for the parameter \n> only used for printing the usage. The usage printing for the whole \n> --format options:\n> \n>   -f, --format key=value[,key=value,...]        Set format of the cameras first stream\n>                                                 height=h                Set height in pixels\n>                                                 pixelformat=pf          Set pixel format\n>                                                 width=w                 Set width in pixels\n> \n> And one would use it as --format width=800,pixelformat=42\n\nAh - that's clear - this is fine then.\n\n> \n>>\n>>> +\n>>>  \tOptionsParser parser;\n>>>  \n>>>  \tparser.addOption(OptCamera, \"Specify which camera to operate on\",\n>>>  \t\t\t \"camera\", ArgumentRequired, \"camera\");\n>>> +\tparser.addOption(OptFormat, \"Set format of the cameras first stream\",\n>>> +\t\t\t formatKeyValue, \"format\");\n>>>  \tparser.addOption(OptHelp, \"Display this help message\", \"help\");\n>>>  \tparser.addOption(OptList, \"List all cameras\", \"list\");\n>>>  \n>>> @@ -54,6 +65,42 @@ static int parseOptions(int argc, char *argv[])\n>>>  \treturn 0;\n>>>  }\n>>>  \n>>> +int str2uint(std::string str, unsigned int *dest)\n>>> +{\n>>> +\tif (!dest || str == \"\" || !sscanf(str.c_str(), \"%d\", dest))\n>>> +\t\treturn -EINVAL;\n>>> +\treturn 0;\n>>> +}\n>>> +\n>>> +bool configureStreams(Camera *camera, std::vector<Stream> &streams)\n>>> +{\n>>> +\tif (!options.isKeyValue(OptFormat))\n>>> +\t\treturn false;\n>>> +\n>>> +\tKeyValueParser::Options format = options.keyValues(OptFormat);\n>>> +\n>>> +\tstd::map<unsigned int, StreamConfiguration> config = camera->streamConfiguration(streams);\n>>> +\tunsigned int id = streams.front().id();\n>>> +\n>>> +\tif (format.isSet(\"width\"))\n>>> +\t\tif (str2uint(format[\"width\"], &config[id].width))\n>>> +\t\t\treturn false;\n>>> +\n>>> +\tif (format.isSet(\"height\"))\n>>> +\t\tif (str2uint(format[\"height\"], &config[id].height))\n>>> +\t\t\treturn false;\n>>> +\n>>> +\t/* TODO: Translate 4CC string to ID. */\n>>> +\tif (format.isSet(\"pixelformat\"))\n>>> +\t\tif (str2uint(format[\"pixelformat\"], &config[id].pixelFormat))\n>>> +\t\t\treturn false;\n>>> +\n>>> +\tif (camera->configureStreams(config))\n>>> +\t\treturn false;\n>>> +\n>>> +\treturn true;\n>>> +}\n>>> +\n>>>  int main(int argc, char **argv)\n>>>  {\n>>>  \tint ret;\n>>> @@ -63,6 +110,8 @@ int main(int argc, char **argv)\n>>>  \t\treturn EXIT_FAILURE;\n>>>  \n>>>  \tCameraManager *cm = CameraManager::instance();\n>>> +\tstd::shared_ptr<Camera> camera;\n>>> +\tstd::vector<Stream> streams;\n>>>  \n>>>  \tret = cm->start();\n>>>  \tif (ret) {\n>>> @@ -71,31 +120,62 @@ int main(int argc, char **argv)\n>>>  \t\treturn EXIT_FAILURE;\n>>>  \t}\n>>>  \n>>> +\tloop = new EventLoop(cm->eventDispatcher());\n>>> +\n>>> +\tstruct sigaction sa = {};\n>>> +\tsa.sa_handler = &signalHandler;\n>>> +\tsigaction(SIGINT, &sa, nullptr);\n>>> +\n>>>  \tif (options.isSet(OptList)) {\n>>>  \t\tstd::cout << \"Available cameras:\" << std::endl;\n>>> -\t\tfor (const std::shared_ptr<Camera> &camera : cm->cameras())\n>>> -\t\t\tstd::cout << \"- \" << camera->name() << std::endl;\n>>> +\t\tfor (const std::shared_ptr<Camera> &cam : cm->cameras())\n>>> +\t\t\tstd::cout << \"- \" << cam->name() << std::endl;\n>>>  \t}\n>>>  \n>>>  \tif (options.isSet(OptCamera)) {\n>>> -\t\tstd::shared_ptr<Camera> cam = cm->get(options[OptCamera]);\n>>> -\n>>> -\t\tif (cam) {\n>>> -\t\t\tstd::cout << \"Using camera \" << cam->name() << std::endl;\n>>> -\t\t} else {\n>>> +\t\tcamera = cm->get(options[OptCamera]);\n>>> +\t\tif (!camera) {\n>>>  \t\t\tstd::cout << \"Camera \" << options[OptCamera]\n>>>  \t\t\t\t  << \" not found\" << std::endl;\n>>> +\t\t\tgoto out;\n>>> +\t\t}\n>>> +\n>>> +\t\tstreams = camera->streams();\n>>> +\t\tif (streams.size() != 1) {\n>>> +\t\t\tstd::cout << \"Camera have \" << streams.size()\n>>\n>> Camera 'has' N streams...\n> \n> Thanks :-)\n> \n>>\n>>> +\t\t\t\t  << \" streams, I only know how to work with 1\"\n>>> +\t\t\t\t  << std::endl;\n>>> +\t\t\tgoto out;\n>>> +\t\t}\n>>> +\n>>> +\t\tif (camera->acquire()) {\n>>> +\t\t\tstd::cout << \"Failed to acquire camera\" << std::endl;\n>>> +\t\t\tgoto out;\n>>>  \t\t}\n>>> +\n>>> +\t\tstd::cout << \"Using camera \" << camera->name() << std::endl;\n>>>  \t}\n>>>  \n>>> -\tloop = new EventLoop(cm->eventDispatcher());\n>>> +\tif (options.isSet(OptFormat)) {\n>>> +\t\tif (!camera) {\n>>> +\t\t\tstd::cout << \"Can't configure stream, no camera selected\" << std::endl;\n>>> +\t\t\tgoto out_camera;\n>>> +\t\t}\n>>>  \n>>> -\tstruct sigaction sa = {};\n>>> -\tsa.sa_handler = &signalHandler;\n>>> -\tsigaction(SIGINT, &sa, nullptr);\n>>> +\t\tif (!configureStreams(camera.get(), streams)) {\n>>> +\t\t\tstd::cout << \"Failed to configure camera\" << std::endl;\n>>> +\t\t\tgoto out_camera;\n>>> +\t\t}\n>>> +\t}\n>>>  \n>>>  \tret = loop->exec();\n>>>  \n>>> +out_camera:\n>>> +\tif (camera) {\n>>> +\t\tcamera->release();\n>>> +\t\tcamera.reset();\n>>\n>> Uhm ... first a pointer call '->' then a direct member call ? '.' ?\n> \n> camera is a shard_ptr<Camera*> so the ->release() access the Camera \n> pointers that the shard_ptr<> holds while .reset() clears the \n> shard_ptr<> of the reference to the Camera hence reducing the refcount \n> by one and potentialy deleting the Camera object. \n\n\nOf course :) Ok - no issues there either then!\n--\nKieran\n\n\n> \n>>\n>>\n>>> +\t}\n>>> +out:\n>>>  \tdelete loop;\n>>>  \n>>>  \tcm->stop();\n>>>\n>>\n>> -- \n>> Regards\n>> --\n>> Kieran\n>","headers":{"Return-Path":"<kieran.bingham@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 6188760DB6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 29 Jan 2019 14:40:03 +0100 (CET)","from [192.168.0.21]\n\t(cpc89242-aztw30-2-0-cust488.18-1.cable.virginm.net [86.31.129.233])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id B698741;\n\tTue, 29 Jan 2019 14:40:02 +0100 (CET)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1548769202;\n\tbh=7rmz6jgvOUVopAxN/x/NJX7Hz/UjCK0VDVZ6vRpuAwI=;\n\th=Reply-To:Subject:To:Cc:References:From:Date:In-Reply-To:From;\n\tb=FKvBQGJFJFVuHDOErWlsiFFl6LzBSA0deZhM5bXKL8bOA/wnEvI+TCo6YrvAn666t\n\tsuu1xFkd+tzZo8+OKWrezRt26ZyRn1t6pi4hIYyq4fYNkpZ14d/Fd85UA5apib9JUF\n\tR4XpjNOzH5GenvmrbcB4gzE+7ylv9xitB2ETCyMc=","Reply-To":"kieran.bingham@ideasonboard.com","To":"=?utf-8?q?Niklas_S=C3=B6derlund?= <niklas.soderlund@ragnatech.se>","Cc":"libcamera-devel@lists.libcamera.org","References":"<20190128004109.25860-1-niklas.soderlund@ragnatech.se>\n\t<20190128004109.25860-7-niklas.soderlund@ragnatech.se>\n\t<7b9a3502-1848-8c37-33f3-03e1aa4db519@ideasonboard.com>\n\t<20190129133426.GF19527@bigcity.dyn.berto.se>","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Openpgp":"preference=signencrypt","Autocrypt":"addr=kieran.bingham@ideasonboard.com; keydata=\n\t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\n\tsbsRB8KNNvVXBOVNwko86rQqF9drZuw=","Organization":"Ideas on Board","Message-ID":"<5091d61e-cce4-9aeb-6357-e3b5c387f5e3@ideasonboard.com>","Date":"Tue, 29 Jan 2019 13:39:59 +0000","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101\n\tThunderbird/60.4.0","MIME-Version":"1.0","In-Reply-To":"<20190129133426.GF19527@bigcity.dyn.berto.se>","Content-Type":"text/plain; charset=utf-8","Content-Language":"en-GB","Content-Transfer-Encoding":"8bit","Subject":"Re: [libcamera-devel] [PATCH 6/6] cam: add --format option to\n\tconfigure a stream","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, 29 Jan 2019 13:40:03 -0000"}},{"id":720,"web_url":"https://patchwork.libcamera.org/comment/720/","msgid":"<20190131105259.GI4197@pendragon.ideasonboard.com>","date":"2019-01-31T10:52:59","subject":"Re: [libcamera-devel] [PATCH 6/6] cam: add --format option to\n\tconfigure a stream","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 Mon, Jan 28, 2019 at 01:41:09AM +0100, Niklas Söderlund wrote:\n> Add a option to configure the first stream of a camera from an argument\n\ns/a option/an option/\n\n> with options and parse the width, height and pixel format from that\n> list.\n> \n> The pixel format is still specified as a integer which should correspond\n> to the kernels FOURCC identifiers. Going forward this should be turned\n> into a string representation and the cam parser should translate between\n> the two.\n> \n> Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> ---\n>  src/cam/main.cpp | 104 +++++++++++++++++++++++++++++++++++++++++------\n>  1 file changed, 92 insertions(+), 12 deletions(-)\n> \n> diff --git a/src/cam/main.cpp b/src/cam/main.cpp\n> index bde47a8f17983912..4b4ce9aa29c80bd1 100644\n> --- a/src/cam/main.cpp\n> +++ b/src/cam/main.cpp\n> @@ -20,7 +20,8 @@ using namespace libcamera;\n>  OptionsParser::Options options;\n>  \n>  enum {\n> -\tOptCamera = 'c',\n> +\tOptCamera = 'C',\n\nWhy do you rename this option ?\n\n> +\tOptFormat = 'f',\n>  \tOptHelp = 'h',\n>  \tOptList = 'l',\n>  };\n> @@ -35,10 +36,20 @@ void signalHandler(int signal)\n>  \n>  static int parseOptions(int argc, char *argv[])\n>  {\n> +\tKeyValueParser formatKeyValue;\n> +\tformatKeyValue.addOption(\"width\", \"Set width in pixels\",\n\nI'd drop the \"Set \" part: \"Width in pixels\". Same for the other options.\n\n> +\t\t\t\t ArgumentRequired, \"w\");\n\nI wonder if we need the argumentName. Is \"width=w\" better than\n\"width=value\" ?\n\n> +\tformatKeyValue.addOption(\"height\", \"Set height in pixels\",\n> +\t\t\t\t ArgumentRequired, \"h\");\n> +\tformatKeyValue.addOption(\"pixelformat\", \"Set pixel format\",\n> +\t\t\t\t ArgumentRequired, \"pf\");\n> +\n>  \tOptionsParser parser;\n>  \n>  \tparser.addOption(OptCamera, \"Specify which camera to operate on\",\n>  \t\t\t \"camera\", ArgumentRequired, \"camera\");\n> +\tparser.addOption(OptFormat, \"Set format of the cameras first stream\",\n\ns/cameras/camera's/\n\n> +\t\t\t formatKeyValue, \"format\");\n>  \tparser.addOption(OptHelp, \"Display this help message\", \"help\");\n>  \tparser.addOption(OptList, \"List all cameras\", \"list\");\n>  \n> @@ -54,6 +65,42 @@ static int parseOptions(int argc, char *argv[])\n>  \treturn 0;\n>  }\n>  \n> +int str2uint(std::string str, unsigned int *dest)\n> +{\n> +\tif (!dest || str == \"\" || !sscanf(str.c_str(), \"%d\", dest))\n\nWouldn't strtoul be simpler than sscanf ?\n\n> +\t\treturn -EINVAL;\n> +\treturn 0;\n> +}\n> +\n> +bool configureStreams(Camera *camera, std::vector<Stream> &streams)\n> +{\n> +\tif (!options.isKeyValue(OptFormat))\n\nCan this happen, given that OptFormat is a key-value argument ? I would\ndrop this check, and possibly the isKeyValue() method of the parser if\nnot needed elsewhere.\n\n> +\t\treturn false;\n> +\n> +\tKeyValueParser::Options format = options.keyValues(OptFormat);\n> +\n> +\tstd::map<unsigned int, StreamConfiguration> config = camera->streamConfiguration(streams);\n> +\tunsigned int id = streams.front().id();\n> +\n> +\tif (format.isSet(\"width\"))\n> +\t\tif (str2uint(format[\"width\"], &config[id].width))\n> +\t\t\treturn false;\n\nDown the road I would like the parser to take a value type argument, and\nexpose an API that will automatically convert to the right type.\n\n> +\n> +\tif (format.isSet(\"height\"))\n> +\t\tif (str2uint(format[\"height\"], &config[id].height))\n> +\t\t\treturn false;\n> +\n> +\t/* TODO: Translate 4CC string to ID. */\n> +\tif (format.isSet(\"pixelformat\"))\n> +\t\tif (str2uint(format[\"pixelformat\"], &config[id].pixelFormat))\n> +\t\t\treturn false;\n> +\n> +\tif (camera->configureStreams(config))\n> +\t\treturn false;\n> +\n> +\treturn true;\n> +}\n> +\n>  int main(int argc, char **argv)\n>  {\n>  \tint ret;\n> @@ -63,6 +110,8 @@ int main(int argc, char **argv)\n>  \t\treturn EXIT_FAILURE;\n>  \n>  \tCameraManager *cm = CameraManager::instance();\n> +\tstd::shared_ptr<Camera> camera;\n> +\tstd::vector<Stream> streams;\n>  \n>  \tret = cm->start();\n>  \tif (ret) {\n> @@ -71,31 +120,62 @@ int main(int argc, char **argv)\n>  \t\treturn EXIT_FAILURE;\n>  \t}\n>  \n> +\tloop = new EventLoop(cm->eventDispatcher());\n> +\n> +\tstruct sigaction sa = {};\n> +\tsa.sa_handler = &signalHandler;\n> +\tsigaction(SIGINT, &sa, nullptr);\n> +\n>  \tif (options.isSet(OptList)) {\n>  \t\tstd::cout << \"Available cameras:\" << std::endl;\n> -\t\tfor (const std::shared_ptr<Camera> &camera : cm->cameras())\n> -\t\t\tstd::cout << \"- \" << camera->name() << std::endl;\n> +\t\tfor (const std::shared_ptr<Camera> &cam : cm->cameras())\n> +\t\t\tstd::cout << \"- \" << cam->name() << std::endl;\n>  \t}\n>  \n>  \tif (options.isSet(OptCamera)) {\n> -\t\tstd::shared_ptr<Camera> cam = cm->get(options[OptCamera]);\n> -\n> -\t\tif (cam) {\n> -\t\t\tstd::cout << \"Using camera \" << cam->name() << std::endl;\n> -\t\t} else {\n> +\t\tcamera = cm->get(options[OptCamera]);\n> +\t\tif (!camera) {\n>  \t\t\tstd::cout << \"Camera \" << options[OptCamera]\n>  \t\t\t\t  << \" not found\" << std::endl;\n\nShould errors be printed to cerr ?\n\n> +\t\t\tgoto out;\n> +\t\t}\n> +\n> +\t\tstreams = camera->streams();\n> +\t\tif (streams.size() != 1) {\n> +\t\t\tstd::cout << \"Camera have \" << streams.size()\n\ns/have/has/\n\n> +\t\t\t\t  << \" streams, I only know how to work with 1\"\n\nI'm not used to software talking to me, but why not ? :-)\n\n> +\t\t\t\t  << std::endl;\n> +\t\t\tgoto out;\n> +\t\t}\n> +\n> +\t\tif (camera->acquire()) {\n> +\t\t\tstd::cout << \"Failed to acquire camera\" << std::endl;\n> +\t\t\tgoto out;\n>  \t\t}\n> +\n> +\t\tstd::cout << \"Using camera \" << camera->name() << std::endl;\n>  \t}\n>  \n> -\tloop = new EventLoop(cm->eventDispatcher());\n> +\tif (options.isSet(OptFormat)) {\n> +\t\tif (!camera) {\n> +\t\t\tstd::cout << \"Can't configure stream, no camera selected\" << std::endl;\n> +\t\t\tgoto out_camera;\n> +\t\t}\n\nI think we'll end up with the cam tool working in one of a small subset\nof modes. I foresee at least a list mode and a capture mode, and\nprobably a few others, but not many. I'd make them mutually exclusive,\nwith list returning immediately after printing the list of cameras, and\ncapture requiring a camera, so this check will likely be moved out of\nthe OptFormat check. We can refactor this later.\n\n>  \n> -\tstruct sigaction sa = {};\n> -\tsa.sa_handler = &signalHandler;\n> -\tsigaction(SIGINT, &sa, nullptr);\n> +\t\tif (!configureStreams(camera.get(), streams)) {\n> +\t\t\tstd::cout << \"Failed to configure camera\" << std::endl;\n> +\t\t\tgoto out_camera;\n> +\t\t}\n> +\t}\n>  \n>  \tret = loop->exec();\n>  \n> +out_camera:\n> +\tif (camera) {\n> +\t\tcamera->release();\n> +\t\tcamera.reset();\n> +\t}\n> +out:\n>  \tdelete loop;\n>  \n>  \tcm->stop();","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 87C4460B10\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 31 Jan 2019 11:53:01 +0100 (CET)","from pendragon.ideasonboard.com (85-76-34-136-nat.elisa-mobile.fi\n\t[85.76.34.136])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 1B4C841;\n\tThu, 31 Jan 2019 11:52:59 +0100 (CET)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1548931981;\n\tbh=CWJmnSKTVqXnGgD9+5eq8ZS3LfqU/Y2kuOCcNgvIrI0=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=MC6y31VpsbWLjBw394no47EcYduSxQKwAyQUvDZlmKJIvDxhjlsZCr2mQE4I3oT/+\n\tEeJDW0KLInYNL0iOELU5Ic2SNlIoGRI6sNeNBZ4v5AO6/6RocCNdgrWuseYGRZ/+MH\n\tVJZzkX9xt7qxdL3gqtpYNRVIX04xj6suN34ysyCw=","Date":"Thu, 31 Jan 2019 12:52:59 +0200","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":"<20190131105259.GI4197@pendragon.ideasonboard.com>","References":"<20190128004109.25860-1-niklas.soderlund@ragnatech.se>\n\t<20190128004109.25860-7-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":"<20190128004109.25860-7-niklas.soderlund@ragnatech.se>","User-Agent":"Mutt/1.10.1 (2018-07-13)","Subject":"Re: [libcamera-devel] [PATCH 6/6] cam: add --format option to\n\tconfigure a stream","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":"Thu, 31 Jan 2019 10:53:01 -0000"}}]