From patchwork Wed Mar 20 16:30:25 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 747 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 98D6461111 for ; Wed, 20 Mar 2019 17:30:28 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id E907C20001C; Wed, 20 Mar 2019 16:30:27 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:25 +0100 Message-Id: <20190320163055.22056-2-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 01/31] libcamera: formats: Add toString() methods 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: Wed, 20 Mar 2019 16:30:29 -0000 Add toString() helpers to pretty print out a V4L2Device or V4L2Subdevice format. Reviewed-by: Kieran Bingham Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/libcamera/include/v4l2_device.h | 2 ++ src/libcamera/include/v4l2_subdevice.h | 2 ++ src/libcamera/v4l2_device.cpp | 18 ++++++++++++++++++ src/libcamera/v4l2_subdevice.cpp | 18 ++++++++++++++++++ 4 files changed, 40 insertions(+) diff --git a/src/libcamera/include/v4l2_device.h b/src/libcamera/include/v4l2_device.h index 5c379fac66dc..258deee8d461 100644 --- a/src/libcamera/include/v4l2_device.h +++ b/src/libcamera/include/v4l2_device.h @@ -100,6 +100,8 @@ public: uint32_t bpl; } planes[3]; unsigned int planesCount; + + const std::string toString() const; }; class V4L2Device : protected Loggable diff --git a/src/libcamera/include/v4l2_subdevice.h b/src/libcamera/include/v4l2_subdevice.h index 1cc0fab73103..700e66bcddac 100644 --- a/src/libcamera/include/v4l2_subdevice.h +++ b/src/libcamera/include/v4l2_subdevice.h @@ -21,6 +21,8 @@ struct V4L2SubdeviceFormat { uint32_t mbus_code; uint32_t width; uint32_t height; + + const std::string toString() const; }; class V4L2Subdevice : protected Loggable diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp index 889c63b3fb63..97dc05288806 100644 --- a/src/libcamera/v4l2_device.cpp +++ b/src/libcamera/v4l2_device.cpp @@ -6,6 +6,8 @@ */ #include +#include +#include #include #include #include @@ -223,6 +225,22 @@ LOG_DEFINE_CATEGORY(V4L2) * \brief The number of valid data planes */ +/** + * \brief Assemble and return a string describing the format + * + * \return A string describing the V4L2DeviceFormat + */ +const std::string V4L2DeviceFormat::toString() const +{ + std::stringstream ss; + + ss.fill(0); + ss << width << "x" << height << "- 0x" << std::hex + << std::setw(8) << fourcc; + + return ss.str(); +} + /** * \class V4L2Device * \brief V4L2Device object and API diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index 5f58904bf9e6..11d22da25728 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -6,6 +6,8 @@ */ #include +#include +#include #include #include #include @@ -69,6 +71,22 @@ LOG_DEFINE_CATEGORY(V4L2Subdev) * \brief The image height in pixels */ +/** + * \brief Assemble and return a string describing the format + * + * \return A string describing the V4L2SubdeviceFormat + */ +const std::string V4L2SubdeviceFormat::toString() const +{ + std::stringstream ss; + + ss.fill(0); + ss << width << "x" << height << "- 0x" << std::hex + << std::setw(4) << mbus_code; + + return ss.str(); +} + /** * \class V4L2Subdevice * \brief A V4L2 subdevice as exposed by the Linux kernel From patchwork Wed Mar 20 16:30:26 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 748 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 718876110D for ; Wed, 20 Mar 2019 17:30:29 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id C55C920000D; Wed, 20 Mar 2019 16:30:28 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:26 +0100 Message-Id: <20190320163055.22056-3-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 02/31] libcamera: formats: Define FormatEnum type 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: Wed, 20 Mar 2019 16:30:30 -0000 Add an internal format.h and format.cpp files to collect libcamera image format related types, helpers and structures. Define and document the FormatEnum type, used to enumerate pixel image formats and associated image resolutions. Reviewed-by: Kieran Bingham Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/libcamera/formats.cpp | 27 ++++++++++++++++++++++++++ src/libcamera/include/formats.h | 22 +++++++++++++++++++++ src/libcamera/include/v4l2_subdevice.h | 4 ++-- src/libcamera/meson.build | 1 + src/libcamera/v4l2_subdevice.cpp | 5 ++--- 5 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 src/libcamera/formats.cpp create mode 100644 src/libcamera/include/formats.h diff --git a/src/libcamera/formats.cpp b/src/libcamera/formats.cpp new file mode 100644 index 000000000000..a6251fe91cec --- /dev/null +++ b/src/libcamera/formats.cpp @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * formats.cpp - Libcamera image formats + */ + +#include "formats.h" + +/** + * \file formats.h + * \brief Types and helper methods to handle libcamera image formats + */ + +namespace libcamera { + +/** + * \typedef FormatEnum + * \brief Type definition for the map of image formats and sizes + * + * Type definition used to enumerate the supported pixel formats and image frame + * sizes. The type associates in a map a pixel code, used to represent memory or + * wire image formats, to a vector of image resolutions represented by SizeRange + * items. + */ + +} /* namespace libcamera */ diff --git a/src/libcamera/include/formats.h b/src/libcamera/include/formats.h new file mode 100644 index 000000000000..5fcfb11318e7 --- /dev/null +++ b/src/libcamera/include/formats.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * formats.h - Libcamera image formats + */ + +#ifndef __LIBCAMERA_FORMATS_H__ +#define __LIBCAMERA_FORMATS_H__ + +#include +#include + +#include "geometry.h" + +namespace libcamera { + +typedef std::map> FormatEnum; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_FORMATS_H__ */ diff --git a/src/libcamera/include/v4l2_subdevice.h b/src/libcamera/include/v4l2_subdevice.h index 700e66bcddac..3ecf08514898 100644 --- a/src/libcamera/include/v4l2_subdevice.h +++ b/src/libcamera/include/v4l2_subdevice.h @@ -11,6 +11,7 @@ #include #include +#include "formats.h" #include "geometry.h" #include "log.h" #include "media_object.h" @@ -42,8 +43,7 @@ public: int setCrop(unsigned int pad, Rectangle *rect); int setCompose(unsigned int pad, Rectangle *rect); - const std::map> - formats(unsigned int pad); + FormatEnum formats(unsigned int pad); int getFormat(unsigned int pad, V4L2SubdeviceFormat *format); int setFormat(unsigned int pad, V4L2SubdeviceFormat *format); diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 8384cd0af451..4433abfceca3 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -6,6 +6,7 @@ libcamera_sources = files([ 'event_dispatcher.cpp', 'event_dispatcher_poll.cpp', 'event_notifier.cpp', + 'formats.cpp', 'geometry.cpp', 'log.cpp', 'media_device.cpp', diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index 11d22da25728..7084f28c0be8 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -210,10 +210,9 @@ int V4L2Subdevice::setCompose(unsigned int pad, Rectangle *rect) * \return A map of image formats associated with a list of image sizes, or * an empty map on error or if the pad does not exist */ -const std::map> -V4L2Subdevice::formats(unsigned int pad) +FormatEnum V4L2Subdevice::formats(unsigned int pad) { - std::map> formatMap = {}; + FormatEnum formatMap = {}; struct v4l2_subdev_mbus_code_enum mbusEnum = {}; int ret; From patchwork Wed Mar 20 16:30:27 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 749 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 00CAA61111 for ; Wed, 20 Mar 2019 17:30:29 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 933DF20000F; Wed, 20 Mar 2019 16:30:29 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:27 +0100 Message-Id: <20190320163055.22056-4-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 03/31] libcamera: ipu3: Make sure sensor provides a compatible format 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: Wed, 20 Mar 2019 16:30:30 -0000 When creating a camera, make sure a the image sensor provides images in a format compatible with IPU3 CIO2 unit requirements. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/libcamera/pipeline/ipu3/ipu3.cpp | 43 ++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 55489c31df2d..2602f89617a3 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include #include #include @@ -78,6 +80,8 @@ private: PipelineHandler::cameraData(camera)); } + int mediaBusToCIO2Format(unsigned int code); + void registerCameras(); std::shared_ptr cio2_; @@ -327,6 +331,22 @@ bool PipelineHandlerIPU3::match(DeviceEnumerator *enumerator) return true; } +int PipelineHandlerIPU3::mediaBusToCIO2Format(unsigned int code) +{ + switch (code) { + case MEDIA_BUS_FMT_SBGGR10_1X10: + return V4L2_PIX_FMT_IPU3_SBGGR10; + case MEDIA_BUS_FMT_SGBRG10_1X10: + return V4L2_PIX_FMT_IPU3_SGBRG10; + case MEDIA_BUS_FMT_SGRBG10_1X10: + return V4L2_PIX_FMT_IPU3_SGRBG10; + case MEDIA_BUS_FMT_SRGGB10_1X10: + return V4L2_PIX_FMT_IPU3_SRGGB10; + default: + return -EINVAL; + } +} + /* * Cameras are created associating an image sensor (represented by a * media entity with function MEDIA_ENT_F_CAM_SENSOR) to one of the four @@ -404,18 +424,37 @@ void PipelineHandlerIPU3::registerCameras() if (ret) continue; - data->cio2_->bufferReady.connect(data.get(), &IPU3CameraData::bufferReady); - + /* + * Make sure the sensor produces at least one image format + * compatible with IPU3 CIO2 requirements. + */ data->sensor_ = new V4L2Subdevice(sensor); ret = data->sensor_->open(); if (ret) continue; + const FormatEnum formats = data->sensor_->formats(0); + auto it = formats.begin(); + for (; it != formats.end(); ++it) { + if (mediaBusToCIO2Format(it->first) != -EINVAL) + break; + } + if (it == formats.end()) { + LOG(IPU3, Info) + << "Sensor '" << data->sensor_->deviceName() + << "' detected, but no supported image format " + << " found: skip camera creation"; + continue; + } + data->csi2_ = new V4L2Subdevice(csi2); ret = data->csi2_->open(); if (ret) continue; + data->cio2_->bufferReady.connect(data.get(), + &IPU3CameraData::bufferReady); + registerCamera(std::move(camera), std::move(data)); LOG(IPU3, Info) From patchwork Wed Mar 20 16:30:28 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 750 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 935746110E for ; Wed, 20 Mar 2019 17:30:30 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 2F0EB200009; Wed, 20 Mar 2019 16:30:30 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:28 +0100 Message-Id: <20190320163055.22056-5-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 04/31] libcamera: ipu3: Set stream configuration from sensor 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: Wed, 20 Mar 2019 16:30:30 -0000 Inspect all image sizes provided by the sensor and select the biggest of them, associated with an image format code supported by the CIO2 unit. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 47 +++++++++++++++++++--------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 2602f89617a3..1df074553fd1 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -5,6 +5,7 @@ * ipu3.cpp - Pipeline handler for Intel IPU3 */ +#include #include #include @@ -74,6 +75,8 @@ private: Stream stream_; }; + static constexpr unsigned int IPU3_BUFFER_COUNT = 4; + IPU3CameraData *cameraData(const Camera *camera) { return static_cast( @@ -106,26 +109,40 @@ std::map PipelineHandlerIPU3::streamConfiguration(Camera *camera, std::set &streams) { - IPU3CameraData *data = cameraData(camera); std::map configs; - V4L2SubdeviceFormat format = {}; + IPU3CameraData *data = cameraData(camera); + V4L2Subdevice *sensor = data->sensor_; + StreamConfiguration *config = &configs[&data->stream_]; + unsigned int bestSize = 0; - /* - * FIXME: As of now, return the image format reported by the sensor. - * In future good defaults should be provided for each stream. - */ - if (data->sensor_->getFormat(0, &format)) { - LOG(IPU3, Error) << "Failed to create stream configurations"; - return configs; + const FormatEnum formats = sensor->formats(0); + for (auto it = formats.begin(); it != formats.end(); ++it) { + int cio2Code = mediaBusToCIO2Format(it->first); + if (cio2Code == -EINVAL) + continue; + + for (const SizeRange &range : it->second) { + unsigned int frameSize = range.maxWidth + * range.maxHeight; + + /* Use the largest image size the sensor provides. */ + if (frameSize < bestSize) + continue; + + bestSize = frameSize; + + config->width = range.maxWidth; + config->height = range.maxHeight; + config->pixelFormat = cio2Code; + } } - StreamConfiguration config = {}; - config.width = format.width; - config.height = format.height; - config.pixelFormat = V4L2_PIX_FMT_IPU3_SGRBG10; - config.bufferCount = 4; + config->bufferCount = IPU3_BUFFER_COUNT; - configs[&data->stream_] = config; + LOG(IPU3, Debug) + << "Stream format set to: " << config->width << "x" + << config->height << "- 0x" << std::hex << std::setfill('0') + << std::setw(4) << config->pixelFormat; return configs; } From patchwork Wed Mar 20 16:30:29 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 751 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3F8C7600FC for ; Wed, 20 Mar 2019 17:30:31 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id BA27C200008; Wed, 20 Mar 2019 16:30:30 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:29 +0100 Message-Id: <20190320163055.22056-6-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 05/31] libcamera: ipu3: Initialize and configure CIO2 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: Wed, 20 Mar 2019 16:30:32 -0000 Group CIO2 devices (cio2, csi2 and image sensor) in a structure associated with the CameraData, to ease management and initialize it at camera registration time, as a CIO2 unit will always be associated with a Camera only. While at there update the IPU3 pipeline handler implementation to avoid name clashes. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 301 +++++++++++++++------------ 1 file changed, 172 insertions(+), 129 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 1df074553fd1..2e351d04a784 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -27,6 +27,24 @@ namespace libcamera { LOG_DEFINE_CATEGORY(IPU3) +struct CIO2Device { + CIO2Device() + : output(nullptr), csi2(nullptr), sensor(nullptr) + { + } + + ~CIO2Device() + { + delete output; + delete csi2; + delete sensor; + } + + V4L2Device *output; + V4L2Subdevice *csi2; + V4L2Subdevice *sensor; +}; + class PipelineHandlerIPU3 : public PipelineHandler { public: @@ -50,33 +68,23 @@ public: bool match(DeviceEnumerator *enumerator); private: + static constexpr unsigned int IPU3_BUFFER_COUNT = 4; + class IPU3CameraData : public CameraData { public: IPU3CameraData(PipelineHandler *pipe) - : CameraData(pipe), cio2_(nullptr), csi2_(nullptr), - sensor_(nullptr) - { - } - - ~IPU3CameraData() + : CameraData(pipe) { - delete cio2_; - delete csi2_; - delete sensor_; } void bufferReady(Buffer *buffer); - V4L2Device *cio2_; - V4L2Subdevice *csi2_; - V4L2Subdevice *sensor_; + CIO2Device cio2; Stream stream_; }; - static constexpr unsigned int IPU3_BUFFER_COUNT = 4; - IPU3CameraData *cameraData(const Camera *camera) { return static_cast( @@ -85,24 +93,25 @@ private: int mediaBusToCIO2Format(unsigned int code); + int initCIO2(unsigned int index, CIO2Device *cio2); void registerCameras(); - std::shared_ptr cio2_; - std::shared_ptr imgu_; + std::shared_ptr cio2MediaDev_; + std::shared_ptr imguMediaDev_; }; PipelineHandlerIPU3::PipelineHandlerIPU3(CameraManager *manager) - : PipelineHandler(manager), cio2_(nullptr), imgu_(nullptr) + : PipelineHandler(manager), cio2MediaDev_(nullptr), imguMediaDev_(nullptr) { } PipelineHandlerIPU3::~PipelineHandlerIPU3() { - if (cio2_) - cio2_->release(); + if (cio2MediaDev_) + cio2MediaDev_->release(); - if (imgu_) - imgu_->release(); + if (imguMediaDev_) + imguMediaDev_->release(); } std::map @@ -111,7 +120,7 @@ PipelineHandlerIPU3::streamConfiguration(Camera *camera, { std::map configs; IPU3CameraData *data = cameraData(camera); - V4L2Subdevice *sensor = data->sensor_; + V4L2Subdevice *sensor = data->cio2.sensor; StreamConfiguration *config = &configs[&data->stream_]; unsigned int bestSize = 0; @@ -152,9 +161,9 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, { IPU3CameraData *data = cameraData(camera); StreamConfiguration *cfg = &config[&data->stream_]; - V4L2Subdevice *sensor = data->sensor_; - V4L2Subdevice *csi2 = data->csi2_; - V4L2Device *cio2 = data->cio2_; + V4L2Subdevice *sensor = data->cio2.sensor; + V4L2Subdevice *csi2 = data->cio2.csi2; + V4L2Device *cio2 = data->cio2.output; V4L2SubdeviceFormat subdevFormat = {}; V4L2DeviceFormat devFormat = {}; int ret; @@ -211,13 +220,14 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, int PipelineHandlerIPU3::allocateBuffers(Camera *camera, Stream *stream) { - IPU3CameraData *data = cameraData(camera); const StreamConfiguration &cfg = stream->configuration(); + IPU3CameraData *data = cameraData(camera); + V4L2Device *cio2 = data->cio2.output; if (!cfg.bufferCount) return -EINVAL; - int ret = data->cio2_->exportBuffers(&stream->bufferPool()); + int ret = cio2->exportBuffers(&stream->bufferPool()); if (ret) { LOG(IPU3, Error) << "Failed to request memory"; return ret; @@ -229,8 +239,9 @@ int PipelineHandlerIPU3::allocateBuffers(Camera *camera, Stream *stream) int PipelineHandlerIPU3::freeBuffers(Camera *camera, Stream *stream) { IPU3CameraData *data = cameraData(camera); + V4L2Device *cio2 = data->cio2.output; - int ret = data->cio2_->releaseBuffers(); + int ret = cio2->releaseBuffers(); if (ret) { LOG(IPU3, Error) << "Failed to release memory"; return ret; @@ -242,9 +253,10 @@ int PipelineHandlerIPU3::freeBuffers(Camera *camera, Stream *stream) int PipelineHandlerIPU3::start(Camera *camera) { IPU3CameraData *data = cameraData(camera); + V4L2Device *cio2 = data->cio2.output; int ret; - ret = data->cio2_->streamOn(); + ret = cio2->streamOn(); if (ret) { LOG(IPU3, Info) << "Failed to start camera " << camera->name(); return ret; @@ -256,8 +268,9 @@ int PipelineHandlerIPU3::start(Camera *camera) void PipelineHandlerIPU3::stop(Camera *camera) { IPU3CameraData *data = cameraData(camera); + V4L2Device *cio2 = data->cio2.output; - if (data->cio2_->streamOff()) + if (cio2->streamOff()) LOG(IPU3, Info) << "Failed to stop camera " << camera->name(); PipelineHandler::stop(camera); @@ -266,6 +279,7 @@ void PipelineHandlerIPU3::stop(Camera *camera) int PipelineHandlerIPU3::queueRequest(Camera *camera, Request *request) { IPU3CameraData *data = cameraData(camera); + V4L2Device *cio2 = data->cio2.output; Stream *stream = &data->stream_; Buffer *buffer = request->findBuffer(stream); @@ -275,7 +289,7 @@ int PipelineHandlerIPU3::queueRequest(Camera *camera, Request *request) return -ENOENT; } - int ret = data->cio2_->queueBuffer(buffer); + int ret = cio2->queueBuffer(buffer); if (ret < 0) return ret; @@ -314,17 +328,17 @@ bool PipelineHandlerIPU3::match(DeviceEnumerator *enumerator) * It is safe to acquire both media devices at this point as * DeviceEnumerator::search() skips the busy ones for us. */ - cio2_ = enumerator->search(cio2_dm); - if (!cio2_) + cio2MediaDev_ = enumerator->search(cio2_dm); + if (!cio2MediaDev_) return false; - cio2_->acquire(); + cio2MediaDev_->acquire(); - imgu_ = enumerator->search(imgu_dm); - if (!imgu_) + imguMediaDev_ = enumerator->search(imgu_dm); + if (!imguMediaDev_) return false; - imgu_->acquire(); + imguMediaDev_->acquire(); /* * Disable all links that are enabled by default on CIO2, as camera @@ -333,17 +347,17 @@ bool PipelineHandlerIPU3::match(DeviceEnumerator *enumerator) * Close the CIO2 media device after, as links are enabled and should * not need to be changed after. */ - if (cio2_->open()) + if (cio2MediaDev_->open()) return false; - if (cio2_->disableLinks()) { - cio2_->close(); + if (cio2MediaDev_->disableLinks()) { + cio2MediaDev_->close(); return false; } registerCameras(); - cio2_->close(); + cio2MediaDev_->close(); return true; } @@ -364,6 +378,111 @@ int PipelineHandlerIPU3::mediaBusToCIO2Format(unsigned int code) } } +/** + * \brief Initialize components of the CIO2 device \a index used by a camera + * \param index The CIO2 device index + * \param cio2 Pointer to the CIO2 instance + * + * Create and open the device and subdevices in the CIO2 instance at \a index, + * if an image sensor is connected to the CSI-2 receiver of this CIO2 instance. + * Enable the media links connecting the CIO2 components to prepare for capture + * operations. + * + * \return 0 on success or a negative error code otherwise + * \retval -EINVAL Failure to create or open a video device or subdevice + * \retval -ENODEV No image sensor is connected to this CIO2 instance + */ +int PipelineHandlerIPU3::initCIO2(unsigned int index, CIO2Device *cio2) +{ + std::string cio2Name = "ipu3-cio2 " + std::to_string(index); + std::string csi2Name = "ipu3-csi2 " + std::to_string(index); + int ret; + + /* Verify a sensor subdevice is connected to this CIO2 instance. */ + MediaEntity *entity = cio2MediaDev_->getEntityByName(csi2Name); + if (!entity) { + LOG(IPU3, Error) + << "Failed to get entity '" << csi2Name << "'"; + return -EINVAL; + } + + const std::vector &pads = entity->pads(); + if (pads.empty()) + return -EINVAL; + + /* IPU3 CSI-2 receivers have a single sink pad at index 0. */ + MediaPad *sink = pads[0]; + const std::vector &links = sink->links(); + if (links.empty()) + return -EINVAL; + + MediaLink *link = links[0]; + MediaEntity *sensorEntity = link->source()->entity(); + if (sensorEntity->function() != MEDIA_ENT_F_CAM_SENSOR) + return -ENODEV; + + ret = link->setEnabled(true); + if (ret) + return ret; + + /* + * Now that we're sure a sensor subdevice is connected, make sure it + * produces at least one image format compatible with CIO2 requirements. + * + * \todo Define when to open and close video device nodes, as they + * might impact on power consumption. + */ + cio2->sensor = new V4L2Subdevice(sensorEntity); + ret = cio2->sensor->open(); + if (ret) { + delete cio2->sensor; + + return ret; + } + + const FormatEnum formats = cio2->sensor->formats(0); + auto it = formats.begin(); + for (; it != formats.end(); ++it) { + if (mediaBusToCIO2Format(it->first) != -EINVAL) + break; + } + if (it == formats.end()) { + LOG(IPU3, Info) << "Sensor '" << cio2->sensor->deviceName() + << "' detected, but no supported image format " + << " found: skip camera creation"; + goto error_delete_sensor; + } + + cio2->csi2 = new V4L2Subdevice(entity); + ret = cio2->csi2->open(); + if (ret) + goto error_delete_csi2; + + entity = cio2MediaDev_->getEntityByName(cio2Name); + if (!entity) { + LOG(IPU3, Error) + << "Failed to get entity '" << cio2Name << "'"; + ret = -EINVAL; + goto error_delete_csi2; + } + + cio2->output = new V4L2Device(entity); + ret = cio2->output->open(); + if (ret) + goto error_delete_output; + + return 0; + +error_delete_output: + delete cio2->output; +error_delete_csi2: + delete cio2->csi2; +error_delete_sensor: + delete cio2->sensor; + + return ret; +} + /* * Cameras are created associating an image sensor (represented by a * media entity with function MEDIA_ENT_F_CAM_SENSOR) to one of the four @@ -377,100 +496,24 @@ void PipelineHandlerIPU3::registerCameras() */ unsigned int numCameras = 0; for (unsigned int id = 0; id < 4; ++id) { - std::string csi2Name = "ipu3-csi2 " + std::to_string(id); - MediaEntity *csi2 = cio2_->getEntityByName(csi2Name); - int ret; - - /* - * This shall not happen, as the device enumerator matched - * all entities described in the cio2_dm DeviceMatch. - * - * As this check is basically free, better stay safe than sorry. - */ - if (!csi2) - continue; - - const std::vector &pads = csi2->pads(); - if (pads.empty()) - continue; - - /* IPU3 CSI-2 receivers have a single sink pad at index 0. */ - MediaPad *sink = pads[0]; - const std::vector &links = sink->links(); - if (links.empty()) - continue; - - /* - * Verify that the receiver is connected to a sensor, enable - * the media link between the two, and create a Camera with - * a unique name. - */ - MediaLink *link = links[0]; - MediaEntity *sensor = link->source()->entity(); - if (sensor->function() != MEDIA_ENT_F_CAM_SENSOR) - continue; - - if (link->setEnabled(true)) - continue; - - std::unique_ptr data = utils::make_unique(this); - - std::string cameraName = sensor->name() + " " + std::to_string(id); + std::unique_ptr data = + utils::make_unique(this); std::set streams{ &data->stream_ }; - std::shared_ptr camera = Camera::create(this, cameraName, streams); - - /* - * Create and open video devices and subdevices associated with - * the camera. - * - * If any of these operations fails, the Camera instance won't - * be registered. The 'camera' shared pointer and the 'data' - * unique pointers go out of scope and delete the objects they - * manage. - */ - std::string cio2Name = "ipu3-cio2 " + std::to_string(id); - MediaEntity *cio2 = cio2_->getEntityByName(cio2Name); - if (!cio2) { - LOG(IPU3, Error) - << "Failed to get entity '" << cio2Name << "'"; - continue; - } - - data->cio2_ = new V4L2Device(cio2); - ret = data->cio2_->open(); - if (ret) - continue; + CIO2Device *cio2 = &data->cio2; + int ret; - /* - * Make sure the sensor produces at least one image format - * compatible with IPU3 CIO2 requirements. - */ - data->sensor_ = new V4L2Subdevice(sensor); - ret = data->sensor_->open(); + ret = initCIO2(id, cio2); if (ret) continue; - const FormatEnum formats = data->sensor_->formats(0); - auto it = formats.begin(); - for (; it != formats.end(); ++it) { - if (mediaBusToCIO2Format(it->first) != -EINVAL) - break; - } - if (it == formats.end()) { - LOG(IPU3, Info) - << "Sensor '" << data->sensor_->deviceName() - << "' detected, but no supported image format " - << " found: skip camera creation"; - continue; - } - - data->csi2_ = new V4L2Subdevice(csi2); - ret = data->csi2_->open(); - if (ret) - continue; + std::string cameraName = cio2->sensor->deviceName() + " " + + std::to_string(id); + std::shared_ptr camera = Camera::create(this, + cameraName, + streams); - data->cio2_->bufferReady.connect(data.get(), - &IPU3CameraData::bufferReady); + cio2->output->bufferReady.connect(data.get(), + &IPU3CameraData::bufferReady); registerCamera(std::move(camera), std::move(data)); From patchwork Wed Mar 20 16:30:30 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 752 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D7A5D611B4 for ; Wed, 20 Mar 2019 17:30:31 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 69090200010; Wed, 20 Mar 2019 16:30:31 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:30 +0100 Message-Id: <20190320163055.22056-7-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 06/31] libcamera: ipu3: Initialize and configure ImgUs 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: Wed, 20 Mar 2019 16:30:32 -0000 Create video devices and subdevices associated with an ImgU unit at camera registration time. Statically assign imgu0 to the first camera and imgu1 to the second one and limit support to two camera. This will have to be revised in future. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 223 +++++++++++++++++++++++++-- 1 file changed, 209 insertions(+), 14 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 2e351d04a784..26fc56a76eb1 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -27,6 +27,38 @@ namespace libcamera { LOG_DEFINE_CATEGORY(IPU3) +class ImgUDevice +{ +public: + ImgUDevice() + : imgu(nullptr), input(nullptr), output(nullptr), + viewfinder(nullptr), stat(nullptr) + { + } + + ~ImgUDevice() + { + delete imgu; + delete input; + delete output; + delete viewfinder; + delete stat; + } + + void init(MediaDevice *media, unsigned int index); + + unsigned int index_; + std::string imguName_; + MediaDevice *mediaDevice_; + + V4L2Subdevice *imgu; + V4L2Device *input; + V4L2Device *output; + V4L2Device *viewfinder; + V4L2Device *stat; + /* \todo Add param video device for 3A tuning */ +}; + struct CIO2Device { CIO2Device() : output(nullptr), csi2(nullptr), sensor(nullptr) @@ -68,6 +100,7 @@ public: bool match(DeviceEnumerator *enumerator); private: + static constexpr unsigned int IPU3_IMGU_COUNT = 2; static constexpr unsigned int IPU3_BUFFER_COUNT = 4; class IPU3CameraData : public CameraData @@ -81,6 +114,7 @@ private: void bufferReady(Buffer *buffer); CIO2Device cio2; + ImgUDevice *imgu; Stream stream_; }; @@ -92,10 +126,18 @@ private: } int mediaBusToCIO2Format(unsigned int code); + V4L2Device *openDevice(MediaDevice *media, const std::string &name); + V4L2Subdevice *openSubdevice(MediaDevice *media, + const std::string &name); int initCIO2(unsigned int index, CIO2Device *cio2); + void deleteCIO2(CIO2Device *cio2); + + int initImgU(ImgUDevice *imgu); + void registerCameras(); + ImgUDevice imgus_[IPU3_IMGU_COUNT]; std::shared_ptr cio2MediaDev_; std::shared_ptr imguMediaDev_; }; @@ -355,11 +397,45 @@ bool PipelineHandlerIPU3::match(DeviceEnumerator *enumerator) return false; } + if (imguMediaDev_->open()) { + cio2MediaDev_->close(); + return false; + } + + if (imguMediaDev_->disableLinks()) + goto error_close_mdev; + + for (unsigned int i = 0; i < IPU3_IMGU_COUNT; ++i) + imgus_[i].init(imguMediaDev_.get(), i); + registerCameras(); cio2MediaDev_->close(); + imguMediaDev_->close(); return true; + +error_close_mdev: + cio2MediaDev_->close(); + imguMediaDev_->close(); + + return false; +} + +/* ---------------------------------------------------------------------------- + * Helpers + */ + +/** + * \brief Initialize fields of the ImgU instance + * \param mediaDevice The ImgU instance media device + * \param index The ImgU instance index + */ +void ImgUDevice::init(MediaDevice *mediaDevice, unsigned int index) +{ + index_ = index; + imguName_ = "ipu3-imgu " + std::to_string(index_); + mediaDevice_ = mediaDevice; } int PipelineHandlerIPU3::mediaBusToCIO2Format(unsigned int code) @@ -378,6 +454,114 @@ int PipelineHandlerIPU3::mediaBusToCIO2Format(unsigned int code) } } +/** + * \brief Create and open the video device with \a name in media device \a media + * + * \todo Make a generic helper out of this method. + * + * \return Pointer to the video device on success, nullptr otherwise + */ +V4L2Device *PipelineHandlerIPU3::openDevice(MediaDevice *media, + const std::string &name) +{ + MediaEntity *entity = media->getEntityByName(name); + if (!entity) { + LOG(IPU3, Error) + << "Failed to get entity '" << name << "'"; + return nullptr; + } + + V4L2Device *dev = new V4L2Device(entity); + if (dev->open()) { + delete dev; + return nullptr; + } + + return dev; +} + +/** + * \brief Create and open the subdevice with \a name in media device \a media + * + * \todo Make a generic helper out of this method. + * + * \return Pointer to the subdevice on success, nullptr otherwise + */ +V4L2Subdevice *PipelineHandlerIPU3::openSubdevice(MediaDevice *media, + const std::string &name) +{ + MediaEntity *entity = media->getEntityByName(name); + if (!entity) { + LOG(IPU3, Error) + << "Failed to get entity '" << name << "'"; + return nullptr; + } + + V4L2Subdevice *dev = new V4L2Subdevice(entity); + if (dev->open()) { + delete dev; + return nullptr; + } + + return dev; +} + +/* ---------------------------------------------------------------------------- + * IPU3 pipeline configuration + */ + +/** + * \brief Initialize and configure components of the ImgU instance + * + * Create and open the devices and subdevices in the ImgU instance. + * This methods configures the ImgU instance for capture operations, and + * should be called at stream configuration time. + * + * \todo Expand the ImgU configuration with controls setting + * + * \return 0 on success or a negative error code otherwise + * \retval -ENODEV Failed to open one of the video devices or subdevices + */ +int PipelineHandlerIPU3::initImgU(ImgUDevice *imgu) +{ + imgu->imgu = openSubdevice(imgu->mediaDevice_, imgu->imguName_); + if (!imgu->imgu) + return -ENODEV; + + imgu->input = openDevice(imgu->mediaDevice_, + imgu->imguName_ + " input"); + if (!imgu->input) + goto error_delete_imgu; + + imgu->output = openDevice(imgu->mediaDevice_, + imgu->imguName_ + " output"); + if (!imgu->output) + goto error_delete_input; + + imgu->viewfinder = openDevice(imgu->mediaDevice_, + imgu->imguName_ + " viewfinder"); + if (!imgu->viewfinder) + goto error_delete_output; + + imgu->stat = openDevice(imgu->mediaDevice_, + imgu->imguName_ + " 3a stat"); + if (!imgu->stat) + goto error_delete_vf; + + return 0; + +error_delete_vf: + delete imgu->viewfinder; +error_delete_output: + delete imgu->output; +error_delete_input: + delete imgu->input; +error_delete_imgu: + delete imgu->imgu; + + return -ENODEV; +} + /** * \brief Initialize components of the CIO2 device \a index used by a camera * \param index The CIO2 device index @@ -458,23 +642,12 @@ int PipelineHandlerIPU3::initCIO2(unsigned int index, CIO2Device *cio2) if (ret) goto error_delete_csi2; - entity = cio2MediaDev_->getEntityByName(cio2Name); - if (!entity) { - LOG(IPU3, Error) - << "Failed to get entity '" << cio2Name << "'"; - ret = -EINVAL; + cio2->output = openDevice(cio2MediaDev_.get(), cio2Name); + if (!cio2->output) goto error_delete_csi2; - } - - cio2->output = new V4L2Device(entity); - ret = cio2->output->open(); - if (ret) - goto error_delete_output; return 0; -error_delete_output: - delete cio2->output; error_delete_csi2: delete cio2->csi2; error_delete_sensor: @@ -483,6 +656,16 @@ error_delete_sensor: return ret; } +/** + * \brief Delete all devices associated with a CIO2 unit + */ +void PipelineHandlerIPU3::deleteCIO2(CIO2Device *cio2) +{ + delete cio2->output; + delete cio2->csi2; + delete cio2->sensor; +} + /* * Cameras are created associating an image sensor (represented by a * media entity with function MEDIA_ENT_F_CAM_SENSOR) to one of the four @@ -495,7 +678,7 @@ void PipelineHandlerIPU3::registerCameras() * image sensor is connected to it. */ unsigned int numCameras = 0; - for (unsigned int id = 0; id < 4; ++id) { + for (unsigned int id = 0; id < 4 && numCameras < 2; ++id) { std::unique_ptr data = utils::make_unique(this); std::set streams{ &data->stream_ }; @@ -506,6 +689,18 @@ void PipelineHandlerIPU3::registerCameras() if (ret) continue; + /** + * \todo Dynamically assign ImgU devices; as of now, limit + * support to two cameras only, and assign imgu0 to the first + * one and imgu1 to the second. + */ + data->imgu = &imgus_[numCameras]; + ret = initImgU(data->imgu); + if (ret) { + deleteCIO2(cio2); + continue; + } + std::string cameraName = cio2->sensor->deviceName() + " " + std::to_string(id); std::shared_ptr camera = Camera::create(this, From patchwork Wed Mar 20 16:30:31 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 753 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7E88C611A2 for ; Wed, 20 Mar 2019 17:30:32 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 0B992200008; Wed, 20 Mar 2019 16:30:31 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:31 +0100 Message-Id: <20190320163055.22056-8-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 07/31] libcamera: ipu3: Propagate image format 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: Wed, 20 Mar 2019 16:30:32 -0000 Apply the requested image format to the sensor device, and apply the adjusted one to the CIO2 device, the ImgU subdevice and its input and output video devices. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 220 +++++++++++++++++++++++---- 1 file changed, 189 insertions(+), 31 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 26fc56a76eb1..2975c218f6c9 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -16,6 +16,7 @@ #include #include "device_enumerator.h" +#include "geometry.h" #include "log.h" #include "media_device.h" #include "pipeline_handler.h" @@ -30,6 +31,11 @@ LOG_DEFINE_CATEGORY(IPU3) class ImgUDevice { public: + static constexpr unsigned int PAD_INPUT = 0; + static constexpr unsigned int PAD_OUTPUT = 2; + static constexpr unsigned int PAD_VF = 3; + static constexpr unsigned int PAD_STAT = 4; + ImgUDevice() : imgu(nullptr), input(nullptr), output(nullptr), viewfinder(nullptr), stat(nullptr) @@ -135,6 +141,13 @@ private: int initImgU(ImgUDevice *imgu); + int setImguFormat(ImgUDevice *imguDevice, + const StreamConfiguration &config, + Rectangle *rect); + int setCIO2Format(CIO2Device *cio2Device, + const StreamConfiguration &config, + V4L2SubdeviceFormat *format); + void registerCameras(); ImgUDevice imgus_[IPU3_IMGU_COUNT]; @@ -202,60 +215,86 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, std::map &config) { IPU3CameraData *data = cameraData(camera); - StreamConfiguration *cfg = &config[&data->stream_]; - V4L2Subdevice *sensor = data->cio2.sensor; - V4L2Subdevice *csi2 = data->cio2.csi2; + const StreamConfiguration &cfg = config[&data->stream_]; + V4L2Device *viewfinder = data->imgu->viewfinder; + V4L2Device *output = data->imgu->output; + V4L2Device *input = data->imgu->input; V4L2Device *cio2 = data->cio2.output; - V4L2SubdeviceFormat subdevFormat = {}; - V4L2DeviceFormat devFormat = {}; int ret; + LOG(IPU3, Info) + << "Requested image format: " << cfg.width << "x" + << cfg.height << " - " << std::hex << std::setw(8) + << cfg.pixelFormat << " on camera:'" << camera->name() << "'"; + /* - * FIXME: as of now, the format gets applied to the sensor and is - * propagated along the pipeline. It should instead be applied on the - * capture device and the sensor format calculated accordingly. + * Verify that the requested size respects the IPU3 alignement + * requirements: the image width shall be a multiple of 8 pixels and + * its height a multiple of 4 pixels. + * + * \todo: consider the BDS scaling factor requirements: + * "the downscaling factor must be an integer value multiple of 1/32" */ + if (cfg.width % 8 || cfg.height % 4) { + LOG(IPU3, Error) << "Stream format not support: bad alignement"; + return -EINVAL; + } - ret = sensor->getFormat(0, &subdevFormat); + /* + * Pass the requested output image size to the sensor and get back the + * adjusted one to be propagated to the CIO2 device and to the ImgU + * input. + */ + V4L2SubdeviceFormat sensorFormat = {}; + ret = setCIO2Format(&data->cio2, cfg, &sensorFormat); if (ret) return ret; - subdevFormat.width = cfg->width; - subdevFormat.height = cfg->height; - ret = sensor->setFormat(0, &subdevFormat); + /* Apply the CIO2 image format to the CIO2 output and ImgU input. */ + V4L2DeviceFormat cio2Format = {}; + cio2Format.width = sensorFormat.width; + cio2Format.height = sensorFormat.height; + cio2Format.fourcc = mediaBusToCIO2Format(sensorFormat.mbus_code); + cio2Format.planesCount = 1; + ret = cio2->setFormat(&cio2Format); if (ret) return ret; - /* Return error if the requested format cannot be applied to sensor. */ - if (subdevFormat.width != cfg->width || - subdevFormat.height != cfg->height) { - LOG(IPU3, Error) - << "Failed to apply image format " - << subdevFormat.width << "x" << subdevFormat.height - << " - got: " << cfg->width << "x" << cfg->height; - return -EINVAL; - } + LOG(IPU3, Debug) + << "CIO2 output format = " << cio2Format.toString(); - ret = csi2->setFormat(0, &subdevFormat); + ret = input->setFormat(&cio2Format); if (ret) return ret; - ret = cio2->getFormat(&devFormat); + /* Apply pad formats and crop/compose rectangle to the ImgU. */ + Rectangle rect = { + .x = 0, + .y = 0, + .w = cio2Format.width, + .h = cio2Format.height, + }; + ret = setImguFormat(data->imgu, cfg, &rect); if (ret) return ret; - devFormat.width = subdevFormat.width; - devFormat.height = subdevFormat.height; - devFormat.fourcc = cfg->pixelFormat; + /* Apply the format to the ImgU output and viewfinder devices. */ + V4L2DeviceFormat outputFormat = {}; + outputFormat.width = cfg.width; + outputFormat.height = cfg.height; + outputFormat.fourcc = V4L2_PIX_FMT_NV12; + outputFormat.planesCount = 2; - ret = cio2->setFormat(&devFormat); + ret = output->setFormat(&outputFormat); if (ret) return ret; - LOG(IPU3, Info) << cio2->driverName() << ": " - << devFormat.width << "x" << devFormat.height - << "- 0x" << std::hex << devFormat.fourcc << " planes: " - << devFormat.planes; + LOG(IPU3, Debug) + << "ImgU output format = " << outputFormat.toString(); + + ret = viewfinder->setFormat(&outputFormat); + if (ret) + return ret; return 0; } @@ -666,6 +705,125 @@ void PipelineHandlerIPU3::deleteCIO2(CIO2Device *cio2) delete cio2->sensor; } +int PipelineHandlerIPU3::setImguFormat(ImgUDevice *imguDevice, + const StreamConfiguration &config, + Rectangle *rect) +{ + V4L2Subdevice *imgu = imguDevice->imgu; + int ret; + + /* + * Configure the 'imgu' subdevice with the requested sizes. + * + * FIXME: the IPU3 driver implementation shall be changed to use the + * actual input sizes as 'imgu input' subdevice sizes, and use the + * desired output sizes to configure the crop/compose rectangles. The + * current implementation uses output sizes as 'imgu input' sizes, and + * uses the input dimension to configure the crop/compose rectangles, + * which contradicts the V4L2 specifications. + */ + ret = imgu->setCrop(ImgUDevice::PAD_INPUT, rect); + if (ret) + return ret; + + ret = imgu->setCompose(ImgUDevice::PAD_INPUT, rect); + if (ret) + return ret; + + LOG(IPU3, Debug) + << "ImgU input feeder and BDS rectangle = (0,0)/" + << rect->w << "x" << rect->h; + + V4L2SubdeviceFormat imguFormat = {}; + imguFormat.width = config.width; + imguFormat.height = config.height; + imguFormat.mbus_code = MEDIA_BUS_FMT_FIXED; + + ret = imgu->setFormat(ImgUDevice::PAD_INPUT, &imguFormat); + if (ret) + return ret; + + ret = imgu->setFormat(ImgUDevice::PAD_OUTPUT, &imguFormat); + if (ret) + return ret; + + LOG(IPU3, Debug) + << "ImgU GDC format = " << imguFormat.toString(); + + ret = imgu->setFormat(ImgUDevice::PAD_VF, &imguFormat); + if (ret) + return ret; + + ret = imgu->setFormat(ImgUDevice::PAD_STAT, &imguFormat); + if (ret) + return ret; + + return 0; +} + +int PipelineHandlerIPU3::setCIO2Format(CIO2Device *cio2Device, + const StreamConfiguration &config, + V4L2SubdeviceFormat *format) +{ + unsigned int imageSize = config.width * config.height; + V4L2Subdevice *sensor = cio2Device->sensor; + V4L2Subdevice *csi2 = cio2Device->csi2; + unsigned int best = ~0; + bool found = false; + int ret; + + const FormatEnum formats = sensor->formats(0); + for (auto it = formats.begin(); it != formats.end(); ++it) { + /* Only consider formats consumable by the CIO2 unit. */ + int cio2Code = mediaBusToCIO2Format(it->first); + if (cio2Code == -EINVAL) + continue; + + for (const SizeRange &size : it->second) { + /* + * Only select formats bigger than the requested sizes + * as the IPU3 cannot up-scale. + */ + if (size.maxWidth < config.width || + size.maxHeight < config.height) + continue; + + unsigned int diff = size.maxWidth * size.maxHeight + - imageSize; + if (diff >= best) + continue; + + best = diff; + found = true; + + format->width = size.maxWidth; + format->height = size.maxHeight; + format->mbus_code = it->first; + } + } + if (!found) { + LOG(IPU3, Error) + << "Unable to find image format suitable to produce: " + << config.width << "x" << config.height + << "- 0x" << std::hex << std::setfill('0') + << std::setw(8) << config.pixelFormat; + return -EINVAL; + } + + /* Apply the selected format to the sensor and the CSI-2 receiver. */ + ret = sensor->setFormat(0, format); + if (ret) + return ret; + + ret = csi2->setFormat(0, format); + if (ret) + return ret; + + LOG(IPU3, Debug) << "CIO2 Image format: " << format->toString(); + + return 0; +} + /* * Cameras are created associating an image sensor (represented by a * media entity with function MEDIA_ENT_F_CAM_SENSOR) to one of the four From patchwork Wed Mar 20 16:30:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 754 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1FA3F611B4 for ; Wed, 20 Mar 2019 17:30:33 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id B04D8200008; Wed, 20 Mar 2019 16:30:32 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:32 +0100 Message-Id: <20190320163055.22056-9-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 08/31] libcamera: ipu3: Implement camera start/stop 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: Wed, 20 Mar 2019 16:30:33 -0000 Start and stop video devices in the pipeline. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/libcamera/pipeline/ipu3/ipu3.cpp | 54 ++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 2975c218f6c9..994c95692dd4 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -334,12 +334,52 @@ int PipelineHandlerIPU3::freeBuffers(Camera *camera, Stream *stream) int PipelineHandlerIPU3::start(Camera *camera) { IPU3CameraData *data = cameraData(camera); - V4L2Device *cio2 = data->cio2.output; int ret; - ret = cio2->streamOn(); + /* + * Enqueue all available buffers to the CIO2 unit to start frame + * capture. Start ImgU video devices and queue buffers to the output + * ones at queueRequest() time. + */ + for (Buffer &buffer : data->cio2.pool.buffers()) { + ret = data->cio2.output->queueBuffer(&buffer); + if (ret) + return ret; + } + + ret = data->cio2.output->streamOn(); if (ret) { - LOG(IPU3, Info) << "Failed to start camera " << camera->name(); + LOG(IPU3, Error) << "Failed to start CIO2"; + stop(camera); + return ret; + } + + /* Start the ImgU video devices. */ + ret = data->imgu->output->streamOn(); + if (ret) { + LOG(IPU3, Error) << "Failed to start ImgU output"; + stop(camera); + return ret; + } + + ret = data->imgu->viewfinder->streamOn(); + if (ret) { + LOG(IPU3, Error) << "Failed to start ImgU viewfinder"; + stop(camera); + return ret; + } + + ret = data->imgu->stat->streamOn(); + if (ret) { + LOG(IPU3, Error) << "Failed to start ImgU stat"; + stop(camera); + return ret; + } + + ret = data->imgu->input->streamOn(); + if (ret) { + LOG(IPU3, Error) << "Failed to start ImgU input"; + stop(camera); return ret; } @@ -349,10 +389,12 @@ int PipelineHandlerIPU3::start(Camera *camera) void PipelineHandlerIPU3::stop(Camera *camera) { IPU3CameraData *data = cameraData(camera); - V4L2Device *cio2 = data->cio2.output; - if (cio2->streamOff()) - LOG(IPU3, Info) << "Failed to stop camera " << camera->name(); + data->cio2.output->streamOff(); + data->imgu->output->streamOff(); + data->imgu->viewfinder->streamOff(); + data->imgu->stat->streamOff(); + data->imgu->input->streamOff(); PipelineHandler::stop(camera); } From patchwork Wed Mar 20 16:30:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 755 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id CC49B611A7 for ; Wed, 20 Mar 2019 17:30:33 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 57455200008; Wed, 20 Mar 2019 16:30:33 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:33 +0100 Message-Id: <20190320163055.22056-10-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 09/31] libcamera: ipu3: Implement buffer allocation 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: Wed, 20 Mar 2019 16:30:34 -0000 Implement buffer allocation in IPU3 pipeline handlers. As the pipeline handler supports a single stream, preprare two buffer pools for 'viewfinder' and 'stat' video devices, and export the 'output' video device buffers to the Stream's pool. Share buffers between the CIO2 output and the ImgU input video devices, as the output of the former should immediately be provided to the latter for further processing. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 48 +++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 994c95692dd4..659a7ca4829f 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -63,6 +63,9 @@ public: V4L2Device *viewfinder; V4L2Device *stat; /* \todo Add param video device for 3A tuning */ + + BufferPool vfPool; + BufferPool statPool; }; struct CIO2Device { @@ -81,6 +84,8 @@ struct CIO2Device { V4L2Device *output; V4L2Subdevice *csi2; V4L2Subdevice *sensor; + + BufferPool pool; }; class PipelineHandlerIPU3 : public PipelineHandler @@ -108,6 +113,8 @@ public: private: static constexpr unsigned int IPU3_IMGU_COUNT = 2; static constexpr unsigned int IPU3_BUFFER_COUNT = 4; + static constexpr unsigned int IPU3_CIO2_BUFFER_COUNT = 4; + static constexpr unsigned int IPU3_IMGU_BUFFER_COUNT = 4; class IPU3CameraData : public CameraData { @@ -301,16 +308,47 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, int PipelineHandlerIPU3::allocateBuffers(Camera *camera, Stream *stream) { - const StreamConfiguration &cfg = stream->configuration(); IPU3CameraData *data = cameraData(camera); + V4L2Device *viewfinder = data->imgu->viewfinder; + V4L2Device *output = data->imgu->output; + V4L2Device *input = data->imgu->input; V4L2Device *cio2 = data->cio2.output; + V4L2Device *stat = data->imgu->stat; + int ret; - if (!cfg.bufferCount) - return -EINVAL; + /* Share buffers between CIO2 output and ImgU input. */ + data->cio2.pool.createBuffers(IPU3_CIO2_BUFFER_COUNT); + ret = cio2->exportBuffers(&data->cio2.pool); + if (ret) { + LOG(IPU3, Error) << "Failed to reserve CIO2 memory"; + return ret; + } + + ret = input->importBuffers(&data->cio2.pool); + if (ret) { + LOG(IPU3, Error) << "Failed to import ImgU memory"; + return ret; + } + + /* Prepare the buffer pools for viewfinder and stat. */ + data->imgu->vfPool.createBuffers(IPU3_IMGU_BUFFER_COUNT); + ret = viewfinder->exportBuffers(&data->imgu->vfPool); + if (ret) { + LOG(IPU3, Error) << "Failed to reserve ImgU viewfinder memory"; + return ret; + } + + data->imgu->statPool.createBuffers(IPU3_IMGU_BUFFER_COUNT); + ret = stat->exportBuffers(&data->imgu->statPool); + if (ret) { + LOG(IPU3, Error) << "Failed to reserve ImgU stat memory"; + return ret; + } - int ret = cio2->exportBuffers(&stream->bufferPool()); + /* Export ImgU output buffers to the stream's pool. */ + ret = output->exportBuffers(&stream->bufferPool()); if (ret) { - LOG(IPU3, Error) << "Failed to request memory"; + LOG(IPU3, Error) << "Failed to reserve ImgU output memory"; return ret; } From patchwork Wed Mar 20 16:30:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 756 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 68D7E612E2 for ; Wed, 20 Mar 2019 17:30:34 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 02D2D200008; Wed, 20 Mar 2019 16:30:33 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:34 +0100 Message-Id: <20190320163055.22056-11-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 10/31] libcamera: ipu3: Implement buffer release 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: Wed, 20 Mar 2019 16:30:35 -0000 Release buffers on all video devices in the pipeline. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/libcamera/pipeline/ipu3/ipu3.cpp | 30 +++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 659a7ca4829f..965794494a4e 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -158,6 +158,7 @@ private: void registerCameras(); ImgUDevice imgus_[IPU3_IMGU_COUNT]; + std::shared_ptr cio2MediaDev_; std::shared_ptr imguMediaDev_; }; @@ -358,13 +359,32 @@ int PipelineHandlerIPU3::allocateBuffers(Camera *camera, Stream *stream) int PipelineHandlerIPU3::freeBuffers(Camera *camera, Stream *stream) { IPU3CameraData *data = cameraData(camera); + V4L2Device *viewfinder = data->imgu->viewfinder; + V4L2Device *output = data->imgu->output; + V4L2Device *input = data->imgu->input; V4L2Device *cio2 = data->cio2.output; + V4L2Device *stat = data->imgu->stat; + int ret; - int ret = cio2->releaseBuffers(); - if (ret) { - LOG(IPU3, Error) << "Failed to release memory"; - return ret; - } + ret = output->releaseBuffers(); + if (ret) + LOG(IPU3, Error) << "Failed to release ImgU output memory"; + + ret = stat->releaseBuffers(); + if (ret) + LOG(IPU3, Error) << "Failed to release ImgU stat memory"; + + ret = viewfinder->releaseBuffers(); + if (ret) + LOG(IPU3, Error) << "Failed to release ImgU viewfinder memory"; + + ret = input->releaseBuffers(); + if (ret) + LOG(IPU3, Error) << "Failed to release ImgU input memory"; + + ret = cio2->releaseBuffers(); + if (ret) + LOG(IPU3, Error) << "Failed to release CIO2 memory"; return 0; } From patchwork Wed Mar 20 16:30:35 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 757 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0933E611A7 for ; Wed, 20 Mar 2019 17:30:35 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 9759120000F; Wed, 20 Mar 2019 16:30:34 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:35 +0100 Message-Id: <20190320163055.22056-12-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 11/31] libcamera: ipu3: Queue requests to the pipeline 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: Wed, 20 Mar 2019 16:30:35 -0000 Implement queueRequest for the IPU3 pipeline manager. When a request is queued, a new buffer is queued to the ImgU output. Also queue buffers for the viewfinder and stat video nodes, even if they're not used at the moment. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 965794494a4e..8410e1f4b4a6 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -161,11 +161,15 @@ private: std::shared_ptr cio2MediaDev_; std::shared_ptr imguMediaDev_; + + unsigned int tmpBufferCount; }; PipelineHandlerIPU3::PipelineHandlerIPU3(CameraManager *manager) : PipelineHandler(manager), cio2MediaDev_(nullptr), imguMediaDev_(nullptr) { + /* FIXME: this is an hack. */ + tmpBufferCount = 0; } PipelineHandlerIPU3::~PipelineHandlerIPU3() @@ -460,9 +464,26 @@ void PipelineHandlerIPU3::stop(Camera *camera) int PipelineHandlerIPU3::queueRequest(Camera *camera, Request *request) { IPU3CameraData *data = cameraData(camera); - V4L2Device *cio2 = data->cio2.output; + V4L2Device *viewfinder = data->imgu->viewfinder; + V4L2Device *output = data->imgu->output; + V4L2Device *stat = data->imgu->stat; Stream *stream = &data->stream_; + Buffer *tmpBuffer; + + /* + * Queue buffer on VF and stat. + * FIXME: this is an hack! + */ + tmpBuffer = &data->imgu->vfPool.buffers()[tmpBufferCount]; + viewfinder->queueBuffer(tmpBuffer); + + tmpBuffer = &data->imgu->statPool.buffers()[tmpBufferCount]; + stat->queueBuffer(tmpBuffer); + + tmpBufferCount++; + tmpBufferCount %= IPU3_IMGU_BUFFER_COUNT; + /* Queue a buffer to the ImgU output for capture. */ Buffer *buffer = request->findBuffer(stream); if (!buffer) { LOG(IPU3, Error) @@ -470,7 +491,7 @@ int PipelineHandlerIPU3::queueRequest(Camera *camera, Request *request) return -ENOENT; } - int ret = cio2->queueBuffer(buffer); + int ret = output->queueBuffer(buffer); if (ret < 0) return ret; From patchwork Wed Mar 20 16:30:36 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 758 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A3E0F611A7 for ; Wed, 20 Mar 2019 17:30:35 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 3C8A020000B; Wed, 20 Mar 2019 16:30:35 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:36 +0100 Message-Id: <20190320163055.22056-13-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 12/31] libcamera: ipu3: Connect CIO2 and ImgU bufferReady signals 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: Wed, 20 Mar 2019 16:30:35 -0000 Connect the CIO2 output bufferRead signal to a slot that simply queue the received buffer to ImgU for processing, and connect the ImgU main output bufferReady signal to the cameraData slot that notifies to applications that a new image buffer is available. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 58 +++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 8410e1f4b4a6..2623b2fe65f1 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -124,7 +124,9 @@ private: { } - void bufferReady(Buffer *buffer); + void imguOutputBufferReady(Buffer *buffer); + void imguInputBufferReady(Buffer *buffer); + void cio2BufferReady(Buffer *buffer); CIO2Device cio2; ImgUDevice *imgu; @@ -398,6 +400,21 @@ int PipelineHandlerIPU3::start(Camera *camera) IPU3CameraData *data = cameraData(camera); int ret; + /* + * Connect video devices' 'bufferReady' signals to their slot to + * implement the image processing pipeline. + * + * Frames produced by the CIO2 unit are shared with the associated + * ImgU input where they get processed and returned through the ImgU + * main and secondary outputs. + */ + data->cio2.output->bufferReady.connect(data, + &IPU3CameraData::cio2BufferReady); + data->imgu->input->bufferReady.connect(data, + &IPU3CameraData::imguInputBufferReady); + data->imgu->output->bufferReady.connect(data, + &IPU3CameraData::imguOutputBufferReady); + /* * Enqueue all available buffers to the CIO2 unit to start frame * capture. Start ImgU video devices and queue buffers to the output @@ -986,9 +1003,6 @@ void PipelineHandlerIPU3::registerCameras() cameraName, streams); - cio2->output->bufferReady.connect(data.get(), - &IPU3CameraData::bufferReady); - registerCamera(std::move(camera), std::move(data)); LOG(IPU3, Info) @@ -1000,7 +1014,29 @@ void PipelineHandlerIPU3::registerCameras() } } -void PipelineHandlerIPU3::IPU3CameraData::bufferReady(Buffer *buffer) +/* ---------------------------------------------------------------------------- + * Buffer Ready slots + */ + +/** + * \brief ImgU input BufferReady slot + * \param buffer The completed buffer + * + * Buffer completed from the ImgU input are immediately queued back to the + * CIO2 unit to continue frame capture. + */ +void PipelineHandlerIPU3::IPU3CameraData::imguInputBufferReady(Buffer *buffer) +{ + cio2.output->queueBuffer(buffer); +} + +/** + * \brief ImgU output BufferReady slot + * \param buffer The completed buffer + * + * Buffer completed from the ImgU output are directed to the applications. + */ +void PipelineHandlerIPU3::IPU3CameraData::imguOutputBufferReady(Buffer *buffer) { Request *request = queuedRequests_.front(); @@ -1008,6 +1044,18 @@ void PipelineHandlerIPU3::IPU3CameraData::bufferReady(Buffer *buffer) pipe_->completeRequest(camera_, request); } +/** + * \brief CIO2 BufferReady slot + * \param buffer The completed buffer + * + * Buffer completed from the CIO2 are immediately queued to the ImgU unit + * for further processing. + */ +void PipelineHandlerIPU3::IPU3CameraData::cio2BufferReady(Buffer *buffer) +{ + imgu->input->queueBuffer(buffer); +} + REGISTER_PIPELINE_HANDLER(PipelineHandlerIPU3); } /* namespace libcamera */ From patchwork Wed Mar 20 16:30:37 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 759 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 38316612E8 for ; Wed, 20 Mar 2019 17:30:36 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id CCCD920000B; Wed, 20 Mar 2019 16:30:35 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:37 +0100 Message-Id: <20190320163055.22056-14-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 13/31] libcamera: ipu3: Use NV12 as default image format 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: Wed, 20 Mar 2019 16:30:37 -0000 Now that images come from the ImgU output, hardcode NV12 as default output format. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/libcamera/pipeline/ipu3/ipu3.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 2623b2fe65f1..b99aae95c6d7 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -211,16 +211,16 @@ PipelineHandlerIPU3::streamConfiguration(Camera *camera, config->width = range.maxWidth; config->height = range.maxHeight; - config->pixelFormat = cio2Code; } } + config->pixelFormat = V4L2_PIX_FMT_NV12; config->bufferCount = IPU3_BUFFER_COUNT; LOG(IPU3, Debug) << "Stream format set to: " << config->width << "x" << config->height << "- 0x" << std::hex << std::setfill('0') - << std::setw(4) << config->pixelFormat; + << std::setw(8) << config->pixelFormat; return configs; } From patchwork Wed Mar 20 16:30:38 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 760 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C8625611B9 for ; Wed, 20 Mar 2019 17:30:36 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 61A3420000F; Wed, 20 Mar 2019 16:30:36 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:38 +0100 Message-Id: <20190320163055.22056-15-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 14/31] HACK: Soraka: Limit resolution to 2560x1920 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: Wed, 20 Mar 2019 16:30:37 -0000 Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index b99aae95c6d7..ed2409907cf0 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -214,6 +214,16 @@ PipelineHandlerIPU3::streamConfiguration(Camera *camera, } } + /* + * FIXME: Soraka: the maximum resolution reported by both sensors + * (2592x1944 for ov5670 and 4224x3136 for ov13858) are returned as + * default configurations but they're not correctly processed by the + * ImgU. Resolutions up tp 2560x1920 have been validated. + * + * \todo Clarify ImgU alignement requirements. + */ + config->width = 2560; + config->height = 1920; config->pixelFormat = V4L2_PIX_FMT_NV12; config->bufferCount = IPU3_BUFFER_COUNT; From patchwork Wed Mar 20 16:30:39 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 761 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 68355611B9 for ; Wed, 20 Mar 2019 17:30:37 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 00C4120000F; Wed, 20 Mar 2019 16:30:36 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:39 +0100 Message-Id: <20190320163055.22056-16-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 15/31] RFC: libcamera: ipu3: Enable ImgU media links 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: Wed, 20 Mar 2019 16:30:37 -0000 As the lenghty comment reports, link enable/disable is not trivial, as links in one ImgU instance interfere with capture operations in the other one. As I struggle to find where to disable links selectively, as of now reset the media graph and enable the required links at streamConfiguration time. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 110 +++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index ed2409907cf0..43fa0e4a7f9d 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -52,6 +52,10 @@ public: } void init(MediaDevice *media, unsigned int index); + int linkSetup(const std::string &source, unsigned int sourcePad, + const std::string &sink, unsigned int sinkPad, + bool enable); + int enableLinks(bool enable); unsigned int index_; std::string imguName_; @@ -264,6 +268,14 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, return -EINVAL; } + /* + * \todo: Enable links selectively based on the requested streams. + * As of now, enable all links unconditionally. + */ + ret = data->imgu->enableLinks(true); + if (ret) + return ret; + /* * Pass the requested output image size to the sensor and get back the * adjusted one to be propagated to the CIO2 device and to the ImgU @@ -589,6 +601,30 @@ bool PipelineHandlerIPU3::match(DeviceEnumerator *enumerator) return false; } + /* + * FIXME: enabled links in one ImgU instance interfere with capture + * operations on the other one. This can be easily triggered by + * capturing from one camera and then trying to capture from the other + * one right after, without disabling media links in the media graph + * first. + * + * The tricky part here is where to disable links on the ImgU instance + * which is currently not in use: + * 1) Link enable/disable cannot be done at start/stop time as video + * devices needs to be linked first before format can be configured on + * them. + * 2) As link enable has to be done at the least in configureStreams, + * before configuring formats, the only place where to disable links + * would be 'stop()', but the Camera class state machine allows + * start()<->stop() sequences without any streamConfiguration() in + * between. + * + * As of now, disable all links in the media graph at 'match()' time, + * to allow testing different cameras in different test applications + * runs. A test application that would use two distinct cameras without + * going through a library teardown->match() sequence would fail + * at the moment. + */ if (imguMediaDev_->disableLinks()) goto error_close_mdev; @@ -625,6 +661,80 @@ void ImgUDevice::init(MediaDevice *mediaDevice, unsigned int index) mediaDevice_ = mediaDevice; } +/** + * \brief Enable or disable a single link on the ImgU instance + * + * This method assumes the media device associated with the ImgU instance + * is open. + * + * \return 0 on success or a negative error code otherwise + */ +int ImgUDevice::linkSetup(const std::string &source, unsigned int sourcePad, + const std::string &sink, unsigned int sinkPad, + bool enable) +{ + MediaLink *link = mediaDevice_->link(source, sourcePad, sink, sinkPad); + if (!link) { + LOG(IPU3, Error) + << "Failed to get link: '" << source << "':" + << sourcePad << " -> '" << sink << "':" << sinkPad; + return -ENODEV; + } + + return link->setEnabled(enable); +} + +/** + * \brief Enable or disable all media links in the ImgU instance to prepare + * for capture operations + * + * \todo This method will probably be removed or changed once links will be + * enabled or disabled selectively. + * + * \return 0 on success or a negative error code otherwise + */ +int ImgUDevice::enableLinks(bool enable) +{ + std::string inputName = imguName_ + " input"; + std::string outputName = imguName_ + " output"; + std::string viewfinderName = imguName_ + " viewfinder"; + std::string statName = imguName_ + " 3a stat"; + int ret; + + /* \todo Establish rules to handle media devices open/close. */ + ret = mediaDevice_->open(); + if (ret) + return ret; + + ret = linkSetup(inputName, 0, imguName_, PAD_INPUT, enable); + if (ret) { + mediaDevice_->close(); + return ret; + } + + ret = linkSetup(imguName_, PAD_OUTPUT, outputName, 0, enable); + if (ret) { + mediaDevice_->close(); + return ret; + } + + ret = linkSetup(imguName_, PAD_VF, viewfinderName, 0, enable); + if (ret) { + mediaDevice_->close(); + return ret; + } + + ret = linkSetup(imguName_, PAD_STAT, statName, 0, enable); + if (ret) { + mediaDevice_->close(); + return ret; + } + + mediaDevice_->close(); + + return 0; +} + int PipelineHandlerIPU3::mediaBusToCIO2Format(unsigned int code) { switch (code) { From patchwork Wed Mar 20 16:30:40 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 762 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 029B3600FC for ; Wed, 20 Mar 2019 17:30:38 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 94A59200008; Wed, 20 Mar 2019 16:30:37 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:40 +0100 Message-Id: <20190320163055.22056-17-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 16/31] libcamera: request: Store the streams in the request 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: Wed, 20 Mar 2019 16:30:38 -0000 Store the streams which the request applies to and provide an accessor method to return them in a set. Signed-off-by: Jacopo Mondi --- include/libcamera/request.h | 2 ++ src/libcamera/request.cpp | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/include/libcamera/request.h b/include/libcamera/request.h index 0dbd425115e8..1bf90de2c6f9 100644 --- a/include/libcamera/request.h +++ b/include/libcamera/request.h @@ -34,6 +34,7 @@ public: int setBuffers(const std::map &streamMap); Buffer *findBuffer(Stream *stream) const; + const std::set &streams() const { return streams_; } Status status() const { return status_; } @@ -49,6 +50,7 @@ private: Camera *camera_; std::map bufferMap_; std::unordered_set pending_; + std::set streams_; Status status_; }; diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp index e0e77e972411..22c516208ede 100644 --- a/src/libcamera/request.cpp +++ b/src/libcamera/request.cpp @@ -51,6 +51,13 @@ Request::Request(Camera *camera) { } +/** + * \fn Request::streams() + * \brief Retrieve the set of streams contained in the request + * + * \return The set of streams contained in the request + */ + /** * \brief Set the streams to capture with associated buffers * \param[in] streamMap The map of streams to buffers @@ -65,6 +72,10 @@ int Request::setBuffers(const std::map &streamMap) } bufferMap_ = streamMap; + + for (const auto &map : streamMap) + streams_.insert(map.first); + return 0; } @@ -77,6 +88,11 @@ int Request::setBuffers(const std::map &streamMap) * map. */ +/** + * \var Request::streams_ + * \brief Set of streams in this request + */ + /** * \brief Return the buffer associated with a stream * \param[in] stream The stream the buffer is associated to From patchwork Wed Mar 20 16:30:41 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 763 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8EB7D600FC for ; Wed, 20 Mar 2019 17:30:38 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 2B14F20000F; Wed, 20 Mar 2019 16:30:38 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:41 +0100 Message-Id: <20190320163055.22056-18-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 17/31] libcamera: request: Add camera() getter method 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: Wed, 20 Mar 2019 16:30:38 -0000 Add a "camera()" getter method to the Request class to retrieve the Camera instance the request has been sent to. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- include/libcamera/request.h | 1 + src/libcamera/request.cpp | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/include/libcamera/request.h b/include/libcamera/request.h index 1bf90de2c6f9..56d179e5f2f5 100644 --- a/include/libcamera/request.h +++ b/include/libcamera/request.h @@ -35,6 +35,7 @@ public: int setBuffers(const std::map &streamMap); Buffer *findBuffer(Stream *stream) const; const std::set &streams() const { return streams_; } + Camera *camera() const { return camera_; } Status status() const { return status_; } diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp index 22c516208ede..51ab6c4e71b2 100644 --- a/src/libcamera/request.cpp +++ b/src/libcamera/request.cpp @@ -58,6 +58,13 @@ Request::Request(Camera *camera) * \return The set of streams contained in the request */ +/** + * \fn Request::camera() + * \brief Retrieve the camera the request has been sent to + * + * \return Pointer to the camera instance the request has been sent to + */ + /** * \brief Set the streams to capture with associated buffers * \param[in] streamMap The map of streams to buffers From patchwork Wed Mar 20 16:30:42 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 764 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 28634612EC for ; Wed, 20 Mar 2019 17:30:39 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id BB5D0200011; Wed, 20 Mar 2019 16:30:38 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:42 +0100 Message-Id: <20190320163055.22056-19-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 18/31] libcamera: ipu3: Create camera with 2 streams 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: Wed, 20 Mar 2019 16:30:39 -0000 Create each IPU3 camera with two streams: 'output' and 'viewfinder' which represents the video stream from main and secondary ImgU output respectively. Return a default configuration for both streams in streamConfiguration(). Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 42 ++++++++++++++++++---------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 43fa0e4a7f9d..44e5eb48549e 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -120,6 +120,10 @@ private: static constexpr unsigned int IPU3_CIO2_BUFFER_COUNT = 4; static constexpr unsigned int IPU3_IMGU_BUFFER_COUNT = 4; + static constexpr unsigned int IPU3_STREAMS_COUNT = 2; + static constexpr unsigned int IPU3_STREAM_OUTPUT = 0; + static constexpr unsigned int IPU3_STREAM_VF = 1; + class IPU3CameraData : public CameraData { public: @@ -135,7 +139,7 @@ private: CIO2Device cio2; ImgUDevice *imgu; - Stream stream_; + Stream streams_[IPU3_STREAMS_COUNT]; }; IPU3CameraData *cameraData(const Camera *camera) @@ -194,7 +198,7 @@ PipelineHandlerIPU3::streamConfiguration(Camera *camera, std::map configs; IPU3CameraData *data = cameraData(camera); V4L2Subdevice *sensor = data->cio2.sensor; - StreamConfiguration *config = &configs[&data->stream_]; + StreamConfiguration config = {}; unsigned int bestSize = 0; const FormatEnum formats = sensor->formats(0); @@ -213,8 +217,8 @@ PipelineHandlerIPU3::streamConfiguration(Camera *camera, bestSize = frameSize; - config->width = range.maxWidth; - config->height = range.maxHeight; + config.width = range.maxWidth; + config.height = range.maxHeight; } } @@ -226,15 +230,22 @@ PipelineHandlerIPU3::streamConfiguration(Camera *camera, * * \todo Clarify ImgU alignement requirements. */ - config->width = 2560; - config->height = 1920; - config->pixelFormat = V4L2_PIX_FMT_NV12; - config->bufferCount = IPU3_BUFFER_COUNT; + config.width = 2560; + config.height = 1920; + config.pixelFormat = V4L2_PIX_FMT_NV12; + config.bufferCount = IPU3_BUFFER_COUNT; + + configs[&data->streams_[IPU3_STREAM_OUTPUT]] = config; + LOG(IPU3, Debug) + << "Stream 'Output' format set to " << config.width << "x" + << config.height << "- 0x" << std::hex << std::setfill('0') + << std::setw(8) << config.pixelFormat; + configs[&data->streams_[IPU3_STREAM_VF]] = config; LOG(IPU3, Debug) - << "Stream format set to: " << config->width << "x" - << config->height << "- 0x" << std::hex << std::setfill('0') - << std::setw(8) << config->pixelFormat; + << "Stream 'Viewfinder' format set to " << config.width << "x" + << config.height << "- 0x" << std::hex << std::setfill('0') + << std::setw(8) << config.pixelFormat; return configs; } @@ -243,7 +254,7 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, std::map &config) { IPU3CameraData *data = cameraData(camera); - const StreamConfiguration &cfg = config[&data->stream_]; + const StreamConfiguration &cfg = config[&data->streams_[0]]; V4L2Device *viewfinder = data->imgu->viewfinder; V4L2Device *output = data->imgu->output; V4L2Device *input = data->imgu->input; @@ -506,7 +517,7 @@ int PipelineHandlerIPU3::queueRequest(Camera *camera, Request *request) V4L2Device *viewfinder = data->imgu->viewfinder; V4L2Device *output = data->imgu->output; V4L2Device *stat = data->imgu->stat; - Stream *stream = &data->stream_; + Stream *stream = &data->streams_[0]; Buffer *tmpBuffer; /* @@ -1097,7 +1108,10 @@ void PipelineHandlerIPU3::registerCameras() for (unsigned int id = 0; id < 4 && numCameras < 2; ++id) { std::unique_ptr data = utils::make_unique(this); - std::set streams{ &data->stream_ }; + std::set streams = { + &data->streams_[IPU3_STREAM_OUTPUT], + &data->streams_[IPU3_STREAM_VF], + }; CIO2Device *cio2 = &data->cio2; int ret; From patchwork Wed Mar 20 16:30:43 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 765 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C87D76110A for ; Wed, 20 Mar 2019 17:30:39 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 54FE6200012; Wed, 20 Mar 2019 16:30:39 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:43 +0100 Message-Id: <20190320163055.22056-20-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 19/31] libcamera: ipu3: Configure 'output' and 'viewfinder' 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: Wed, 20 Mar 2019 16:30:40 -0000 Re-work stream configuration to handle the two video streams 'output' and 'viewfinder' separately. As the IPU3 driver requires viewfinder and stat video nodes to be operated not to stall ImgU processing, keep track of which streams have been requested by the application, and configure 'output', 'viewfinder' and 'stat' regardless of the user requests. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 259 ++++++++++++++++++++++----- 1 file changed, 216 insertions(+), 43 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 44e5eb48549e..4ed8c1fec1e3 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -140,6 +140,7 @@ private: ImgUDevice *imgu; Stream streams_[IPU3_STREAMS_COUNT]; + unsigned int activeStreamsMask; }; IPU3CameraData *cameraData(const Camera *camera) @@ -148,6 +149,44 @@ private: PipelineHandler::cameraData(camera)); } + bool isOutput(IPU3CameraData *data, Stream *stream) + { + return &data->streams_[IPU3_STREAM_OUTPUT] == stream; + } + bool isOutputActive(IPU3CameraData *data) + { + return (data->activeStreamsMask & (1 << IPU3_STREAM_OUTPUT)) ? + true : false; + } + void setOutputActive(IPU3CameraData *data) + { + data->activeStreamsMask |= (1 << IPU3_STREAM_OUTPUT); + } + bool isViewfinder(IPU3CameraData *data, Stream *stream) + { + return &data->streams_[IPU3_STREAM_VF] == stream; + } + bool isViewfinderActive(IPU3CameraData *data) + { + return (data->activeStreamsMask & (1 << IPU3_STREAM_VF)) ? + true : false; + } + void setViewfinderActive(IPU3CameraData *data) + { + data->activeStreamsMask |= (1 << IPU3_STREAM_VF); + } + bool isStreamActive(IPU3CameraData *data, Stream *stream) + { + if (isOutput(data, stream) && + isOutputActive(data)) + return true; + if (isViewfinder(data, stream) && + isViewfinderActive(data)) + return true; + + return false; + } + int mediaBusToCIO2Format(unsigned int code); V4L2Device *openDevice(MediaDevice *media, const std::string &name); V4L2Subdevice *openSubdevice(MediaDevice *media, @@ -158,9 +197,17 @@ private: int initImgU(ImgUDevice *imgu); - int setImguFormat(ImgUDevice *imguDevice, - const StreamConfiguration &config, - Rectangle *rect); + int setInputFormat(ImgUDevice *imguDevice, + const StreamConfiguration &config, + Rectangle *rect); + int setOutputFormat(ImgUDevice *imguDevice, + V4L2Device *output, + const StreamConfiguration &config); + int setViewfinderFormat(ImgUDevice *imguDevice, + V4L2Device *Viewfinder, + const StreamConfiguration &config); + int setStatFormat(ImgUDevice *imguDevice, + const StreamConfiguration &config); int setCIO2Format(CIO2Device *cio2Device, const StreamConfiguration &config, V4L2SubdeviceFormat *format); @@ -251,32 +298,66 @@ PipelineHandlerIPU3::streamConfiguration(Camera *camera, } int PipelineHandlerIPU3::configureStreams(Camera *camera, - std::map &config) + std::map &config) { IPU3CameraData *data = cameraData(camera); - const StreamConfiguration &cfg = config[&data->streams_[0]]; V4L2Device *viewfinder = data->imgu->viewfinder; V4L2Device *output = data->imgu->output; V4L2Device *input = data->imgu->input; V4L2Device *cio2 = data->cio2.output; + StreamConfiguration CIO2Config = {}; int ret; - LOG(IPU3, Info) - << "Requested image format: " << cfg.width << "x" - << cfg.height << " - " << std::hex << std::setw(8) - << cfg.pixelFormat << " on camera:'" << camera->name() << "'"; + /* Remove previously configured stream masks to store the new ones. */ + data->activeStreamsMask = 0; - /* - * Verify that the requested size respects the IPU3 alignement - * requirements: the image width shall be a multiple of 8 pixels and - * its height a multiple of 4 pixels. - * - * \todo: consider the BDS scaling factor requirements: - * "the downscaling factor must be an integer value multiple of 1/32" - */ - if (cfg.width % 8 || cfg.height % 4) { - LOG(IPU3, Error) << "Stream format not support: bad alignement"; - return -EINVAL; + for (auto const &streamConfig : config) { + Stream *stream = streamConfig.first; + const StreamConfiguration &cfg = streamConfig.second; + + /* + * Verify that the requested size respects the IPU3 alignement + * requirements: the image width shall be a multiple of 8 pixels + * and its height a multiple of 4 pixels. + * + * \todo: consider the BDS scaling factor requirements: "the + * downscaling factor must be an integer value multiple of 1/32" + */ + if (cfg.width % 8 || cfg.height % 4) { + LOG(IPU3, Error) + << "Stream format not support: bad alignement"; + return -EINVAL; + } + + LOG(IPU3, Info) + << "Requested image format: " << cfg.width << "x" + << cfg.height << " - " << std::hex << std::setw(8) + << cfg.pixelFormat << " on camera:'" << camera->name() + << "'"; + + /* + * FIXME: As viewfinder should be operated even when + * applications do not intend to use it, we need to keep track + * of which streams have to be configured, to make meaningful + * decisions at configure and request queueing time. + * + * Walk here all the streams to configure and collect the + * active ones in a bitmaks. + */ + if (isOutput(data, stream)) + setOutputActive(data); + if (isViewfinder(data, stream)) + setViewfinderActive(data); + + /* + * Collect the maximum width and height: IPU3 can downscale + * only. + */ + if (cfg.width > CIO2Config.width) + CIO2Config.width = cfg.width; + if (cfg.height > CIO2Config.height) + CIO2Config.height = cfg.height; } /* @@ -293,7 +374,7 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, * input. */ V4L2SubdeviceFormat sensorFormat = {}; - ret = setCIO2Format(&data->cio2, cfg, &sensorFormat); + ret = setCIO2Format(&data->cio2, CIO2Config, &sensorFormat); if (ret) return ret; @@ -307,41 +388,64 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, if (ret) return ret; - LOG(IPU3, Debug) - << "CIO2 output format = " << cio2Format.toString(); + LOG(IPU3, Debug) << "CIO2 output format = " << cio2Format.toString(); ret = input->setFormat(&cio2Format); if (ret) return ret; - /* Apply pad formats and crop/compose rectangle to the ImgU. */ + /* Apply pad formats and crop/compose rectangle to the ImgU input. */ Rectangle rect = { .x = 0, .y = 0, .w = cio2Format.width, .h = cio2Format.height, }; - ret = setImguFormat(data->imgu, cfg, &rect); + ret = setInputFormat(data->imgu, CIO2Config, &rect); if (ret) return ret; - /* Apply the format to the ImgU output and viewfinder devices. */ - V4L2DeviceFormat outputFormat = {}; - outputFormat.width = cfg.width; - outputFormat.height = cfg.height; - outputFormat.fourcc = V4L2_PIX_FMT_NV12; - outputFormat.planesCount = 2; + for (auto const &streamConfig : config) { + Stream *stream = streamConfig.first; + const StreamConfiguration &cfg = streamConfig.second; - ret = output->setFormat(&outputFormat); - if (ret) - return ret; + if (isOutput(data, stream)) { + ret = setOutputFormat(data->imgu, output, cfg); + if (ret) + return ret; - LOG(IPU3, Debug) - << "ImgU output format = " << outputFormat.toString(); + ret = setStatFormat(data->imgu, cfg); + if (ret) + return ret; - ret = viewfinder->setFormat(&outputFormat); - if (ret) - return ret; + /* + * FIXME: even if viewfinder is not in use, we need to + * configure and operate it. Use the same size used + * for main output. + */ + if (!isViewfinderActive(data)) { + ret = setViewfinderFormat(data->imgu, + viewfinder, cfg); + if (ret) + return ret; + } + } else if (isViewfinder(data, stream)) { + ret = setViewfinderFormat(data->imgu, viewfinder, cfg); + if (ret) + return ret; + + /* Operating the main output is mandatory. */ + if (!isOutputActive(data)) { + ret = setOutputFormat(data->imgu, output, cfg); + if (ret) + return ret; + + ret = setStatFormat(data->imgu, cfg); + if (ret) + return ret; + } + } + } return 0; } @@ -974,9 +1078,9 @@ void PipelineHandlerIPU3::deleteCIO2(CIO2Device *cio2) delete cio2->sensor; } -int PipelineHandlerIPU3::setImguFormat(ImgUDevice *imguDevice, - const StreamConfiguration &config, - Rectangle *rect) +int PipelineHandlerIPU3::setInputFormat(ImgUDevice *imguDevice, + const StreamConfiguration &config, + Rectangle *rect) { V4L2Subdevice *imgu = imguDevice->imgu; int ret; @@ -1012,17 +1116,86 @@ int PipelineHandlerIPU3::setImguFormat(ImgUDevice *imguDevice, if (ret) return ret; + LOG(IPU3, Debug) << "ImgU GDC format = " << imguFormat.toString(); + + return 0; +} + +int PipelineHandlerIPU3::setOutputFormat(ImgUDevice *imguDevice, + V4L2Device *output, + const StreamConfiguration &config) +{ + V4L2Subdevice *imgu = imguDevice->imgu; + int ret; + + V4L2SubdeviceFormat imguFormat = {}; + imguFormat.width = config.width; + imguFormat.height = config.height; + imguFormat.mbus_code = MEDIA_BUS_FMT_FIXED; + ret = imgu->setFormat(ImgUDevice::PAD_OUTPUT, &imguFormat); if (ret) return ret; + V4L2DeviceFormat outputFormat = {}; + outputFormat.width = config.width; + outputFormat.height = config.height; + outputFormat.fourcc = V4L2_PIX_FMT_NV12; + outputFormat.planesCount = 2; + + ret = output->setFormat(&outputFormat); + if (ret) + return ret; + LOG(IPU3, Debug) - << "ImgU GDC format = " << imguFormat.toString(); + << "ImgU output format = " << outputFormat.toString(); + + return 0; +} + +int PipelineHandlerIPU3::setViewfinderFormat(ImgUDevice *imguDevice, + V4L2Device *viewfinder, + const StreamConfiguration &config) +{ + V4L2Subdevice *imgu = imguDevice->imgu; + int ret; + + V4L2SubdeviceFormat imguFormat = {}; + imguFormat.width = config.width; + imguFormat.height = config.height; + imguFormat.mbus_code = MEDIA_BUS_FMT_FIXED; ret = imgu->setFormat(ImgUDevice::PAD_VF, &imguFormat); if (ret) return ret; + V4L2DeviceFormat viewfinderFormat = {}; + viewfinderFormat.width = config.width; + viewfinderFormat.height = config.height; + viewfinderFormat.fourcc = V4L2_PIX_FMT_NV12; + viewfinderFormat.planesCount = 2; + + ret = viewfinder->setFormat(&viewfinderFormat); + if (ret) + return ret; + + LOG(IPU3, Debug) + << "ImgU viewfinder format = " << viewfinderFormat.toString(); + + return 0; +} + +int PipelineHandlerIPU3::setStatFormat(ImgUDevice *imguDevice, + const StreamConfiguration &config) +{ + V4L2Subdevice *imgu = imguDevice->imgu; + int ret; + + V4L2SubdeviceFormat imguFormat = {}; + imguFormat.width = config.width; + imguFormat.height = config.height; + imguFormat.mbus_code = MEDIA_BUS_FMT_FIXED; + ret = imgu->setFormat(ImgUDevice::PAD_STAT, &imguFormat); if (ret) return ret; From patchwork Wed Mar 20 16:30:44 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 766 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 779986110A for ; Wed, 20 Mar 2019 17:30:40 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 1779520000D; Wed, 20 Mar 2019 16:30:39 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:44 +0100 Message-Id: <20190320163055.22056-21-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 20/31] libcamera: ipu3: Add multiple stream memory management 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: Wed, 20 Mar 2019 16:30:40 -0000 Add support for allocating and freeing memory for multiple streams. --- src/libcamera/pipeline/ipu3/ipu3.cpp | 140 ++++++++++++++++++--------- 1 file changed, 96 insertions(+), 44 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 4ed8c1fec1e3..0507fc380e68 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -70,6 +70,7 @@ public: BufferPool vfPool; BufferPool statPool; + BufferPool outputPool; }; struct CIO2Device { @@ -458,42 +459,70 @@ int PipelineHandlerIPU3::allocateBuffers(Camera *camera, Stream *stream) V4L2Device *input = data->imgu->input; V4L2Device *cio2 = data->cio2.output; V4L2Device *stat = data->imgu->stat; + ImgUDevice *imgu = data->imgu; int ret; - /* Share buffers between CIO2 output and ImgU input. */ - data->cio2.pool.createBuffers(IPU3_CIO2_BUFFER_COUNT); - ret = cio2->exportBuffers(&data->cio2.pool); - if (ret) { - LOG(IPU3, Error) << "Failed to reserve CIO2 memory"; - return ret; - } + if (data->cio2.pool.count() == 0) { + /* Share buffers between CIO2 output and ImgU input. */ + data->cio2.pool.createBuffers(IPU3_CIO2_BUFFER_COUNT); + ret = cio2->exportBuffers(&data->cio2.pool); + if (ret) { + LOG(IPU3, Error) << "Failed to reserve CIO2 memory"; + return ret; + } - ret = input->importBuffers(&data->cio2.pool); - if (ret) { - LOG(IPU3, Error) << "Failed to import ImgU memory"; - return ret; - } + ret = input->importBuffers(&data->cio2.pool); + if (ret) { + LOG(IPU3, Error) << "Failed to import ImgU memory"; + return ret; + } - /* Prepare the buffer pools for viewfinder and stat. */ - data->imgu->vfPool.createBuffers(IPU3_IMGU_BUFFER_COUNT); - ret = viewfinder->exportBuffers(&data->imgu->vfPool); - if (ret) { - LOG(IPU3, Error) << "Failed to reserve ImgU viewfinder memory"; - return ret; + imgu->statPool.createBuffers(IPU3_IMGU_BUFFER_COUNT); + ret = stat->exportBuffers(&imgu->statPool); + if (ret) { + LOG(IPU3, Error) << "Failed to reserve ImgU stat memory"; + return ret; + } } - data->imgu->statPool.createBuffers(IPU3_IMGU_BUFFER_COUNT); - ret = stat->exportBuffers(&data->imgu->statPool); - if (ret) { - LOG(IPU3, Error) << "Failed to reserve ImgU stat memory"; - return ret; - } + if (isOutput(data, stream)) { + /* Export ImgU output buffers to the stream's pool. */ + ret = output->exportBuffers(&stream->bufferPool()); + if (ret) { + LOG(IPU3, Error) + << "Failed to reserve ImgU output memory"; + return ret; + } - /* Export ImgU output buffers to the stream's pool. */ - ret = output->exportBuffers(&stream->bufferPool()); - if (ret) { - LOG(IPU3, Error) << "Failed to reserve ImgU output memory"; - return ret; + if (!isViewfinderActive(data)) { + /* Internally allocate buffers for viewfinder. */ + imgu->vfPool.createBuffers(IPU3_IMGU_BUFFER_COUNT); + ret = viewfinder->exportBuffers(&imgu->vfPool); + if (ret) { + LOG(IPU3, Error) + << "Failed to reserve ImgU viewfinder memory"; + return ret; + } + } + } else if (isViewfinder(data, stream)) { + /* Export ImgU viewfinder buffers to the stream's pool. */ + ret = viewfinder->exportBuffers(&stream->bufferPool()); + if (ret) { + LOG(IPU3, Error) + << "Failed to reserve ImgU viewfinder memory"; + return ret; + } + + if (!isOutputActive(data)) { + /* Internally allocate buffers for output. */ + imgu->outputPool.createBuffers(IPU3_IMGU_BUFFER_COUNT); + ret = output->exportBuffers(&imgu->outputPool); + if (ret) { + LOG(IPU3, Error) + << "Failed to reserve ImgU output memory"; + return ret; + } + } } return 0; @@ -509,25 +538,48 @@ int PipelineHandlerIPU3::freeBuffers(Camera *camera, Stream *stream) V4L2Device *stat = data->imgu->stat; int ret; - ret = output->releaseBuffers(); - if (ret) - LOG(IPU3, Error) << "Failed to release ImgU output memory"; + if (data->cio2.pool.count()) { + ret = input->releaseBuffers(); + if (ret) + LOG(IPU3, Error) << "Failed to release ImgU input memory"; - ret = stat->releaseBuffers(); - if (ret) - LOG(IPU3, Error) << "Failed to release ImgU stat memory"; + ret = cio2->releaseBuffers(); + if (ret) + LOG(IPU3, Error) << "Failed to release CIO2 memory"; - ret = viewfinder->releaseBuffers(); - if (ret) - LOG(IPU3, Error) << "Failed to release ImgU viewfinder memory"; + ret = stat->releaseBuffers(); + if (ret) + LOG(IPU3, Error) << "Failed to release ImgU stat memory"; - ret = input->releaseBuffers(); - if (ret) - LOG(IPU3, Error) << "Failed to release ImgU input memory"; + } - ret = cio2->releaseBuffers(); - if (ret) - LOG(IPU3, Error) << "Failed to release CIO2 memory"; + if (isOutput(data, stream)) { + ret = output->releaseBuffers(); + if (ret) + LOG(IPU3, Error) + << "Failed to release ImgU output memory"; + + if (isViewfinderActive(data)) + return 0; + + ret = viewfinder->releaseBuffers(); + if (ret) + LOG(IPU3, Error) + << "Failed to release ImgU viewfinder memory"; + } else if (isViewfinder(data, stream)) { + ret = viewfinder->releaseBuffers(); + if (ret) + LOG(IPU3, Error) + << "Failed to release ImgU viewfinder memory"; + + if (isOutputActive(data)) + return 0; + + ret = output->releaseBuffers(); + if (ret) + LOG(IPU3, Error) + << "Failed to release ImgU output memory"; + } return 0; } From patchwork Wed Mar 20 16:30:45 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 767 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1AD50611B4 for ; Wed, 20 Mar 2019 17:30:41 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id A2582200012; Wed, 20 Mar 2019 16:30:40 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:45 +0100 Message-Id: <20190320163055.22056-22-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 21/31] RFC: libcamera: pipeline_handlers: Add preAllocateBuffers 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: Wed, 20 Mar 2019 16:30:41 -0000 Add a preAllocateBuffers virtual method to the PipelineHandler base class and call it before performing per-stream memory allocation. Implement the method in the IPU3 pipeline handler to perform memory allocation on the CIO2 unit and the ImgU input and stat video devices. Signed-off-by: Jacopo Mondi --- src/libcamera/camera.cpp | 10 ++++- src/libcamera/include/pipeline_handler.h | 5 +++ src/libcamera/pipeline/ipu3/ipu3.cpp | 54 ++++++++++++++---------- src/libcamera/pipeline_handler.cpp | 21 ++++++++- 4 files changed, 66 insertions(+), 24 deletions(-) diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp index 8ee9cc086616..8020dff8f8ea 100644 --- a/src/libcamera/camera.cpp +++ b/src/libcamera/camera.cpp @@ -455,6 +455,8 @@ int Camera::configureStreams(std::map &config) */ int Camera::allocateBuffers() { + int ret; + if (disconnected_) return -ENODEV; @@ -467,8 +469,14 @@ int Camera::allocateBuffers() return -EINVAL; } + ret = pipe_->preAllocateBuffers(this, activeStreams_); + if (ret) { + LOG(Camera, Error) << "Buffers pre-allocation failed"; + return ret; + } + for (Stream *stream : activeStreams_) { - int ret = pipe_->allocateBuffers(this, stream); + ret = pipe_->allocateBuffers(this, stream); if (ret) { LOG(Camera, Error) << "Failed to allocate buffers"; freeBuffers(); diff --git a/src/libcamera/include/pipeline_handler.h b/src/libcamera/include/pipeline_handler.h index acb376e07030..7ce5b67cc7fc 100644 --- a/src/libcamera/include/pipeline_handler.h +++ b/src/libcamera/include/pipeline_handler.h @@ -57,6 +57,11 @@ public: virtual int configureStreams(Camera *camera, std::map &config) = 0; + virtual int preAllocateBuffers(Camera *camera, + const std::set &activeStreams) + { + return 0; + } virtual int allocateBuffers(Camera *camera, Stream *stream) = 0; virtual int freeBuffers(Camera *camera, Stream *stream) = 0; diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 0507fc380e68..5f323888d84f 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -105,6 +105,8 @@ public: int configureStreams(Camera *camera, std::map &config) override; + int preAllocateBuffers(Camera *camera, + const std::set &activeStreams) override; int allocateBuffers(Camera *camera, Stream *stream) override; int freeBuffers(Camera *camera, Stream *stream) override; @@ -451,40 +453,48 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, return 0; } -int PipelineHandlerIPU3::allocateBuffers(Camera *camera, Stream *stream) +int PipelineHandlerIPU3::preAllocateBuffers(Camera *camera, + const std::set &activeStreams) { IPU3CameraData *data = cameraData(camera); - V4L2Device *viewfinder = data->imgu->viewfinder; - V4L2Device *output = data->imgu->output; V4L2Device *input = data->imgu->input; V4L2Device *cio2 = data->cio2.output; V4L2Device *stat = data->imgu->stat; ImgUDevice *imgu = data->imgu; int ret; - if (data->cio2.pool.count() == 0) { - /* Share buffers between CIO2 output and ImgU input. */ - data->cio2.pool.createBuffers(IPU3_CIO2_BUFFER_COUNT); - ret = cio2->exportBuffers(&data->cio2.pool); - if (ret) { - LOG(IPU3, Error) << "Failed to reserve CIO2 memory"; - return ret; - } + /* Share buffers between CIO2 output and ImgU input. */ + data->cio2.pool.createBuffers(IPU3_CIO2_BUFFER_COUNT); + ret = cio2->exportBuffers(&data->cio2.pool); + if (ret) { + LOG(IPU3, Error) << "Failed to reserve CIO2 memory"; + return ret; + } - ret = input->importBuffers(&data->cio2.pool); - if (ret) { - LOG(IPU3, Error) << "Failed to import ImgU memory"; - return ret; - } + ret = input->importBuffers(&data->cio2.pool); + if (ret) { + LOG(IPU3, Error) << "Failed to import ImgU memory"; + return ret; + } - imgu->statPool.createBuffers(IPU3_IMGU_BUFFER_COUNT); - ret = stat->exportBuffers(&imgu->statPool); - if (ret) { - LOG(IPU3, Error) << "Failed to reserve ImgU stat memory"; - return ret; - } + imgu->statPool.createBuffers(IPU3_IMGU_BUFFER_COUNT); + ret = stat->exportBuffers(&imgu->statPool); + if (ret) { + LOG(IPU3, Error) << "Failed to reserve ImgU stat memory"; + return ret; } + return 0; +} + +int PipelineHandlerIPU3::allocateBuffers(Camera *camera, Stream *stream) +{ + IPU3CameraData *data = cameraData(camera); + V4L2Device *viewfinder = data->imgu->viewfinder; + V4L2Device *output = data->imgu->output; + ImgUDevice *imgu = data->imgu; + int ret; + if (isOutput(data, stream)) { /* Export ImgU output buffers to the stream's pool. */ ret = output->exportBuffers(&stream->bufferPool()); diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index 1a858f2638ce..1f556ed789b6 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -189,6 +189,24 @@ PipelineHandler::~PipelineHandler() * \return 0 on success or a negative error code otherwise */ +/** + * \fn PipelineHandler::preAllocateBuffers() + * \brief Perform operations to prepare for memory allocation. Optional for + * pipeline handlers to implement + * \param[in] camera The camera the streams belongs to + * \param[in] activeStreams The set of active streams + * + * If operations to prepare for the per-stream memory allocation are required, + * this virtual method provides an entry point for pipeline handlers to do so. + * + * This method is optional to implement for pipeline handlers, and its intended + * caller is the Camera class, which calls it once before performing per-stream + * memory allocation by calling the PipelineHandler::allocateBuffers() method + * once per each active stream. + * + * \return 0 on success or a negative error code otherwise + */ + /** * \fn PipelineHandler::allocateBuffers() * \brief Allocate buffers for a stream @@ -198,7 +216,8 @@ PipelineHandler::~PipelineHandler() * This method allocates buffers internally in the pipeline handler and * associates them with the stream's buffer pool. * - * The intended caller of this method is the Camera class. + * The intended caller of this method is the Camera class which calls it + * once per each active stream. * * \return 0 on success or a negative error code otherwise */ From patchwork Wed Mar 20 16:30:46 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 768 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id AD56A611B4 for ; Wed, 20 Mar 2019 17:30:41 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 4171320000D; Wed, 20 Mar 2019 16:30:41 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:46 +0100 Message-Id: <20190320163055.22056-23-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 22/31] RFC: libcamera: pipeline_handlers: Add postFreeBuffers 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: Wed, 20 Mar 2019 16:30:41 -0000 Add a postFreeBuffers virtual method to the PipelineHandler base class and call if after performing per-stream memory release. Implement the method in the IPU3 pipeline handler to perform memory release on the CIO2 unit and ImgU input and stat video nodes. Signed-off-by: Jacopo Mondi --- src/libcamera/camera.cpp | 2 + src/libcamera/include/pipeline_handler.h | 4 ++ src/libcamera/pipeline/ipu3/ipu3.cpp | 48 +++++++++++++++--------- src/libcamera/pipeline_handler.cpp | 19 +++++++++- 4 files changed, 54 insertions(+), 19 deletions(-) diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp index 8020dff8f8ea..cf618ec567fc 100644 --- a/src/libcamera/camera.cpp +++ b/src/libcamera/camera.cpp @@ -514,6 +514,8 @@ int Camera::freeBuffers() pipe_->freeBuffers(this, stream); } + pipe_->postFreeBuffers(this); + state_ = CameraConfigured; return 0; diff --git a/src/libcamera/include/pipeline_handler.h b/src/libcamera/include/pipeline_handler.h index 7ce5b67cc7fc..d3066550f1b7 100644 --- a/src/libcamera/include/pipeline_handler.h +++ b/src/libcamera/include/pipeline_handler.h @@ -64,6 +64,10 @@ public: } virtual int allocateBuffers(Camera *camera, Stream *stream) = 0; virtual int freeBuffers(Camera *camera, Stream *stream) = 0; + virtual int postFreeBuffers(Camera *camera) + { + return 0; + } virtual int start(Camera *camera) = 0; virtual void stop(Camera *camera); diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 5f323888d84f..ac2b14156d4f 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -109,6 +109,7 @@ public: const std::set &activeStreams) override; int allocateBuffers(Camera *camera, Stream *stream) override; int freeBuffers(Camera *camera, Stream *stream) override; + int postFreeBuffers(Camera *camera) override; int start(Camera *camera) override; void stop(Camera *camera) override; @@ -543,26 +544,8 @@ int PipelineHandlerIPU3::freeBuffers(Camera *camera, Stream *stream) IPU3CameraData *data = cameraData(camera); V4L2Device *viewfinder = data->imgu->viewfinder; V4L2Device *output = data->imgu->output; - V4L2Device *input = data->imgu->input; - V4L2Device *cio2 = data->cio2.output; - V4L2Device *stat = data->imgu->stat; int ret; - if (data->cio2.pool.count()) { - ret = input->releaseBuffers(); - if (ret) - LOG(IPU3, Error) << "Failed to release ImgU input memory"; - - ret = cio2->releaseBuffers(); - if (ret) - LOG(IPU3, Error) << "Failed to release CIO2 memory"; - - ret = stat->releaseBuffers(); - if (ret) - LOG(IPU3, Error) << "Failed to release ImgU stat memory"; - - } - if (isOutput(data, stream)) { ret = output->releaseBuffers(); if (ret) @@ -594,6 +577,35 @@ int PipelineHandlerIPU3::freeBuffers(Camera *camera, Stream *stream) return 0; } +int PipelineHandlerIPU3::postFreeBuffers(Camera *camera) +{ + IPU3CameraData *data = cameraData(camera); + V4L2Device *input = data->imgu->input; + V4L2Device *cio2 = data->cio2.output; + V4L2Device *stat = data->imgu->stat; + int retval = 0; + + int ret = input->releaseBuffers(); + if (ret) { + retval |= ret; + LOG(IPU3, Error) << "Failed to release ImgU input memory"; + } + + ret = cio2->releaseBuffers(); + if (ret) { + retval |= ret; + LOG(IPU3, Error) << "Failed to release CIO2 memory"; + } + + ret = stat->releaseBuffers(); + if (ret) { + retval |= ret; + LOG(IPU3, Error) << "Failed to release ImgU stat memory"; + } + + return retval; +} + int PipelineHandlerIPU3::start(Camera *camera) { IPU3CameraData *data = cameraData(camera); diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index 1f556ed789b6..d0dee64b9844 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -231,7 +231,24 @@ PipelineHandler::~PipelineHandler() * After a capture session has been stopped all buffers associated with the * stream shall be freed. * - * The intended caller of this method is the Camera class. + * The intended caller of this method is the Camera class which calls it + * once per each active stream. + * + * \return 0 on success or a negative error code otherwise + */ + +/** + * \fn PipelineHandler::postFreeBuffers() + * \brief Perform post-memory release operations. Optional for pipeline + * handlers to implement + * \param[in] camera The camera to release memory on + * + * If any clean up operation is required this virtual method provides an entry + * point for pipeline handlers to do so. + * + * The intended caller of this method is the Camera class, which call it once + * after performing per-stream memory release by calling + * PipelineHandler::freeBuffers() on each active stream. * * \return 0 on success or a negative error code otherwise */ From patchwork Wed Mar 20 16:30:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 769 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4485561391 for ; Wed, 20 Mar 2019 17:30:42 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id D0DF5200012; Wed, 20 Mar 2019 16:30:41 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:47 +0100 Message-Id: <20190320163055.22056-24-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 23/31] libcamera: ipu3: Enable media links conditionally 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: Wed, 20 Mar 2019 16:30:43 -0000 Add a method to the IPU3 pipeline handler class to enable media links on the ImgU device conditionally to the requested stream configuration. FIXME: media links for viewfinder and stat node should be enabled unconditionally. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 128 +++++++++++++++------------ 1 file changed, 71 insertions(+), 57 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index ac2b14156d4f..ff1e5329c83d 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -55,7 +55,6 @@ public: int linkSetup(const std::string &source, unsigned int sourcePad, const std::string &sink, unsigned int sinkPad, bool enable); - int enableLinks(bool enable); unsigned int index_; std::string imguName_; @@ -201,6 +200,8 @@ private: int initImgU(ImgUDevice *imgu); + int enableImgULinks(IPU3CameraData *data, bool enable); + int setInputFormat(ImgUDevice *imguDevice, const StreamConfiguration &config, Rectangle *rect); @@ -364,11 +365,8 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, CIO2Config.height = cfg.height; } - /* - * \todo: Enable links selectively based on the requested streams. - * As of now, enable all links unconditionally. - */ - ret = data->imgu->enableLinks(true); + /* Enable links selectively based on the requested streams. */ + ret = enableImgULinks(data, true); if (ret) return ret; @@ -873,57 +871,6 @@ int ImgUDevice::linkSetup(const std::string &source, unsigned int sourcePad, return link->setEnabled(enable); } -/** - * \brief Enable or disable all media links in the ImgU instance to prepare - * for capture operations - * - * \todo This method will probably be removed or changed once links will be - * enabled or disabled selectively. - * - * \return 0 on success or a negative error code otherwise - */ -int ImgUDevice::enableLinks(bool enable) -{ - std::string inputName = imguName_ + " input"; - std::string outputName = imguName_ + " output"; - std::string viewfinderName = imguName_ + " viewfinder"; - std::string statName = imguName_ + " 3a stat"; - int ret; - - /* \todo Establish rules to handle media devices open/close. */ - ret = mediaDevice_->open(); - if (ret) - return ret; - - ret = linkSetup(inputName, 0, imguName_, PAD_INPUT, enable); - if (ret) { - mediaDevice_->close(); - return ret; - } - - ret = linkSetup(imguName_, PAD_OUTPUT, outputName, 0, enable); - if (ret) { - mediaDevice_->close(); - return ret; - } - - ret = linkSetup(imguName_, PAD_VF, viewfinderName, 0, enable); - if (ret) { - mediaDevice_->close(); - return ret; - } - - ret = linkSetup(imguName_, PAD_STAT, statName, 0, enable); - if (ret) { - mediaDevice_->close(); - return ret; - } - - mediaDevice_->close(); - - return 0; -} - int PipelineHandlerIPU3::mediaBusToCIO2Format(unsigned int code) { switch (code) { @@ -1152,6 +1099,73 @@ void PipelineHandlerIPU3::deleteCIO2(CIO2Device *cio2) delete cio2->sensor; } +/** + * \brief Enable links on the ImgU media graph based on the requested + * stream configuration + * + * FIXME: viewfinder and stat should be enabled conditionally on the requested + * stream configuration. As of now, the IPU3 driver requires them to be + * operated unconditionally not to stall ImgU operations. + * + * \return 0 on success or a negative error code otherwise + */ +int PipelineHandlerIPU3::enableImgULinks(IPU3CameraData *data, bool enable) +{ + ImgUDevice *imgu = data->imgu; + std::string inputName = imgu->imguName_ + " input"; + std::string outputName = imgu->imguName_ + " output"; + std::string viewfinderName = imgu->imguName_ + " viewfinder"; + std::string statName = imgu->imguName_ + " 3a stat"; + MediaDevice *media = imgu->mediaDevice_; + int ret; + + /* \todo Establish rules to handle media devices open/close. */ + ret = media->open(); + if (ret) + return ret; + + ret = imgu->linkSetup(inputName, 0, imgu->imguName_, + ImgUDevice::PAD_INPUT, enable); + if (ret) { + media->close(); + return ret; + } + + /* Output has to be operated unconditionally. */ + ret = imgu->linkSetup(imgu->imguName_, ImgUDevice::PAD_OUTPUT, + outputName, 0, enable); + if (ret) { + media->close(); + return ret; + } + + /* + * FIXME: viewfinder should be linked and operated only if required + * but currently the IPU3 driver requires it regardless of the stream + * configuration. + */ + if (isViewfinderActive(data) || true) { + ret = imgu->linkSetup(imgu->imguName_, ImgUDevice::PAD_VF, + viewfinderName, 0, enable); + if (ret) { + media->close(); + return ret; + } + } + + /* FIXME: stat should be conditionally operated as well. */ + ret = imgu->linkSetup(imgu->imguName_, ImgUDevice::PAD_STAT, + statName, 0, enable); + if (ret) { + media->close(); + return ret; + } + + media->close(); + + return 0; +} + int PipelineHandlerIPU3::setInputFormat(ImgUDevice *imguDevice, const StreamConfiguration &config, Rectangle *rect) From patchwork Wed Mar 20 16:30:48 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 770 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D9826611B4 for ; Wed, 20 Mar 2019 17:30:42 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 7109E200010; Wed, 20 Mar 2019 16:30:42 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:48 +0100 Message-Id: <20190320163055.22056-25-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 24/31] libcamera: ipu3: Queue request for multiple streams 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: Wed, 20 Mar 2019 16:30:43 -0000 Add support for queue request on the main and secondary outputs of the ImgU. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 46 ++++++++++++++++------------ 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index ff1e5329c83d..b2df9a4ac922 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -689,38 +689,46 @@ void PipelineHandlerIPU3::stop(Camera *camera) int PipelineHandlerIPU3::queueRequest(Camera *camera, Request *request) { + std::set streams = request->streams(); IPU3CameraData *data = cameraData(camera); V4L2Device *viewfinder = data->imgu->viewfinder; V4L2Device *output = data->imgu->output; V4L2Device *stat = data->imgu->stat; - Stream *stream = &data->streams_[0]; + ImgUDevice *imgu = data->imgu; Buffer *tmpBuffer; - /* - * Queue buffer on VF and stat. - * FIXME: this is an hack! - */ - tmpBuffer = &data->imgu->vfPool.buffers()[tmpBufferCount]; - viewfinder->queueBuffer(tmpBuffer); + for (Stream *stream : streams) { + Buffer *buffer = request->findBuffer(stream); + if (!buffer) { + LOG(IPU3, Error) << "Attempt to queue invalid request"; + return -ENOENT; + } + + V4L2Device *videoDevice = isOutput(data, stream) + ? output : viewfinder; + + int ret = videoDevice->queueBuffer(buffer); + if (ret < 0) + return ret; + + if (isOutput(data, stream) && !isViewfinderActive(data)) { + tmpBuffer = &imgu->vfPool.buffers()[tmpBufferCount]; + viewfinder->queueBuffer(tmpBuffer); + } + if (isViewfinder(data, stream) && !isOutputActive(data)) { + tmpBuffer = &imgu->outputPool.buffers()[tmpBufferCount]; + output->queueBuffer(tmpBuffer); + } + } + + /* Queue buffer on stat unconditionally. */ tmpBuffer = &data->imgu->statPool.buffers()[tmpBufferCount]; stat->queueBuffer(tmpBuffer); tmpBufferCount++; tmpBufferCount %= IPU3_IMGU_BUFFER_COUNT; - /* Queue a buffer to the ImgU output for capture. */ - Buffer *buffer = request->findBuffer(stream); - if (!buffer) { - LOG(IPU3, Error) - << "Attempt to queue request with invalid stream"; - return -ENOENT; - } - - int ret = output->queueBuffer(buffer); - if (ret < 0) - return ret; - PipelineHandler::queueRequest(camera, request); return 0; From patchwork Wed Mar 20 16:30:49 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 771 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C30CD61373 for ; Wed, 20 Mar 2019 17:30:43 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 5B0A1200009; Wed, 20 Mar 2019 16:30:43 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:49 +0100 Message-Id: <20190320163055.22056-26-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 25/31] libcamera: ipu3: Connect viewfinder's BufferReady signal 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: Wed, 20 Mar 2019 16:30:44 -0000 Connect the viewfinder buffer ready signal to the IPU3CameraData slot that complets the buffer first, and if not waiting for other buffers completes the request as well. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index b2df9a4ac922..db1ec2a7c3e2 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -135,7 +135,7 @@ private: { } - void imguOutputBufferReady(Buffer *buffer); + void imguCaptureBufferReady(Buffer *buffer); void imguInputBufferReady(Buffer *buffer); void cio2BufferReady(Buffer *buffer); @@ -621,8 +621,13 @@ int PipelineHandlerIPU3::start(Camera *camera) &IPU3CameraData::cio2BufferReady); data->imgu->input->bufferReady.connect(data, &IPU3CameraData::imguInputBufferReady); - data->imgu->output->bufferReady.connect(data, - &IPU3CameraData::imguOutputBufferReady); + + if (isOutputActive(data)) + data->imgu->output->bufferReady.connect(data, + &IPU3CameraData::imguCaptureBufferReady); + if (isViewfinderActive(data)) + data->imgu->viewfinder->bufferReady.connect(data, + &IPU3CameraData::imguCaptureBufferReady); /* * Enqueue all available buffers to the CIO2 unit to start frame @@ -1434,17 +1439,19 @@ void PipelineHandlerIPU3::IPU3CameraData::imguInputBufferReady(Buffer *buffer) } /** - * \brief ImgU output BufferReady slot + * \brief ImgU main and secondary output BufferReady slot * \param buffer The completed buffer * - * Buffer completed from the ImgU output are directed to the applications. + * Buffer completed from the ImgU main and secondary outputs are directed to + * the applications. */ -void PipelineHandlerIPU3::IPU3CameraData::imguOutputBufferReady(Buffer *buffer) +void PipelineHandlerIPU3::IPU3CameraData::imguCaptureBufferReady(Buffer *buffer) { Request *request = queuedRequests_.front(); - pipe_->completeBuffer(camera_, request, buffer); - pipe_->completeRequest(camera_, request); + /* TODO: this will probably need locking. */ + if (pipe_->completeBuffer(camera_, request, buffer)) + pipe_->completeRequest(camera_, request); } /** From patchwork Wed Mar 20 16:30:50 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 772 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 603B0611A2 for ; Wed, 20 Mar 2019 17:30:44 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 01A3E20000F; Wed, 20 Mar 2019 16:30:43 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:50 +0100 Message-Id: <20190320163055.22056-27-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 26/31] HACK: cam: Allow camera with multiple streams 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: Wed, 20 Mar 2019 16:30:45 -0000 Signed-off-by: Jacopo Mondi --- src/cam/main.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/cam/main.cpp b/src/cam/main.cpp index 1ca7862bf237..9257f391988b 100644 --- a/src/cam/main.cpp +++ b/src/cam/main.cpp @@ -240,14 +240,6 @@ int main(int argc, char **argv) goto out; } - const std::set &streams = camera->streams(); - if (streams.size() != 1) { - std::cout << "Camera has " << streams.size() - << " streams, only 1 is supported" - << std::endl; - goto out; - } - if (camera->acquire()) { std::cout << "Failed to acquire camera" << std::endl; goto out; From patchwork Wed Mar 20 16:30:51 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 773 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 04A9F611AA for ; Wed, 20 Mar 2019 17:30:45 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 8BA2B200003; Wed, 20 Mar 2019 16:30:44 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:51 +0100 Message-Id: <20190320163055.22056-28-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 27/31] src: cam: Create requests with multiple streams 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: Wed, 20 Mar 2019 16:30:45 -0000 Add support for multiple streams to request creation and enqueuing to the 'capture()' method of the cam test application. Signed-off-by: Jacopo Mondi --- src/cam/main.cpp | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/cam/main.cpp b/src/cam/main.cpp index 9257f391988b..201dbda765fe 100644 --- a/src/cam/main.cpp +++ b/src/cam/main.cpp @@ -144,8 +144,6 @@ static int capture() return ret; } - Stream *stream = *streams.begin(); - ret = camera->allocateBuffers(); if (ret) { std::cerr << "Failed to allocate buffers" @@ -153,11 +151,14 @@ static int capture() return ret; } - camera->requestCompleted.connect(requestComplete); - - BufferPool &pool = stream->bufferPool(); - - for (Buffer &buffer : pool.buffers()) { + /* + * Create the requests to be later enqueued. + * + * FIXME: Assume all streams have the same number of buffers: use + * the first stream's buffer pool and create on request per buffer. + */ + unsigned int bufferCount = (*streams.begin())->bufferPool().count(); + for (unsigned int i = 0; i < bufferCount; ++i) { Request *request = camera->createRequest(); if (!request) { std::cerr << "Can't create request" << std::endl; @@ -165,9 +166,14 @@ static int capture() goto out; } - std::map map; - map[stream] = &buffer; - ret = request->setBuffers(map); + /* Provide to each request a stream to buffer association map. */ + std::map requestMap; + for (Stream *stream : streams) { + Buffer *buffer = &stream->bufferPool().buffers()[i]; + requestMap[stream] = buffer; + } + + ret = request->setBuffers(requestMap); if (ret < 0) { std::cerr << "Can't set buffers for request" << std::endl; goto out; @@ -176,6 +182,8 @@ static int capture() requests.push_back(request); } + camera->requestCompleted.connect(requestComplete); + ret = camera->start(); if (ret) { std::cout << "Failed to start capture" << std::endl; From patchwork Wed Mar 20 16:30:52 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 774 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C73AD611AA for ; Wed, 20 Mar 2019 17:30:45 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 25DE4200015; Wed, 20 Mar 2019 16:30:44 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:52 +0100 Message-Id: <20190320163055.22056-29-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 28/31] src: cam: Add output name to frame writer 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: Wed, 20 Mar 2019 16:30:46 -0000 Add a parameter to the frame writer 'write()' method to allow specify which output the frame has been produced from. Signed-off-by: Jacopo Mondi --- src/cam/buffer_writer.cpp | 4 ++-- src/cam/buffer_writer.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cam/buffer_writer.cpp b/src/cam/buffer_writer.cpp index 2d2258b4cd1c..2d99d2d40c16 100644 --- a/src/cam/buffer_writer.cpp +++ b/src/cam/buffer_writer.cpp @@ -19,13 +19,13 @@ BufferWriter::BufferWriter(const std::string &pattern) { } -int BufferWriter::write(libcamera::Buffer *buffer) +int BufferWriter::write(libcamera::Buffer *buffer, const std::string &name) { std::string filename; size_t pos; int fd, ret = 0; - filename = pattern_; + filename = pattern_ + "-" + name; pos = filename.find_first_of('#'); if (pos != std::string::npos) { std::stringstream ss; diff --git a/src/cam/buffer_writer.h b/src/cam/buffer_writer.h index 9705773e0e39..62d6fbeed403 100644 --- a/src/cam/buffer_writer.h +++ b/src/cam/buffer_writer.h @@ -16,7 +16,7 @@ class BufferWriter public: BufferWriter(const std::string &pattern = "frame-#.bin"); - int write(libcamera::Buffer *buffer); + int write(libcamera::Buffer *buffer, const std::string &name); private: std::string pattern_; From patchwork Wed Mar 20 16:30:53 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 775 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 614496135F for ; Wed, 20 Mar 2019 17:30:46 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id F050620000F; Wed, 20 Mar 2019 16:30:45 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:53 +0100 Message-Id: <20190320163055.22056-30-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 29/31] src: cam: Handle multiple streams in request complete 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: Wed, 20 Mar 2019 16:30:47 -0000 Add support for requests with multiple streams in 'requestComplete()' method. Each stream content is optionally dumped to disk with its output name. Signed-off-by: Jacopo Mondi --- src/cam/main.cpp | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/src/cam/main.cpp b/src/cam/main.cpp index 201dbda765fe..a2364ef92bad 100644 --- a/src/cam/main.cpp +++ b/src/cam/main.cpp @@ -98,28 +98,40 @@ static int configureStreams(Camera *camera, std::set &streams) return camera->configureStreams(config); } -static void requestComplete(Request *request, const std::map &buffers) +static void requestComplete(Request *request, + const std::map &streamMap) { static uint64_t last = 0; if (request->status() == Request::RequestCancelled) return; - Buffer *buffer = buffers.begin()->second; - - double fps = buffer->timestamp() - last; - fps = last && fps ? 1000000000.0 / fps : 0.0; - last = buffer->timestamp(); + Camera *camera = request->camera(); + std::set streams = camera->streams(); + for (const auto &completedStream : streamMap) { + Stream *stream = completedStream.first; + Buffer *buffer = completedStream.second; + + /* Dump the buffer content! */ + double fps = buffer->timestamp() - last; + fps = last && fps ? 1000000000.0 / fps : 0.0; + last = buffer->timestamp(); + + std::string streamName = stream == (*streams.begin()) ? + "output" : "viewfinder"; + std::cout << "stream: " << streamName + << " seq: " << std::setw(6) << std::setfill('0') + << buffer->sequence() + << " buf: " << buffer->index() + << " bytesused: " << buffer->bytesused() + << " timestamp: " << buffer->timestamp() + << " fps: " << std::fixed << std::setprecision(2) << fps + << std::endl; - std::cout << "seq: " << std::setw(6) << std::setfill('0') << buffer->sequence() - << " buf: " << buffer->index() - << " bytesused: " << buffer->bytesused() - << " timestamp: " << buffer->timestamp() - << " fps: " << std::fixed << std::setprecision(2) << fps - << std::endl; - if (writer) - writer->write(buffer); + if (writer) + writer->write(buffer, streamName); + } request = camera->createRequest(); if (!request) { @@ -127,7 +139,7 @@ static void requestComplete(Request *request, const std::map return; } - request->setBuffers(buffers); + request->setBuffers(streamMap); camera->queueRequest(request); } From patchwork Wed Mar 20 16:30:54 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 776 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 01C82611A2 for ; Wed, 20 Mar 2019 17:30:47 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 8DEB6200011; Wed, 20 Mar 2019 16:30:46 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:54 +0100 Message-Id: <20190320163055.22056-31-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 30/31] HACK: src: cam: Play with streams combinations 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: Wed, 20 Mar 2019 16:30:47 -0000 Make the 'configureStreams()' method of the camera application accept a map of stream configuration to be used to create and fill requests. This allow to easily change which streams to capture from. while at there, hardcode the viewfinder output size to 640x480 to demostrate the two output can have different resolutions. This commit is clearly an hack and shall be removed once it is possible to specify per-stream configuration from the command line. Signed-off-by: Jacopo Mondi --- src/cam/main.cpp | 48 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/src/cam/main.cpp b/src/cam/main.cpp index a2364ef92bad..28ea0b7d76b2 100644 --- a/src/cam/main.cpp +++ b/src/cam/main.cpp @@ -75,26 +75,40 @@ static int parseOptions(int argc, char *argv[]) return 0; } -static int configureStreams(Camera *camera, std::set &streams) +static int configureStreams(Camera *camera, std::set &streams, + std::map &config) { KeyValueParser::Options format = options[OptFormat]; - Stream *id = *streams.begin(); + auto it = streams.begin(); + Stream *output = *it; + Stream *viewfinder = *(++it); - std::map config = + std::map defaultConfig = camera->streamConfiguration(streams); if (options.isSet(OptFormat)) { if (format.isSet("width")) - config[id].width = format["width"]; + defaultConfig[output].width = format["width"]; if (format.isSet("height")) - config[id].height = format["height"]; + defaultConfig[output].height = format["height"]; /* TODO: Translate 4CC string to ID. */ if (format.isSet("pixelformat")) - config[id].pixelFormat = format["pixelformat"]; + defaultConfig[output].pixelFormat = format["pixelformat"]; } + /* Configure the secondary output stream. */ + defaultConfig[viewfinder].width = 640; + defaultConfig[viewfinder].height = 480; + + /* + * HACK: add output/viewfinder to 'config' + * to play with stream combinations. + */ + config[output] = defaultConfig[output]; + config[viewfinder] = defaultConfig[viewfinder]; + return camera->configureStreams(config); } @@ -145,17 +159,21 @@ static void requestComplete(Request *request, static int capture() { + std::set cameraStreams = camera->streams(); + std::map config; int ret; - std::set streams = camera->streams(); - std::vector requests; - - ret = configureStreams(camera.get(), streams); + ret = configureStreams(camera.get(), cameraStreams, config); if (ret < 0) { std::cout << "Failed to configure camera" << std::endl; return ret; } + if (config.empty()) { + std::cout << "Stream configuration is empty" << std::endl; + return ret; + } + ret = camera->allocateBuffers(); if (ret) { std::cerr << "Failed to allocate buffers" @@ -163,13 +181,19 @@ static int capture() return ret; } + /* Store only the active streams. */ + std::set activeStreams; + for (const auto &iter : config) + activeStreams.insert(iter.first); + /* * Create the requests to be later enqueued. * * FIXME: Assume all streams have the same number of buffers: use * the first stream's buffer pool and create on request per buffer. */ - unsigned int bufferCount = (*streams.begin())->bufferPool().count(); + std::vector requests; + unsigned int bufferCount = (*activeStreams.begin())->bufferPool().count(); for (unsigned int i = 0; i < bufferCount; ++i) { Request *request = camera->createRequest(); if (!request) { @@ -180,7 +204,7 @@ static int capture() /* Provide to each request a stream to buffer association map. */ std::map requestMap; - for (Stream *stream : streams) { + for (Stream *stream : activeStreams) { Buffer *buffer = &stream->bufferPool().buffers()[i]; requestMap[stream] = buffer; } From patchwork Wed Mar 20 16:30:55 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 777 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 95AC4611A2 for ; Wed, 20 Mar 2019 17:30:47 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 2E3A9200003; Wed, 20 Mar 2019 16:30:47 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 20 Mar 2019 17:30:55 +0100 Message-Id: <20190320163055.22056-32-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190320163055.22056-1-jacopo@jmondi.org> References: <20190320163055.22056-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 31/31] HACK: cam: Add options to select the stream to use 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: Wed, 20 Mar 2019 16:30:47 -0000 Add -o and -v options switches to the cam application to select which streams to capture from. Signed-off-by: Jacopo Mondi --- src/cam/main.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/cam/main.cpp b/src/cam/main.cpp index 28ea0b7d76b2..8c5d55d11bbe 100644 --- a/src/cam/main.cpp +++ b/src/cam/main.cpp @@ -31,6 +31,8 @@ enum { OptFormat = 'f', OptHelp = 'h', OptList = 'l', + OptOutput = 'o', + OptViefinder = 'v', }; void signalHandler(int signal) @@ -65,6 +67,12 @@ static int parseOptions(int argc, char *argv[]) parser.addOption(OptHelp, OptionNone, "Display this help message", "help"); parser.addOption(OptList, OptionNone, "List all cameras", "list"); + parser.addOption(OptOutput, OptionNone, "Use output stream\n" + "If no '-o' or '-v' options are specified, use viewfinder stream only", + "list"); + parser.addOption(OptViefinder, OptionNone, "Use viewfinder stream\n" + "If no '-o' or '-v' options are specified, use viewfinder stream only", + "list"); options = parser.parse(argc, argv); if (!options.valid() || options.isSet(OptHelp)) { @@ -103,11 +111,15 @@ static int configureStreams(Camera *camera, std::set &streams, defaultConfig[viewfinder].height = 480; /* - * HACK: add output/viewfinder to 'config' - * to play with stream combinations. + * HACK: Select which stream to capture: use output if required, + * use viewfinder if required or if no option has been specified + * from the command line. */ - config[output] = defaultConfig[output]; - config[viewfinder] = defaultConfig[viewfinder]; + if (options.isSet(OptOutput)) + config[output] = defaultConfig[output]; + if (options.isSet(OptViefinder) || + (!options.isSet(OptViefinder) && !options.isSet(OptOutput))) + config[viewfinder] = defaultConfig[viewfinder]; return camera->configureStreams(config); }