Patch Detail
Show a patch.
GET /api/1.1/patches/22966/?format=api
{ "id": 22966, "url": "https://patchwork.libcamera.org/api/1.1/patches/22966/?format=api", "web_url": "https://patchwork.libcamera.org/patch/22966/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/1.1/projects/1/?format=api", "name": "libcamera", "link_name": "libcamera", "list_id": "libcamera_core", "list_email": "libcamera-devel@lists.libcamera.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20250314202943.112109-7-mzamazal@redhat.com>", "date": "2025-03-14T20:29:34", "name": "[RFC,6/7] apps: cam: Track sink streams", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "fd6f8c87887f874a57e812be5800b8ca704715d8", "submitter": { "id": 177, "url": "https://patchwork.libcamera.org/api/1.1/people/177/?format=api", "name": "Milan Zamazal", "email": "mzamazal@redhat.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/22966/mbox/", "series": [ { "id": 5062, "url": "https://patchwork.libcamera.org/api/1.1/series/5062/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=5062", "date": "2025-03-14T20:29:28", "name": "Support different outputs for cam streams", "version": 1, "mbox": "https://patchwork.libcamera.org/series/5062/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/22966/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/22966/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 40460C32F7\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 14 Mar 2025 20:30:20 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 5FFE968955;\n\tFri, 14 Mar 2025 21:30:19 +0100 (CET)", "from us-smtp-delivery-124.mimecast.com\n\t(us-smtp-delivery-124.mimecast.com [170.10.133.124])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id EA94368950\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 14 Mar 2025 21:30:12 +0100 (CET)", "from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com\n\t(ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97])\n\tby relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n\tcipher=TLS_AES_256_GCM_SHA384) id us-mta-34-A9Oi_dspMUG95FoA1n3thQ-1;\n\tFri, 14 Mar 2025 16:30:10 -0400", "from mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com\n\t(mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com\n\t[10.30.177.40])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\tkey-exchange X25519 server-signature RSA-PSS (2048 bits)\n\tserver-digest SHA256) (No client certificate requested)\n\tby mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix)\n\twith ESMTPS id 82C21180025E; Fri, 14 Mar 2025 20:30:09 +0000 (UTC)", "from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.32.19])\n\tby mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix)\n\twith ESMTP id 07CB01954B32; Fri, 14 Mar 2025 20:30:07 +0000 (UTC)" ], "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=redhat.com header.i=@redhat.com\n\theader.b=\"PpelEAWJ\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1741984212;\n\th=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n\tto:to:cc:cc:mime-version:mime-version:content-type:content-type:\n\tcontent-transfer-encoding:content-transfer-encoding:\n\tin-reply-to:in-reply-to:references:references;\n\tbh=9fwSjLBWr1oMZz3V0RPmlAXDkKTDuWUYQerCdEJ/8TE=;\n\tb=PpelEAWJa7BONBBKmgkM9ltEm7iWPLerDuzSnIjSKUO5oJYKUDoRWr80Aw2OBieL4mloOY\n\tg3vTII8g2rB7A8wo0ZX8wAdZgprI2dpzNrLWlyf8+gnZyCa5p7gTyIClfP741yNV6RDQd7\n\toFukH/VJBfjPh7vy7lZ3UOKLacyuONY=", "X-MC-Unique": "A9Oi_dspMUG95FoA1n3thQ-1", "X-Mimecast-MFC-AGG-ID": "A9Oi_dspMUG95FoA1n3thQ_1741984209", "From": "Milan Zamazal <mzamazal@redhat.com>", "To": "libcamera-devel@lists.libcamera.org", "Cc": "Milan Zamazal <mzamazal@redhat.com>,\n\tLaurent Pinchart <laurent.pinchart@ideasonboard.com>", "Subject": "[RFC PATCH 6/7] apps: cam: Track sink streams", "Date": "Fri, 14 Mar 2025 21:29:34 +0100", "Message-ID": "<20250314202943.112109-7-mzamazal@redhat.com>", "In-Reply-To": "<20250314202943.112109-1-mzamazal@redhat.com>", "References": "<20250314202943.112109-1-mzamazal@redhat.com>", "MIME-Version": "1.0", "X-Scanned-By": "MIMEDefang 3.0 on 10.30.177.40", "X-Mimecast-Spam-Score": "0", "X-Mimecast-MFC-PROC-ID": "_0zZGioEsa_W0p5eNcFGKEd2n3KNY8CV_Q6aO4B2Imc_1741984209", "X-Mimecast-Originator": "redhat.com", "Content-Transfer-Encoding": "8bit", "content-type": "text/plain; charset=\"US-ASCII\"; x-default=true", "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": "In order to support different sinks for different streams, we must track\nthe relationship between sinks and streams. Let's track the\ncorresponding streams in FrameSink. Different kinds of sinks use\ndifferent approaches to multiple streams; keeping the sinks to handle\nthat this way is the simplest.\n\nLet's add FrameSink class member and some utility methods for the\npurpose.\n\nWe still create only one, the default, sink, so all the streams are\nadded to the default sink unconditionally. This will be changed in\na followup patch.\n\nOperations on each given sink are applied only for streams the sink\ncontains.\n\nSigned-off-by: Milan Zamazal <mzamazal@redhat.com>\n---\n src/apps/cam/camera_session.cpp | 9 ++++++++-\n src/apps/cam/file_sink.cpp | 3 ++-\n src/apps/cam/frame_sink.cpp | 14 ++++++++++++++\n src/apps/cam/frame_sink.h | 26 ++++++++++++++++++++++++++\n src/apps/cam/kms_sink.cpp | 8 +++++++-\n src/apps/cam/sdl_sink.cpp | 15 ++++++++-------\n 6 files changed, 65 insertions(+), 10 deletions(-)", "diff": "diff --git a/src/apps/cam/camera_session.cpp b/src/apps/cam/camera_session.cpp\nindex b1f5209d..5124029b 100644\n--- a/src/apps/cam/camera_session.cpp\n+++ b/src/apps/cam/camera_session.cpp\n@@ -292,6 +292,12 @@ int CameraSession::start()\n \t\tdefaultSink = std::move(sink);\n \t}\n \n+\tfor (unsigned int i = 0; i < config_->size(); i++) {\n+\t\tconst StreamConfiguration &cfg = config_->at(i);\n+\t\tif (defaultSink)\n+\t\t\tdefaultSink->addStream(cfg.stream());\n+\t}\n+\n \tif (defaultSink)\n \t\tsinks_.push_back(std::move(defaultSink));\n \n@@ -374,7 +380,8 @@ int CameraSession::startCapture()\n \t\t\t}\n \n \t\t\tfor (auto &sink : sinks_)\n-\t\t\t\tsink->mapBuffer(buffer.get());\n+\t\t\t\tif (sink->assignedStream(stream))\n+\t\t\t\t\tsink->mapBuffer(buffer.get());\n \t\t}\n \n \t\trequests_.push_back(std::move(request));\ndiff --git a/src/apps/cam/file_sink.cpp b/src/apps/cam/file_sink.cpp\nindex 76e21db9..9ef4011b 100644\n--- a/src/apps/cam/file_sink.cpp\n+++ b/src/apps/cam/file_sink.cpp\n@@ -96,7 +96,8 @@ void FileSink::mapBuffer(FrameBuffer *buffer)\n bool FileSink::processRequest(Request *request)\n {\n \tfor (auto [stream, buffer] : request->buffers())\n-\t\twriteBuffer(stream, buffer, request->metadata());\n+\t\tif (assignedStream(stream))\n+\t\t\twriteBuffer(stream, buffer, request->metadata());\n \n \treturn true;\n }\ndiff --git a/src/apps/cam/frame_sink.cpp b/src/apps/cam/frame_sink.cpp\nindex 68d6f2c1..51c85124 100644\n--- a/src/apps/cam/frame_sink.cpp\n+++ b/src/apps/cam/frame_sink.cpp\n@@ -7,6 +7,8 @@\n \n #include \"frame_sink.h\"\n \n+#include <iostream>\n+\n /**\n * \\class FrameSink\n * \\brief Abstract class to model a consumer of frames\n@@ -65,3 +67,15 @@ int FrameSink::stop()\n * \\return True if the request has been processed synchronously, false if\n * processing has been queued\n */\n+\n+const libcamera::StreamConfiguration &FrameSink::findConfiguration(\n+\tconst libcamera::CameraConfiguration &config)\n+{\n+\tfor (unsigned int i = 0; i < config.size(); i++)\n+\t\tif (assignedStream(config.at(i).stream()))\n+\t\t\treturn config.at(i);\n+\n+\t/* This should never happen. */\n+\tstd::cerr << \"No camera configuration for frame sink\" << std::endl;\n+\treturn config.at(0);\n+}\ndiff --git a/src/apps/cam/frame_sink.h b/src/apps/cam/frame_sink.h\nindex 11105c6c..c51db775 100644\n--- a/src/apps/cam/frame_sink.h\n+++ b/src/apps/cam/frame_sink.h\n@@ -7,8 +7,13 @@\n \n #pragma once\n \n+#include <vector>\n+\n #include <libcamera/base/signal.h>\n \n+#include <libcamera/camera.h>\n+#include <libcamera/stream.h>\n+\n namespace libcamera {\n class CameraConfiguration;\n class FrameBuffer;\n@@ -27,6 +32,27 @@ public:\n \tvirtual int start();\n \tvirtual int stop();\n \n+\tvoid addStream(libcamera::Stream *const stream)\n+\t{\n+\t\tstreams_.push_back(stream);\n+\t}\n+\n+\tbool assignedStream(const libcamera::Stream *const stream)\n+\t{\n+\t\treturn std::find(streams_.begin(), streams_.end(), stream) != streams_.end();\n+\t}\n+\n+\tbool empty()\n+\t{\n+\t\treturn streams_.empty();\n+\t}\n+\n \tvirtual bool processRequest(libcamera::Request *request) = 0;\n \tlibcamera::Signal<libcamera::Request *> requestProcessed;\n+\n+protected:\n+\tconst libcamera::StreamConfiguration &findConfiguration(\n+\t\tconst libcamera::CameraConfiguration &config);\n+\n+\tstd::vector<libcamera::Stream *> streams_;\n };\ndiff --git a/src/apps/cam/kms_sink.cpp b/src/apps/cam/kms_sink.cpp\nindex 6490a5c0..1fc559ed 100644\n--- a/src/apps/cam/kms_sink.cpp\n+++ b/src/apps/cam/kms_sink.cpp\n@@ -110,7 +110,7 @@ int KMSSink::configure(const libcamera::CameraConfiguration &config)\n \tplane_ = nullptr;\n \tmode_ = nullptr;\n \n-\tconst libcamera::StreamConfiguration &cfg = config.at(0);\n+\tconst libcamera::StreamConfiguration &cfg = findConfiguration(config);\n \n \t/* Find the best mode for the stream size. */\n \tconst std::vector<DRM::Mode> &modes = connector_->modes();\n@@ -456,6 +456,12 @@ bool KMSSink::processRequest(libcamera::Request *camRequest)\n \t\treturn true;\n \n \tlibcamera::FrameBuffer *buffer = camRequest->buffers().begin()->second;\n+\tfor (auto [stream, buf] : camRequest->buffers()) {\n+\t\tif (assignedStream(stream)) {\n+\t\t\tbuffer = buf;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n \tauto iter = buffers_.find(buffer);\n \tif (iter == buffers_.end())\n \t\treturn true;\ndiff --git a/src/apps/cam/sdl_sink.cpp b/src/apps/cam/sdl_sink.cpp\nindex e8a54f7a..8a7df372 100644\n--- a/src/apps/cam/sdl_sink.cpp\n+++ b/src/apps/cam/sdl_sink.cpp\n@@ -44,18 +44,17 @@ int SDLSink::configure(const libcamera::CameraConfiguration &config)\n \tif (ret < 0)\n \t\treturn ret;\n \n-\tif (config.size() > 1) {\n+\tif (streams_.size() > 1) {\n \t\tstd::cerr\n-\t\t\t<< \"SDL sink only supports one camera stream at present, streaming first camera stream\"\n+\t\t\t<< \"SDL sink only supports one camera stream at present, streaming first stream\"\n \t\t\t<< std::endl;\n-\t} else if (config.empty()) {\n+\t} else if (streams_.empty()) {\n \t\tstd::cerr << \"Require at least one camera stream to process\"\n \t\t\t << std::endl;\n \t\treturn -EINVAL;\n \t}\n \n-\tconst libcamera::StreamConfiguration &cfg = config.at(0);\n-\trect_.w = cfg.size.width;\n+\tconst libcamera::StreamConfiguration &cfg = findConfiguration(config);\n \trect_.h = cfg.size.height;\n \n \tswitch (cfg.pixelFormat) {\n@@ -163,8 +162,10 @@ void SDLSink::mapBuffer(FrameBuffer *buffer)\n bool SDLSink::processRequest(Request *request)\n {\n \tfor (auto [stream, buffer] : request->buffers()) {\n-\t\trenderBuffer(buffer);\n-\t\tbreak; /* to be expanded to launch SDL window per buffer */\n+\t\tif (assignedStream(stream)) {\n+\t\t\trenderBuffer(buffer);\n+\t\t\tbreak; /* to be expanded to launch SDL window per buffer */\n+\t\t}\n \t}\n \n \treturn true;\n", "prefixes": [ "RFC", "6/7" ] }