From patchwork Wed Apr 3 08:01:36 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 888 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C0E2A6110D for ; Wed, 3 Apr 2019 10:01:10 +0200 (CEST) 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 relay3-d.mail.gandi.net (Postfix) with ESMTPSA id EEEEF6000A; Wed, 3 Apr 2019 08:01:08 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 3 Apr 2019 10:01:36 +0200 Message-Id: <20190403080148.11479-2-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190403080148.11479-1-jacopo@jmondi.org> References: <20190403080148.11479-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v8 01/13] 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: Wed, 03 Apr 2019 08:01:11 -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. Reviewed-by: Laurent Pinchart Reviewed-by: Niklas Söderlund 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 6dc8e74d2801..f76001d94562 100644 --- a/src/libcamera/geometry.cpp +++ b/src/libcamera/geometry.cpp @@ -73,7 +73,16 @@ const std::string Rectangle::toString() const /** * \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 b14f9732f3db..d8d587d3b47b 100644 --- a/src/libcamera/include/geometry.h +++ b/src/libcamera/include/geometry.h @@ -22,10 +22,17 @@ struct Rectangle { }; struct SizeRange { + SizeRange() + : 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 Wed Apr 3 08:01:37 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 887 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A45B1610C5 for ; Wed, 3 Apr 2019 10:01:10 +0200 (CEST) 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 relay3-d.mail.gandi.net (Postfix) with ESMTPSA id DDE1960006; Wed, 3 Apr 2019 08:01:09 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 3 Apr 2019 10:01:37 +0200 Message-Id: <20190403080148.11479-3-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190403080148.11479-1-jacopo@jmondi.org> References: <20190403080148.11479-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v8 02/13] libcamera: geometry: Add Size structure X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 03 Apr 2019 08:01:11 -0000 Add a simple Size structure that contains an image width and height. Reviewed-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Signed-off-by: Jacopo Mondi --- src/libcamera/geometry.cpp | 29 +++++++++++++++++++++++++++++ src/libcamera/include/geometry.h | 15 +++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/src/libcamera/geometry.cpp b/src/libcamera/geometry.cpp index f76001d94562..d0c63c353ab3 100644 --- a/src/libcamera/geometry.cpp +++ b/src/libcamera/geometry.cpp @@ -105,4 +105,33 @@ const std::string Rectangle::toString() const * \brief The maximum image height */ +/** + * \struct Size + * \brief Describe a two-dimensional size + * + * The Size structure defines a two-dimensional size with integer precision. + */ + +/** + * \fn Size::Size() + * \brief Construct a Size with width and height set to 0 + */ + +/** + * \fn Size::Size(unsigned int width, unsigned int height) + * \brief Construct a Size with given \a width and \a height + * \param width The Size width + * \param height The Size height + */ + +/** + * \var Size::width + * \brief The Size width + */ + +/** + * \var Size::height + * \brief The Size height + */ + } /* namespace libcamera */ diff --git a/src/libcamera/include/geometry.h b/src/libcamera/include/geometry.h index d8d587d3b47b..f41017aa47bf 100644 --- a/src/libcamera/include/geometry.h +++ b/src/libcamera/include/geometry.h @@ -40,6 +40,21 @@ struct SizeRange { unsigned int maxHeight; }; +struct Size { + Size() + : Size(0, 0) + { + } + + Size(unsigned int w, unsigned int h) + : width(w), height(h) + { + } + + unsigned int width; + unsigned int height; +}; + } /* namespace libcamera */ #endif /* __LIBCAMERA_GEOMETRY_H__ */ From patchwork Wed Apr 3 08:01:38 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 889 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D3941610C5 for ; Wed, 3 Apr 2019 10:01:11 +0200 (CEST) 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 relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 1476360006; Wed, 3 Apr 2019 08:01:10 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 3 Apr 2019 10:01:38 +0200 Message-Id: <20190403080148.11479-4-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190403080148.11479-1-jacopo@jmondi.org> References: <20190403080148.11479-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v8 03/13] 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: Wed, 03 Apr 2019 08:01:12 -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. Reviewed-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 247 +++++++++++++++------------ 1 file changed, 138 insertions(+), 109 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 55489c31df2d..993954777694 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -24,6 +24,28 @@ namespace libcamera { LOG_DEFINE_CATEGORY(IPU3) +class CIO2Device +{ +public: + CIO2Device() + : output_(nullptr), csi2_(nullptr), sensor_(nullptr) + { + } + + ~CIO2Device() + { + delete output_; + delete csi2_; + delete sensor_; + } + + int init(const MediaDevice *media, unsigned int index); + + V4L2Device *output_; + V4L2Subdevice *csi2_; + V4L2Subdevice *sensor_; +}; + class PipelineHandlerIPU3 : public PipelineHandler { public: @@ -51,23 +73,13 @@ private: { 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_; }; @@ -80,22 +92,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 @@ -110,7 +122,7 @@ PipelineHandlerIPU3::streamConfiguration(Camera *camera, * 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)) { + if (data->cio2_.sensor_->getFormat(0, &format)) { LOG(IPU3, Error) << "Failed to create stream configurations"; return configs; } @@ -131,9 +143,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; @@ -190,13 +202,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; @@ -208,8 +221,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; @@ -221,9 +235,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; @@ -235,8 +250,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); @@ -245,6 +261,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); @@ -254,7 +271,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; @@ -293,17 +310,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 @@ -312,17 +329,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; } @@ -336,85 +353,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 the sensor 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; - } + CIO2Device *cio2 = &data->cio2_; - data->cio2_ = new V4L2Device(cio2); - ret = data->cio2_->open(); + int ret = cio2->init(cio2MediaDev_.get(), id); if (ret) continue; - data->cio2_->bufferReady.connect(data.get(), &IPU3CameraData::bufferReady); + std::string cameraName = cio2->sensor_->entityName() + " " + + 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)); @@ -435,6 +395,75 @@ void PipelineHandlerIPU3::IPU3CameraData::bufferReady(Buffer *buffer) pipe_->completeRequest(camera_, request); } +/*------------------------------------------------------------------------------ + * CIO2 Device + */ + +/** + * \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 video device and subdevices in the CIO2 instance at \a + * index, if a supported 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 -ENODEV No supported 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 + * and enable the media link between the two. + */ + 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; + + /* + * \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; + + 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 Wed Apr 3 08:01:39 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 890 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BEC146110D for ; Wed, 3 Apr 2019 10:01:12 +0200 (CEST) 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 relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 049396000F; Wed, 3 Apr 2019 08:01:11 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 3 Apr 2019 10:01:39 +0200 Message-Id: <20190403080148.11479-5-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190403080148.11479-1-jacopo@jmondi.org> References: <20190403080148.11479-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v8 04/13] libcamera: ipu3: Cache the sensor size and format X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 03 Apr 2019 08:01:13 -0000 Cache the sensor maximum size and the media bus code used to produce it. Reviewed-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 51 +++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 993954777694..1a1517268145 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include #include #include @@ -41,9 +43,15 @@ public: int init(const MediaDevice *media, unsigned int index); + static int mediaBusToFormat(unsigned int code); + V4L2Device *output_; V4L2Subdevice *csi2_; V4L2Subdevice *sensor_; + + /* Maximum sizes and the mbus code used to produce them. */ + unsigned int mbusCode_; + Size maxSize_; }; class PipelineHandlerIPU3 : public PipelineHandler @@ -407,7 +415,7 @@ void PipelineHandlerIPU3::IPU3CameraData::bufferReady(Buffer *buffer) * Create and open the video device and subdevices in the CIO2 instance at \a * index, if a supported 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. + * to prepare for capture operations and cached the sensor maximum size. * * \return 0 on success or a negative error code otherwise * \retval -ENODEV No supported image sensor is connected to this CIO2 instance @@ -442,6 +450,10 @@ int CIO2Device::init(const MediaDevice *media, unsigned int index) 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 size. + * * \todo Define when to open and close video device nodes, as they * might impact on power consumption. */ @@ -450,6 +462,27 @@ int CIO2Device::init(const MediaDevice *media, unsigned int index) if (ret) return ret; + for (auto it : sensor_->formats(0)) { + int mbusCode = CIO2Device::mediaBusToFormat(it.first); + if (mbusCode < 0) + continue; + + for (const SizeRange &size : it.second) { + if (maxSize_.width < size.maxWidth && + maxSize_.height < size.maxHeight) { + maxSize_.width = size.maxWidth; + maxSize_.height = size.maxHeight; + mbusCode_ = mbusCode; + } + } + } + if (maxSize_.width == 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) @@ -464,6 +497,22 @@ int CIO2Device::init(const MediaDevice *media, unsigned int index) return 0; } +int CIO2Device::mediaBusToFormat(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; + } +} + REGISTER_PIPELINE_HANDLER(PipelineHandlerIPU3); } /* namespace libcamera */ From patchwork Wed Apr 3 08:01:40 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 891 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BFE53611A7 for ; Wed, 3 Apr 2019 10:01:13 +0200 (CEST) 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 relay3-d.mail.gandi.net (Postfix) with ESMTPSA id E43836000E; Wed, 3 Apr 2019 08:01:12 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 3 Apr 2019 10:01:40 +0200 Message-Id: <20190403080148.11479-6-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190403080148.11479-1-jacopo@jmondi.org> References: <20190403080148.11479-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v8 05/13] 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: Wed, 03 Apr 2019 08:01:14 -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. Reviewed-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 154 +++++++++++++++++++++++++-- 1 file changed, 144 insertions(+), 10 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 1a1517268145..9274d35c8be8 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -26,6 +26,43 @@ namespace libcamera { 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) + { + } + + ~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: @@ -88,6 +125,7 @@ private: void bufferReady(Buffer *buffer); CIO2Device cio2_; + ImgUDevice *imgu_; Stream stream_; }; @@ -98,8 +136,10 @@ private: PipelineHandler::cameraData(camera)); } - void registerCameras(); + int registerCameras(); + ImgUDevice imgu0_; + ImgUDevice imgu1_; std::shared_ptr cio2MediaDev_; std::shared_ptr imguMediaDev_; }; @@ -290,6 +330,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"); @@ -345,36 +387,68 @@ bool PipelineHandlerIPU3::match(DeviceEnumerator *enumerator) return false; } - registerCameras(); + if (imguMediaDev_->open()) { + cio2MediaDev_->close(); + return false; + } + + if (imguMediaDev_->disableLinks()) + goto error; + ret = registerCameras(); + +error: cio2MediaDev_->close(); + imguMediaDev_->close(); - return true; + return ret == 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 - * CIO2 CSI-2 receivers. +/** + * \brief Initialise ImgU and CIO2 devices associated with cameras + * + * Initialise 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 the sensor 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->sensor_->entityName() + " " + std::to_string(id); std::shared_ptr camera = Camera::create(this, @@ -393,6 +467,8 @@ void PipelineHandlerIPU3::registerCameras() numCameras++; } + + return numCameras ? 0 : -ENODEV; } void PipelineHandlerIPU3::IPU3CameraData::bufferReady(Buffer *buffer) @@ -403,6 +479,64 @@ 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; + + /* + * The media entities presence in the media device has been verified + * by the match() function: no need to check for newly created + * video devices and subdevice validity here. + */ + 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 Wed Apr 3 08:01:41 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 892 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 015F5611A9 for ; Wed, 3 Apr 2019 10:01:15 +0200 (CEST) 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 relay3-d.mail.gandi.net (Postfix) with ESMTPSA id E2A0C60007; Wed, 3 Apr 2019 08:01:13 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 3 Apr 2019 10:01:41 +0200 Message-Id: <20190403080148.11479-7-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190403080148.11479-1-jacopo@jmondi.org> References: <20190403080148.11479-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v8 06/13] 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: Wed, 03 Apr 2019 08:01:15 -0000 Apply the requested stream configuration to the CIO2 device, and propagate formats through the the ImgU subdevice and its input and output video devices. Reviewed-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 298 ++++++++++++++++++++++----- 1 file changed, 249 insertions(+), 49 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 9274d35c8be8..a4e6f28d1da9 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 @@ -34,22 +35,35 @@ public: static constexpr unsigned int PAD_VF = 3; static constexpr unsigned int PAD_STAT = 4; + /* ImgU output descriptor: group data specific to an ImgU output. */ + struct ImgUOutput { + V4L2Device *dev; + unsigned int pad; + std::string name; + }; + ImgUDevice() - : imgu_(nullptr), input_(nullptr), output_(nullptr), - viewfinder_(nullptr), stat_(nullptr) + : imgu_(nullptr), input_(nullptr) { + output_.dev = nullptr; + viewfinder_.dev = nullptr; + stat_.dev = nullptr; } ~ImgUDevice() { delete imgu_; delete input_; - delete output_; - delete viewfinder_; - delete stat_; + delete output_.dev; + delete viewfinder_.dev; + delete stat_.dev; } int init(MediaDevice *media, unsigned int index); + int configureInput(const StreamConfiguration &config, + V4L2DeviceFormat *inputFormat); + int configureOutput(ImgUOutput *output, + const StreamConfiguration &config); unsigned int index_; std::string name_; @@ -57,9 +71,9 @@ public: V4L2Subdevice *imgu_; V4L2Device *input_; - V4L2Device *output_; - V4L2Device *viewfinder_; - V4L2Device *stat_; + ImgUOutput output_; + ImgUOutput viewfinder_; + ImgUOutput stat_; /* \todo Add param video device for 3A tuning */ }; @@ -79,6 +93,8 @@ public: } int init(const MediaDevice *media, unsigned int index); + int configure(const StreamConfiguration &config, + V4L2DeviceFormat *outputFormat); static int mediaBusToFormat(unsigned int code); @@ -190,60 +206,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::setfill('0') + << 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) << "Invalid stream size: bad alignment"; + return -EINVAL; + } - ret = sensor->getFormat(0, &subdevFormat); - if (ret) - return ret; - - subdevFormat.width = cfg->width; - subdevFormat.height = cfg->height; - ret = sensor->setFormat(0, &subdevFormat); - if (ret) - return ret; - - /* Return error if the requested format cannot be applied to sensor. */ - if (subdevFormat.width != cfg->width || - subdevFormat.height != cfg->height) { + if (cfg.width > cio2->maxSize_.width || + cfg.height > cio2->maxSize_.height) { LOG(IPU3, Error) - << "Failed to apply image format " - << subdevFormat.width << "x" << subdevFormat.height - << " - got: " << cfg->width << "x" << cfg->height; + << "Invalid stream size: larger than sensor resolution"; return -EINVAL; } - ret = csi2->setFormat(0, &subdevFormat); + /* + * Pass the requested stream size to the CIO2 unit and get back the + * adjusted format to be propagated to the ImgU output devices. + */ + V4L2DeviceFormat cio2Format = {}; + ret = cio2->configure(cfg, &cio2Format); if (ret) return ret; - ret = cio2->getFormat(&devFormat); + ret = imgu->configureInput(cfg, &cio2Format); if (ret) return ret; - devFormat.width = subdevFormat.width; - devFormat.height = subdevFormat.height; - devFormat.fourcc = cfg->pixelFormat; + /* Apply the format to the ImgU output, viewfinder and stat. */ + ret = imgu->configureOutput(&imgu->output_, cfg); + if (ret) + return ret; - ret = cio2->setFormat(&devFormat); + ret = imgu->configureOutput(&imgu->viewfinder_, cfg); if (ret) return ret; - LOG(IPU3, Info) << cio2->driverName() << ": " - << devFormat.width << "x" << devFormat.height - << "- 0x" << std::hex << devFormat.fourcc << " planes: " - << devFormat.planes; + ret = imgu->configureOutput(&imgu->stat_, cfg); + if (ret) + return ret; return 0; } @@ -519,21 +537,131 @@ int ImgUDevice::init(MediaDevice *media, unsigned int index) if (ret) return ret; - output_ = V4L2Device::fromEntityName(media, name_ + " output"); - ret = output_->open(); + output_.dev = V4L2Device::fromEntityName(media, name_ + " output"); + ret = output_.dev->open(); + if (ret) + return ret; + + output_.pad = PAD_OUTPUT; + output_.name = "output"; + + viewfinder_.dev = V4L2Device::fromEntityName(media, + name_ + " viewfinder"); + ret = viewfinder_.dev->open(); + if (ret) + return ret; + + viewfinder_.pad = PAD_VF; + viewfinder_.name = "viewfinder"; + + stat_.dev = V4L2Device::fromEntityName(media, name_ + " 3a stat"); + ret = stat_.dev->open(); + if (ret) + return ret; + + stat_.pad = PAD_STAT; + stat_.name = "stat"; + + return 0; +} + +/** + * \brief Configure the ImgU unit input + * \param[in] config The requested stream configuration + * \param[in] inputFormat The format to be applied to ImgU input + * + * \return 0 on success or a negative error code otherwise + */ +int ImgUDevice::configureInput(const StreamConfiguration &config, + V4L2DeviceFormat *inputFormat) +{ + /* Configure the ImgU input video device with the requested sizes. */ + int ret = input_->setFormat(inputFormat); + if (ret) + return ret; + + LOG(IPU3, Debug) << "ImgU input format = " << inputFormat->toString(); + + /* + * \todo The IPU3 driver implementation shall be changed to use the + * input sizes as 'ImgU Input' subdevice sizes, and use the desired + * GDC output sizes to configure the crop/compose rectangles. + * + * The current IPU3 driver implementation uses GDC sizes as the + * 'ImgU Input' subdevice sizes, and the input video device sizes + * to configure the crop/compose rectangles, contradicting the + * V4L2 specification. + */ + Rectangle rect = { + .x = 0, + .y = 0, + .w = inputFormat->width, + .h = inputFormat->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; - viewfinder_ = V4L2Device::fromEntityName(media, name_ + " viewfinder"); - ret = viewfinder_->open(); + LOG(IPU3, Debug) << "ImgU GDC format = " << imguFormat.toString(); + + return 0; +} + +/** + * \brief Configure the ImgU unit \a id video output + * \param[in] output The ImgU output device to configure + * \param[in] config The requested configuration + * + * \return 0 on success or a negative error code otherwise + */ +int ImgUDevice::configureOutput(ImgUOutput *output, + const StreamConfiguration &config) +{ + V4L2Device *dev = output->dev; + unsigned int pad = output->pad; + + 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; - stat_ = V4L2Device::fromEntityName(media, name_ + " 3a stat"); - ret = stat_->open(); + /* No need to apply format to the stat node. */ + if (output == &stat_) + return 0; + + V4L2DeviceFormat outputFormat = {}; + outputFormat.width = config.width; + outputFormat.height = config.height; + outputFormat.fourcc = V4L2_PIX_FMT_NV12; + outputFormat.planesCount = 2; + + ret = dev->setFormat(&outputFormat); if (ret) return ret; + LOG(IPU3, Debug) << "ImgU " << output->name << " format = " + << outputFormat.toString(); + return 0; } @@ -631,6 +759,78 @@ int CIO2Device::init(const MediaDevice *media, unsigned int index) return 0; } +/** + * \brief Configure the CIO2 unit + * \param[in] config The requested configuration + * \param[out] outputFormat The CIO2 unit output image format + * + * \return 0 on success or a negative error code otherwise + */ +int CIO2Device::configure(const StreamConfiguration &config, + V4L2DeviceFormat *outputFormat) +{ + unsigned int imageSize = config.width * config.height; + V4L2SubdeviceFormat sensorFormat = {}; + unsigned int best = ~0; + int ret; + + for (auto it : sensor_->formats(0)) { + /* Only consider formats consumable by the CIO2 unit. */ + if (CIO2Device::mediaBusToFormat(it.first) < 0) + continue; + + for (const SizeRange &size : it.second) { + /* + * Only select formats bigger than the requested sizes + * as the IPU3 cannot up-scale. + * + * \todo: Unconditionally scale on the sensor as much + * as possible. This will need to be revisited when + * implementing the scaling policy. + */ + if (size.maxWidth < config.width || + size.maxHeight < config.height) + continue; + + unsigned int diff = size.maxWidth * size.maxHeight + - imageSize; + if (diff >= best) + continue; + + best = diff; + + sensorFormat.width = size.maxWidth; + sensorFormat.height = size.maxHeight; + sensorFormat.mbus_code = it.first; + } + } + + /* + * Apply the selected format to the sensor, the CSI-2 receiver and + * the CIO2 output device. + */ + ret = sensor_->setFormat(0, &sensorFormat); + if (ret) + return ret; + + ret = csi2_->setFormat(0, &sensorFormat); + if (ret) + return ret; + + outputFormat->width = sensorFormat.width; + outputFormat->height = sensorFormat.height; + outputFormat->fourcc = CIO2Device::mediaBusToFormat(sensorFormat.mbus_code); + outputFormat->planesCount = 1; + + ret = output_->setFormat(outputFormat); + if (ret) + return ret; + + LOG(IPU3, Debug) << "CIO2 output format " << outputFormat->toString(); + + return 0; +} + int CIO2Device::mediaBusToFormat(unsigned int code) { switch (code) { From patchwork Wed Apr 3 08:01:42 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 893 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0035061111 for ; Wed, 3 Apr 2019 10:01:15 +0200 (CEST) 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 relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 3D00E60006; Wed, 3 Apr 2019 08:01:14 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 3 Apr 2019 10:01:42 +0200 Message-Id: <20190403080148.11479-8-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190403080148.11479-1-jacopo@jmondi.org> References: <20190403080148.11479-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v8 07/13] 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: Wed, 03 Apr 2019 08:01:16 -0000 Implement buffer allocation and release in IPU3 pipeline handlers. As the pipeline handler currently 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. This works around the fact that the ImgU requires buffers to be queued on all its outputs, even when they are not in use. 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. Reviewed-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 154 ++++++++++++++++++++++++--- 1 file changed, 140 insertions(+), 14 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index a4e6f28d1da9..a838fd3a096d 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -40,6 +40,7 @@ public: V4L2Device *dev; unsigned int pad; std::string name; + BufferPool *pool; }; ImgUDevice() @@ -65,6 +66,10 @@ public: int configureOutput(ImgUOutput *output, const StreamConfiguration &config); + int importBuffers(BufferPool *pool); + int exportBuffers(ImgUOutput *output, BufferPool *pool); + void freeBuffers(); + unsigned int index_; std::string name_; MediaDevice *media_; @@ -75,11 +80,16 @@ public: ImgUOutput viewfinder_; ImgUOutput stat_; /* \todo Add param video device for 3A tuning */ + + BufferPool vfPool_; + BufferPool statPool_; }; class CIO2Device { public: + static constexpr unsigned int CIO2_BUFFER_COUNT = 4; + CIO2Device() : output_(nullptr), csi2_(nullptr), sensor_(nullptr) { @@ -96,6 +106,9 @@ public: int configure(const StreamConfiguration &config, V4L2DeviceFormat *outputFormat); + BufferPool *exportBuffers(); + void freeBuffers(); + static int mediaBusToFormat(unsigned int code); V4L2Device *output_; @@ -105,6 +118,8 @@ public: /* Maximum sizes and the mbus code used to produce them. */ unsigned int mbusCode_; Size maxSize_; + + BufferPool pool_; }; class PipelineHandlerIPU3 : public PipelineHandler @@ -268,18 +283,41 @@ 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(&imgu->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(); + + imgu->viewfinder_.pool->createBuffers(bufferCount); + ret = imgu->exportBuffers(&imgu->viewfinder_, imgu->viewfinder_.pool); + if (ret) + return ret; + + imgu->stat_.pool->createBuffers(bufferCount); + ret = imgu->exportBuffers(&imgu->stat_, imgu->stat_.pool); + if (ret) return ret; - } return 0; } @@ -287,13 +325,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; } @@ -553,6 +587,7 @@ int ImgUDevice::init(MediaDevice *media, unsigned int index) viewfinder_.pad = PAD_VF; viewfinder_.name = "viewfinder"; + viewfinder_.pool = &vfPool_; stat_.dev = V4L2Device::fromEntityName(media, name_ + " 3a stat"); ret = stat_.dev->open(); @@ -561,6 +596,7 @@ int ImgUDevice::init(MediaDevice *media, unsigned int index) stat_.pad = PAD_STAT; stat_.name = "stat"; + stat_.pool = &statPool_; return 0; } @@ -665,6 +701,69 @@ int ImgUDevice::configureOutput(ImgUOutput *output, return 0; } +/** + * \brief Import buffers from \a pool into the ImgU input + * \param[in] pool The buffer pool to import + * + * \return 0 on success or a negative error code otherwise + */ +int ImgUDevice::importBuffers(BufferPool *pool) +{ + int ret = input_->importBuffers(pool); + if (ret) { + LOG(IPU3, Error) << "Failed to import ImgU input buffers"; + return ret; + } + + return 0; +} + +/** + * \brief Export buffers from \a output to the provided \a pool + * \param[in] output The ImgU output device + * \param[in] pool The buffer pool where to export buffers + * + * Export memory buffers reserved in the video device memory associated with + * \a output id to the buffer pool provided as argument. + * + * \return 0 on success or a negative error code otherwise + */ +int ImgUDevice::exportBuffers(ImgUOutput *output, BufferPool *pool) +{ + int ret = output->dev->exportBuffers(pool); + if (ret) { + LOG(IPU3, Error) << "Failed to export ImgU " + << output->name << " buffers"; + return ret; + } + + return 0; +} + +/** + * \brief Release buffers for all the ImgU video devices + */ +void ImgUDevice::freeBuffers() +{ + int ret; + + ret = output_.dev->releaseBuffers(); + if (ret) + LOG(IPU3, Error) << "Failed to release ImgU output buffers"; + + ret = stat_.dev->releaseBuffers(); + if (ret) + LOG(IPU3, Error) << "Failed to release ImgU stat buffers"; + + ret = viewfinder_.dev->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 */ @@ -831,6 +930,33 @@ int CIO2Device::configure(const StreamConfiguration &config, return 0; } +/** + * \brief Allocate 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 can be imported by another 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"; +} + int CIO2Device::mediaBusToFormat(unsigned int code) { switch (code) { From patchwork Wed Apr 3 08:01:43 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 894 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 04D9D611B7 for ; Wed, 3 Apr 2019 10:01:17 +0200 (CEST) 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 relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 472676001B; Wed, 3 Apr 2019 08:01:15 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 3 Apr 2019 10:01:43 +0200 Message-Id: <20190403080148.11479-9-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190403080148.11479-1-jacopo@jmondi.org> References: <20190403080148.11479-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v8 08/13] libcamera: ipu3: Implement camera start/stop X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 03 Apr 2019 08:01:17 -0000 Start and stop video devices in the pipeline. Reviewed-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 104 +++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 7 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index a838fd3a096d..d8a41543243e 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -70,6 +70,9 @@ public: int exportBuffers(ImgUOutput *output, BufferPool *pool); void freeBuffers(); + int start(); + int stop(); + unsigned int index_; std::string name_; MediaDevice *media_; @@ -109,6 +112,9 @@ public: BufferPool *exportBuffers(); void freeBuffers(); + int start(); + int stop(); + static int mediaBusToFormat(unsigned int code); V4L2Device *output_; @@ -335,25 +341,43 @@ 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) + goto error; + + ret = imgu->start(); if (ret) { - LOG(IPU3, Info) << "Failed to start camera " << camera->name(); - return ret; + imgu->stop(); + cio2->stop(); + goto error; } return 0; + +error: + LOG(IPU3, Error) << "Failed to start camera " << camera->name(); + + return ret; } void PipelineHandlerIPU3::stop(Camera *camera) { IPU3CameraData *data = cameraData(camera); - V4L2Device *cio2 = data->cio2_.output_; + int ret; - if (cio2->streamOff()) - LOG(IPU3, Info) << "Failed to stop camera " << camera->name(); + ret = data->cio2_.stop(); + ret |= data->imgu_->stop(); + if (ret) + LOG(IPU3, Warning) << "Failed to stop camera " + << camera->name(); PipelineHandler::stop(camera); } @@ -764,6 +788,50 @@ void ImgUDevice::freeBuffers() LOG(IPU3, Error) << "Failed to release ImgU input buffers"; } +int ImgUDevice::start() +{ + int ret; + + /* Start the ImgU video devices. */ + ret = output_.dev->streamOn(); + if (ret) { + LOG(IPU3, Error) << "Failed to start ImgU output"; + return ret; + } + + ret = viewfinder_.dev->streamOn(); + if (ret) { + LOG(IPU3, Error) << "Failed to start ImgU viewfinder"; + return ret; + } + + ret = stat_.dev->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; +} + +int ImgUDevice::stop() +{ + int ret; + + ret = output_.dev->streamOff(); + ret |= viewfinder_.dev->streamOff(); + ret |= stat_.dev->streamOff(); + ret |= input_->streamOff(); + + return ret; +} + /*------------------------------------------------------------------------------ * CIO2 Device */ @@ -957,6 +1025,28 @@ 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) + return ret; + + return 0; +} + +int CIO2Device::stop() +{ + return output_->streamOff(); +} + int CIO2Device::mediaBusToFormat(unsigned int code) { switch (code) { From patchwork Wed Apr 3 08:01: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: 895 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id DB7486110D for ; Wed, 3 Apr 2019 10:01:17 +0200 (CEST) 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 relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 2871F6001D; Wed, 3 Apr 2019 08:01:17 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 3 Apr 2019 10:01:44 +0200 Message-Id: <20190403080148.11479-10-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190403080148.11479-1-jacopo@jmondi.org> References: <20190403080148.11479-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v8 09/13] 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: Wed, 03 Apr 2019 08:01:18 -0000 Implement queueRequest for the IPU3 pipeline manager. When a request is queued, a new buffer is queued to the ImgU output for capture. Reviewed-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Signed-off-by: Jacopo Mondi --- 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 d8a41543243e..3225de29d168 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -385,9 +385,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_.dev; Stream *stream = &data->stream_; + /* Queue a buffer to the ImgU output for capture. */ Buffer *buffer = request->findBuffer(stream); if (!buffer) { LOG(IPU3, Error) @@ -395,7 +396,7 @@ int PipelineHandlerIPU3::queueRequest(Camera *camera, Request *request) return -ENOENT; } - int ret = cio2->queueBuffer(buffer); + int ret = output->queueBuffer(buffer); if (ret < 0) return ret; From patchwork Wed Apr 3 08:01: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: 896 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id EDDD9610C5 for ; Wed, 3 Apr 2019 10:01:18 +0200 (CEST) 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 relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 1880660007; Wed, 3 Apr 2019 08:01:17 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 3 Apr 2019 10:01:45 +0200 Message-Id: <20190403080148.11479-11-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190403080148.11479-1-jacopo@jmondi.org> References: <20190403080148.11479-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v8 10/13] libcamera: ipu3: Connect CIO2 and ImgU bufferReady signals X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 03 Apr 2019 08:01:19 -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. Reviewed-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Signed-off-by: Jacopo Mondi --- 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 3225de29d168..5fe036a3b239 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -159,7 +159,9 @@ private: { } - void bufferReady(Buffer *buffer); + void imguOutputBufferReady(Buffer *buffer); + void imguInputBufferReady(Buffer *buffer); + void cio2BufferReady(Buffer *buffer); CIO2Device cio2_; ImgUDevice *imgu_; @@ -526,15 +528,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 passed to 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_.dev->bufferReady.connect(data.get(), + &IPU3CameraData::imguOutputBufferReady); + + /* Create and register the Camera instance. */ std::string cameraName = cio2->sensor_->entityName() + " " + 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) @@ -548,7 +563,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(); @@ -556,6 +593,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 Wed Apr 3 08:01:46 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 897 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id EA347610C5 for ; Wed, 3 Apr 2019 10:01:19 +0200 (CEST) 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 relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 2AB126001C; Wed, 3 Apr 2019 08:01:18 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 3 Apr 2019 10:01:46 +0200 Message-Id: <20190403080148.11479-12-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190403080148.11479-1-jacopo@jmondi.org> References: <20190403080148.11479-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v8 11/13] libcamera: ipu3: Set stream configuration X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 03 Apr 2019 08:01:20 -0000 Use the cached sensor maximum resolution and the pixel format generated by the ImgU output devices as default stream configuration. While at it, replace the hardcoded numerical value for the number of buffers with a named constexpr. Reviewed-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 34 ++++++++++++---------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 5fe036a3b239..792ff42c0eaa 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -169,6 +169,8 @@ private: Stream stream_; }; + static constexpr unsigned int IPU3_BUFFER_COUNT = 4; + IPU3CameraData *cameraData(const Camera *camera) { return static_cast( @@ -201,26 +203,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->cio2_.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_]; + Size *maxSize = &data->.cio2_.maxSize_; + + config->width = maxSize->width; + config->height = maxSize->height; + 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(8) << config->pixelFormat; return configs; } From patchwork Wed Apr 3 08:01:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 898 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D9F6D611AB for ; Wed, 3 Apr 2019 10:01:20 +0200 (CEST) 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 relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 219CB6001E; Wed, 3 Apr 2019 08:01:19 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 3 Apr 2019 10:01:47 +0200 Message-Id: <20190403080148.11479-13-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190403080148.11479-1-jacopo@jmondi.org> References: <20190403080148.11479-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v8 12/13] 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: Wed, 03 Apr 2019 08:01:21 -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. Reviewed-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 792ff42c0eaa..a1e53c9a5a06 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -206,10 +206,17 @@ PipelineHandlerIPU3::streamConfiguration(Camera *camera, std::map configs; IPU3CameraData *data = cameraData(camera); StreamConfiguration *config = &configs[&data->stream_]; - Size *maxSize = &data->.cio2_.maxSize_; - config->width = maxSize->width; - config->height = maxSize->height; + /* + * FIXME: Soraka: the maximum resolution reported by both sensors + * (2592x1944 for ov5670 and 4224x3136 for ov13858) are returned as + * default configurations but they're not correctly processed by the + * ImgU. Resolutions up tp 2560x1920 have been validated. + * + * \todo Clarify ImgU alignement requirements. + */ + config->width = 2560; + config->height = 1920; config->pixelFormat = V4L2_PIX_FMT_NV12; config->bufferCount = IPU3_BUFFER_COUNT; From patchwork Wed Apr 3 08:01:48 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 899 Return-Path: Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E9EC261197 for ; Wed, 3 Apr 2019 10:01:21 +0200 (CEST) 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 relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 0FF8960007; Wed, 3 Apr 2019 08:01:20 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Wed, 3 Apr 2019 10:01:48 +0200 Message-Id: <20190403080148.11479-14-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190403080148.11479-1-jacopo@jmondi.org> References: <20190403080148.11479-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v8 13/13] libcamera: ipu3: Enable ImgU media links X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 03 Apr 2019 08:01:22 -0000 As the lengthy 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. Reviewed-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 102 +++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index a1e53c9a5a06..48205301f1ae 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -73,6 +73,11 @@ public: int start(); int 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_; @@ -263,6 +268,14 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, return -EINVAL; } + /* + * \todo: Enable links selectively based on the requested streams. + * As of now, enable all links unconditionally. + */ + ret = data->imgu_->enableLinks(true); + if (ret) + return ret; + /* * Pass the requested stream size to the CIO2 unit and get back the * adjusted format to be propagated to the ImgU output devices. @@ -474,6 +487,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; @@ -885,6 +922,71 @@ int ImgUDevice::stop() return ret; } +/** + * \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) +{ + std::string viewfinderName = name_ + " viewfinder"; + std::string outputName = name_ + " output"; + std::string statName = name_ + " 3a stat"; + std::string inputName = name_ + " input"; + int ret; + + /* \todo Establish rules to handle media devices open/close. */ + ret = media_->open(); + if (ret) + return ret; + + ret = linkSetup(inputName, 0, name_, PAD_INPUT, enable); + if (ret) + goto done; + + ret = linkSetup(name_, PAD_OUTPUT, outputName, 0, enable); + if (ret) + goto done; + + ret = linkSetup(name_, PAD_VF, viewfinderName, 0, enable); + if (ret) + goto done; + + ret = linkSetup(name_, PAD_STAT, statName, 0, enable); + +done: + media_->close(); + + return ret; +} + /*------------------------------------------------------------------------------ * CIO2 Device */