From patchwork Tue Mar 26 08:38:44 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 796 Return-Path: Received: from relay10.mail.gandi.net (relay10.mail.gandi.net [217.70.178.230]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 25E91610D5 for ; Tue, 26 Mar 2019 09:38:30 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay10.mail.gandi.net (Postfix) with ESMTPSA id 452C724000D; Tue, 26 Mar 2019 08:38:29 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 26 Mar 2019 09:38:44 +0100 Message-Id: <20190326083902.26121-2-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190326083902.26121-1-jacopo@jmondi.org> References: <20190326083902.26121-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 01/19] 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: Tue, 26 Mar 2019 08:38:30 -0000 Add toString() helpers to pretty print out a V4L2Device or V4L2Subdevice format. Reviewed-by: Laurent Pinchart Reviewed-by: Kieran Bingham Signed-off-by: Jacopo Mondi Reviewed-by: Niklas Söderlund --- 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..93d81517fedb 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..cf873487b22c 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 Tue Mar 26 08:38:45 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 797 Return-Path: Received: from relay10.mail.gandi.net (relay10.mail.gandi.net [217.70.178.230]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3D79461113 for ; Tue, 26 Mar 2019 09:38:31 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay10.mail.gandi.net (Postfix) with ESMTPSA id 5065C240016; Tue, 26 Mar 2019 08:38:30 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 26 Mar 2019 09:38:45 +0100 Message-Id: <20190326083902.26121-3-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190326083902.26121-1-jacopo@jmondi.org> References: <20190326083902.26121-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 02/19] 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: Tue, 26 Mar 2019 08:38:31 -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: Laurent Pinchart Reviewed-by: Kieran Bingham Signed-off-by: Jacopo Mondi Reviewed-by: Niklas Söderlund --- 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..56f4ddb51ffa --- /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 format (for memory + * formats) or a media bus code (for bus 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 cf873487b22c..8260e6ebce0e 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 Tue Mar 26 08:38: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: 798 Return-Path: Received: from relay10.mail.gandi.net (relay10.mail.gandi.net [217.70.178.230]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id DAADD611A7 for ; Tue, 26 Mar 2019 09:38:31 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay10.mail.gandi.net (Postfix) with ESMTPSA id 626EA24000C; Tue, 26 Mar 2019 08:38:31 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 26 Mar 2019 09:38:46 +0100 Message-Id: <20190326083902.26121-4-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190326083902.26121-1-jacopo@jmondi.org> References: <20190326083902.26121-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 03/19] libcamera: geometry: Add 0-initialized SizeRange constructor 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: Tue, 26 Mar 2019 08:38:32 -0000 Add constructor to SizeRange which initialize all the size range fields to 0. While at there make the in-line constructor declarations respect the coding style by moving braces to a new line. Signed-off-by: Jacopo Mondi --- src/libcamera/geometry.cpp | 11 ++++++++++- src/libcamera/include/geometry.h | 9 ++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/libcamera/geometry.cpp b/src/libcamera/geometry.cpp index b6b6592bdfec..dbc37ca8e3f4 100644 --- a/src/libcamera/geometry.cpp +++ b/src/libcamera/geometry.cpp @@ -57,7 +57,16 @@ namespace libcamera { /** * \fn SizeRange::SizeRange() - * \brief Construct a size range + * \brief Construct a size range initialized to 0 + */ + +/** + * \fn SizeRange::SizeRange(unsigned int minW, unsigned int minH, unsigned int maxW, unsigned int maxH) + * \brief Construct an initialized size range + * \param minW The minimum width + * \param minH The minimum height + * \param maxW The maximum width + * \param maxH The maximum height */ /** diff --git a/src/libcamera/include/geometry.h b/src/libcamera/include/geometry.h index eadc4ed4f9cb..749746495204 100644 --- a/src/libcamera/include/geometry.h +++ b/src/libcamera/include/geometry.h @@ -18,10 +18,17 @@ struct Rectangle { }; struct SizeRange { + SizeRange(void) + : SizeRange(0, 0, 0, 0) + { + } + SizeRange(unsigned int minW, unsigned int minH, unsigned int maxW, unsigned int maxH) : minWidth(minW), minHeight(minH), maxWidth(maxW), - maxHeight(maxH) {} + maxHeight(maxH) + { + } unsigned int minWidth; unsigned int minHeight; From patchwork Tue Mar 26 08:38: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: 799 Return-Path: Received: from relay10.mail.gandi.net (relay10.mail.gandi.net [217.70.178.230]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 85989611A7 for ; Tue, 26 Mar 2019 09:38:32 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay10.mail.gandi.net (Postfix) with ESMTPSA id 12826240014; Tue, 26 Mar 2019 08:38:31 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 26 Mar 2019 09:38:47 +0100 Message-Id: <20190326083902.26121-5-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190326083902.26121-1-jacopo@jmondi.org> References: <20190326083902.26121-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 04/19] libcamera: geometry: Add toString to Rectangle 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: Tue, 26 Mar 2019 08:38:32 -0000 Add toString() helpers to pretty print out the sizes of a Rectangle. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/libcamera/geometry.cpp | 16 ++++++++++++++++ src/libcamera/include/geometry.h | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/src/libcamera/geometry.cpp b/src/libcamera/geometry.cpp index dbc37ca8e3f4..f76001d94562 100644 --- a/src/libcamera/geometry.cpp +++ b/src/libcamera/geometry.cpp @@ -5,6 +5,8 @@ * geometry.cpp - Geometry-related structures */ +#include + #include "geometry.h" /** @@ -46,6 +48,20 @@ namespace libcamera { * \brief The distance between the top and bottom sides */ +/** + * \brief Assemble and return a string describing the rectangle + * + * \return A string describing the Rectangle + */ +const std::string Rectangle::toString() const +{ + std::stringstream ss; + + ss << "(" << x << "x" << y << ")/" << w << "x" << h; + + return ss.str(); +} + /** * \struct SizeRange * \brief Describe a range of image sizes diff --git a/src/libcamera/include/geometry.h b/src/libcamera/include/geometry.h index 749746495204..567a54299b24 100644 --- a/src/libcamera/include/geometry.h +++ b/src/libcamera/include/geometry.h @@ -8,6 +8,8 @@ #ifndef __LIBCAMERA_GEOMETRY_H__ #define __LIBCAMERA_GEOMETRY_H__ +#include + namespace libcamera { struct Rectangle { @@ -15,6 +17,8 @@ struct Rectangle { int y; unsigned int w; unsigned int h; + + const std::string toString() const; }; struct SizeRange { From patchwork Tue Mar 26 08:38: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: 800 Return-Path: Received: from relay10.mail.gandi.net (relay10.mail.gandi.net [217.70.178.230]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3B0E961113 for ; Tue, 26 Mar 2019 09:38:33 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay10.mail.gandi.net (Postfix) with ESMTPSA id ADE6B240005; Tue, 26 Mar 2019 08:38:32 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 26 Mar 2019 09:38:48 +0100 Message-Id: <20190326083902.26121-6-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190326083902.26121-1-jacopo@jmondi.org> References: <20190326083902.26121-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 05/19] libcamera: v4l2_subdevice: Rename deviceName() 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: Tue, 26 Mar 2019 08:38:33 -0000 Rename the 'deviceName()' method to 'entityName()' as it actually returns the name of the entity backing the v4l2 subdevice. While at it, make the names getter methods return a const reference instead of returning by copy. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/libcamera/include/v4l2_subdevice.h | 4 ++-- src/libcamera/v4l2_subdevice.cpp | 4 ++-- test/v4l2_subdevice/list_formats.cpp | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libcamera/include/v4l2_subdevice.h b/src/libcamera/include/v4l2_subdevice.h index 3ecf08514898..f42cccabda94 100644 --- a/src/libcamera/include/v4l2_subdevice.h +++ b/src/libcamera/include/v4l2_subdevice.h @@ -37,8 +37,8 @@ public: bool isOpen() const; void close(); - std::string deviceNode() const { return entity_->deviceNode(); } - std::string deviceName() const { return entity_->name(); } + const std::string &deviceNode() const { return entity_->deviceNode(); } + const std::string &entityName() const { return entity_->name(); } int setCrop(unsigned int pad, Rectangle *rect); int setCompose(unsigned int pad, Rectangle *rect); diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index 8260e6ebce0e..10925f9fe497 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -166,7 +166,7 @@ void V4L2Subdevice::close() */ /** - * \fn V4L2Subdevice::deviceName() + * \fn V4L2Subdevice::entityName() * \brief Retrieve the name of the media entity associated with the subdevice * * \return The name of the media entity the subdevice is associated to @@ -315,7 +315,7 @@ int V4L2Subdevice::setFormat(unsigned int pad, V4L2SubdeviceFormat *format) std::string V4L2Subdevice::logPrefix() const { - return "'" + deviceName() + "'"; + return "'" + entityName() + "'"; } int V4L2Subdevice::enumPadSizes(unsigned int pad,unsigned int code, diff --git a/test/v4l2_subdevice/list_formats.cpp b/test/v4l2_subdevice/list_formats.cpp index bf8597797d4b..db486554b7b5 100644 --- a/test/v4l2_subdevice/list_formats.cpp +++ b/test/v4l2_subdevice/list_formats.cpp @@ -51,7 +51,7 @@ int ListFormatsTest::run() formats = scaler_->formats(0); if (formats.empty()) { cerr << "Failed to list formats on pad 0 of subdevice " - << scaler_->deviceName() << endl; + << scaler_->entityName() << endl; return TestFail; } for (auto it = formats.begin(); it != formats.end(); ++it) @@ -60,7 +60,7 @@ int ListFormatsTest::run() formats = scaler_->formats(1); if (formats.empty()) { cerr << "Failed to list formats on pad 1 of subdevice " - << scaler_->deviceName() << endl; + << scaler_->entityName() << endl; return TestFail; } for (auto it = formats.begin(); it != formats.end(); ++it) @@ -70,7 +70,7 @@ int ListFormatsTest::run() formats = scaler_->formats(2); if (!formats.empty()) { cerr << "Listing formats on non-existing pad 2 of subdevice " - << scaler_->deviceName() + << scaler_->entityName() << " should return an empty format list" << endl; return TestFail; } From patchwork Tue Mar 26 08:38: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: 801 Return-Path: Received: from relay10.mail.gandi.net (relay10.mail.gandi.net [217.70.178.230]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0FF6961111 for ; Tue, 26 Mar 2019 09:38:34 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay10.mail.gandi.net (Postfix) with ESMTPSA id 770CC24000A; Tue, 26 Mar 2019 08:38:33 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 26 Mar 2019 09:38:49 +0100 Message-Id: <20190326083902.26121-7-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190326083902.26121-1-jacopo@jmondi.org> References: <20190326083902.26121-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 06/19] libcamera: v4l2_device: Create device from entity name 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: Tue, 26 Mar 2019 08:38:34 -0000 Add a static method to V4L2Device class to create a V4L2Device instance from a media entity name. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/libcamera/include/v4l2_device.h | 4 ++++ src/libcamera/v4l2_device.cpp | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/libcamera/include/v4l2_device.h b/src/libcamera/include/v4l2_device.h index 258deee8d461..482d7891dd49 100644 --- a/src/libcamera/include/v4l2_device.h +++ b/src/libcamera/include/v4l2_device.h @@ -22,6 +22,7 @@ namespace libcamera { class Buffer; class BufferPool; class EventNotifier; +class MediaDevice; class MediaEntity; struct V4L2Capability final : v4l2_capability { @@ -107,6 +108,9 @@ public: class V4L2Device : protected Loggable { public: + static V4L2Device *fromEntityName(const MediaDevice *media, + const std::string &name); + explicit V4L2Device(const std::string &deviceNode); explicit V4L2Device(const MediaEntity *entity); V4L2Device(const V4L2Device &) = delete; diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp index 93d81517fedb..68be5a064258 100644 --- a/src/libcamera/v4l2_device.cpp +++ b/src/libcamera/v4l2_device.cpp @@ -19,6 +19,7 @@ #include #include "log.h" +#include "media_device.h" #include "media_object.h" #include "v4l2_device.h" @@ -264,6 +265,27 @@ const std::string V4L2DeviceFormat::toString() const * released. */ +/** + * \brief Create a new video device instance from entity with \a name in + * media device \a media + * \param[in] media The media device where the entity is registered + * \param[in] name The media entity name + * + * Releasing memory of the newly created instance is responsibility of the + * caller of this function. + * + * \return A newly created V4L2Device on success, nullptr otherwise + */ +V4L2Device *V4L2Device::fromEntityName(const MediaDevice *media, + const std::string &name) +{ + MediaEntity *entity = media->getEntityByName(name); + if (!entity) + return nullptr; + + return new V4L2Device(entity); +} + /** * \brief Construct a V4L2Device * \param deviceNode The file-system path to the video device node From patchwork Tue Mar 26 08:38: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: 802 Return-Path: Received: from relay10.mail.gandi.net (relay10.mail.gandi.net [217.70.178.230]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BE49961111 for ; Tue, 26 Mar 2019 09:38:34 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay10.mail.gandi.net (Postfix) with ESMTPSA id 392A024000A; Tue, 26 Mar 2019 08:38:34 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 26 Mar 2019 09:38:50 +0100 Message-Id: <20190326083902.26121-8-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190326083902.26121-1-jacopo@jmondi.org> References: <20190326083902.26121-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 07/19] libcamera: v4l2_subdevice: Create device from entity name 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: Tue, 26 Mar 2019 08:38:35 -0000 Add a static method to V4L2Subdevice class to create a V4L2Subdevice instance from a media entity name. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/libcamera/include/v4l2_subdevice.h | 5 +++++ src/libcamera/v4l2_subdevice.cpp | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/libcamera/include/v4l2_subdevice.h b/src/libcamera/include/v4l2_subdevice.h index f42cccabda94..0067109931d1 100644 --- a/src/libcamera/include/v4l2_subdevice.h +++ b/src/libcamera/include/v4l2_subdevice.h @@ -18,6 +18,8 @@ namespace libcamera { +class MediaDevice; + struct V4L2SubdeviceFormat { uint32_t mbus_code; uint32_t width; @@ -29,6 +31,9 @@ struct V4L2SubdeviceFormat { class V4L2Subdevice : protected Loggable { public: + static V4L2Subdevice *fromEntityName(const MediaDevice *media, + const std::string &name); + explicit V4L2Subdevice(const MediaEntity *entity); V4L2Subdevice(const V4L2Subdevice &) = delete; V4L2Subdevice &operator=(const V4L2Subdevice &) = delete; diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index 10925f9fe497..e28857c9aeb1 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -16,6 +16,7 @@ #include "geometry.h" #include "log.h" +#include "media_device.h" #include "media_object.h" #include "v4l2_subdevice.h" @@ -101,6 +102,27 @@ const std::string V4L2SubdeviceFormat::toString() const * any device left open will be closed, and any resources released. */ +/** + * \brief Create a new video subdevice instance from entity with \a name in + * media device \a media + * \param[in] media The media device where the entity is registered + * \param[in] name The media entity name + * + * Releasing memory of the newly created instance is responsibility of the + * caller of this function. + * + * \return A newly created V4L2Subdevice on success, nullptr otherwise + */ +V4L2Subdevice *V4L2Subdevice::fromEntityName(const MediaDevice *media, + const std::string &name) +{ + MediaEntity *entity = media->getEntityByName(name); + if (!entity) + return nullptr; + + return new V4L2Subdevice(entity); +} + /** * \brief Create a V4L2 subdevice from a MediaEntity using its device node * path From patchwork Tue Mar 26 08:38: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: 803 Return-Path: Received: from relay10.mail.gandi.net (relay10.mail.gandi.net [217.70.178.230]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6ECBA61243 for ; Tue, 26 Mar 2019 09:38:35 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay10.mail.gandi.net (Postfix) with ESMTPSA id EC9EF240005; Tue, 26 Mar 2019 08:38:34 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 26 Mar 2019 09:38:51 +0100 Message-Id: <20190326083902.26121-9-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190326083902.26121-1-jacopo@jmondi.org> References: <20190326083902.26121-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 08/19] libcamera: ipu3: Cache the camera sizes 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: Tue, 26 Mar 2019 08:38:36 -0000 When creating a camera, make sure a the image sensor provides images in a format compatible with IPU3 CIO2 unit requirements and cache the minimum and maximum camera sizes. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 56 +++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 55489c31df2d..d42c81273cc6 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -8,11 +8,14 @@ #include #include +#include + #include #include #include #include "device_enumerator.h" +#include "geometry.h" #include "log.h" #include "media_device.h" #include "pipeline_handler.h" @@ -24,6 +27,22 @@ namespace libcamera { LOG_DEFINE_CATEGORY(IPU3) +static int 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; + } +} + class PipelineHandlerIPU3 : public PipelineHandler { public: @@ -70,6 +89,9 @@ private: V4L2Subdevice *sensor_; Stream stream_; + + /* Maximum sizes and the mbus code used to produce them. */ + std::pair maxSizes_; }; IPU3CameraData *cameraData(const Camera *camera) @@ -404,18 +426,48 @@ 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 and cache the camera + * maximum sizes. + */ data->sensor_ = new V4L2Subdevice(sensor); ret = data->sensor_->open(); if (ret) continue; + for (auto it : data->sensor_->formats(0)) { + int mbusCode = mediaBusToCIO2Format(it.first); + if (mbusCode < 0) + continue; + + for (const SizeRange &size : it.second) { + SizeRange &maxSize = data->maxSizes_.second; + + if (maxSize.maxWidth < size.maxWidth && + maxSize.maxHeight < size.maxHeight) { + maxSize.maxWidth = size.maxWidth; + maxSize.maxHeight = size.maxHeight; + data->maxSizes_.first = mbusCode; + } + } + } + if (data->maxSizes_.second.maxWidth == 0) { + LOG(IPU3, Info) + << "Sensor '" << data->sensor_->entityName() + << "' 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 Tue Mar 26 08:38: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: 804 Return-Path: Received: from relay10.mail.gandi.net (relay10.mail.gandi.net [217.70.178.230]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0E5F96110D for ; Tue, 26 Mar 2019 09:38:36 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay10.mail.gandi.net (Postfix) with ESMTPSA id 9939E240005; Tue, 26 Mar 2019 08:38:35 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 26 Mar 2019 09:38:52 +0100 Message-Id: <20190326083902.26121-10-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190326083902.26121-1-jacopo@jmondi.org> References: <20190326083902.26121-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 09/19] 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: Tue, 26 Mar 2019 08:38:36 -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 | 35 +++++++++++++--------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index d42c81273cc6..04cd02653711 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 @@ -94,6 +95,8 @@ private: std::pair maxSizes_; }; + static constexpr unsigned int IPU3_BUFFER_COUNT = 4; + IPU3CameraData *cameraData(const Camera *camera) { return static_cast( @@ -124,26 +127,20 @@ std::map PipelineHandlerIPU3::streamConfiguration(Camera *camera, std::set &streams) { - IPU3CameraData *data = cameraData(camera); std::map configs; - V4L2SubdeviceFormat format = {}; - - /* - * 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; - } - - StreamConfiguration config = {}; - config.width = format.width; - config.height = format.height; - config.pixelFormat = V4L2_PIX_FMT_IPU3_SGRBG10; - config.bufferCount = 4; - - configs[&data->stream_] = config; + IPU3CameraData *data = cameraData(camera); + StreamConfiguration *config = &configs[&data->stream_]; + SizeRange &maxRange = data->maxSizes_.second; + + config->width = maxRange.maxWidth; + config->height = maxRange.maxHeight; + config->pixelFormat = data->maxSizes_.first; + 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; return configs; } From patchwork Tue Mar 26 08:38: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: 805 Return-Path: Received: from relay10.mail.gandi.net (relay10.mail.gandi.net [217.70.178.230]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BA0AB6110D for ; Tue, 26 Mar 2019 09:38:36 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay10.mail.gandi.net (Postfix) with ESMTPSA id 3BEFC240005; Tue, 26 Mar 2019 08:38:36 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 26 Mar 2019 09:38:53 +0100 Message-Id: <20190326083902.26121-11-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190326083902.26121-1-jacopo@jmondi.org> References: <20190326083902.26121-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 10/19] libcamera: ipu3: Create CIO2Device class 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: Tue, 26 Mar 2019 08:38:36 -0000 Group CIO2 components (cio2, csi2 and image sensor) in a class associated with the CameraData, to ease management and initialization of CIO2 unit at camera registration time. A CIO2 unit will always be associated with a single Camera only. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 320 +++++++++++++++------------ 1 file changed, 175 insertions(+), 145 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 04cd02653711..21205b39afee 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -44,6 +44,32 @@ static int mediaBusToCIO2Format(unsigned int code) } } +class CIO2Device +{ +public: + CIO2Device() + : output_(nullptr), csi2_(nullptr), sensor_(nullptr) + { + } + + ~CIO2Device() + { + delete output_; + delete csi2_; + delete sensor_; + } + + const std::string &name() const; + int init(const MediaDevice *media, unsigned int index); + + V4L2Device *output_; + V4L2Subdevice *csi2_; + V4L2Subdevice *sensor_; + + /* Maximum sizes and the mbus code used to produce them. */ + std::pair maxSizes_; +}; + class PipelineHandlerIPU3 : public PipelineHandler { public: @@ -67,36 +93,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_; - - /* Maximum sizes and the mbus code used to produce them. */ - std::pair maxSizes_; }; - static constexpr unsigned int IPU3_BUFFER_COUNT = 4; - IPU3CameraData *cameraData(const Camera *camera) { return static_cast( @@ -105,22 +118,22 @@ private: 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 @@ -130,11 +143,12 @@ PipelineHandlerIPU3::streamConfiguration(Camera *camera, std::map configs; IPU3CameraData *data = cameraData(camera); StreamConfiguration *config = &configs[&data->stream_]; - SizeRange &maxRange = data->maxSizes_.second; + CIO2Device *cio2 = &data->cio2_; + SizeRange &maxRange = cio2->maxSizes_.second; config->width = maxRange.maxWidth; config->height = maxRange.maxHeight; - config->pixelFormat = data->maxSizes_.first; + config->pixelFormat = cio2->maxSizes_.first; config->bufferCount = IPU3_BUFFER_COUNT; LOG(IPU3, Debug) @@ -150,9 +164,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; @@ -209,13 +223,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; @@ -227,8 +242,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; @@ -240,9 +256,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; @@ -254,8 +271,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); @@ -264,6 +282,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); @@ -273,7 +292,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; @@ -312,17 +331,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 @@ -331,17 +350,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; } @@ -355,115 +374,28 @@ void PipelineHandlerIPU3::registerCameras() { /* * For each CSI-2 receiver on the IPU3, create a Camera if an - * image sensor is connected to it. + * image sensor is connected to it and it can produce images in + * a compatible format. */ 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_; - /* - * Make sure the sensor produces at least one image format - * compatible with IPU3 CIO2 requirements and cache the camera - * maximum sizes. - */ - data->sensor_ = new V4L2Subdevice(sensor); - ret = data->sensor_->open(); + int ret = cio2->init(cio2MediaDev_.get(), id); if (ret) continue; - for (auto it : data->sensor_->formats(0)) { - int mbusCode = mediaBusToCIO2Format(it.first); - if (mbusCode < 0) - continue; - - for (const SizeRange &size : it.second) { - SizeRange &maxSize = data->maxSizes_.second; - - if (maxSize.maxWidth < size.maxWidth && - maxSize.maxHeight < size.maxHeight) { - maxSize.maxWidth = size.maxWidth; - maxSize.maxHeight = size.maxHeight; - data->maxSizes_.first = mbusCode; - } - } - } - if (data->maxSizes_.second.maxWidth == 0) { - LOG(IPU3, Info) - << "Sensor '" << data->sensor_->entityName() - << "' 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->name() + " " + + 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)); @@ -484,6 +416,104 @@ void PipelineHandlerIPU3::IPU3CameraData::bufferReady(Buffer *buffer) pipe_->completeRequest(camera_, request); } +/*------------------------------------------------------------------------------ + * CIO2 Device + */ + +const std::string &CIO2Device::name() const +{ + return sensor_->entityName(); +} + +/** + * \brief Initialize components of the CIO2 device with \a index + * \param[in] media The CIO2 media device + * \param[in] index The CIO2 device index + * + * 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 and cache the sensor maximum sizes. + * + * \return 0 on success or a negative error code otherwise + * \retval -ENODEV No image sensor is connected to this CIO2 instance + */ +int CIO2Device::init(const MediaDevice *media, unsigned int index) +{ + int ret; + + /* Verify that a sensor subdevice is connected to this CIO2 instance. */ + std::string csi2Name = "ipu3-csi2 " + std::to_string(index); + MediaEntity *csi2Entity = media->getEntityByName(csi2Name); + const std::vector &pads = csi2Entity->pads(); + if (pads.empty()) + return -ENODEV; + + /* 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 -ENODEV; + + 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 + * and cache the camera maximum sizes. + * + * \todo Define when to open and close video device nodes, as they + * might impact on power consumption. + */ + sensor_ = new V4L2Subdevice(sensorEntity); + ret = sensor_->open(); + if (ret) + return ret; + + for (auto it : sensor_->formats(0)) { + int mbusCode = mediaBusToCIO2Format(it.first); + if (mbusCode < 0) + continue; + + for (const SizeRange &size : it.second) { + SizeRange &maxRange = maxSizes_.second; + + if (maxRange.maxWidth < size.maxWidth && + maxRange.maxHeight < size.maxHeight) { + maxRange.maxWidth = size.maxWidth; + maxRange.maxHeight = size.maxHeight; + maxSizes_.first = mbusCode; + } + } + } + if (maxSizes_.second.maxWidth == 0) { + LOG(IPU3, Info) << "Sensor '" << sensor_->entityName() + << "' detected, but no supported image format " + << " found: skip camera creation"; + return -ENODEV; + } + + csi2_ = new V4L2Subdevice(csi2Entity); + ret = csi2_->open(); + if (ret) + return ret; + + std::string cio2Name = "ipu3-cio2 " + std::to_string(index); + output_ = V4L2Device::fromEntityName(media, cio2Name); + ret = output_->open(); + if (ret) + return ret; + + return 0; +} + REGISTER_PIPELINE_HANDLER(PipelineHandlerIPU3); } /* namespace libcamera */ From patchwork Tue Mar 26 08:38:54 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 806 Return-Path: Received: from relay10.mail.gandi.net (relay10.mail.gandi.net [217.70.178.230]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 665F56110D for ; Tue, 26 Mar 2019 09:38:37 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay10.mail.gandi.net (Postfix) with ESMTPSA id E32ED240011; Tue, 26 Mar 2019 08:38:36 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 26 Mar 2019 09:38:54 +0100 Message-Id: <20190326083902.26121-12-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190326083902.26121-1-jacopo@jmondi.org> References: <20190326083902.26121-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 11/19] libcamera: ipu3: Create ImgUDevice class 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: Tue, 26 Mar 2019 08:38:37 -0000 Group ImgU components in a class associated with a camera at camera registration time and provide an intialization method to create and open all video devices and subdevices of the ImgU. Statically assign imgu0 to the first camera and imgu1 to the second one and limit support to two cameras. This will have to be revised in the future. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- src/libcamera/pipeline/ipu3/ipu3.cpp | 154 +++++++++++++++++++++++++-- 1 file changed, 145 insertions(+), 9 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 21205b39afee..0a059b75cadf 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -44,6 +44,43 @@ static int mediaBusToCIO2Format(unsigned int code) } } +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) + { + } + + ~ImgUDevice() + { + delete imgu_; + delete input_; + delete output_; + delete viewfinder_; + delete stat_; + } + + int init(MediaDevice *media, unsigned int index); + + unsigned int index_; + std::string name_; + MediaDevice *media_; + + V4L2Subdevice *imgu_; + V4L2Device *input_; + V4L2Device *output_; + V4L2Device *viewfinder_; + V4L2Device *stat_; + /* \todo Add param video device for 3A tuning */ +}; + class CIO2Device { public: @@ -106,6 +143,7 @@ private: void bufferReady(Buffer *buffer); CIO2Device cio2_; + ImgUDevice *imgu_; Stream stream_; }; @@ -116,8 +154,10 @@ private: PipelineHandler::cameraData(camera)); } - void registerCameras(); + int registerCameras(); + ImgUDevice imgu0_; + ImgUDevice imgu1_; std::shared_ptr cio2MediaDev_; std::shared_ptr imguMediaDev_; }; @@ -303,6 +343,8 @@ int PipelineHandlerIPU3::queueRequest(Camera *camera, Request *request) bool PipelineHandlerIPU3::match(DeviceEnumerator *enumerator) { + int ret; + DeviceMatch cio2_dm("ipu3-cio2"); cio2_dm.add("ipu3-csi2 0"); cio2_dm.add("ipu3-cio2 0"); @@ -358,36 +400,75 @@ bool PipelineHandlerIPU3::match(DeviceEnumerator *enumerator) return false; } - registerCameras(); + if (imguMediaDev_->open()) { + cio2MediaDev_->close(); + return false; + } + + if (imguMediaDev_->disableLinks()) + goto error; + + ret = registerCameras(); + if (ret) + goto error; cio2MediaDev_->close(); + imguMediaDev_->close(); return true; + +error: + cio2MediaDev_->close(); + imguMediaDev_->close(); + + return false; } -/* - * Cameras are created associating an image sensor (represented by a - * media entity with function MEDIA_ENT_F_CAM_SENSOR) to one of the four - * CIO2 CSI-2 receivers. +/** + * \brief Initialize ImgU devices and CIO2 ones associated with cameras + * + * Initialize the two ImgU instances and create cameras with an associated + * CIO2 device instance. + * + * \return 0 on success or a negative error code for error or if no camera + * has been created + * \retval -ENODEV no camera has been created */ -void PipelineHandlerIPU3::registerCameras() +int PipelineHandlerIPU3::registerCameras() { + int ret; + + ret = imgu0_.init(imguMediaDev_.get(), 0); + if (ret) + return ret; + + ret = imgu1_.init(imguMediaDev_.get(), 1); + if (ret) + return ret; + /* * For each CSI-2 receiver on the IPU3, create a Camera if an * image sensor is connected to it and it can produce images in * a compatible format. */ 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_ }; CIO2Device *cio2 = &data->cio2_; - int ret = cio2->init(cio2MediaDev_.get(), id); + ret = cio2->init(cio2MediaDev_.get(), id); 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_ = numCameras ? &imgu1_ : &imgu0_; + std::string cameraName = cio2->name() + " " + std::to_string(id); std::shared_ptr camera = Camera::create(this, @@ -406,6 +487,8 @@ void PipelineHandlerIPU3::registerCameras() numCameras++; } + + return numCameras ? 0 : -ENODEV; } void PipelineHandlerIPU3::IPU3CameraData::bufferReady(Buffer *buffer) @@ -416,6 +499,59 @@ void PipelineHandlerIPU3::IPU3CameraData::bufferReady(Buffer *buffer) pipe_->completeRequest(camera_, request); } +/* ----------------------------------------------------------------------------- + * ImgU Device + */ + +/** + * \brief Initialize components of the ImgU instance + * \param[in] mediaDevice The ImgU instance media device + * \param[in] index The ImgU instance index + * + * Create and open the V4L2 devices and subdevices of the ImgU instance + * with \a index. + * + * In case of errors the created V4L2Device and V4L2Subdevice instances + * are destroyed at pipeline handler delete time. + * + * \return 0 on success or a negative error code otherwise + */ +int ImgUDevice::init(MediaDevice *media, unsigned int index) +{ + int ret; + + index_ = index; + name_ = "ipu3-imgu " + std::to_string(index_); + media_ = media; + + imgu_ = V4L2Subdevice::fromEntityName(media, name_); + ret = imgu_->open(); + if (ret) + return ret; + + input_ = V4L2Device::fromEntityName(media, name_ + " input"); + ret = input_->open(); + if (ret) + return ret; + + output_ = V4L2Device::fromEntityName(media, name_ + " output"); + ret = output_->open(); + if (ret) + return ret; + + viewfinder_ = V4L2Device::fromEntityName(media, name_ + " viewfinder"); + ret = viewfinder_->open(); + if (ret) + return ret; + + stat_ = V4L2Device::fromEntityName(media, name_ + " 3a stat"); + ret = stat_->open(); + if (ret) + return ret; + + return 0; +} + /*------------------------------------------------------------------------------ * CIO2 Device */ From patchwork Tue Mar 26 08:38: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: 807 Return-Path: Received: from relay10.mail.gandi.net (relay10.mail.gandi.net [217.70.178.230]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4027F611A7 for ; Tue, 26 Mar 2019 09:38:38 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay10.mail.gandi.net (Postfix) with ESMTPSA id A9C65240006; Tue, 26 Mar 2019 08:38:37 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 26 Mar 2019 09:38:55 +0100 Message-Id: <20190326083902.26121-13-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190326083902.26121-1-jacopo@jmondi.org> References: <20190326083902.26121-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 12/19] libcamera: ipu3: Apply image format 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: Tue, 26 Mar 2019 08:38:39 -0000 Apply the requested image format to the CIO2 device, and apply the resulting adjusted one to the the ImgU subdevice and its input and output video devices. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 300 +++++++++++++++++++++++---- 1 file changed, 265 insertions(+), 35 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 0a059b75cadf..63b84706b9b2 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -52,6 +52,20 @@ public: static constexpr unsigned int PAD_VF = 3; static constexpr unsigned int PAD_STAT = 4; + /* ImgU output identifiers: used as indexes for the below maps. */ + enum OutputId { + MAIN_OUTPUT, + SECONDARY_OUTPUT, + STAT, + }; + + /* ImgU output descriptor: group data specific to an ImgU output. */ + struct outputDesc { + V4L2Device *dev; + unsigned int pad; + std::string name; + }; + ImgUDevice() : imgu_(nullptr), input_(nullptr), output_(nullptr), viewfinder_(nullptr), stat_(nullptr) @@ -67,7 +81,25 @@ public: delete stat_; } + /* Imgu output map accessors. */ + V4L2Device *outputDevice(enum OutputId id) + { + return outputMap[id].dev; + } + unsigned int outputPad(enum OutputId id) + { + return outputMap[id].pad; + } + const std::string &outputName(enum OutputId id) + { + return outputMap[id].name; + } + int init(MediaDevice *media, unsigned int index); + int configureInput(const StreamConfiguration &config, + const V4L2SubdeviceFormat &cio2Format); + int configureOutput(enum OutputId id, + const StreamConfiguration &config); unsigned int index_; std::string name_; @@ -79,6 +111,9 @@ public: V4L2Device *viewfinder_; V4L2Device *stat_; /* \todo Add param video device for 3A tuning */ + + /* ImgU output map: associate an output id with its descriptor. */ + std::map outputMap; }; class CIO2Device @@ -98,6 +133,8 @@ public: const std::string &name() const; int init(const MediaDevice *media, unsigned int index); + int configure(const StreamConfiguration &config, + V4L2SubdeviceFormat *format); V4L2Device *output_; V4L2Subdevice *csi2_; @@ -203,61 +240,62 @@ 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_; - V4L2Device *cio2 = data->cio2_.output_; - V4L2SubdeviceFormat subdevFormat = {}; - V4L2DeviceFormat devFormat = {}; + const StreamConfiguration &cfg = config[&data->stream_]; + CIO2Device *cio2 = &data->cio2_; + ImgUDevice *imgu = data->imgu_; int ret; + LOG(IPU3, Info) + << "Requested image format: " << cfg.width << "x" + << cfg.height << "-0x" << 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) and the camera maximum sizes. + * + * \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 size not support: bad alignement"; + return -EINVAL; + } + + SizeRange cio2MaxSize = cio2->maxSizes_.second; + if (cfg.width > cio2MaxSize.maxWidth || + cfg.height > cio2MaxSize.maxHeight) { + LOG(IPU3, Error) << "Stream size not support: too big"; + 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 to the ImgU devices. + */ + V4L2SubdeviceFormat cio2Format = {}; + ret = cio2->configure(cfg, &cio2Format); if (ret) return ret; - subdevFormat.width = cfg->width; - subdevFormat.height = cfg->height; - ret = sensor->setFormat(0, &subdevFormat); + ret = imgu->configureInput(cfg, 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; - } - - ret = csi2->setFormat(0, &subdevFormat); + /* Apply the format to the ImgU output, viewfinder and stat. */ + ret = imgu->configureOutput(ImgUDevice::MAIN_OUTPUT, cfg); if (ret) return ret; - ret = cio2->getFormat(&devFormat); + ret = imgu->configureOutput(ImgUDevice::SECONDARY_OUTPUT, cfg); if (ret) return ret; - devFormat.width = subdevFormat.width; - devFormat.height = subdevFormat.height; - devFormat.fourcc = cfg->pixelFormat; - - ret = cio2->setFormat(&devFormat); + ret = imgu->configureOutput(ImgUDevice::STAT, cfg); if (ret) return ret; - LOG(IPU3, Info) << cio2->driverName() << ": " - << devFormat.width << "x" << devFormat.height - << "- 0x" << std::hex << devFormat.fourcc << " planes: " - << devFormat.planes; - return 0; } @@ -539,16 +577,140 @@ int ImgUDevice::init(MediaDevice *media, unsigned int index) if (ret) return ret; + struct outputDesc desc = {}; + desc.dev = output_; + desc.pad = PAD_OUTPUT; + desc.name = "output"; + outputMap[MAIN_OUTPUT] = desc; + viewfinder_ = V4L2Device::fromEntityName(media, name_ + " viewfinder"); ret = viewfinder_->open(); if (ret) return ret; + desc = {}; + desc.dev = viewfinder_; + desc.pad = PAD_VF; + desc.name = "viewfinder"; + outputMap[SECONDARY_OUTPUT] = desc; + stat_ = V4L2Device::fromEntityName(media, name_ + " 3a stat"); ret = stat_->open(); if (ret) return ret; + desc = {}; + desc.dev = stat_; + desc.pad = PAD_STAT; + desc.name = "stat"; + outputMap[STAT] = desc; + + return 0; +} + +/** + * \brief Configure the ImgU unit input + * \param[in] config The requested GDC format configuration + * \param[in] cio2Format The CIO2 output format to be applied to ImgU input + * + * FIXME: the IPU3 driver implementation shall be changed to use the + * CIO2 output sizes as 'ImgU Input' subdevice sizes, and use the + * GDC output sizes to configure the crop/compose rectangles. + * The current IPU3 driver implementation uses GDC output sizes as + * 'ImgU Input' sizes, and the CIO2 output sizes to configure the + * crop/compose rectangles, contradicting the V4L2 specification. + * + * \return 0 on success or a negative error code otherwise + */ +int ImgUDevice::configureInput(const StreamConfiguration &config, + const V4L2SubdeviceFormat &cio2Format) +{ + int ret; + + /* Configure the ImgU subdevice input pad with the requested sizes. */ + V4L2DeviceFormat inputFormat = {}; + inputFormat.width = cio2Format.width; + inputFormat.height = cio2Format.height; + inputFormat.fourcc = mediaBusToCIO2Format(cio2Format.mbus_code); + inputFormat.planesCount = 1; + + ret = input_->setFormat(&inputFormat); + if (ret) + return ret; + + LOG(IPU3, Debug) << "ImgU input format = " << inputFormat.toString(); + + Rectangle rect = { + .x = 0, + .y = 0, + .w = cio2Format.width, + .h = cio2Format.height, + }; + ret = imgu_->setCrop(PAD_INPUT, &rect); + if (ret) + return ret; + + ret = imgu_->setCompose(PAD_INPUT, &rect); + if (ret) + return ret; + + LOG(IPU3, Debug) << "ImgU input feeder and BDS rectangle = " + << rect.toString(); + + V4L2SubdeviceFormat imguFormat = {}; + imguFormat.width = config.width; + imguFormat.height = config.height; + imguFormat.mbus_code = MEDIA_BUS_FMT_FIXED; + + ret = imgu_->setFormat(PAD_INPUT, &imguFormat); + if (ret) + return ret; + + LOG(IPU3, Debug) << "ImgU GDC format = " << imguFormat.toString(); + + return 0; +} + +/** + * \brief Configure the ImgU unit \a id video output + * \param[in] id The output device node identifier + * \param[in] config The requested configuration + * + * \return 0 on success or a negative error code otherwise + */ +int ImgUDevice::configureOutput(enum OutputId id, + const StreamConfiguration &config) +{ + V4L2Device *output = outputDevice(id); + unsigned int pad = outputPad(id); + const std::string name = outputName(id); + + V4L2SubdeviceFormat imguFormat = {}; + imguFormat.width = config.width; + imguFormat.height = config.height; + imguFormat.mbus_code = MEDIA_BUS_FMT_FIXED; + + int ret = imgu_->setFormat(pad, &imguFormat); + if (ret) + return ret; + + /* No need to apply format to the stat node. */ + if (id == STAT) + return 0; + + 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 " << name << " format = " + << outputFormat.toString(); + return 0; } @@ -650,6 +812,74 @@ int CIO2Device::init(const MediaDevice *media, unsigned int index) return 0; } +/** + * \brief Configure the CIO2 unit + * \param[in] config The requested configuration + * \param[out] format The CIO2 unit output image format to be applied on ImgU + * + * \return 0 on success or a negative error code otherwise + */ +int CIO2Device::configure(const StreamConfiguration &config, + V4L2SubdeviceFormat *format) +{ + unsigned int imageSize = config.width * config.height; + unsigned int best = ~0; + int ret; + + for (auto it : sensor_->formats(0)) { + /* Only consider formats consumable by the CIO2 unit. */ + if (mediaBusToCIO2Format(it.first) < 0) + 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; + + format->width = size.maxWidth; + format->height = size.maxHeight; + format->mbus_code = it.first; + } + } + + /* + * Apply the selected format to the sensor, the CSI-2 receiver and + * the CIO2 output device. + */ + ret = sensor_->setFormat(0, format); + if (ret) + return ret; + + ret = csi2_->setFormat(0, format); + if (ret) + return ret; + + V4L2DeviceFormat cio2Format = {}; + cio2Format.width = format->width; + cio2Format.height = format->height; + cio2Format.fourcc = mediaBusToCIO2Format(format->mbus_code); + cio2Format.planesCount = 1; + + ret = output_->setFormat(&cio2Format); + if (ret) + return ret; + + LOG(IPU3, Debug) << "CIO2 output format = " << cio2Format.toString(); + + return 0; +} + REGISTER_PIPELINE_HANDLER(PipelineHandlerIPU3); } /* namespace libcamera */ From patchwork Tue Mar 26 08:38:56 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 808 Return-Path: Received: from relay10.mail.gandi.net (relay10.mail.gandi.net [217.70.178.230]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 052476110D for ; Tue, 26 Mar 2019 09:38:39 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay10.mail.gandi.net (Postfix) with ESMTPSA id 71477240006; Tue, 26 Mar 2019 08:38:38 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 26 Mar 2019 09:38:56 +0100 Message-Id: <20190326083902.26121-14-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190326083902.26121-1-jacopo@jmondi.org> References: <20190326083902.26121-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 13/19] libcamera: ipu3: Implement memory handling 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: Tue, 26 Mar 2019 08:38:40 -0000 Implement buffer allocation and relase in IPU3 pipeline handlers. As the pipeline handler supports a single stream, provide two internal 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 | 174 ++++++++++++++++++++++++--- 1 file changed, 160 insertions(+), 14 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 63b84706b9b2..d3519bb1d536 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -64,6 +64,7 @@ public: V4L2Device *dev; unsigned int pad; std::string name; + BufferPool *pool; }; ImgUDevice() @@ -94,6 +95,10 @@ public: { return outputMap[id].name; } + BufferPool *outputPool(enum OutputId id) + { + return outputMap[id].pool; + } int init(MediaDevice *media, unsigned int index); int configureInput(const StreamConfiguration &config, @@ -101,6 +106,11 @@ public: int configureOutput(enum OutputId id, const StreamConfiguration &config); + int importBuffers(BufferPool *pool); + int exportBuffers(enum OutputId id, BufferPool *pool); + int exportBuffers(enum OutputId id, unsigned int count); + void freeBuffers(); + unsigned int index_; std::string name_; MediaDevice *media_; @@ -114,11 +124,16 @@ public: /* ImgU output map: associate an output id with its descriptor. */ std::map outputMap; + + BufferPool vfPool; + BufferPool statPool; }; class CIO2Device { public: + static constexpr unsigned int CIO2_BUFFER_COUNT = 4; + CIO2Device() : output_(nullptr), csi2_(nullptr), sensor_(nullptr) { @@ -136,12 +151,17 @@ public: int configure(const StreamConfiguration &config, V4L2SubdeviceFormat *format); + BufferPool *exportBuffers(); + void freeBuffers(); + V4L2Device *output_; V4L2Subdevice *csi2_; V4L2Subdevice *sensor_; /* Maximum sizes and the mbus code used to produce them. */ std::pair maxSizes_; + + BufferPool pool_; }; class PipelineHandlerIPU3 : public PipelineHandler @@ -301,18 +321,39 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, int PipelineHandlerIPU3::allocateBuffers(Camera *camera, Stream *stream) { - const StreamConfiguration &cfg = stream->configuration(); IPU3CameraData *data = cameraData(camera); - V4L2Device *cio2 = data->cio2_.output_; + CIO2Device *cio2 = &data->cio2_; + ImgUDevice *imgu = data->imgu_; + int ret; - if (!cfg.bufferCount) - return -EINVAL; + /* Share buffers between CIO2 output and ImgU input. */ + BufferPool *pool = cio2->exportBuffers(); + if (!pool) + return -ENOMEM; - int ret = cio2->exportBuffers(&stream->bufferPool()); - if (ret) { - LOG(IPU3, Error) << "Failed to request memory"; + ret = imgu->importBuffers(pool); + if (ret) + return ret; + + /* Export ImgU output buffers to the stream's pool. */ + ret = imgu->exportBuffers(ImgUDevice::MAIN_OUTPUT, + &stream->bufferPool()); + if (ret) + return ret; + + /* + * Reserve memory in viewfinder and stat output devices. Use the + * same number of buffers as the ones requested for the output + * stream. + */ + unsigned int bufferCount = stream->bufferPool().count(); + ret = imgu->exportBuffers(ImgUDevice::SECONDARY_OUTPUT, bufferCount); + if (ret) + return ret; + + ret = imgu->exportBuffers(ImgUDevice::STAT, bufferCount); + if (ret) return ret; - } return 0; } @@ -320,13 +361,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 = cio2->releaseBuffers(); - if (ret) { - LOG(IPU3, Error) << "Failed to release memory"; - return ret; - } + data->cio2_.freeBuffers(); + data->imgu_->freeBuffers(); return 0; } @@ -592,6 +629,7 @@ int ImgUDevice::init(MediaDevice *media, unsigned int index) desc.dev = viewfinder_; desc.pad = PAD_VF; desc.name = "viewfinder"; + desc.pool = &vfPool; outputMap[SECONDARY_OUTPUT] = desc; stat_ = V4L2Device::fromEntityName(media, name_ + " 3a stat"); @@ -603,6 +641,7 @@ int ImgUDevice::init(MediaDevice *media, unsigned int index) desc.dev = stat_; desc.pad = PAD_STAT; desc.name = "stat"; + desc.pool = &statPool; outputMap[STAT] = desc; return 0; @@ -714,6 +753,86 @@ int ImgUDevice::configureOutput(enum OutputId id, return 0; } +/** + * \brief Import buffers from CIO2 device into the ImgU + * \param[in] pool The buffer pool to import + * + * \return 0 on success or a negative error code otherwise + */ +int ImgUDevice::importBuffers(BufferPool *pool) +{ + return input_->importBuffers(pool); +} + +/** + * \brief Export buffers from output \a id to the provided \a pool + * \param[in] id The ImgU output identifier + * \param[in] pool The buffer pool where to export buffers + * + * Export memory buffers reserved in the video device memory associated with + * output \a id to the buffer pool provided as argument. + * + * \return 0 on success or a negative error code otherwise + */ +int ImgUDevice::exportBuffers(enum OutputId id, BufferPool *pool) +{ + V4L2Device *output = outputDevice(id); + const std::string &name = outputName(id); + + int ret = output->exportBuffers(pool); + if (ret) { + LOG(IPU3, Error) << "Failed to reserve ImgU " + << name << " buffers"; + return ret; + } + + return 0; +} + +/** + * \brief Export buffers from output \a id to the an internal buffer pool + * \param[in] id The ImgU output identifier + * \param[in] count The number of buffers to reserve + * + * Export memory buffers reserved in the video device memory associated with + * output \a id to the output internal buffer pool. + * + * \return 0 on success or a negative error code otherwise + */ +int ImgUDevice::exportBuffers(enum OutputId id, unsigned int count) +{ + BufferPool *pool = outputPool(id); + + /* Internal buffer pools needs memory to be allocated first. */ + pool->createBuffers(count); + + return exportBuffers(id, pool); +} + +/** + * \brief Release buffers of the ImgU devices + */ +void ImgUDevice::freeBuffers() +{ + int ret; + + ret = output_->releaseBuffers(); + if (ret) + LOG(IPU3, Error) << "Failed to release ImgU output buffers"; + + ret = stat_->releaseBuffers(); + if (ret) + LOG(IPU3, Error) << "Failed to release ImgU stat buffers"; + + ret = viewfinder_->releaseBuffers(); + if (ret) + LOG(IPU3, Error) << "Failed to release ImgU viewfinder buffers"; + + ret = input_->releaseBuffers(); + if (ret) + LOG(IPU3, Error) << "Failed to release ImgU input buffers"; +} + /*------------------------------------------------------------------------------ * CIO2 Device */ @@ -880,6 +999,33 @@ int CIO2Device::configure(const StreamConfiguration &config, return 0; } +/** + * \brief Reserve CIO2 memory buffers and export them in a BufferPool + * + * Allocate memory buffers in the CIO2 video device and export them to + * a buffer pool that will be later imported by the ImgU device. + * + * \return The buffer pool with export buffers on success or nullptr otherwise + */ +BufferPool *CIO2Device::exportBuffers() +{ + pool_.createBuffers(CIO2_BUFFER_COUNT); + + int ret = output_->exportBuffers(&pool_); + if (ret) { + LOG(IPU3, Error) << "Failed to export CIO2 buffers"; + return nullptr; + } + + return &pool_; +} + +void CIO2Device::freeBuffers() +{ + if (output_->releaseBuffers()) + LOG(IPU3, Error) << "Failed to release CIO2 buffers"; +} + REGISTER_PIPELINE_HANDLER(PipelineHandlerIPU3); } /* namespace libcamera */ From patchwork Tue Mar 26 08:38:57 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 809 Return-Path: Received: from relay10.mail.gandi.net (relay10.mail.gandi.net [217.70.178.230]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BCEF361111 for ; Tue, 26 Mar 2019 09:38:39 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay10.mail.gandi.net (Postfix) with ESMTPSA id 3538B240006; Tue, 26 Mar 2019 08:38:39 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 26 Mar 2019 09:38:57 +0100 Message-Id: <20190326083902.26121-15-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190326083902.26121-1-jacopo@jmondi.org> References: <20190326083902.26121-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 14/19] 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: Tue, 26 Mar 2019 08:38:40 -0000 Start and stop video devices in the pipeline. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- src/libcamera/pipeline/ipu3/ipu3.cpp | 93 ++++++++++++++++++++++++++-- 1 file changed, 87 insertions(+), 6 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index d3519bb1d536..5b3c44174566 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -111,6 +111,9 @@ public: int exportBuffers(enum OutputId id, unsigned int count); void freeBuffers(); + int start(); + void stop(); + unsigned int index_; std::string name_; MediaDevice *media_; @@ -154,6 +157,9 @@ public: BufferPool *exportBuffers(); void freeBuffers(); + int start(); + void stop(); + V4L2Device *output_; V4L2Subdevice *csi2_; V4L2Subdevice *sensor_; @@ -371,12 +377,24 @@ int PipelineHandlerIPU3::freeBuffers(Camera *camera, Stream *stream) int PipelineHandlerIPU3::start(Camera *camera) { IPU3CameraData *data = cameraData(camera); - V4L2Device *cio2 = data->cio2_.output_; + CIO2Device *cio2 = &data->cio2_; + ImgUDevice *imgu = data->imgu_; int ret; - ret = cio2->streamOn(); + /* + * Start the ImgU video devices, buffers will be queued to the + * ImgU output and viewfinder when requests will be queued. + */ + ret = cio2->start(); + if (ret) { + cio2->stop(); + return ret; + } + + ret = imgu->start(); if (ret) { - LOG(IPU3, Info) << "Failed to start camera " << camera->name(); + imgu->stop(); + cio2->stop(); return ret; } @@ -386,10 +404,9 @@ 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_.stop(); + data->imgu_->stop(); PipelineHandler::stop(camera); } @@ -833,6 +850,46 @@ void ImgUDevice::freeBuffers() LOG(IPU3, Error) << "Failed to release ImgU input buffers"; } +int ImgUDevice::start() +{ + int ret; + + /* Start the ImgU video devices. */ + ret = output_->streamOn(); + if (ret) { + LOG(IPU3, Error) << "Failed to start ImgU output"; + return ret; + } + + ret = viewfinder_->streamOn(); + if (ret) { + LOG(IPU3, Error) << "Failed to start ImgU viewfinder"; + return ret; + } + + ret = stat_->streamOn(); + if (ret) { + LOG(IPU3, Error) << "Failed to start ImgU stat"; + return ret; + } + + ret = input_->streamOn(); + if (ret) { + LOG(IPU3, Error) << "Failed to start ImgU input"; + return ret; + } + + return 0; +} + +void ImgUDevice::stop() +{ + output_->streamOff(); + viewfinder_->streamOff(); + stat_->streamOff(); + input_->streamOff(); +} + /*------------------------------------------------------------------------------ * CIO2 Device */ @@ -1026,6 +1083,30 @@ void CIO2Device::freeBuffers() LOG(IPU3, Error) << "Failed to release CIO2 buffers"; } +int CIO2Device::start() +{ + int ret; + + for (Buffer &buffer : pool_.buffers()) { + ret = output_->queueBuffer(&buffer); + if (ret) + return ret; + } + + ret = output_->streamOn(); + if (ret) { + LOG(IPU3, Error) << "Failed to start CIO2"; + return ret; + } + + return 0; +} + +void CIO2Device::stop() +{ + output_->streamOff(); +} + REGISTER_PIPELINE_HANDLER(PipelineHandlerIPU3); } /* namespace libcamera */ From patchwork Tue Mar 26 08:38:58 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 810 Return-Path: Received: from relay10.mail.gandi.net (relay10.mail.gandi.net [217.70.178.230]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 516CB6110D for ; Tue, 26 Mar 2019 09:38:40 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay10.mail.gandi.net (Postfix) with ESMTPSA id DF6A924000D; Tue, 26 Mar 2019 08:38:39 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 26 Mar 2019 09:38:58 +0100 Message-Id: <20190326083902.26121-16-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190326083902.26121-1-jacopo@jmondi.org> References: <20190326083902.26121-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 15/19] libcamera: ipu3: Queue requests to ImgU 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: Tue, 26 Mar 2019 08:38:40 -0000 Implement queueRequest for the IPU3 pipeline manager. When a request is queued, a new buffer is queued to the ImgU output for capture. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- src/libcamera/pipeline/ipu3/ipu3.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 5b3c44174566..9e8a20849ed0 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -414,9 +414,10 @@ void PipelineHandlerIPU3::stop(Camera *camera) int PipelineHandlerIPU3::queueRequest(Camera *camera, Request *request) { IPU3CameraData *data = cameraData(camera); - V4L2Device *cio2 = data->cio2_.output_; + V4L2Device *output = data->imgu_->output_; Stream *stream = &data->stream_; + /* Queue a buffer to the ImgU output for capture. */ Buffer *buffer = request->findBuffer(stream); if (!buffer) { LOG(IPU3, Error) @@ -424,7 +425,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 Tue Mar 26 08:38:59 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 811 Return-Path: Received: from relay10.mail.gandi.net (relay10.mail.gandi.net [217.70.178.230]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id EE0D86110D for ; Tue, 26 Mar 2019 09:38:40 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay10.mail.gandi.net (Postfix) with ESMTPSA id 7C16E240009; Tue, 26 Mar 2019 08:38:40 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 26 Mar 2019 09:38:59 +0100 Message-Id: <20190326083902.26121-17-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190326083902.26121-1-jacopo@jmondi.org> References: <20190326083902.26121-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 16/19] 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: Tue, 26 Mar 2019 08:38:41 -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 Reviewed-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- src/libcamera/pipeline/ipu3/ipu3.cpp | 59 +++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 9e8a20849ed0..7a5e715458ae 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -203,7 +203,9 @@ private: { } - void bufferReady(Buffer *buffer); + void imguOutputBufferReady(Buffer *buffer); + void imguInputBufferReady(Buffer *buffer); + void cio2BufferReady(Buffer *buffer); CIO2Device cio2_; ImgUDevice *imgu_; @@ -562,15 +564,28 @@ int PipelineHandlerIPU3::registerCameras() */ data->imgu_ = numCameras ? &imgu1_ : &imgu0_; + /* + * 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.get(), + &IPU3CameraData::cio2BufferReady); + data->imgu_->input_->bufferReady.connect(data.get(), + &IPU3CameraData::imguInputBufferReady); + data->imgu_->output_->bufferReady.connect(data.get(), + &IPU3CameraData::imguOutputBufferReady); + + /* Create and register the Camera instance. */ std::string cameraName = cio2->name() + " " + std::to_string(id); std::shared_ptr camera = Camera::create(this, cameraName, streams); - cio2->output_->bufferReady.connect(data.get(), - &IPU3CameraData::bufferReady); - registerCamera(std::move(camera), std::move(data)); LOG(IPU3, Info) @@ -584,7 +599,29 @@ int PipelineHandlerIPU3::registerCameras() return numCameras ? 0 : -ENODEV; } -void PipelineHandlerIPU3::IPU3CameraData::bufferReady(Buffer *buffer) +/* ----------------------------------------------------------------------------- + * Buffer Ready slots + */ + +/** + * \brief Handle buffers completion at the ImgU input + * \param buffer The completed buffer + * + * Buffers 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 Handle buffers completion at the ImgU output + * \param buffer The completed buffer + * + * Buffers completed from the ImgU output are directed to the application. + */ +void PipelineHandlerIPU3::IPU3CameraData::imguOutputBufferReady(Buffer *buffer) { Request *request = queuedRequests_.front(); @@ -592,6 +629,18 @@ void PipelineHandlerIPU3::IPU3CameraData::bufferReady(Buffer *buffer) pipe_->completeRequest(camera_, request); } +/** + * \brief Handle buffers completion at the CIO2 output + * \param buffer The completed buffer + * + * Buffers completed from the CIO2 are immediately queued to the ImgU unit + * for further processing. + */ +void PipelineHandlerIPU3::IPU3CameraData::cio2BufferReady(Buffer *buffer) +{ + imgu_->input_->queueBuffer(buffer); +} + /* ----------------------------------------------------------------------------- * ImgU Device */ From patchwork Tue Mar 26 08:39:00 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 812 Return-Path: Received: from relay10.mail.gandi.net (relay10.mail.gandi.net [217.70.178.230]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D54296110D for ; Tue, 26 Mar 2019 09:38:41 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay10.mail.gandi.net (Postfix) with ESMTPSA id 222BF240006; Tue, 26 Mar 2019 08:38:40 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 26 Mar 2019 09:39:00 +0100 Message-Id: <20190326083902.26121-18-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190326083902.26121-1-jacopo@jmondi.org> References: <20190326083902.26121-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 17/19] 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: Tue, 26 Mar 2019 08:38:42 -0000 Now that images come from the ImgU output, hardcode NV12 as default output format. Reviewed-by: Laurent Pinchart Signed-off-by: Jacopo Mondi Reviewed-by: Niklas Söderlund --- 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 7a5e715458ae..7b7baa5ac5fb 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -253,13 +253,13 @@ PipelineHandlerIPU3::streamConfiguration(Camera *camera, config->width = maxRange.maxWidth; config->height = maxRange.maxHeight; - config->pixelFormat = cio2->maxSizes_.first; + 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 Tue Mar 26 08:39:01 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 813 Return-Path: Received: from relay10.mail.gandi.net (relay10.mail.gandi.net [217.70.178.230]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7BBD261112 for ; Tue, 26 Mar 2019 09:38:42 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay10.mail.gandi.net (Postfix) with ESMTPSA id 1011A24000A; Tue, 26 Mar 2019 08:38:41 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 26 Mar 2019 09:39:01 +0100 Message-Id: <20190326083902.26121-19-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190326083902.26121-1-jacopo@jmondi.org> References: <20190326083902.26121-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 18/19] libcamera: ipu3: 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: Tue, 26 Mar 2019 08:38:42 -0000 As the procedure to configure the intermediate sizes and the alignement requirements of the ImgU device have not been clarified yet, return as default configuration the (2560x1920) resolution that has been validated for both cameras. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- src/libcamera/pipeline/ipu3/ipu3.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 7b7baa5ac5fb..66efcc37d695 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -248,11 +248,17 @@ PipelineHandlerIPU3::streamConfiguration(Camera *camera, std::map configs; IPU3CameraData *data = cameraData(camera); StreamConfiguration *config = &configs[&data->stream_]; - CIO2Device *cio2 = &data->cio2_; - SizeRange &maxRange = cio2->maxSizes_.second; - config->width = maxRange.maxWidth; - config->height = maxRange.maxHeight; + /* + * 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 Tue Mar 26 08:39:02 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 814 Return-Path: Received: from relay10.mail.gandi.net (relay10.mail.gandi.net [217.70.178.230]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2170961112 for ; Tue, 26 Mar 2019 09:38:43 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay10.mail.gandi.net (Postfix) with ESMTPSA id ADA3024000A; Tue, 26 Mar 2019 08:38:42 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 26 Mar 2019 09:39:02 +0100 Message-Id: <20190326083902.26121-20-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190326083902.26121-1-jacopo@jmondi.org> References: <20190326083902.26121-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 19/19] 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: Tue, 26 Mar 2019 08:38:43 -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 it is not yet clear if this behaviour is intended, as of now reset the media graph during pipeline's match() and enable the required links at streamConfiguration time. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- src/libcamera/pipeline/ipu3/ipu3.cpp | 111 +++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 66efcc37d695..f92728ae5b85 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -114,6 +114,11 @@ public: int start(); void stop(); + 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 name_; MediaDevice *media_; @@ -304,6 +309,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 to the ImgU devices. @@ -506,6 +519,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; @@ -946,6 +983,80 @@ void ImgUDevice::stop() input_->streamOff(); } +/** + * \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 = media_->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) +{ + int ret; + + /* \todo Establish rules to handle media devices open/close. */ + ret = media_->open(); + if (ret) + return ret; + + std::string inputName = name_ + " input"; + ret = linkSetup(inputName, 0, name_, PAD_INPUT, enable); + if (ret) { + media_->close(); + return ret; + } + + std::string outputName = name_ + " output"; + ret = linkSetup(name_, PAD_OUTPUT, outputName, 0, enable); + if (ret) { + media_->close(); + return ret; + } + + std::string viewfinderName = name_ + " viewfinder"; + ret = linkSetup(name_, PAD_VF, viewfinderName, 0, enable); + if (ret) { + media_->close(); + return ret; + } + + std::string statName = name_ + " 3a stat"; + ret = linkSetup(name_, PAD_STAT, statName, 0, enable); + if (ret) { + media_->close(); + return ret; + } + + media_->close(); + + return 0; +} + /*------------------------------------------------------------------------------ * CIO2 Device */