From patchwork Tue Mar 12 12:12:29 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 716 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 187BF600FC for ; Tue, 12 Mar 2019 13:12:20 +0100 (CET) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id A15BD1C000A; Tue, 12 Mar 2019 12:12:19 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 12 Mar 2019 13:12:29 +0100 Message-Id: <20190312121242.2253-2-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190312121242.2253-1-jacopo@jmondi.org> References: <20190312121242.2253-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 01/14] 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, 12 Mar 2019 12:12:20 -0000 Add toString() helpers to pretty print out a V4L2Device or V4L2Subdevice format. Signed-off-by: Jacopo Mondi Reviewed-by: Kieran Bingham --- 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 a88a5f5ff036..0bdcfc1d3c8f 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 << " planes: " << planesCount; + + 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..7c56ba3ba510 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(8) + << mbus_code; + + return ss.str(); +} + /** * \class V4L2Subdevice * \brief A V4L2 subdevice as exposed by the Linux kernel From patchwork Tue Mar 12 12:12:30 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 717 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A9AA3610D5 for ; Tue, 12 Mar 2019 13:12:20 +0100 (CET) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 417651C000A; Tue, 12 Mar 2019 12:12:20 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 12 Mar 2019 13:12:30 +0100 Message-Id: <20190312121242.2253-3-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190312121242.2253-1-jacopo@jmondi.org> References: <20190312121242.2253-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 02/14] libcamera: v4l2_subdevice: Define format enumeration 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, 12 Mar 2019 12:12:20 -0000 Provide a type definition for the map used to enumerate the subdevice image formats and associated sizes. Signed-off-by: Jacopo Mondi --- src/libcamera/include/v4l2_subdevice.h | 5 +++-- src/libcamera/v4l2_subdevice.cpp | 14 +++++++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/libcamera/include/v4l2_subdevice.h b/src/libcamera/include/v4l2_subdevice.h index 700e66bcddac..15add95a825c 100644 --- a/src/libcamera/include/v4l2_subdevice.h +++ b/src/libcamera/include/v4l2_subdevice.h @@ -17,6 +17,8 @@ namespace libcamera { +typedef std::map> SubdevFormatEnum; + struct V4L2SubdeviceFormat { uint32_t mbus_code; uint32_t width; @@ -42,8 +44,7 @@ public: int setCrop(unsigned int pad, Rectangle *rect); int setCompose(unsigned int pad, Rectangle *rect); - const std::map> - formats(unsigned int pad); + const SubdevFormatEnum formats(unsigned int pad); int getFormat(unsigned int pad, V4L2SubdeviceFormat *format); int setFormat(unsigned int pad, V4L2SubdeviceFormat *format); diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index 7c56ba3ba510..153330bccc97 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -28,6 +28,15 @@ namespace libcamera { LOG_DEFINE_CATEGORY(V4L2Subdev) +/** + * \typedef SubdevFormatEnum + * \brief Type definition for the map of image formats and associated sizes + * + * Type definition for the map of media bus codes and associated image + * resolutions used by V4L2Subdevice to report the enumeration of supported + * image formats. + */ + /** * \struct V4L2SubdeviceFormat * \brief The V4L2 sub-device image format and sizes @@ -210,10 +219,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) +const SubdevFormatEnum V4L2Subdevice::formats(unsigned int pad) { - std::map> formatMap = {}; + SubdevFormatEnum formatMap = {}; struct v4l2_subdev_mbus_code_enum mbusEnum = {}; int ret; From patchwork Tue Mar 12 12:12:31 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 718 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4E44E610D5 for ; Tue, 12 Mar 2019 13:12:21 +0100 (CET) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id D67011C000A; Tue, 12 Mar 2019 12:12:20 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 12 Mar 2019 13:12:31 +0100 Message-Id: <20190312121242.2253-4-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190312121242.2253-1-jacopo@jmondi.org> References: <20190312121242.2253-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 03/14] libcamera: ipu3: Get default image sizes 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, 12 Mar 2019 12:12:22 -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 | 94 ++++++++++++++++++++++++---- 1 file changed, 82 insertions(+), 12 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 55489c31df2d..0f18e4692e77 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -6,8 +6,11 @@ */ #include +#include #include +#include + #include #include #include @@ -72,12 +75,16 @@ private: Stream stream_; }; + static constexpr unsigned int IPU3_BUFFER_COUNT = 4; + IPU3CameraData *cameraData(const Camera *camera) { return static_cast( PipelineHandler::cameraData(camera)); } + int mediaBusToCIO2Format(unsigned int code); + void registerCameras(); std::shared_ptr cio2_; @@ -102,26 +109,45 @@ std::map PipelineHandlerIPU3::streamConfiguration(Camera *camera, std::set &streams) { - IPU3CameraData *data = cameraData(camera); std::map configs; - V4L2SubdeviceFormat format = {}; + IPU3CameraData *data = cameraData(camera); + V4L2Subdevice *sensor = data->sensor_; + StreamConfiguration *config = &configs[&data->stream_]; /* - * FIXME: As of now, return the image format reported by the sensor. - * In future good defaults should be provided for each stream. + * Make sure the sensor produces a raw format compatible with the + * CIO2 and use the largest image size the sensor provides. */ - if (data->sensor_->getFormat(0, &format)) { - LOG(IPU3, Error) << "Failed to create stream configurations"; + const SubdevFormatEnum formats = sensor->formats(0); + for (auto it = formats.begin(); it != formats.end(); ++it) { + int cio2Code = mediaBusToCIO2Format(it->first); + if (cio2Code == -EINVAL) + continue; + + for (const SizeRange &range : it->second) { + if (range.maxWidth <= config->width || + range.maxHeight <= config->height) + continue; + + config->width = range.maxWidth; + config->height = range.maxHeight; + config->pixelFormat = cio2Code; + } + } + + /* If not suitable format has been found, return an empty config. */ + if (!config->pixelFormat) { + LOG(IPU3, Error) << "Sensor image format not supported"; + return configs; } - StreamConfiguration config = {}; - config.width = format.width; - config.height = format.height; - config.pixelFormat = V4L2_PIX_FMT_IPU3_SGRBG10; - config.bufferCount = 4; + config->bufferCount = IPU3_BUFFER_COUNT; - configs[&data->stream_] = config; + LOG(IPU3, Debug) + << "Stream format set to = (" << config->width << "x" + << config->height << ") - 0x" << std::hex << std::setfill('0') + << std::setw(8) << config->pixelFormat; return configs; } @@ -327,6 +353,50 @@ bool PipelineHandlerIPU3::match(DeviceEnumerator *enumerator) return true; } +int PipelineHandlerIPU3::mediaBusToCIO2Format(unsigned int code) +{ + switch(code) { + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE: + case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE: + case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE: + case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE: + case MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8: + case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8: + case MEDIA_BUS_FMT_SBGGR12_1X12: + case MEDIA_BUS_FMT_SBGGR14_1X14: + case MEDIA_BUS_FMT_SBGGR16_1X16: + return V4L2_PIX_FMT_IPU3_SBGGR10; + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8: + case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8: + case MEDIA_BUS_FMT_SGBRG12_1X12: + case MEDIA_BUS_FMT_SGBRG14_1X14: + case MEDIA_BUS_FMT_SGBRG16_1X16: + return V4L2_PIX_FMT_IPU3_SGBRG10; + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8: + case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8: + case MEDIA_BUS_FMT_SGRBG12_1X12: + case MEDIA_BUS_FMT_SGRBG14_1X14: + case MEDIA_BUS_FMT_SGRBG16_1X16: + return V4L2_PIX_FMT_IPU3_SGRBG10; + case MEDIA_BUS_FMT_SRGGB8_1X8: + case MEDIA_BUS_FMT_SRGGB10_1X10: + case MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8: + case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8: + case MEDIA_BUS_FMT_SRGGB12_1X12: + case MEDIA_BUS_FMT_SRGGB14_1X14: + case MEDIA_BUS_FMT_SRGGB16_1X16: + return V4L2_PIX_FMT_IPU3_SRGGB10; + default: + return -EINVAL; + } +} + /* * Cameras are created associating an image sensor (represented by a * media entity with function MEDIA_ENT_F_CAM_SENSOR) to one of the four From patchwork Tue Mar 12 12:12:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 719 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E78C6600FC for ; Tue, 12 Mar 2019 13:12:21 +0100 (CET) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 748DF1C0005; Tue, 12 Mar 2019 12:12:21 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 12 Mar 2019 13:12:32 +0100 Message-Id: <20190312121242.2253-5-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190312121242.2253-1-jacopo@jmondi.org> References: <20190312121242.2253-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 04/14] libcamera: ipu3: Initialize and configure CIO2 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 12 Mar 2019 12:12:22 -0000 Group CIO2 devices (cio2, csi2 and image sensor) in a structure associated with the CameraData, to ease management and initialize it at camera registration time, as a CIO2 unit will always be associated with a Camera only. Update the IPU3 pipeline handler implementation to avoid name clashes and break-out IPU3CameraData from the pipeline handler class. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 289 ++++++++++++++++----------- 1 file changed, 167 insertions(+), 122 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 0f18e4692e77..0a2516ac7d61 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -27,6 +27,39 @@ namespace libcamera { LOG_DEFINE_CATEGORY(IPU3) +struct CIO2Device { + CIO2Device() + : output(nullptr), csi2(nullptr), sensor(nullptr) + { + } + + ~CIO2Device() + { + delete output; + delete csi2; + delete sensor; + } + + V4L2Device *output; + V4L2Subdevice *csi2; + V4L2Subdevice *sensor; +}; + +class IPU3CameraData : public CameraData +{ +public: + IPU3CameraData(PipelineHandler *pipe) + : CameraData(pipe) + { + } + + void bufferReady(Buffer *buffer); + + CIO2Device cio2; + + Stream stream_; +}; + class PipelineHandlerIPU3 : public PipelineHandler { public: @@ -50,31 +83,6 @@ public: bool match(DeviceEnumerator *enumerator); private: - class IPU3CameraData : public CameraData - { - public: - IPU3CameraData(PipelineHandler *pipe) - : CameraData(pipe), cio2_(nullptr), csi2_(nullptr), - sensor_(nullptr) - { - } - - ~IPU3CameraData() - { - delete cio2_; - delete csi2_; - delete sensor_; - } - - void bufferReady(Buffer *buffer); - - V4L2Device *cio2_; - V4L2Subdevice *csi2_; - V4L2Subdevice *sensor_; - - Stream stream_; - }; - static constexpr unsigned int IPU3_BUFFER_COUNT = 4; IPU3CameraData *cameraData(const Camera *camera) @@ -85,24 +93,25 @@ private: int mediaBusToCIO2Format(unsigned int code); + int initCIO2(unsigned int index, CIO2Device *cio2); void registerCameras(); - std::shared_ptr cio2_; - std::shared_ptr imgu_; + std::shared_ptr cio2MediaDev_; + std::shared_ptr imguMediaDev_; }; PipelineHandlerIPU3::PipelineHandlerIPU3(CameraManager *manager) - : PipelineHandler(manager), cio2_(nullptr), imgu_(nullptr) + : PipelineHandler(manager), cio2MediaDev_(nullptr), imguMediaDev_(nullptr) { } PipelineHandlerIPU3::~PipelineHandlerIPU3() { - if (cio2_) - cio2_->release(); + if (cio2MediaDev_) + cio2MediaDev_->release(); - if (imgu_) - imgu_->release(); + if (imguMediaDev_) + imguMediaDev_->release(); } std::map @@ -111,7 +120,7 @@ PipelineHandlerIPU3::streamConfiguration(Camera *camera, { std::map configs; IPU3CameraData *data = cameraData(camera); - V4L2Subdevice *sensor = data->sensor_; + V4L2Subdevice *sensor = data->cio2.sensor; StreamConfiguration *config = &configs[&data->stream_]; /* @@ -157,9 +166,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; @@ -216,13 +225,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; @@ -234,8 +244,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; @@ -247,9 +258,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; @@ -261,8 +273,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); @@ -271,6 +284,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); @@ -280,7 +294,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; @@ -319,17 +333,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 @@ -338,17 +352,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; } @@ -397,6 +411,95 @@ int PipelineHandlerIPU3::mediaBusToCIO2Format(unsigned int code) } } +/** + * \brief Initialize components of the CIO2 device \a index used by a camera + * \param index The CIO2 device index + * \param cio2 Pointer to the CIO2 instance + * + * Create and open the device and subdevices in the CIO2 instance at \a index, + * if an image sensor is connected to the CSI-2 receiver of this CIO2 instance. + * Enable the media links connecting the CIO2 components to prepare for capture + * operations. + * + * \return 0 on success or a negative error code otherwise + * \retval -EINVAL Failure to create or open a video device or subdevice + * \retval -ENODEV No image sensor is connected to this CIO2 instance + */ +int PipelineHandlerIPU3::initCIO2(unsigned int index, CIO2Device *cio2) +{ + std::string cio2Name = "ipu3-cio2 " + std::to_string(index); + std::string csi2Name = "ipu3-csi2 " + std::to_string(index); + int ret; + + /* Verify a sensor subdevice is connected to this CIO2 instance. */ + MediaEntity *entity = cio2MediaDev_->getEntityByName(csi2Name); + if (!entity) { + LOG(IPU3, Error) + << "Failed to get entity '" << csi2Name << "'"; + return -EINVAL; + } + + const std::vector &pads = entity->pads(); + if (pads.empty()) + return -EINVAL; + + /* IPU3 CSI-2 receivers have a single sink pad at index 0. */ + MediaPad *sink = pads[0]; + const std::vector &links = sink->links(); + if (links.empty()) + return -EINVAL; + + MediaLink *link = links[0]; + MediaEntity *sensorEntity = link->source()->entity(); + if (sensorEntity->function() != MEDIA_ENT_F_CAM_SENSOR) + return -ENODEV; + + ret = link->setEnabled(true); + if (ret) + return ret; + + /* + * Now that we're sure a sensor subdevice is connected, create and open + * video devices and subdevices associated with this CIO2 unit. + * + * \todo Define when to open and close video device nodes, as they + * might impact on power consumption. + */ + cio2->sensor = new V4L2Subdevice(sensorEntity); + ret = cio2->sensor->open(); + if (ret) + goto error_delete_sensor; + + cio2->csi2 = new V4L2Subdevice(entity); + ret = cio2->csi2->open(); + if (ret) + goto error_delete_csi2; + + entity = cio2MediaDev_->getEntityByName(cio2Name); + if (!entity) { + LOG(IPU3, Error) + << "Failed to get entity '" << cio2Name << "'"; + ret = -EINVAL; + goto error_delete_csi2; + } + + cio2->output = new V4L2Device(entity); + ret = cio2->output->open(); + if (ret) + goto error_delete_output; + + return 0; + +error_delete_output: + delete cio2->output; +error_delete_csi2: + delete cio2->csi2; +error_delete_sensor: + delete cio2->sensor; + + return ret; +} + /* * Cameras are created associating an image sensor (represented by a * media entity with function MEDIA_ENT_F_CAM_SENSOR) to one of the four @@ -410,81 +513,23 @@ void PipelineHandlerIPU3::registerCameras() */ unsigned int numCameras = 0; for (unsigned int id = 0; id < 4; ++id) { - std::string csi2Name = "ipu3-csi2 " + std::to_string(id); - MediaEntity *csi2 = cio2_->getEntityByName(csi2Name); - int ret; - - /* - * This shall not happen, as the device enumerator matched - * all entities described in the cio2_dm DeviceMatch. - * - * As this check is basically free, better stay safe than sorry. - */ - if (!csi2) - continue; - - const std::vector &pads = csi2->pads(); - if (pads.empty()) - continue; - - /* IPU3 CSI-2 receivers have a single sink pad at index 0. */ - MediaPad *sink = pads[0]; - const std::vector &links = sink->links(); - if (links.empty()) - continue; - - /* - * Verify that the receiver is connected to a sensor, enable - * the media link between the two, and create a Camera with - * a unique name. - */ - MediaLink *link = links[0]; - MediaEntity *sensor = link->source()->entity(); - if (sensor->function() != MEDIA_ENT_F_CAM_SENSOR) - continue; - - if (link->setEnabled(true)) - continue; - - std::unique_ptr data = utils::make_unique(this); - - std::string cameraName = sensor->name() + " " + std::to_string(id); + std::unique_ptr data = + utils::make_unique(this); std::set streams{ &data->stream_ }; - std::shared_ptr camera = Camera::create(this, cameraName, streams); - - /* - * Create and open video devices and subdevices associated with - * the camera. - * - * If any of these operations fails, the Camera instance won't - * be registered. The 'camera' shared pointer and the 'data' - * unique pointers go out of scope and delete the objects they - * manage. - */ - std::string cio2Name = "ipu3-cio2 " + std::to_string(id); - MediaEntity *cio2 = cio2_->getEntityByName(cio2Name); - if (!cio2) { - LOG(IPU3, Error) - << "Failed to get entity '" << cio2Name << "'"; - continue; - } + CIO2Device *cio2 = &data->cio2; + int ret; - data->cio2_ = new V4L2Device(cio2); - ret = data->cio2_->open(); + ret = initCIO2(id, cio2); if (ret) continue; - data->cio2_->bufferReady.connect(data.get(), &IPU3CameraData::bufferReady); + std::string cameraName = cio2->sensor->deviceName() + " " + + std::to_string(id); + std::shared_ptr camera = + Camera::create(this, cameraName, streams); - data->sensor_ = new V4L2Subdevice(sensor); - ret = data->sensor_->open(); - if (ret) - continue; - - data->csi2_ = new V4L2Subdevice(csi2); - ret = data->csi2_->open(); - if (ret) - continue; + cio2->output->bufferReady.connect(data.get(), + &IPU3CameraData::bufferReady); registerCamera(std::move(camera), std::move(data)); @@ -497,7 +542,7 @@ void PipelineHandlerIPU3::registerCameras() } } -void PipelineHandlerIPU3::IPU3CameraData::bufferReady(Buffer *buffer) +void IPU3CameraData::bufferReady(Buffer *buffer) { Request *request = queuedRequests_.front(); From patchwork Tue Mar 12 12:12:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 720 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 959A3600FC for ; Tue, 12 Mar 2019 13:12:22 +0100 (CET) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 1DD3F1C0005; Tue, 12 Mar 2019 12:12:21 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 12 Mar 2019 13:12:33 +0100 Message-Id: <20190312121242.2253-6-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190312121242.2253-1-jacopo@jmondi.org> References: <20190312121242.2253-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 05/14] libcamera: ipu3: Initialize and configure ImgUs X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 12 Mar 2019 12:12:22 -0000 Create video devices and subdevices associated with an ImgU unit at camera registration time. Statically assign imgu0 to the first camera and imgu1 to the second one and limit support to two camera. This will have to be revised in future. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 222 +++++++++++++++++++++++++-- 1 file changed, 208 insertions(+), 14 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 0a2516ac7d61..009ee341f18c 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -27,6 +27,37 @@ namespace libcamera { LOG_DEFINE_CATEGORY(IPU3) +class ImgUDevice { +public: + ImgUDevice() + : imgu(nullptr), input(nullptr), output(nullptr), + viewfinder(nullptr), stat(nullptr) + { + } + + ~ImgUDevice() + { + delete imgu; + delete input; + delete output; + delete viewfinder; + delete stat; + } + + void init(MediaDevice *media, unsigned int index); + + unsigned int index_; + std::string imguName_; + MediaDevice *mediaDevice_; + + V4L2Subdevice *imgu; + V4L2Device *input; + V4L2Device *output; + V4L2Device *viewfinder; + V4L2Device *stat; + /* \todo Add param video device for 3A tuning */ +}; + struct CIO2Device { CIO2Device() : output(nullptr), csi2(nullptr), sensor(nullptr) @@ -56,6 +87,7 @@ public: void bufferReady(Buffer *buffer); CIO2Device cio2; + ImgUDevice *imgu; Stream stream_; }; @@ -83,6 +115,7 @@ public: bool match(DeviceEnumerator *enumerator); private: + static constexpr unsigned int IPU3_IMGU_COUNT = 2; static constexpr unsigned int IPU3_BUFFER_COUNT = 4; IPU3CameraData *cameraData(const Camera *camera) @@ -92,10 +125,18 @@ private: } int mediaBusToCIO2Format(unsigned int code); + V4L2Device *openDevice(MediaDevice *media, const std::string &name); + V4L2Subdevice *openSubdevice(MediaDevice *media, + const std::string &name); int initCIO2(unsigned int index, CIO2Device *cio2); + void deleteCIO2(CIO2Device *cio2); + + int initImgU(ImgUDevice *imgu); + void registerCameras(); + ImgUDevice imgus_[IPU3_IMGU_COUNT]; std::shared_ptr cio2MediaDev_; std::shared_ptr imguMediaDev_; }; @@ -360,11 +401,45 @@ bool PipelineHandlerIPU3::match(DeviceEnumerator *enumerator) return false; } + if (imguMediaDev_->open()) { + cio2MediaDev_->close(); + return false; + } + + if (imguMediaDev_->disableLinks()) + goto error_close_mdev; + + for (unsigned int i = 0; i < IPU3_IMGU_COUNT; ++i) + imgus_[i].init(imguMediaDev_.get(), i); + registerCameras(); cio2MediaDev_->close(); + imguMediaDev_->close(); return true; + +error_close_mdev: + cio2MediaDev_->close(); + imguMediaDev_->close(); + + return false; +} + +/* ---------------------------------------------------------------------------- + * Helpers + */ + +/** + * \brief Initialize fields of the ImgU instance + * \param mediaDevice The ImgU instance media device + * \param index The ImgU instance index + */ +void ImgUDevice::init(MediaDevice *mediaDevice, unsigned int index) +{ + index_ = index; + imguName_ = "ipu3-imgu " + std::to_string(index_); + mediaDevice_ = mediaDevice; } int PipelineHandlerIPU3::mediaBusToCIO2Format(unsigned int code) @@ -411,6 +486,114 @@ int PipelineHandlerIPU3::mediaBusToCIO2Format(unsigned int code) } } +/** + * \brief Create and open the video device with \a name in media device \a media + * + * \todo Make a generic helper out of this method. + * + * \return Pointer to the video device on success, nullptr otherwise + */ +V4L2Device *PipelineHandlerIPU3::openDevice(MediaDevice *media, + const std::string &name) +{ + MediaEntity *entity = media->getEntityByName(name); + if (!entity) { + LOG(IPU3, Error) + << "Failed to get entity '" << name << "'"; + return nullptr; + } + + V4L2Device *dev = new V4L2Device(entity); + if (dev->open()) { + delete dev; + return nullptr; + } + + return dev; +} + +/** + * \brief Create and open the subdevice with \a name in media device \a media + * + * \todo Make a generic helper out of this method. + * + * \return Pointer to the subdevice on success, nullptr otherwise + */ +V4L2Subdevice *PipelineHandlerIPU3::openSubdevice(MediaDevice *media, + const std::string &name) +{ + MediaEntity *entity = media->getEntityByName(name); + if (!entity) { + LOG(IPU3, Error) + << "Failed to get entity '" << name << "'"; + return nullptr; + } + + V4L2Subdevice *dev = new V4L2Subdevice(entity); + if (dev->open()) { + delete dev; + return nullptr; + } + + return dev; +} + +/* ---------------------------------------------------------------------------- + * IPU3 pipeline configuration + */ + +/** + * \brief Initialize and configure components of the ImgU instance + * + * Create and open the devices and subdevices in the ImgU instance. + * This methods configures the ImgU instance for capture operations, and + * should be called at stream configuration time. + * + * \todo Expand the ImgU configuration with controls setting + * + * \return 0 on success or a negative error code otherwise + * \retval -ENODEV Failed to open one of the video devices or subdevices + */ +int PipelineHandlerIPU3::initImgU(ImgUDevice *imgu) +{ + imgu->imgu = openSubdevice(imgu->mediaDevice_, imgu->imguName_); + if (!imgu->imgu) + return -ENODEV; + + imgu->input = openDevice(imgu->mediaDevice_, + imgu->imguName_ + " input"); + if (!imgu->input) + goto error_delete_imgu; + + imgu->output = openDevice(imgu->mediaDevice_, + imgu->imguName_ + " output"); + if (!imgu->output) + goto error_delete_input; + + imgu->viewfinder = openDevice(imgu->mediaDevice_, + imgu->imguName_ + " viewfinder"); + if (!imgu->viewfinder) + goto error_delete_output; + + imgu->stat = openDevice(imgu->mediaDevice_, + imgu->imguName_ + " 3a stat"); + if (!imgu->stat) + goto error_delete_vf; + + return 0; + +error_delete_vf: + delete imgu->viewfinder; +error_delete_output: + delete imgu->output; +error_delete_input: + delete imgu->input; +error_delete_imgu: + delete imgu->imgu; + + return -ENODEV; +} + /** * \brief Initialize components of the CIO2 device \a index used by a camera * \param index The CIO2 device index @@ -475,23 +658,12 @@ int PipelineHandlerIPU3::initCIO2(unsigned int index, CIO2Device *cio2) if (ret) goto error_delete_csi2; - entity = cio2MediaDev_->getEntityByName(cio2Name); - if (!entity) { - LOG(IPU3, Error) - << "Failed to get entity '" << cio2Name << "'"; - ret = -EINVAL; + cio2->output = openDevice(cio2MediaDev_.get(), cio2Name); + if (!cio2->output) goto error_delete_csi2; - } - - cio2->output = new V4L2Device(entity); - ret = cio2->output->open(); - if (ret) - goto error_delete_output; return 0; -error_delete_output: - delete cio2->output; error_delete_csi2: delete cio2->csi2; error_delete_sensor: @@ -500,6 +672,16 @@ error_delete_sensor: return ret; } +/** + * \brief Delete all devices associated with a CIO2 unit + */ +void PipelineHandlerIPU3::deleteCIO2(CIO2Device *cio2) +{ + delete cio2->output; + delete cio2->csi2; + delete cio2->sensor; +} + /* * Cameras are created associating an image sensor (represented by a * media entity with function MEDIA_ENT_F_CAM_SENSOR) to one of the four @@ -512,7 +694,7 @@ void PipelineHandlerIPU3::registerCameras() * image sensor is connected to it. */ unsigned int numCameras = 0; - for (unsigned int id = 0; id < 4; ++id) { + for (unsigned int id = 0; id < 4 && numCameras < 2; ++id) { std::unique_ptr data = utils::make_unique(this); std::set streams{ &data->stream_ }; @@ -523,6 +705,18 @@ void PipelineHandlerIPU3::registerCameras() if (ret) continue; + /** + * \todo Dynamically assign ImgU devices; as of now, limit + * support to two cameras only, and assign imgu0 to the first + * one and imgu1 to the second. + */ + data->imgu = &imgus_[numCameras]; + ret = initImgU(data->imgu); + if (ret) { + deleteCIO2(cio2); + continue; + } + std::string cameraName = cio2->sensor->deviceName() + " " + std::to_string(id); std::shared_ptr camera = From patchwork Tue Mar 12 12:12:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 721 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 42791611A2 for ; Tue, 12 Mar 2019 13:12:23 +0100 (CET) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id BE6CE1C0005; Tue, 12 Mar 2019 12:12:22 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 12 Mar 2019 13:12:34 +0100 Message-Id: <20190312121242.2253-7-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190312121242.2253-1-jacopo@jmondi.org> References: <20190312121242.2253-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 06/14] libcamera: ipu3: Propagate image format X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 12 Mar 2019 12:12:23 -0000 Apply the requested image format to the sensor device, and apply the adjusted one to the CIO2 device, the ImgU subdevice and its input and output video devices. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 220 +++++++++++++++++++++++---- 1 file changed, 189 insertions(+), 31 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 009ee341f18c..3502c39f5e31 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -16,6 +16,7 @@ #include #include "device_enumerator.h" +#include "geometry.h" #include "log.h" #include "media_device.h" #include "pipeline_handler.h" @@ -29,6 +30,11 @@ LOG_DEFINE_CATEGORY(IPU3) class ImgUDevice { public: + static constexpr unsigned int PAD_INPUT = 0; + static constexpr unsigned int PAD_OUTPUT = 2; + static constexpr unsigned int PAD_VF = 3; + static constexpr unsigned int PAD_STAT = 4; + ImgUDevice() : imgu(nullptr), input(nullptr), output(nullptr), viewfinder(nullptr), stat(nullptr) @@ -134,6 +140,13 @@ private: int initImgU(ImgUDevice *imgu); + int setImguFormat(ImgUDevice *imguDevice, + const StreamConfiguration &config, + Rectangle *rect); + int setCIO2Format(CIO2Device *cio2Device, + const StreamConfiguration &config, + V4L2SubdeviceFormat *format); + void registerCameras(); ImgUDevice imgus_[IPU3_IMGU_COUNT]; @@ -206,60 +219,86 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, std::map &config) { IPU3CameraData *data = cameraData(camera); - StreamConfiguration *cfg = &config[&data->stream_]; - V4L2Subdevice *sensor = data->cio2.sensor; - V4L2Subdevice *csi2 = data->cio2.csi2; + const StreamConfiguration &cfg = config[&data->stream_]; + V4L2Device *viewfinder = data->imgu->viewfinder; + V4L2Device *output = data->imgu->output; + V4L2Device *input = data->imgu->input; V4L2Device *cio2 = data->cio2.output; - V4L2SubdeviceFormat subdevFormat = {}; - V4L2DeviceFormat devFormat = {}; int ret; + LOG(IPU3, Info) + << "Requested image format: " << cfg.width << "x" + << cfg.height << " - " << std::hex << std::setw(8) + << cfg.pixelFormat << " on camera:'" << camera->name() << "'"; + /* - * FIXME: as of now, the format gets applied to the sensor and is - * propagated along the pipeline. It should instead be applied on the - * capture device and the sensor format calculated accordingly. + * Verify that the requested size respects the IPU3 alignement + * requirements: the image width shall be a multiple of 8 pixels and + * its height a multiple of 4 pixels. + * + * \todo: consider the BDS scaling factor requirements: + * "the downscaling factor must be an integer value multiple of 1/32" */ + if (cfg.width % 8 || cfg.height % 4) { + LOG(IPU3, Error) << "Stream format not support: bad alignement"; + return -EINVAL; + } - ret = sensor->getFormat(0, &subdevFormat); + /* + * Pass the requested output image size to the sensor and get back the + * adjusted one to be propagated to the CIO2 device and to the ImgU + * input. + */ + V4L2SubdeviceFormat sensorFormat = {}; + ret = setCIO2Format(&data->cio2, cfg, &sensorFormat); if (ret) return ret; - subdevFormat.width = cfg->width; - subdevFormat.height = cfg->height; - ret = sensor->setFormat(0, &subdevFormat); + /* Apply the CIO2 image format to the CIO2 output and ImgU input. */ + V4L2DeviceFormat cio2Format = {}; + cio2Format.width = sensorFormat.width; + cio2Format.height = sensorFormat.height; + cio2Format.fourcc = mediaBusToCIO2Format(sensorFormat.mbus_code); + cio2Format.planesCount = 1; + ret = cio2->setFormat(&cio2Format); if (ret) return ret; - /* Return error if the requested format cannot be applied to sensor. */ - if (subdevFormat.width != cfg->width || - subdevFormat.height != cfg->height) { - LOG(IPU3, Error) - << "Failed to apply image format " - << subdevFormat.width << "x" << subdevFormat.height - << " - got: " << cfg->width << "x" << cfg->height; - return -EINVAL; - } + LOG(IPU3, Debug) + << "CIO2 output format = " << cio2Format.toString(); - ret = csi2->setFormat(0, &subdevFormat); + ret = input->setFormat(&cio2Format); if (ret) return ret; - ret = cio2->getFormat(&devFormat); + /* Apply pad formats and crop/compose rectangle to the ImgU. */ + Rectangle rect = { + .x = 0, + .y = 0, + .w = cio2Format.width, + .h = cio2Format.height, + }; + ret = setImguFormat(data->imgu, cfg, &rect); if (ret) return ret; - devFormat.width = subdevFormat.width; - devFormat.height = subdevFormat.height; - devFormat.fourcc = cfg->pixelFormat; + /* Apply the format to the ImgU output and viewfinder devices. */ + V4L2DeviceFormat outputFormat = {}; + outputFormat.width = cfg.width; + outputFormat.height = cfg.height; + outputFormat.fourcc = V4L2_PIX_FMT_NV12; + outputFormat.planesCount = 2; - ret = cio2->setFormat(&devFormat); + ret = output->setFormat(&outputFormat); if (ret) return ret; - LOG(IPU3, Info) << cio2->driverName() << ": " - << devFormat.width << "x" << devFormat.height - << "- 0x" << std::hex << devFormat.fourcc << " planes: " - << devFormat.planes; + LOG(IPU3, Debug) + << "ImgU output format = " << outputFormat.toString(); + + ret = viewfinder->setFormat(&outputFormat); + if (ret) + return ret; return 0; } @@ -682,6 +721,125 @@ void PipelineHandlerIPU3::deleteCIO2(CIO2Device *cio2) delete cio2->sensor; } +int PipelineHandlerIPU3::setImguFormat(ImgUDevice *imguDevice, + const StreamConfiguration &config, + Rectangle *rect) +{ + V4L2Subdevice *imgu = imguDevice->imgu; + int ret; + + /* + * Configure the 'imgu' subdevice with the requested sizes. + * + * FIXME: the IPU3 driver implementation shall be changed to use the + * actual input sizes as 'imgu input' subdevice sizes, and use the + * desired output sizes to configure the crop/compose rectangles. The + * current implementation uses output sizes as 'imgu input' sizes, and + * uses the input dimension to configure the crop/compose rectangles, + * which contradicts the V4L2 specifications. + */ + ret = imgu->setCrop(ImgUDevice::PAD_INPUT, rect); + if (ret) + return ret; + + ret = imgu->setCompose(ImgUDevice::PAD_INPUT, rect); + if (ret) + return ret; + + LOG(IPU3, Debug) + << "ImgU input feeder and BDS rectangle = (0,0)/" + << rect->w << "x" << rect->h; + + V4L2SubdeviceFormat imguFormat = {}; + imguFormat.width = config.width; + imguFormat.height = config.height; + imguFormat.mbus_code = MEDIA_BUS_FMT_FIXED; + + ret = imgu->setFormat(ImgUDevice::PAD_INPUT, &imguFormat); + if (ret) + return ret; + + ret = imgu->setFormat(ImgUDevice::PAD_OUTPUT, &imguFormat); + if (ret) + return ret; + + LOG(IPU3, Debug) + << "ImgU GDC format = " << imguFormat.toString(); + + ret = imgu->setFormat(ImgUDevice::PAD_VF, &imguFormat); + if (ret) + return ret; + + ret = imgu->setFormat(ImgUDevice::PAD_STAT, &imguFormat); + if (ret) + return ret; + + return 0; +} + +int PipelineHandlerIPU3::setCIO2Format(CIO2Device *cio2Device, + const StreamConfiguration &config, + V4L2SubdeviceFormat *format) +{ + unsigned int imageSize = config.width * config.height; + V4L2Subdevice *sensor = cio2Device->sensor; + V4L2Subdevice *csi2 = cio2Device->csi2; + unsigned int best = ~0; + bool found = false; + int ret; + + const SubdevFormatEnum formats = sensor->formats(0); + for (auto it = formats.begin(); it != formats.end(); ++it) { + /* Only consider formats consumable by the CIO2 unit. */ + int cio2Code = mediaBusToCIO2Format(it->first); + if (cio2Code == -EINVAL) + continue; + + for (const SizeRange &size : it->second) { + /* + * Only select formats bigger than the requested sizes + * as the IPU3 cannot up-scale. + */ + if (size.maxWidth < config.width || + size.maxHeight < config.height) + continue; + + unsigned int diff = size.maxWidth * size.maxHeight + - imageSize; + if (diff >= best) + continue; + + best = diff; + found = true; + + format->width = size.maxWidth; + format->height = size.maxHeight; + format->mbus_code = it->first; + } + } + if (!found) { + LOG(IPU3, Error) + << "Unable to find image format suitable to produce: " + << config.width << "x" << config.height + << "- 0x" << std::hex << std::setfill('0') + << std::setw(8) << config.pixelFormat; + return -EINVAL; + } + + /* Apply the selected format to the sensor and the CSI-2 receiver. */ + ret = sensor->setFormat(0, format); + if (ret) + return ret; + + ret = csi2->setFormat(0, format); + if (ret) + return ret; + + LOG(IPU3, Debug) << "CIO2 Image format: " << format->toString(); + + return 0; +} + /* * Cameras are created associating an image sensor (represented by a * media entity with function MEDIA_ENT_F_CAM_SENSOR) to one of the four From patchwork Tue Mar 12 12:12:35 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 722 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C706C611A2 for ; Tue, 12 Mar 2019 13:12:23 +0100 (CET) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 5BE4A1C000A; Tue, 12 Mar 2019 12:12:23 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 12 Mar 2019 13:12:35 +0100 Message-Id: <20190312121242.2253-8-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190312121242.2253-1-jacopo@jmondi.org> References: <20190312121242.2253-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 07/14] 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, 12 Mar 2019 12:12:24 -0000 Start and stop video devices in the pipeline. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 54 ++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 3502c39f5e31..363b24ceead2 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -338,12 +338,52 @@ int PipelineHandlerIPU3::freeBuffers(Camera *camera, Stream *stream) int PipelineHandlerIPU3::start(Camera *camera) { IPU3CameraData *data = cameraData(camera); - V4L2Device *cio2 = data->cio2.output; int ret; - ret = cio2->streamOn(); + /* + * Enqueue all available buffers to the CIO2 unit to start frame + * capture. Start ImgU video devices and queue buffers to the output + * ones at queueRequest() time. + */ + for (Buffer &buffer: data->cio2.pool.buffers()) { + ret = data->cio2.output->queueBuffer(&buffer); + if (ret) + return ret; + } + + ret = data->cio2.output->streamOn(); if (ret) { - LOG(IPU3, Info) << "Failed to start camera " << camera->name(); + LOG(IPU3, Error) << "Failed to start CIO2"; + stop(camera); + return ret; + } + + /* Start the ImgU video devices. */ + ret = data->imgu->output->streamOn(); + if (ret) { + LOG(IPU3, Error) << "Failed to start ImgU output"; + stop(camera); + return ret; + } + + ret = data->imgu->viewfinder->streamOn(); + if (ret) { + LOG(IPU3, Error) << "Failed to start ImgU viewfinder"; + stop(camera); + return ret; + } + + ret = data->imgu->stat->streamOn(); + if (ret) { + LOG(IPU3, Error) << "Failed to start ImgU stat"; + stop(camera); + return ret; + } + + ret = data->imgu->input->streamOn(); + if (ret) { + LOG(IPU3, Error) << "Failed to start ImgU input"; + stop(camera); return ret; } @@ -353,10 +393,12 @@ int PipelineHandlerIPU3::start(Camera *camera) void PipelineHandlerIPU3::stop(Camera *camera) { IPU3CameraData *data = cameraData(camera); - V4L2Device *cio2 = data->cio2.output; - if (cio2->streamOff()) - LOG(IPU3, Info) << "Failed to stop camera " << camera->name(); + data->cio2.output->streamOff(); + data->imgu->output->streamOff(); + data->imgu->viewfinder->streamOff(); + data->imgu->stat->streamOff(); + data->imgu->input->streamOff(); PipelineHandler::stop(camera); } From patchwork Tue Mar 12 12:12:36 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 723 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 62522611A2 for ; Tue, 12 Mar 2019 13:12:24 +0100 (CET) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id EEBE41C000A; Tue, 12 Mar 2019 12:12:23 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 12 Mar 2019 13:12:36 +0100 Message-Id: <20190312121242.2253-9-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190312121242.2253-1-jacopo@jmondi.org> References: <20190312121242.2253-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 08/14] libcamera: ipu3: Implement buffer allocation X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 12 Mar 2019 12:12:25 -0000 Implement buffer allocation in IPU3 pipeline handlers. As the pipeline handler supports a single stream, preprare two buffer pools for 'viewfinder' and 'stat' video devices, and export the 'output' video device buffers to the Stream's pool. Share buffers between the CIO2 output and the ImgU input video devices, as the output of the former should immediately be provided to the latter for further processing. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 48 +++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 363b24ceead2..ad866346e13c 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -62,6 +62,9 @@ public: V4L2Device *viewfinder; V4L2Device *stat; /* \todo Add param video device for 3A tuning */ + + BufferPool vfPool; + BufferPool statPool; }; struct CIO2Device { @@ -80,6 +83,8 @@ struct CIO2Device { V4L2Device *output; V4L2Subdevice *csi2; V4L2Subdevice *sensor; + + BufferPool pool; }; class IPU3CameraData : public CameraData @@ -123,6 +128,8 @@ public: private: static constexpr unsigned int IPU3_IMGU_COUNT = 2; static constexpr unsigned int IPU3_BUFFER_COUNT = 4; + static constexpr unsigned int IPU3_CIO2_BUFFER_COUNT = 4; + static constexpr unsigned int IPU3_IMGU_BUFFER_COUNT = 4; IPU3CameraData *cameraData(const Camera *camera) { @@ -305,16 +312,47 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, int PipelineHandlerIPU3::allocateBuffers(Camera *camera, Stream *stream) { - const StreamConfiguration &cfg = stream->configuration(); IPU3CameraData *data = cameraData(camera); + V4L2Device *viewfinder = data->imgu->viewfinder; + V4L2Device *output = data->imgu->output; + V4L2Device *input = data->imgu->input; V4L2Device *cio2 = data->cio2.output; + V4L2Device *stat = data->imgu->stat; + int ret; - if (!cfg.bufferCount) - return -EINVAL; + /* Share buffers between CIO2 output and ImgU input. */ + data->cio2.pool.createBuffers(IPU3_CIO2_BUFFER_COUNT); + ret = cio2->exportBuffers(&data->cio2.pool); + if (ret) { + LOG(IPU3, Error) << "Failed to reserve CIO2 memory"; + return ret; + } + + ret = input->importBuffers(&data->cio2.pool); + if (ret) { + LOG(IPU3, Error) << "Failed to import ImgU memory"; + return ret; + } + + /* Prepare the buffer pools for viewfinder and stat. */ + data->imgu->vfPool.createBuffers(IPU3_IMGU_BUFFER_COUNT); + ret = viewfinder->exportBuffers(&data->imgu->vfPool); + if (ret) { + LOG(IPU3, Error) << "Failed to reserve ImgU viewfinder memory"; + return ret; + } + + data->imgu->statPool.createBuffers(IPU3_IMGU_BUFFER_COUNT); + ret = stat->exportBuffers(&data->imgu->statPool); + if (ret) { + LOG(IPU3, Error) << "Failed to reserve ImgU stat memory"; + return ret; + } - int ret = cio2->exportBuffers(&stream->bufferPool()); + /* Export ImgU output buffers to the stream's pool. */ + ret = output->exportBuffers(&stream->bufferPool()); if (ret) { - LOG(IPU3, Error) << "Failed to request memory"; + LOG(IPU3, Error) << "Failed to reserve ImgU output memory"; return ret; } From patchwork Tue Mar 12 12:12:37 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 724 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 00E2E610D5 for ; Tue, 12 Mar 2019 13:12:25 +0100 (CET) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 8A3871C0005; Tue, 12 Mar 2019 12:12:24 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 12 Mar 2019 13:12:37 +0100 Message-Id: <20190312121242.2253-10-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190312121242.2253-1-jacopo@jmondi.org> References: <20190312121242.2253-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 09/14] libcamera: ipu3: Implement buffer release X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 12 Mar 2019 12:12:25 -0000 Release buffers on all video devices in the pipeline. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 30 +++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index ad866346e13c..badde4839f99 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -157,6 +157,7 @@ private: void registerCameras(); ImgUDevice imgus_[IPU3_IMGU_COUNT]; + std::shared_ptr cio2MediaDev_; std::shared_ptr imguMediaDev_; }; @@ -362,13 +363,32 @@ int PipelineHandlerIPU3::allocateBuffers(Camera *camera, Stream *stream) int PipelineHandlerIPU3::freeBuffers(Camera *camera, Stream *stream) { IPU3CameraData *data = cameraData(camera); + V4L2Device *viewfinder = data->imgu->viewfinder; + V4L2Device *output = data->imgu->output; + V4L2Device *input = data->imgu->input; V4L2Device *cio2 = data->cio2.output; + V4L2Device *stat = data->imgu->stat; + int ret; - int ret = cio2->releaseBuffers(); - if (ret) { - LOG(IPU3, Error) << "Failed to release memory"; - return ret; - } + ret = output->releaseBuffers(); + if (ret) + LOG(IPU3, Error) << "Failed to release ImgU output memory"; + + ret = stat->releaseBuffers(); + if (ret) + LOG(IPU3, Error) << "Failed to release ImgU stat memory"; + + ret = viewfinder->releaseBuffers(); + if (ret) + LOG(IPU3, Error) << "Failed to release ImgU viewfinder memory"; + + ret = input->releaseBuffers(); + if (ret) + LOG(IPU3, Error) << "Failed to release ImgU input memory"; + + ret = cio2->releaseBuffers(); + if (ret) + LOG(IPU3, Error) << "Failed to release CIO2 memory"; return 0; } From patchwork Tue Mar 12 12:12:38 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 725 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 92A41611A7 for ; Tue, 12 Mar 2019 13:12:25 +0100 (CET) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 262981C0005; Tue, 12 Mar 2019 12:12:24 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 12 Mar 2019 13:12:38 +0100 Message-Id: <20190312121242.2253-11-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190312121242.2253-1-jacopo@jmondi.org> References: <20190312121242.2253-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 10/14] libcamera: ipu3: Queue requests to the pipeline X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 12 Mar 2019 12:12:25 -0000 Implement queueRequest for the IPU3 pipeline manager. When a request is queued, a new buffer is queued to the ImgU output. Also queue buffers for the viewfinder and stat video nodes, even if they're not used at the moment. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index badde4839f99..1a7b96d9ada7 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -160,11 +160,15 @@ private: std::shared_ptr cio2MediaDev_; std::shared_ptr imguMediaDev_; + + unsigned int tmpBufferCount; }; PipelineHandlerIPU3::PipelineHandlerIPU3(CameraManager *manager) : PipelineHandler(manager), cio2MediaDev_(nullptr), imguMediaDev_(nullptr) { + /* FIXME: this is an hack. */ + tmpBufferCount = 0; } PipelineHandlerIPU3::~PipelineHandlerIPU3() @@ -464,9 +468,26 @@ void PipelineHandlerIPU3::stop(Camera *camera) int PipelineHandlerIPU3::queueRequest(Camera *camera, Request *request) { IPU3CameraData *data = cameraData(camera); - V4L2Device *cio2 = data->cio2.output; + V4L2Device *viewfinder = data->imgu->viewfinder; + V4L2Device *output = data->imgu->output; + V4L2Device *stat = data->imgu->stat; Stream *stream = &data->stream_; + Buffer *tmpBuffer; + + /* + * Queue buffer on VF and stat. + * FIXME: this is an hack! + */ + tmpBuffer = &data->imgu->vfPool.buffers()[tmpBufferCount]; + viewfinder->queueBuffer(tmpBuffer); + + tmpBuffer = &data->imgu->statPool.buffers()[tmpBufferCount]; + stat->queueBuffer(tmpBuffer); + + tmpBufferCount++; + tmpBufferCount %= IPU3_IMGU_BUFFER_COUNT; + /* Queue a buffer to the ImgU output for capture. */ Buffer *buffer = request->findBuffer(stream); if (!buffer) { LOG(IPU3, Error) @@ -474,7 +495,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 12 12:12:39 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 726 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3D4E8610D5 for ; Tue, 12 Mar 2019 13:12:26 +0100 (CET) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id BFFBC1C0002; Tue, 12 Mar 2019 12:12:25 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 12 Mar 2019 13:12:39 +0100 Message-Id: <20190312121242.2253-12-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190312121242.2253-1-jacopo@jmondi.org> References: <20190312121242.2253-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 11/14] 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, 12 Mar 2019 12:12:26 -0000 Connect the CIO2 output bufferRead signal to a slot that simply queue the received buffer to ImgU for processing, and connect the ImgU main output bufferReady signal to the cameraData slot that notifies to applications that a new image buffer is available. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 58 +++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 1a7b96d9ada7..4d08383291ea 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -95,7 +95,9 @@ public: { } - void bufferReady(Buffer *buffer); + void imguOutputBufferReady(Buffer *buffer); + void imguInputBufferReady(Buffer *buffer); + void cio2BufferReady(Buffer *buffer); CIO2Device cio2; ImgUDevice *imgu; @@ -402,6 +404,21 @@ int PipelineHandlerIPU3::start(Camera *camera) IPU3CameraData *data = cameraData(camera); int ret; + /* + * Connect video devices' 'bufferReady' signals to their slot to + * implement the image processing pipeline. + * + * Frames produced by the CIO2 unit are shared with the associated + * ImgU input where they get processed and returned through the ImgU + * main and secondary outputs. + */ + data->cio2.output->bufferReady.connect(data, + &IPU3CameraData::cio2BufferReady); + data->imgu->input->bufferReady.connect(data, + &IPU3CameraData::imguInputBufferReady); + data->imgu->output->bufferReady.connect(data, + &IPU3CameraData::imguOutputBufferReady); + /* * Enqueue all available buffers to the CIO2 unit to start frame * capture. Start ImgU video devices and queue buffers to the output @@ -1001,9 +1018,6 @@ void PipelineHandlerIPU3::registerCameras() 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) @@ -1015,7 +1029,29 @@ void PipelineHandlerIPU3::registerCameras() } } -void IPU3CameraData::bufferReady(Buffer *buffer) +/* ---------------------------------------------------------------------------- + * Buffer Ready slots + */ + +/** + * \brief ImgU input BufferReady slot + * \param buffer The completed buffer + * + * Buffer completed from the ImgU input are immediately queued back to the + * CIO2 unit to continue frame capture. + */ +void IPU3CameraData::imguInputBufferReady(Buffer *buffer) +{ + cio2.output->queueBuffer(buffer); +} + +/** + * \brief ImgU output BufferReady slot + * \param buffer The completed buffer + * + * Buffer completed from the ImgU output are directed to the applications. + */ +void IPU3CameraData::imguOutputBufferReady(Buffer *buffer) { Request *request = queuedRequests_.front(); @@ -1023,6 +1059,18 @@ void IPU3CameraData::bufferReady(Buffer *buffer) pipe_->completeRequest(camera_, request); } +/** + * \brief CIO2 BufferReady slot + * \param buffer The completed buffer + * + * Buffer completed from the CIO2 are immediately queued to the ImgU unit + * for further processing. + */ +void IPU3CameraData::cio2BufferReady(Buffer *buffer) +{ + imgu->input->queueBuffer(buffer); +} + REGISTER_PIPELINE_HANDLER(PipelineHandlerIPU3); } /* namespace libcamera */ From patchwork Tue Mar 12 12:12:40 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 727 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id CA4F5612E8 for ; Tue, 12 Mar 2019 13:12:26 +0100 (CET) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 61BEC1C0002; Tue, 12 Mar 2019 12:12:26 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 12 Mar 2019 13:12:40 +0100 Message-Id: <20190312121242.2253-13-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190312121242.2253-1-jacopo@jmondi.org> References: <20190312121242.2253-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 12/14] 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, 12 Mar 2019 12:12:27 -0000 Now that images come from the ImgU output, hardcode NV12 as default output format. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 4d08383291ea..f998f900b219 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -190,6 +190,7 @@ PipelineHandlerIPU3::streamConfiguration(Camera *camera, IPU3CameraData *data = cameraData(camera); V4L2Subdevice *sensor = data->cio2.sensor; StreamConfiguration *config = &configs[&data->stream_]; + bool found = false; /* * Make sure the sensor produces a raw format compatible with the @@ -208,17 +209,18 @@ PipelineHandlerIPU3::streamConfiguration(Camera *camera, config->width = range.maxWidth; config->height = range.maxHeight; - config->pixelFormat = cio2Code; + found = true; } } /* If not suitable format has been found, return an empty config. */ - if (!config->pixelFormat) { + if (!found) { LOG(IPU3, Error) << "Sensor image format not supported"; return configs; } + config->pixelFormat = V4L2_PIX_FMT_NV12; config->bufferCount = IPU3_BUFFER_COUNT; LOG(IPU3, Debug) From patchwork Tue Mar 12 12:12:41 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 728 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6266B611A8 for ; Tue, 12 Mar 2019 13:12:27 +0100 (CET) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id F16D41C0002; Tue, 12 Mar 2019 12:12:26 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 12 Mar 2019 13:12:41 +0100 Message-Id: <20190312121242.2253-14-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190312121242.2253-1-jacopo@jmondi.org> References: <20190312121242.2253-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 13/14] HACK: Soraka: Limit resolution to 2560x1920 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 12 Mar 2019 12:12:27 -0000 Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index f998f900b219..a113fd6ee74b 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -220,6 +220,16 @@ PipelineHandlerIPU3::streamConfiguration(Camera *camera, return configs; } + /* + * 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 12 12:12:42 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 729 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 01CC7611A8 for ; Tue, 12 Mar 2019 13:12:28 +0100 (CET) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 88C291C0002; Tue, 12 Mar 2019 12:12:27 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 12 Mar 2019 13:12:42 +0100 Message-Id: <20190312121242.2253-15-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190312121242.2253-1-jacopo@jmondi.org> References: <20190312121242.2253-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 14/14] RFC: libcamera: ipu3: Enable ImgU media links X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 12 Mar 2019 12:12:28 -0000 As the lenghty comment reports, link enable/disable is not trivial, as links in one ImgU instance interfere with capture operations in the other one. As I struggle to find where to disable links selectively, as of now reset the media graph and only enable the required links at streamConfiguration time. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 107 +++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index a113fd6ee74b..1c0d63f912d5 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -51,6 +51,10 @@ public: } void init(MediaDevice *media, unsigned int index); + int linkSetup(const std::string &source, unsigned int sourcePad, + const std::string &sink, unsigned int sinkPad, + bool enable); + int enableLinks(bool enable); unsigned int index_; std::string imguName_; @@ -270,6 +274,35 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, return -EINVAL; } + /* + * 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, then trying to capture from the other + * one right after without disabling media links in the media graph. + * + * The tricky part here is where to disable links on the ImgU instance + * which is 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 here, before configuring formats, + * the only place where to disable links would be 'stop()', but the + * camera state machine allows start()<->stop() sequences without any + * streamConfiguration() in between. + * + * As of now, disable all links in the media graph before enabling + * the requested ones only. + */ + data->imgu->mediaDevice_->disableLinks(); + + /* + * \todo: Enable links selectively based on the requested streams. + * As of now, enable all links unconditionally. + */ + ret = data->imgu->enableLinks(true); + if (ret) + return ret; + /* * Pass the requested output image size to the sensor and get back the * adjusted one to be propagated to the CIO2 device and to the ImgU @@ -631,6 +664,80 @@ void ImgUDevice::init(MediaDevice *mediaDevice, unsigned int index) mediaDevice_ = mediaDevice; } +/** + * \brief Enable or disable a single link on the ImgU instance + * + * This method assumes the media device associated with the ImgU instance + * is open. + * + * \return 0 on success or a negative error code otherwise + */ +int ImgUDevice::linkSetup(const std::string &source, unsigned int sourcePad, + const std::string &sink, unsigned int sinkPad, + bool enable) +{ + MediaLink *link = mediaDevice_->link(source, sourcePad, sink, sinkPad); + if (!link) { + LOG(IPU3, Error) + << "Failed to get link: '" << source << "':" + << sourcePad << " -> '" << sink << "':" << sinkPad; + return -ENODEV; + } + + return link->setEnabled(enable); +} + +/** + * \brief Enable or disable all media links in the ImgU instance to prepare + * for capture operations + * + * \todo This method will probably be removed or changed once links will be + * enabled or disabled selectively. + * + * \return 0 on success or a negative error code otherwise + */ +int ImgUDevice::enableLinks(bool enable) +{ + std::string inputName = imguName_ + " input"; + std::string outputName = imguName_ + " output"; + std::string viewfinderName = imguName_ + " viewfinder"; + std::string statName = imguName_ + " 3a stat"; + int ret; + + /* \todo Establish rules to handle media devices open/close. */ + ret = mediaDevice_->open(); + if (ret) + return ret; + + ret = linkSetup(inputName, 0, imguName_, PAD_INPUT, enable); + if (ret) { + mediaDevice_->close(); + return ret; + } + + ret = linkSetup(imguName_, PAD_OUTPUT, outputName, 0, enable); + if (ret) { + mediaDevice_->close(); + return ret; + } + + ret = linkSetup(imguName_, PAD_VF, viewfinderName, 0, enable); + if (ret) { + mediaDevice_->close(); + return ret; + } + + ret = linkSetup(imguName_, PAD_STAT, statName, 0, enable); + if (ret) { + mediaDevice_->close(); + return ret; + } + + mediaDevice_->close(); + + return 0; +} + int PipelineHandlerIPU3::mediaBusToCIO2Format(unsigned int code) { switch(code) {