From patchwork Tue Aug 17 15:42:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siyuan Fan X-Patchwork-Id: 13378 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 15E73BD87C for ; Tue, 17 Aug 2021 15:42:08 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D49C3688A2; Tue, 17 Aug 2021 17:42:07 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=foxmail.com header.i=@foxmail.com header.b="yyFK77i+"; dkim-atps=neutral Received: from out162-62-57-252.mail.qq.com (out162-62-57-252.mail.qq.com [162.62.57.252]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4F2EF6025C for ; Tue, 17 Aug 2021 17:42:06 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=foxmail.com; s=s201512; t=1629214923; bh=DWtivy05nTGHyPkjDPkoKhqut1dksWt2RYr8riNC19A=; h=From:To:Cc:Subject:Date; b=yyFK77i+SNcK4zG9otTxNA0+6hzN+2t7xCCydxVKHnHRbf/a3m78przcju8dEbI2b 7wqPtfe9rqdMnVotro9cIFTo4t+L8LaKz/QD53IjB/hbCOT7BCgi7qCmNP3tJT2yfn gKj63l/0czIXtBtC+CInU8AlUen4XyiCEfcK7B3k= Received: from localhost.localdomain ([123.126.82.10]) by newxmesmtplogicsvrszc7.qq.com (NewEsmtp) with SMTP id A81A1CD5; Tue, 17 Aug 2021 23:42:01 +0800 X-QQ-mid: xmsmtpt1629214921t6h6x25w3 Message-ID: X-QQ-XMAILINFO: MDlC9u6qHHGcke0xx4Xm5HXv3CpktQWDq0h7nNaW6gC1Is3s/WiCDZmC5VFdOx d9LNvTgBo/BnXHuH0Dg3bJdWJRmhOXAdNpGAhoCypNvcgW0GBz4Om6kIxydXva3W8wVhmXhOqKsb LCDMBJipssz1xWarUfbvOiMiPkvjfA1LifenESD6/JztePOG47yrc9s/nWG88Byl9wOJ/HP4WncB rM13bSWDPaYvhjK2Z06K8hO83r99UCD4plZbbZKpe/XVEs8tV1QxlygL8pBPooUSHpwXCL6nPyLn ysDiJp5ZohcEn9gmOHp0mRKmhCaReFJNu1yYSx4VyxwZpxh1CIYWwCG6HJRrRZJSmwGLLJVPblCk bZJYlO7VtjGFhT3otbZ4NjzxpXuZnRIvXQ65fh/cVcqDXke6tZx3q4rtnfEffaR2mG2MNT8WGcis REOajfGFSTLZ6gzQ+8U+HTPUg7afsvvf2EY/LV2I+oPXPiskp7vXo/yfqIUwmL2ZqAKfJ9Qc9eRw 9/nCXmN+j2zmX3U/S70QV+ioEbd0fIE6g+XjxviJgOcIrCOMr7NLvnUotGg6ST1UriCpySQGkMiU BtWh1H2FDWMOMedP98VlFtFvfsHraiIkt8kZjTEI4U8AXUNnZUqkf29JLZ829HA4qJbf7JNIrurw APorP2piBpCkDeEd2SJEnvtGiAjdJ1GwTqnTz2qclXN77PcegvrfNL3n4XTpwAPZ5/Sor0NPAxgm qIr7pyiXDs/amTtzvPTUc8fDv88Mqms4DtcXeGQt76UdYgRyHSvMwV80fVX1/qFo+T0VIto0ruTL RRpD+lwwJudCeEWGiGPUsSN9igO8QEXpPcaW+G2NOD6WoUvEpzs3mym7PihW0d/hPJi/wSiQe/jU I2f4KOpk4WU+lIzl+C9gI0rK+bzMmir0IN2uISCF7IVwCBdi1gy7OUTha1CgadbqRaQ9y8OQkF9G 3XU/UwAO+GOuQPHa6A3Z7jxU9bGS+peRYknu5//G/g1qR6AdjC9HqrKlkLDItHdWqa0xLS7ywI1I vGRJN+Ug== From: Siyuan Fan To: libcamera-devel@lists.libcamera.org Date: Tue, 17 Aug 2021 16:42:00 +0100 X-OQ-MSGID: <20210817154200.6763-1-siyuan.fan@foxmail.com> X-Mailer: git-send-email 2.20.1 MIME-Version: 1.0 Subject: [libcamera-devel] [RFC PATCH v3 1/4] pipeline: isp: The software ISP-based pipeline handler X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" From: Fan Siyuan Using the output format supported by ISP initializes StreamFormats. In validate(), if the request format is not supported, adjust format to RGB888. Signed-off-by: Fan Siyuan --- src/libcamera/pipeline/isp/isp.cpp | 315 +++++++++++++++++++++++++++++ 1 file changed, 315 insertions(+) create mode 100644 src/libcamera/pipeline/isp/isp.cpp diff --git a/src/libcamera/pipeline/isp/isp.cpp b/src/libcamera/pipeline/isp/isp.cpp new file mode 100644 index 00000000..49f55ddb --- /dev/null +++ b/src/libcamera/pipeline/isp/isp.cpp @@ -0,0 +1,315 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2021, Siyuan Fan + * + * isp.cpp - The software ISP-based pipeline handler + */ + +#include "../../swisp/isp.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "libcamera/internal/device_enumerator.h" +#include "libcamera/internal/media_device.h" +#include "libcamera/internal/pipeline_handler.h" +#include "libcamera/internal/v4l2_videodevice.h" + +namespace libcamera { + +LOG_DEFINE_CATEGORY(ISP) + +class ISPCameraData : public CameraData +{ +public: + ISPCameraData(PipelineHandler *pipe, MediaDevice *media) + : CameraData(pipe), media_(media), video_(nullptr) + { + } + + ~ISPCameraData() + { + delete video_; + } + + int init(); + void bufferReady(FrameBuffer *buffer); + void ISPCompleted(FrameBuffer *rawbuffer, FrameBuffer *rgbBuffer); + + Stream stream_; + ISPCPU isp_; + int width_; + int height_; + + std::vector> rawBuffers_; + std::queue rawBufferQueue_; + std::queue rgbBufferQueue_; + + MediaDevice *media_; + V4L2VideoDevice *video_; +}; + + +class ISPCameraConfiguration : public CameraConfiguration +{ +public: + ISPCameraConfiguration(); + + Status validate() override; +}; + +class PipelineHandlerISP : public PipelineHandler +{ +public: + PipelineHandlerISP(CameraManager *manager); + + CameraConfiguration *generateConfiguration(Camera *camera, + const StreamRoles &roles) override; + int configure(Camera *camera, CameraConfiguration *config) override; + + int exportFrameBuffers(Camera *camera, Stream *stream, + std::vector> *buffers) override; + + int start(Camera *camera, const ControlList *controls) override; + void stop(Camera *camera) override; + + int queueRequestDevice(Camera *camera, Request *request) override; + + bool match(DeviceEnumerator *enumerator) override; + +private: + ISPCameraData *cameraData(const Camera *camera) + { + return static_cast( + PipelineHandler::cameraData(camera)); + } +}; + +ISPCameraConfiguration::ISPCameraConfiguration() + : CameraConfiguration() +{ +} + +CameraConfiguration::Status ISPCameraConfiguration::validate() +{ + Status status = Valid; + + if (config_.empty()) + return Invalid; + + if (config_.size() > 1) { + config_.resize(1); + status = Adjusted; + } + + StreamConfiguration &cfg = config_[0]; + const std::vector formats = cfg.formats().pixelformats(); + if (std::find(formats.begin(), formats.end(), cfg.pixelFormat) == formats.end()) { + cfg.pixelFormat = cfg.formats().pixelformats()[0]; + LOG(ISP, Debug) << "Adjusting format to" << cfg.pixelFormat.toString(); + status = Adjusted; + } + + cfg.bufferCount = 4; + + return status; +} + +PipelineHandlerISP::PipelineHandlerISP(CameraManager *manager) + : PipelineHandler(manager) +{ +} + +CameraConfiguration *PipelineHandlerISP::generateConfiguration(Camera *camera, + const StreamRoles &roles) +{ + ISPCameraData *data = cameraData(camera); + CameraConfiguration *config = new ISPCameraConfiguration(); + + if (roles.empty()) + return config; + + std::map> ispFormat; + ispFormat = data->isp_.pixelFormatConfiguration(); + StreamFormats formats(ispFormat); + StreamConfiguration cfg(formats); + + cfg.pixelFormat = formats::RGB888; + cfg.size = { 640, 480 }; + cfg.bufferCount = 4; + + config->addConfiguration(cfg); + + config->validate(); + + data->isp_.outputpixelformat = data->isp_.getOutputPixelFormat(config->at(0).pixelFormat); ; + + return config; +} + +int PipelineHandlerISP::configure(Camera *camera, CameraConfiguration *config) +{ + ISPCameraData *data = cameraData(camera); + StreamConfiguration &cfg = config->at(0); + + PixelFormat bayerFormat = formats::SBGGR10; + V4L2DeviceFormat format = {}; + format.fourcc = data->video_->toV4L2PixelFormat(bayerFormat);; + format.size = {640, 480}; + + data->width_ = format.size.width; + data->height_ = format.size.height; + + int ret = data->video_->setFormat(&format); + if (ret) + return ret; + + cfg.setStream(&data->stream_); + cfg.stride = format.planes[0].bpl; + + return 0; +} + +int PipelineHandlerISP::exportFrameBuffers(Camera *camera, Stream *stream, + std::vector> *buffers) +{ + unsigned int count = stream->configuration().bufferCount; + ISPCameraData *data = cameraData(camera); + + count = data->isp_.exportBuffers(buffers, count, data->width_, data->height_); + + return count; + +} + +int PipelineHandlerISP::start(Camera *camera, [[maybe_unused]] const ControlList *controls) +{ + ISPCameraData *data = cameraData(camera); + unsigned int count = data->stream_.configuration().bufferCount; + + int ret = data->video_->allocateBuffers(count, &data->rawBuffers_); + if (ret < 0) { + LOG(ISP, Error) << strerror(-ret); + return ret; + } + + for (unsigned int i = 0; i < count; i++) { + data->rawBufferQueue_.push(data->rawBuffers_[i].get()); + } + + + ret = data->video_->streamOn(); + if (ret < 0) { + data->video_->releaseBuffers(); + return ret; + } + + data->isp_.startThreadISP(); + + return 0; +} + +void PipelineHandlerISP::stop(Camera *camera) +{ + ISPCameraData *data = cameraData(camera); + + if (!(data->rawBuffers_.empty())) { + data->rawBuffers_.clear(); + } + + data->isp_.stopThreadISP(); + + data->video_->streamOff(); + data->video_->releaseBuffers(); +} + +int PipelineHandlerISP::queueRequestDevice(Camera *camera, Request *request) +{ + ISPCameraData *data = cameraData(camera); + FrameBuffer *rgbBuffer = request->findBuffer(&data->stream_); + if (!rgbBuffer) { + LOG(ISP, Error) << "Attempt to queue request with invalid stream"; + return -ENOENT; + } + data->rgbBufferQueue_.push(rgbBuffer); + + FrameBuffer *buffer = data->rawBufferQueue_.front(); + int ret = data->video_->queueBuffer(buffer); + if (ret < 0) { + LOG(ISP, Error) << "Queue raw buffer error"; + return ret; + } + data->rawBufferQueue_.pop(); + + return 0; +} + +bool PipelineHandlerISP::match(DeviceEnumerator *enumerator) +{ + DeviceMatch unicam("unicam"); + + unicam.add("unicam-embedded"); + unicam.add("unicam-image"); + + MediaDevice *unicam_ = acquireMediaDevice(enumerator, unicam); + if (!unicam_) { + LOG(ISP, Debug) << "unicam Device not found"; + return false; + } + + LOG(ISP, Debug) << "unicam Device Identified"; + + std::unique_ptr data = std::make_unique(this, unicam_); + + if(data->init()) return false; + + std::set streams{&data->stream_}; + std::shared_ptr camera = Camera::create(this, data->video_->deviceName(), streams); + registerCamera(std::move(camera), std::move(data)); + + return true; +} + + +void ISPCameraData::ISPCompleted(FrameBuffer *rawBuffer, FrameBuffer *rgbBuffer) +{ + Request *request = rgbBuffer->request(); + + rawBufferQueue_.push(rawBuffer); + + pipe_->completeBuffer(request, rgbBuffer); + pipe_->completeRequest(request); + +} + +void ISPCameraData::bufferReady(FrameBuffer *buffer) +{ + FrameBuffer *rgbBuffer = rgbBufferQueue_.front(); + isp_.invokeMethod(&ISPCPU::processing, ConnectionTypeQueued, buffer, rgbBuffer, width_, height_); + rgbBufferQueue_.pop(); + +} + +int ISPCameraData::init() +{ + video_ = new V4L2VideoDevice(media_->getEntityByName("unicam-image")); + if (video_->open()) + return -ENODEV; + + video_->bufferReady.connect(this, &ISPCameraData::bufferReady); + isp_.ispCompleted.connect(this, &ISPCameraData::ISPCompleted); + + return 0; +} + +REGISTER_PIPELINE_HANDLER(PipelineHandlerISP) + +} /* namespace libcamera */