From patchwork Fri Mar 14 20:29:34 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 22966 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 40460C32F7 for ; Fri, 14 Mar 2025 20:30:20 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5FFE968955; Fri, 14 Mar 2025 21:30:19 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="PpelEAWJ"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id EA94368950 for ; Fri, 14 Mar 2025 21:30:12 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1741984212; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=9fwSjLBWr1oMZz3V0RPmlAXDkKTDuWUYQerCdEJ/8TE=; b=PpelEAWJa7BONBBKmgkM9ltEm7iWPLerDuzSnIjSKUO5oJYKUDoRWr80Aw2OBieL4mloOY g3vTII8g2rB7A8wo0ZX8wAdZgprI2dpzNrLWlyf8+gnZyCa5p7gTyIClfP741yNV6RDQd7 oFukH/VJBfjPh7vy7lZ3UOKLacyuONY= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-34-A9Oi_dspMUG95FoA1n3thQ-1; Fri, 14 Mar 2025 16:30:10 -0400 X-MC-Unique: A9Oi_dspMUG95FoA1n3thQ-1 X-Mimecast-MFC-AGG-ID: A9Oi_dspMUG95FoA1n3thQ_1741984209 Received: from mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.40]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 82C21180025E; Fri, 14 Mar 2025 20:30:09 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.32.19]) by mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 07CB01954B32; Fri, 14 Mar 2025 20:30:07 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Laurent Pinchart 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-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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" In order to support different sinks for different streams, we must track the relationship between sinks and streams. Let's track the corresponding streams in FrameSink. Different kinds of sinks use different approaches to multiple streams; keeping the sinks to handle that this way is the simplest. Let's add FrameSink class member and some utility methods for the purpose. We still create only one, the default, sink, so all the streams are added to the default sink unconditionally. This will be changed in a followup patch. Operations on each given sink are applied only for streams the sink contains. Signed-off-by: Milan Zamazal --- src/apps/cam/camera_session.cpp | 9 ++++++++- src/apps/cam/file_sink.cpp | 3 ++- src/apps/cam/frame_sink.cpp | 14 ++++++++++++++ src/apps/cam/frame_sink.h | 26 ++++++++++++++++++++++++++ src/apps/cam/kms_sink.cpp | 8 +++++++- src/apps/cam/sdl_sink.cpp | 15 ++++++++------- 6 files changed, 65 insertions(+), 10 deletions(-) diff --git a/src/apps/cam/camera_session.cpp b/src/apps/cam/camera_session.cpp index b1f5209d..5124029b 100644 --- a/src/apps/cam/camera_session.cpp +++ b/src/apps/cam/camera_session.cpp @@ -292,6 +292,12 @@ int CameraSession::start() defaultSink = std::move(sink); } + for (unsigned int i = 0; i < config_->size(); i++) { + const StreamConfiguration &cfg = config_->at(i); + if (defaultSink) + defaultSink->addStream(cfg.stream()); + } + if (defaultSink) sinks_.push_back(std::move(defaultSink)); @@ -374,7 +380,8 @@ int CameraSession::startCapture() } for (auto &sink : sinks_) - sink->mapBuffer(buffer.get()); + if (sink->assignedStream(stream)) + sink->mapBuffer(buffer.get()); } requests_.push_back(std::move(request)); diff --git a/src/apps/cam/file_sink.cpp b/src/apps/cam/file_sink.cpp index 76e21db9..9ef4011b 100644 --- a/src/apps/cam/file_sink.cpp +++ b/src/apps/cam/file_sink.cpp @@ -96,7 +96,8 @@ void FileSink::mapBuffer(FrameBuffer *buffer) bool FileSink::processRequest(Request *request) { for (auto [stream, buffer] : request->buffers()) - writeBuffer(stream, buffer, request->metadata()); + if (assignedStream(stream)) + writeBuffer(stream, buffer, request->metadata()); return true; } diff --git a/src/apps/cam/frame_sink.cpp b/src/apps/cam/frame_sink.cpp index 68d6f2c1..51c85124 100644 --- a/src/apps/cam/frame_sink.cpp +++ b/src/apps/cam/frame_sink.cpp @@ -7,6 +7,8 @@ #include "frame_sink.h" +#include + /** * \class FrameSink * \brief Abstract class to model a consumer of frames @@ -65,3 +67,15 @@ int FrameSink::stop() * \return True if the request has been processed synchronously, false if * processing has been queued */ + +const libcamera::StreamConfiguration &FrameSink::findConfiguration( + const libcamera::CameraConfiguration &config) +{ + for (unsigned int i = 0; i < config.size(); i++) + if (assignedStream(config.at(i).stream())) + return config.at(i); + + /* This should never happen. */ + std::cerr << "No camera configuration for frame sink" << std::endl; + return config.at(0); +} diff --git a/src/apps/cam/frame_sink.h b/src/apps/cam/frame_sink.h index 11105c6c..c51db775 100644 --- a/src/apps/cam/frame_sink.h +++ b/src/apps/cam/frame_sink.h @@ -7,8 +7,13 @@ #pragma once +#include + #include +#include +#include + namespace libcamera { class CameraConfiguration; class FrameBuffer; @@ -27,6 +32,27 @@ public: virtual int start(); virtual int stop(); + void addStream(libcamera::Stream *const stream) + { + streams_.push_back(stream); + } + + bool assignedStream(const libcamera::Stream *const stream) + { + return std::find(streams_.begin(), streams_.end(), stream) != streams_.end(); + } + + bool empty() + { + return streams_.empty(); + } + virtual bool processRequest(libcamera::Request *request) = 0; libcamera::Signal requestProcessed; + +protected: + const libcamera::StreamConfiguration &findConfiguration( + const libcamera::CameraConfiguration &config); + + std::vector streams_; }; diff --git a/src/apps/cam/kms_sink.cpp b/src/apps/cam/kms_sink.cpp index 6490a5c0..1fc559ed 100644 --- a/src/apps/cam/kms_sink.cpp +++ b/src/apps/cam/kms_sink.cpp @@ -110,7 +110,7 @@ int KMSSink::configure(const libcamera::CameraConfiguration &config) plane_ = nullptr; mode_ = nullptr; - const libcamera::StreamConfiguration &cfg = config.at(0); + const libcamera::StreamConfiguration &cfg = findConfiguration(config); /* Find the best mode for the stream size. */ const std::vector &modes = connector_->modes(); @@ -456,6 +456,12 @@ bool KMSSink::processRequest(libcamera::Request *camRequest) return true; libcamera::FrameBuffer *buffer = camRequest->buffers().begin()->second; + for (auto [stream, buf] : camRequest->buffers()) { + if (assignedStream(stream)) { + buffer = buf; + break; + } + } auto iter = buffers_.find(buffer); if (iter == buffers_.end()) return true; diff --git a/src/apps/cam/sdl_sink.cpp b/src/apps/cam/sdl_sink.cpp index e8a54f7a..8a7df372 100644 --- a/src/apps/cam/sdl_sink.cpp +++ b/src/apps/cam/sdl_sink.cpp @@ -44,18 +44,17 @@ int SDLSink::configure(const libcamera::CameraConfiguration &config) if (ret < 0) return ret; - if (config.size() > 1) { + if (streams_.size() > 1) { std::cerr - << "SDL sink only supports one camera stream at present, streaming first camera stream" + << "SDL sink only supports one camera stream at present, streaming first stream" << std::endl; - } else if (config.empty()) { + } else if (streams_.empty()) { std::cerr << "Require at least one camera stream to process" << std::endl; return -EINVAL; } - const libcamera::StreamConfiguration &cfg = config.at(0); - rect_.w = cfg.size.width; + const libcamera::StreamConfiguration &cfg = findConfiguration(config); rect_.h = cfg.size.height; switch (cfg.pixelFormat) { @@ -163,8 +162,10 @@ void SDLSink::mapBuffer(FrameBuffer *buffer) bool SDLSink::processRequest(Request *request) { for (auto [stream, buffer] : request->buffers()) { - renderBuffer(buffer); - break; /* to be expanded to launch SDL window per buffer */ + if (assignedStream(stream)) { + renderBuffer(buffer); + break; /* to be expanded to launch SDL window per buffer */ + } } return true;