{"id":23241,"url":"https://patchwork.libcamera.org/api/patches/23241/?format=json","web_url":"https://patchwork.libcamera.org/patch/23241/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/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":"<20250423091208.2935632-1-paul.elder@ideasonboard.com>","date":"2025-04-23T09:12:08","name":"apps: cam: Try raw role if default viewfinder role fails","commit_ref":null,"pull_url":null,"state":"accepted","archived":false,"hash":"b729d4cc780def44338b7cde03fb4aa5cf232246","submitter":{"id":17,"url":"https://patchwork.libcamera.org/api/people/17/?format=json","name":"Paul Elder","email":"paul.elder@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/23241/mbox/","series":[{"id":5143,"url":"https://patchwork.libcamera.org/api/series/5143/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=5143","date":"2025-04-23T09:12:08","name":"apps: cam: Try raw role if default viewfinder role fails","version":1,"mbox":"https://patchwork.libcamera.org/series/5143/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/23241/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/23241/checks/","tags":{},"headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 5433BC327D\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 23 Apr 2025 09:12:34 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 5155968AC5;\n\tWed, 23 Apr 2025 11:12:33 +0200 (CEST)","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 76A6F617E5\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 23 Apr 2025 11:12:31 +0200 (CEST)","from neptunite.hamster-moth.ts.net (unknown\n\t[IPv6:2404:7a81:160:2100:7551:2625:7c9e:4259])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 1FA6822A;\n\tWed, 23 Apr 2025 11:12:28 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"N54xd/u0\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1745399550;\n\tbh=jSlpadac187sUbrkBHG6AuY4BzbIEFj2lcpTzEPDfBc=;\n\th=From:To:Cc:Subject:Date:From;\n\tb=N54xd/u00yZ4KPhjzZ+IfT8ehWmrTzLnu8mEgWj7FG6Fr9kIfJxB1HnaKu8yUvoP0\n\t2KnXq38X+cUFHSgDZ2oKDg9+sEz+rfCGmdG42SCE5MatohSJLb5kraNpSoQvHF736Z\n\tO+1EFEg0BZfggBQmQwxqJkh8olrm7iZmVwdfhQgs=","From":"Paul Elder <paul.elder@ideasonboard.com>","To":"libcamera-devel@lists.libcamera.org","Cc":"Paul Elder <paul.elder@ideasonboard.com>","Subject":"[PATCH] apps: cam: Try raw role if default viewfinder role fails","Date":"Wed, 23 Apr 2025 18:12:08 +0900","Message-ID":"<20250423091208.2935632-1-paul.elder@ideasonboard.com>","X-Mailer":"git-send-email 2.47.2","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","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>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"},"content":"cam currently defaults to the viewfinder role when no role is specified.\nThis means that on platforms that only support the raw role (such as a\nraw sensor with no softISP on a simple pipeline platform),\ngenerateConfiguration() would return nullptr and cam would bail out.\n\nAt least this is what is supposed to happen based on the little\ndocumentation that we have written regarding generateConfiguration(),\nspecifically in the application writer's guide, which is probably the\nmost influential piece of documentation:\n\n  The ``Camera::generateConfiguration()`` function accepts a list of\n  desired roles and generates a ``CameraConfiguration`` with the best\n  stream parameters configuration for each of the requested roles. If the\n  camera can handle the requested roles, it returns an initialized\n  ``CameraConfiguration`` and a null pointer if it can't.\n\nCurrently the simple pipeline handler will return a raw configuration\nanyway (if it only supports raw) even if a non-raw role was requested.\nThus cam receives a raw configuration instead of a nullptr when no role\nis specified and viewfinder is requested.\n\nHowever, in the near future, support for raw streams with softISP on the\nsimple pipeline handler will be merged. This will notably change the\nbehavior of the simple pipeline handler to return nullptr if a non-raw\nrole was requested on a platform that only supports raw. This is proper\nbehavior according to documentation, but changes cam's behavior as it\nused to capture fine with no parameters but will no longer be able to.\n\nTechnically this is an issue with the roles API, as we are mixing\nroles in the sense of \"configuration hints\" (eg. viewfinder vs recording\nvs still capture) with roles in the sense of \"platform capabilities\"\n(raw vs everything else). In the long term the proper solution is to\nrework the roles API.\n\nIn the meantime, fix cam so that it will try the raw role if the default\nviewfinder role returns no configuration. cam is an app that is capable\nof using the raw stream, so this is appropriate behavior. If roles are\nspecified, then do not retry, as in this situation the user knows what\nstreams they can use and what they want.\n\nSigned-off-by: Paul Elder <paul.elder@ideasonboard.com>\n---\n src/apps/cam/camera_session.cpp    | 29 +++++++++++++++++++++++++----\n src/apps/common/stream_options.cpp |  3 +--\n src/apps/qcam/main_window.cpp      |  3 +++\n 3 files changed, 29 insertions(+), 6 deletions(-)","diff":"diff --git a/src/apps/cam/camera_session.cpp b/src/apps/cam/camera_session.cpp\nindex 97c1ae44995e..f63fcb228519 100644\n--- a/src/apps/cam/camera_session.cpp\n+++ b/src/apps/cam/camera_session.cpp\n@@ -62,11 +62,32 @@ CameraSession::CameraSession(CameraManager *cm,\n \t\treturn;\n \t}\n \n-\tstd::vector<StreamRole> roles = StreamKeyValueParser::roles(options_[OptStream]);\n+\tstd::vector<StreamRole> roles =\n+\t\tStreamKeyValueParser::roles(options_[OptStream]);\n+\tstd::vector<std::vector<StreamRole>> tryRoles;\n+\tif (!roles.empty()) {\n+\t\t/*\n+\t\t * If the roles are explicitly specified then there's no need\n+\t\t * to try other roles\n+\t\t */\n+\t\ttryRoles.push_back(roles);\n+\t} else {\n+\t\ttryRoles.push_back({ StreamRole::Viewfinder });\n+\t\ttryRoles.push_back({ StreamRole::Raw });\n+\t}\n+\n+\tstd::unique_ptr<CameraConfiguration> config;\n+\tbool valid = false;\n+\tfor (std::vector<StreamRole> &rolesIt : tryRoles) {\n+\t\tconfig = camera_->generateConfiguration(rolesIt);\n+\t\tif (config && config->size() == rolesIt.size()) {\n+\t\t\troles = rolesIt;\n+\t\t\tvalid = true;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n \n-\tstd::unique_ptr<CameraConfiguration> config =\n-\t\tcamera_->generateConfiguration(roles);\n-\tif (!config || config->size() != roles.size()) {\n+\tif (!valid) {\n \t\tstd::cerr << \"Failed to get default stream configuration\"\n \t\t\t  << std::endl;\n \t\treturn;\ndiff --git a/src/apps/common/stream_options.cpp b/src/apps/common/stream_options.cpp\nindex 99239e07e302..288f86530351 100644\n--- a/src/apps/common/stream_options.cpp\n+++ b/src/apps/common/stream_options.cpp\n@@ -42,9 +42,8 @@ KeyValueParser::Options StreamKeyValueParser::parse(const char *arguments)\n \n std::vector<StreamRole> StreamKeyValueParser::roles(const OptionValue &values)\n {\n-\t/* If no configuration values to examine default to viewfinder. */\n \tif (values.empty())\n-\t\treturn { StreamRole::Viewfinder };\n+\t\treturn {};\n \n \tconst std::vector<OptionValue> &streamParameters = values.toArray();\n \ndiff --git a/src/apps/qcam/main_window.cpp b/src/apps/qcam/main_window.cpp\nindex d2ccbd2318fa..224a7e5a693a 100644\n--- a/src/apps/qcam/main_window.cpp\n+++ b/src/apps/qcam/main_window.cpp\n@@ -356,6 +356,9 @@ int MainWindow::startCapture()\n \n \t/* Verify roles are supported. */\n \tswitch (roles.size()) {\n+\tcase 0:\n+\t\troles[0] = StreamRole::Viewfinder;\n+\t\tbreak;\n \tcase 1:\n \t\tif (roles[0] != StreamRole::Viewfinder) {\n \t\t\tqWarning() << \"Only viewfinder supported for single stream\";\n","prefixes":[]}