[libcamera-devel] [PATCH 6/6] cam: add --format option to configure a stream
Laurent Pinchart
laurent.pinchart at ideasonboard.com
Thu Jan 31 11:52:59 CET 2019
Hi Niklas,
Thank you for the patch.
On Mon, Jan 28, 2019 at 01:41:09AM +0100, Niklas Söderlund wrote:
> Add a option to configure the first stream of a camera from an argument
s/a option/an option/
> with options 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 <niklas.soderlund at ragnatech.se>
> ---
> src/cam/main.cpp | 104 +++++++++++++++++++++++++++++++++++++++++------
> 1 file changed, 92 insertions(+), 12 deletions(-)
>
> diff --git a/src/cam/main.cpp b/src/cam/main.cpp
> index bde47a8f17983912..4b4ce9aa29c80bd1 100644
> --- a/src/cam/main.cpp
> +++ b/src/cam/main.cpp
> @@ -20,7 +20,8 @@ using namespace libcamera;
> OptionsParser::Options options;
>
> enum {
> - OptCamera = 'c',
> + OptCamera = 'C',
Why do you rename this option ?
> + OptFormat = 'f',
> OptHelp = 'h',
> OptList = 'l',
> };
> @@ -35,10 +36,20 @@ void signalHandler(int signal)
>
> static int parseOptions(int argc, char *argv[])
> {
> + KeyValueParser formatKeyValue;
> + formatKeyValue.addOption("width", "Set width in pixels",
I'd drop the "Set " part: "Width in pixels". Same for the other options.
> + ArgumentRequired, "w");
I wonder if we need the argumentName. Is "width=w" better than
"width=value" ?
> + formatKeyValue.addOption("height", "Set height in pixels",
> + ArgumentRequired, "h");
> + formatKeyValue.addOption("pixelformat", "Set pixel format",
> + ArgumentRequired, "pf");
> +
> OptionsParser parser;
>
> parser.addOption(OptCamera, "Specify which camera to operate on",
> "camera", ArgumentRequired, "camera");
> + parser.addOption(OptFormat, "Set format of the cameras first stream",
s/cameras/camera's/
> + formatKeyValue, "format");
> parser.addOption(OptHelp, "Display this help message", "help");
> parser.addOption(OptList, "List all cameras", "list");
>
> @@ -54,6 +65,42 @@ static int parseOptions(int argc, char *argv[])
> return 0;
> }
>
> +int str2uint(std::string str, unsigned int *dest)
> +{
> + if (!dest || str == "" || !sscanf(str.c_str(), "%d", dest))
Wouldn't strtoul be simpler than sscanf ?
> + return -EINVAL;
> + return 0;
> +}
> +
> +bool configureStreams(Camera *camera, std::vector<Stream> &streams)
> +{
> + if (!options.isKeyValue(OptFormat))
Can this happen, given that OptFormat is a key-value argument ? I would
drop this check, and possibly the isKeyValue() method of the parser if
not needed elsewhere.
> + return false;
> +
> + KeyValueParser::Options format = options.keyValues(OptFormat);
> +
> + std::map<unsigned int, StreamConfiguration> config = camera->streamConfiguration(streams);
> + unsigned int id = streams.front().id();
> +
> + if (format.isSet("width"))
> + if (str2uint(format["width"], &config[id].width))
> + return false;
Down the road I would like the parser to take a value type argument, and
expose an API that will automatically convert to the right type.
> +
> + if (format.isSet("height"))
> + if (str2uint(format["height"], &config[id].height))
> + return false;
> +
> + /* TODO: Translate 4CC string to ID. */
> + if (format.isSet("pixelformat"))
> + if (str2uint(format["pixelformat"], &config[id].pixelFormat))
> + return false;
> +
> + if (camera->configureStreams(config))
> + return false;
> +
> + return true;
> +}
> +
> int main(int argc, char **argv)
> {
> int ret;
> @@ -63,6 +110,8 @@ int main(int argc, char **argv)
> return EXIT_FAILURE;
>
> CameraManager *cm = CameraManager::instance();
> + std::shared_ptr<Camera> camera;
> + std::vector<Stream> streams;
>
> ret = cm->start();
> if (ret) {
> @@ -71,31 +120,62 @@ int main(int argc, char **argv)
> return EXIT_FAILURE;
> }
>
> + loop = new EventLoop(cm->eventDispatcher());
> +
> + struct sigaction sa = {};
> + sa.sa_handler = &signalHandler;
> + sigaction(SIGINT, &sa, nullptr);
> +
> if (options.isSet(OptList)) {
> std::cout << "Available cameras:" << std::endl;
> - for (const std::shared_ptr<Camera> &camera : cm->cameras())
> - std::cout << "- " << camera->name() << std::endl;
> + for (const std::shared_ptr<Camera> &cam : cm->cameras())
> + std::cout << "- " << cam->name() << std::endl;
> }
>
> if (options.isSet(OptCamera)) {
> - std::shared_ptr<Camera> cam = cm->get(options[OptCamera]);
> -
> - if (cam) {
> - std::cout << "Using camera " << cam->name() << std::endl;
> - } else {
> + camera = cm->get(options[OptCamera]);
> + if (!camera) {
> std::cout << "Camera " << options[OptCamera]
> << " not found" << std::endl;
Should errors be printed to cerr ?
> + goto out;
> + }
> +
> + streams = camera->streams();
> + if (streams.size() != 1) {
> + std::cout << "Camera have " << streams.size()
s/have/has/
> + << " streams, I only know how to work with 1"
I'm not used to software talking to me, but why not ? :-)
> + << std::endl;
> + goto out;
> + }
> +
> + if (camera->acquire()) {
> + std::cout << "Failed to acquire camera" << std::endl;
> + goto out;
> }
> +
> + std::cout << "Using camera " << camera->name() << std::endl;
> }
>
> - loop = new EventLoop(cm->eventDispatcher());
> + if (options.isSet(OptFormat)) {
> + if (!camera) {
> + std::cout << "Can't configure stream, no camera selected" << std::endl;
> + goto out_camera;
> + }
I think we'll end up with the cam tool working in one of a small subset
of modes. I foresee at least a list mode and a capture mode, and
probably a few others, but not many. I'd make them mutually exclusive,
with list returning immediately after printing the list of cameras, and
capture requiring a camera, so this check will likely be moved out of
the OptFormat check. We can refactor this later.
>
> - struct sigaction sa = {};
> - sa.sa_handler = &signalHandler;
> - sigaction(SIGINT, &sa, nullptr);
> + if (!configureStreams(camera.get(), streams)) {
> + std::cout << "Failed to configure camera" << std::endl;
> + goto out_camera;
> + }
> + }
>
> ret = loop->exec();
>
> +out_camera:
> + if (camera) {
> + camera->release();
> + camera.reset();
> + }
> +out:
> delete loop;
>
> cm->stop();
--
Regards,
Laurent Pinchart
More information about the libcamera-devel
mailing list