From patchwork Fri Jan 25 21:21:53 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 395 X-Patchwork-Delegate: niklas.soderlund@ragnatech.se Return-Path: Received: from bin-mail-out-05.binero.net (bin-mail-out-05.binero.net [195.74.38.228]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6291A60C6A for ; Fri, 25 Jan 2019 22:22:13 +0100 (CET) X-Halon-ID: 4460ee51-20e7-11e9-9adf-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 4460ee51-20e7-11e9-9adf-005056917a89; Fri, 25 Jan 2019 22:22:06 +0100 (CET) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Fri, 25 Jan 2019 22:21:53 +0100 Message-Id: <20190125212154.26950-2-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190125212154.26950-1-niklas.soderlund@ragnatech.se> References: <20190125212154.26950-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [RFC 1/2] cam: options: add parser for suboptions X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 25 Jan 2019 21:22:13 -0000 The cam utility will make use of lists of key/value pairs from the command line arguments. This is needed so that a user can among other things describe complex stream format descriptions, which consists of a set of parameters. Signed-off-by: Niklas Söderlund --- src/cam/options.cpp | 68 +++++++++++++++++++++++++++++++++++++++++++++ src/cam/options.h | 24 ++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/src/cam/options.cpp b/src/cam/options.cpp index 55c42540f92478e6..3299cdfed69703fa 100644 --- a/src/cam/options.cpp +++ b/src/cam/options.cpp @@ -180,3 +180,71 @@ void OptionsParser::Options::clear() { values_.clear(); } + +void SubOptionsParser::addToken(const char *name) +{ + if (!name) + return; + + /* Reject duplicate options. */ + for (const char *option : options_) + if (!strcmp(name, option)) + return; + + options_.push_back(name); +} + +SubOptionsParser::Options SubOptionsParser::parse(const char *argc) +{ + const char **tokens; + char *dupe, *subs, *value; + Options options; + + tokens = new const char *[options_.size() + 1](); + for (unsigned int i = 0; i < options_.size(); i++) + tokens[i] = options_.at(i); + + dupe = strdup(argc); + subs = dupe; + while (*subs != '\0') { + int opt = getsubopt(&subs, (char *const *)tokens, &value); + + if (opt == -1 || !value || value[0] == '\0') { + if (opt == -1) + std::cerr << "Invalid option " << value << std::endl; + else + std::cerr << "Missing argument for option " + << tokens[opt] << std::endl; + + options.clear(); + break; + } + + options.values_[tokens[opt]] = value; + } + + free(dupe); + delete[] tokens; + + return options; +} + +bool SubOptionsParser::Options::valid() const +{ + return !values_.empty(); +} + +bool SubOptionsParser::Options::isSet(std::string opt) const +{ + return values_.find(opt) != values_.end(); +} + +const std::string &SubOptionsParser::Options::operator[](std::string opt) const +{ + return values_.find(opt)->second; +} + +void SubOptionsParser::Options::clear() +{ + values_.clear(); +} diff --git a/src/cam/options.h b/src/cam/options.h index f99ea7300a71c24f..653dda0c76e52251 100644 --- a/src/cam/options.h +++ b/src/cam/options.h @@ -57,4 +57,28 @@ private: std::map optionsMap_; }; +class SubOptionsParser +{ +public: + class Options + { + public: + bool valid() const; + bool isSet(std::string opt) const; + const std::string &operator[](std::string opt) const; + + private: + friend class SubOptionsParser; + std::map values_; + void clear(); + }; + + void addToken(const char *token); + + Options parse(const char *argc); + +private: + std::vector options_; +}; + #endif /* __CAM_OPTIONS_H__ */ From patchwork Fri Jan 25 21:21:54 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 396 X-Patchwork-Delegate: niklas.soderlund@ragnatech.se Return-Path: Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6C4E660C7F for ; Fri, 25 Jan 2019 22:22:13 +0100 (CET) X-Halon-ID: 44a80b3b-20e7-11e9-9adf-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 44a80b3b-20e7-11e9-9adf-005056917a89; Fri, 25 Jan 2019 22:22:07 +0100 (CET) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Fri, 25 Jan 2019 22:21:54 +0100 Message-Id: <20190125212154.26950-3-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190125212154.26950-1-niklas.soderlund@ragnatech.se> References: <20190125212154.26950-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [RFC 2/2] cam: make the --format option take arguments X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 25 Jan 2019 21:22:13 -0000 Instead of configuring a static frame dimension of 640x480 make the format option take a list of arguments and parse the width, height and pixel format from that list. The pixel format is still specified as a integer which should correspond to the kernels FOURCC identifiers. Going forward this should be turned into a string representation and the cam parser should translate between the two. Signed-off-by: Niklas Söderlund --- src/cam/main.cpp | 71 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 63 insertions(+), 8 deletions(-) diff --git a/src/cam/main.cpp b/src/cam/main.cpp index b8c05d9079be3cb3..9fee77d6ddec31bc 100644 --- a/src/cam/main.cpp +++ b/src/cam/main.cpp @@ -41,7 +41,15 @@ static int parseOptions(int argc, char *argv[]) parser.addOption(OptCamera, "Specify which camera to operate on", "camera", OptionsParser::ArgumentRequired, "camera"); - parser.addOption(OptFormat, "Configure the first stream to 640x480", "format"); + parser.addOption(OptFormat, + "Set format of the cameras first stream\n" + "\tformatdesc is a string of key=value pairs joined by a commas\n\n" + "\twidth= Specify the width (int)\n" + "\theight= Specify the height (int)\n" + "\tpixelformat= Specify the pixelformat (int)\n" + "\n\tAny combination of options are valid, example: --format width=800,height=600", + "format", OptionsParser::ArgumentRequired, + "formatdesc"); parser.addOption(OptHelp, "Display this help message", "help"); parser.addOption(OptList, "List all cameras", "list"); @@ -57,6 +65,57 @@ static int parseOptions(int argc, char *argv[]) return 0; } +int str2uint(std::string str, unsigned int *dest) +{ + unsigned long tmp = stoul(str); + *dest = tmp; + if (*dest != tmp) + return -EINVAL;; + return 0; +} + +bool configureStreams(Camera *camera, const std::string &arg) +{ + SubOptionsParser parser; + parser.addToken("width"); + parser.addToken("height"); + parser.addToken("pixelformat"); + SubOptionsParser::Options format = parser.parse(arg.c_str()); + + if (!format.valid()) + return false; + + std::vector streams = camera->streams(); + StreamConfiguration config = StreamConfiguration(streams.front()); + + if (format.isSet("width") && format.isSet("height")) { + unsigned int width, height; + + if (str2uint(format["width"], &width) || str2uint(format["height"], &height)) + return false; + + config.setDimension(width, height); + } + + if (format.isSet("pixelformat")) { + unsigned int pixelformat; + + /* TODO: Translate 4CC string to ID. */ + if (str2uint(format["pixelformat"], &pixelformat)) + return false; + + config.setPixelFormat(pixelformat); + } + + std::vector configs; + configs.push_back(&config); + + if (camera->configure(configs)) + return false; + + return true; +} + int main(int argc, char **argv) { int ret; @@ -117,14 +176,10 @@ int main(int argc, char **argv) goto out_camera; } - StreamConfiguration config = StreamConfiguration(streams.front()); - config.setDimension(640, 480); - - std::vector configs; - configs.push_back(&config); - - if (camera->configure(configs)) + if (!configureStreams(camera.get(), options[OptFormat])) { std::cout << "Failed to configure camera" << std::endl; + goto out_camera; + } } ret = loop->exec();