From patchwork Tue Apr 9 19:25: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: 956 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2662460004 for ; Tue, 9 Apr 2019 21:25:06 +0200 (CEST) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id B649A20000B; Tue, 9 Apr 2019 19:25:05 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 9 Apr 2019 21:25:37 +0200 Message-Id: <20190409192548.20325-2-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190409192548.20325-1-jacopo@jmondi.org> References: <20190409192548.20325-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 01/12] libcamera: ipu3: Sub-class Stream with IPU3Stream 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, 09 Apr 2019 19:25:06 -0000 In preparation for multiple stream support provide a Stream sub-class to maintain IPU3 specific data. In order to be able to sub-class Stream remove the 'final' specifier from the class definition and make its private members protected. Signed-off-by: Jacopo Mondi --- include/libcamera/stream.h | 4 ++-- src/libcamera/pipeline/ipu3/ipu3.cpp | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/include/libcamera/stream.h b/include/libcamera/stream.h index d0f7b0e12485..8a47930f8614 100644 --- a/include/libcamera/stream.h +++ b/include/libcamera/stream.h @@ -43,7 +43,7 @@ private: Size size_; }; -class Stream final +class Stream { public: class StillCapture : public StreamUsage @@ -68,7 +68,7 @@ public: BufferPool &bufferPool() { return bufferPool_; } const StreamConfiguration &configuration() const { return configuration_; } -private: +protected: friend class Camera; BufferPool bufferPool_; diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index ca09da753b90..00907bb53891 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -133,6 +133,18 @@ public: BufferPool pool_; }; +class IPU3Stream : public Stream +{ +public: + IPU3Stream() + : active_(false) + { + } + + bool active_; + std::string name_; +}; + class PipelineHandlerIPU3 : public PipelineHandler { public: @@ -171,7 +183,7 @@ private: CIO2Device cio2_; ImgUDevice *imgu_; - Stream stream_; + IPU3Stream stream_; }; static constexpr unsigned int IPU3_BUFFER_COUNT = 4; @@ -404,7 +416,7 @@ int PipelineHandlerIPU3::queueRequest(Camera *camera, Request *request) { IPU3CameraData *data = cameraData(camera); V4L2Device *output = data->imgu_->output_.dev; - Stream *stream = &data->stream_; + IPU3Stream *stream = &data->stream_; /* Queue a buffer to the ImgU output for capture. */ Buffer *buffer = request->findBuffer(stream); From patchwork Tue Apr 9 19:25: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: 957 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C458B60DBD for ; Tue, 9 Apr 2019 21:25:06 +0200 (CEST) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 4DEA820000C; Tue, 9 Apr 2019 19:25:06 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 9 Apr 2019 21:25:38 +0200 Message-Id: <20190409192548.20325-3-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190409192548.20325-1-jacopo@jmondi.org> References: <20190409192548.20325-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 02/12] libcamera: ipu3: Create camera with 2 streams X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 09 Apr 2019 19:25:07 -0000 Create each IPU3 camera with two streams: 'output' and 'viewfinder' which represents the video stream from main and secondary ImgU output respectively. Re-work stream configuration to handle the two video streams 'output' and 'viewfinder' separately. As the IPU3 driver requires viewfinder and stat video nodes to be started not to stall ImgU processing: for this reason configure 'output', 'viewfinder' and 'stat' regardless of the user requested active streams. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 180 +++++++++++++++++++-------- 1 file changed, 125 insertions(+), 55 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 00907bb53891..712e57c5a459 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -61,7 +61,7 @@ public: } int init(MediaDevice *media, unsigned int index); - int configureInput(const StreamConfiguration &config, + int configureInput(const Size &config, V4L2DeviceFormat *inputFormat); int configureOutput(ImgUOutput *output, const StreamConfiguration &config); @@ -111,7 +111,7 @@ public: } int init(const MediaDevice *media, unsigned int index); - int configure(const StreamConfiguration &config, + int configure(const Size &config, V4L2DeviceFormat *outputFormat); BufferPool *exportBuffers(); @@ -137,12 +137,14 @@ class IPU3Stream : public Stream { public: IPU3Stream() - : active_(false) + : active_(false), device_(nullptr), cfg_(nullptr) { } bool active_; std::string name_; + ImgUDevice::ImgUOutput *device_; + const StreamConfiguration *cfg_; }; class PipelineHandlerIPU3 : public PipelineHandler @@ -183,7 +185,8 @@ private: CIO2Device cio2_; ImgUDevice *imgu_; - IPU3Stream stream_; + IPU3Stream outStream_; + IPU3Stream vfStream_; }; static constexpr unsigned int IPU3_BUFFER_COUNT = 4; @@ -222,7 +225,7 @@ PipelineHandlerIPU3::streamConfiguration(Camera *camera, { CameraConfiguration configs; IPU3CameraData *data = cameraData(camera); - StreamConfiguration *config = &configs[&data->stream_]; + StreamConfiguration config = {}; /* * FIXME: Soraka: the maximum resolution reported by both sensors @@ -232,15 +235,22 @@ PipelineHandlerIPU3::streamConfiguration(Camera *camera, * * \todo Clarify ImgU alignement requirements. */ - config->width = 2560; - config->height = 1920; - config->pixelFormat = V4L2_PIX_FMT_NV12; - config->bufferCount = IPU3_BUFFER_COUNT; + config.width = 2560; + config.height = 1920; + config.pixelFormat = V4L2_PIX_FMT_NV12; + config.bufferCount = IPU3_BUFFER_COUNT; + configs[&data->outStream_] = config; LOG(IPU3, Debug) - << "Stream format set to " << config->width << "x" - << config->height << "-0x" << std::hex << std::setfill('0') - << std::setw(8) << config->pixelFormat; + << "Stream 'output' format set to " << config.width << "x" + << config.height << "-0x" << std::hex << std::setfill('0') + << std::setw(8) << config.pixelFormat; + + configs[&data->vfStream_] = config; + LOG(IPU3, Debug) + << "Stream 'viewfinder' format set to " << config.width << "x" + << config.height << "-0x" << std::hex << std::setfill('0') + << std::setw(8) << config.pixelFormat; return configs; } @@ -249,35 +259,59 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, const CameraConfiguration &config) { IPU3CameraData *data = cameraData(camera); - const StreamConfiguration &cfg = config[&data->stream_]; + IPU3Stream *outStream = &data->outStream_; + IPU3Stream *vfStream = &data->vfStream_; CIO2Device *cio2 = &data->cio2_; ImgUDevice *imgu = data->imgu_; + Size cio2Config = {}; 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() << "'"; + outStream->active_ = false; + vfStream->active_ = false; + for (const auto &s : config) { + IPU3Stream *stream = static_cast(s); + const StreamConfiguration &cfg = config[stream]; - /* - * 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; - } + /* + * Verify that the requested size respects the IPU3 alignment + * 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; + } - if (cfg.width > cio2->maxSize_.width || - cfg.height > cio2->maxSize_.height) { - LOG(IPU3, Error) - << "Invalid stream size: larger than sensor resolution"; - return -EINVAL; + if (cfg.width > cio2->maxSize_.width || + cfg.height > cio2->maxSize_.height) { + LOG(IPU3, Error) + << "Invalid stream size: larger than sensor resolution"; + return -EINVAL; + } + + LOG(IPU3, Info) + << "Stream '" << stream->name_ << "' " + << cfg.width << "x" << cfg.height << "-0x" + << std::hex << std::setw(8) << cfg.pixelFormat + << " on camera'" << camera->name() << "'"; + + /* + * Collect the maximum width and height: IPU3 can downscale + * only. + */ + if (cfg.width > cio2Config.width) + cio2Config.width = cfg.width; + if (cfg.height > cio2Config.height) + cio2Config.height = cfg.height; + + stream->active_ = true; + stream->cfg_ = &cfg; } /* @@ -293,24 +327,51 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, * adjusted format to be propagated to the ImgU output devices. */ V4L2DeviceFormat cio2Format = {}; - ret = cio2->configure(cfg, &cio2Format); + ret = cio2->configure(cio2Config, &cio2Format); if (ret) return ret; - ret = imgu->configureInput(cfg, &cio2Format); + ret = imgu->configureInput(cio2Config, &cio2Format); if (ret) return ret; - /* Apply the format to the ImgU output, viewfinder and stat. */ - ret = imgu->configureOutput(&imgu->output_, cfg); - if (ret) - return ret; + /* Apply the format to the configured streams output devices. */ + for (auto const &s : config) { + IPU3Stream *stream = static_cast(s); - ret = imgu->configureOutput(&imgu->viewfinder_, cfg); - if (ret) - return ret; + ret = imgu->configureOutput(stream->device_, *stream->cfg_); + if (ret) + return ret; + } - ret = imgu->configureOutput(&imgu->stat_, cfg); + /* + * As we need to set format also on the non-active streams, use + * the configuration of the active one for that purpose (there should + * be at least one active stream in the configuration request). + */ + if (!outStream->active_) { + ret = imgu->configureOutput(outStream->device_, + *vfStream->cfg_); + if (ret) + return ret; + } + + if (!vfStream->active_) { + ret = imgu->configureOutput(vfStream->device_, + *outStream->cfg_); + if (ret) + return ret; + } + + /* + * Apply the largest available format to the stat node. + * \todo Revise this when we'll actually use the stat node. + */ + StreamConfiguration statConfig = {}; + statConfig.width = cio2Format.width; + statConfig.height = cio2Format.height; + + ret = imgu->configureOutput(&imgu->stat_, statConfig); if (ret) return ret; @@ -416,7 +477,7 @@ int PipelineHandlerIPU3::queueRequest(Camera *camera, Request *request) { IPU3CameraData *data = cameraData(camera); V4L2Device *output = data->imgu_->output_.dev; - IPU3Stream *stream = &data->stream_; + IPU3Stream *stream = &data->outStream_; /* Queue a buffer to the ImgU output for capture. */ Buffer *buffer = request->findBuffer(stream); @@ -567,7 +628,10 @@ int PipelineHandlerIPU3::registerCameras() for (unsigned int id = 0; id < 4 && numCameras < 2; ++id) { std::unique_ptr data = utils::make_unique(this); - std::set streams{ &data->stream_ }; + std::set streams = { + &data->outStream_, + &data->vfStream_, + }; CIO2Device *cio2 = &data->cio2_; ret = cio2->init(cio2MediaDev_.get(), id); @@ -575,11 +639,14 @@ int PipelineHandlerIPU3::registerCameras() 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. + * \todo Dynamically assign ImgU and output devices to each + * stream and camera; 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_; + data->outStream_.device_ = &data->imgu_->output_; + data->vfStream_.device_ = &data->imgu_->viewfinder_; /* * Connect video devices' 'bufferReady' signals to their @@ -596,7 +663,10 @@ int PipelineHandlerIPU3::registerCameras() data->imgu_->output_.dev->bufferReady.connect(data.get(), &IPU3CameraData::imguOutputBufferReady); - /* Create and register the Camera instance. */ + + /* Initialize and register the Camera and its streams. */ + data->outStream_.name_ = "output"; + data->vfStream_.name_ = "viewfinder"; std::string cameraName = cio2->sensor_->entityName() + " " + std::to_string(id); std::shared_ptr camera = Camera::create(this, @@ -730,12 +800,12 @@ int ImgUDevice::init(MediaDevice *media, unsigned int index) /** * \brief Configure the ImgU unit input - * \param[in] config The requested stream configuration + * \param[in] config The requested stream sizes * \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, +int ImgUDevice::configureInput(const Size &config, V4L2DeviceFormat *inputFormat) { /* Configure the ImgU input video device with the requested sizes. */ @@ -1096,12 +1166,12 @@ int CIO2Device::init(const MediaDevice *media, unsigned int index) /** * \brief Configure the CIO2 unit - * \param[in] config The requested configuration + * \param[in] config The requested image sizes * \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, +int CIO2Device::configure(const Size &config, V4L2DeviceFormat *outputFormat) { unsigned int imageSize = config.width * config.height; From patchwork Tue Apr 9 19:25: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: 958 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 614DC60DB8 for ; Tue, 9 Apr 2019 21:25:07 +0200 (CEST) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id DB263200008; Tue, 9 Apr 2019 19:25:06 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 9 Apr 2019 21:25:39 +0200 Message-Id: <20190409192548.20325-4-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190409192548.20325-1-jacopo@jmondi.org> References: <20190409192548.20325-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 03/12] libcamera: camera: allocateBuffers: Pass the stream set 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, 09 Apr 2019 19:25:07 -0000 Pipeline handlers might need to perform allocation of internal buffers, setup operations, or simple sanity check before going into the per-stream buffer allocation. As of now, PipelineHandler::allocateBuffers() is called once for each active stream, leaving no space for stream-independent configuration. Change this by providing to the pipeline handlers the full set of active streams, and ask them to loop over them to perform per-streams allocations. While at it, propagate the freeBuffer() error code to the applications in case of failure. Signed-off-by: Jacopo Mondi Reviewed-by: Niklas Söderlund Reviewed-by: Laurent Pinchart --- src/libcamera/camera.cpp | 17 +++++++++-------- src/libcamera/include/pipeline_handler.h | 6 ++++-- src/libcamera/pipeline/ipu3/ipu3.cpp | 13 +++++++++---- src/libcamera/pipeline/uvcvideo.cpp | 13 +++++++++---- src/libcamera/pipeline/vimc.cpp | 13 +++++++++---- src/libcamera/pipeline_handler.cpp | 11 ++++++----- 6 files changed, 46 insertions(+), 27 deletions(-) diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp index bdf14b31d8ee..cb392ca3b7e7 100644 --- a/src/libcamera/camera.cpp +++ b/src/libcamera/camera.cpp @@ -647,13 +647,11 @@ int Camera::allocateBuffers() return -EINVAL; } - for (Stream *stream : activeStreams_) { - int ret = pipe_->allocateBuffers(this, stream); - if (ret) { - LOG(Camera, Error) << "Failed to allocate buffers"; - freeBuffers(); - return ret; - } + int ret = pipe_->allocateBuffers(this, activeStreams_); + if (ret) { + LOG(Camera, Error) << "Failed to allocate buffers"; + freeBuffers(); + return ret; } state_ = CameraPrepared; @@ -683,9 +681,12 @@ int Camera::freeBuffers() * by the V4L2 device that has allocated them. */ stream->bufferPool().destroyBuffers(); - pipe_->freeBuffers(this, stream); } + int ret = pipe_->freeBuffers(this, activeStreams_); + if (ret) + return ret; + state_ = CameraConfigured; return 0; diff --git a/src/libcamera/include/pipeline_handler.h b/src/libcamera/include/pipeline_handler.h index b6cbd3bae51b..253820e8eaf8 100644 --- a/src/libcamera/include/pipeline_handler.h +++ b/src/libcamera/include/pipeline_handler.h @@ -57,8 +57,10 @@ public: streamConfiguration(Camera *camera, const std::vector &usages) = 0; virtual int configureStreams(Camera *camera, const CameraConfiguration &config) = 0; - virtual int allocateBuffers(Camera *camera, Stream *stream) = 0; - virtual int freeBuffers(Camera *camera, Stream *stream) = 0; + virtual int allocateBuffers(Camera *camera, + const std::set &streams) = 0; + virtual int freeBuffers(Camera *camera, + const std::set &streams) = 0; virtual int start(Camera *camera) = 0; virtual void stop(Camera *camera); diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 712e57c5a459..527213a8970a 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -159,8 +159,10 @@ public: int configureStreams(Camera *camera, const CameraConfiguration &config) override; - int allocateBuffers(Camera *camera, Stream *stream) override; - int freeBuffers(Camera *camera, Stream *stream) override; + int allocateBuffers(Camera *camera, + const std::set &streams) override; + int freeBuffers(Camera *camera, + const std::set &streams) override; int start(Camera *camera) override; void stop(Camera *camera) override; @@ -378,9 +380,11 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, return 0; } -int PipelineHandlerIPU3::allocateBuffers(Camera *camera, Stream *stream) +int PipelineHandlerIPU3::allocateBuffers(Camera *camera, + const std::set &streams) { IPU3CameraData *data = cameraData(camera); + Stream *stream = *streams.begin(); CIO2Device *cio2 = &data->cio2_; ImgUDevice *imgu = data->imgu_; int ret; @@ -419,7 +423,8 @@ int PipelineHandlerIPU3::allocateBuffers(Camera *camera, Stream *stream) return 0; } -int PipelineHandlerIPU3::freeBuffers(Camera *camera, Stream *stream) +int PipelineHandlerIPU3::freeBuffers(Camera *camera, + const std::set &streams) { IPU3CameraData *data = cameraData(camera); diff --git a/src/libcamera/pipeline/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo.cpp index cd472cfadd86..b8f634d88b46 100644 --- a/src/libcamera/pipeline/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo.cpp @@ -32,8 +32,10 @@ public: int configureStreams(Camera *camera, const CameraConfiguration &config) override; - int allocateBuffers(Camera *camera, Stream *stream) override; - int freeBuffers(Camera *camera, Stream *stream) override; + int allocateBuffers(Camera *camera, + const std::set &streams) override; + int freeBuffers(Camera *camera, + const std::set &streams) override; int start(Camera *camera) override; void stop(Camera *camera) override; @@ -127,9 +129,11 @@ int PipelineHandlerUVC::configureStreams(Camera *camera, return 0; } -int PipelineHandlerUVC::allocateBuffers(Camera *camera, Stream *stream) +int PipelineHandlerUVC::allocateBuffers(Camera *camera, + const std::set &streams) { UVCCameraData *data = cameraData(camera); + Stream *stream = *streams.begin(); const StreamConfiguration &cfg = stream->configuration(); LOG(UVC, Debug) << "Requesting " << cfg.bufferCount << " buffers"; @@ -137,7 +141,8 @@ int PipelineHandlerUVC::allocateBuffers(Camera *camera, Stream *stream) return data->video_->exportBuffers(&stream->bufferPool()); } -int PipelineHandlerUVC::freeBuffers(Camera *camera, Stream *stream) +int PipelineHandlerUVC::freeBuffers(Camera *camera, + const std::set &streams) { UVCCameraData *data = cameraData(camera); return data->video_->releaseBuffers(); diff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp index c8bbe2a19847..22449e47bc2d 100644 --- a/src/libcamera/pipeline/vimc.cpp +++ b/src/libcamera/pipeline/vimc.cpp @@ -32,8 +32,10 @@ public: int configureStreams(Camera *camera, const CameraConfiguration &config) override; - int allocateBuffers(Camera *camera, Stream *stream) override; - int freeBuffers(Camera *camera, Stream *stream) override; + int allocateBuffers(Camera *camera, + const std::set &streams) override; + int freeBuffers(Camera *camera, + const std::set &streams) override; int start(Camera *camera) override; void stop(Camera *camera) override; @@ -127,9 +129,11 @@ int PipelineHandlerVimc::configureStreams(Camera *camera, return 0; } -int PipelineHandlerVimc::allocateBuffers(Camera *camera, Stream *stream) +int PipelineHandlerVimc::allocateBuffers(Camera *camera, + const std::set &streams) { VimcCameraData *data = cameraData(camera); + Stream *stream = *streams.begin(); const StreamConfiguration &cfg = stream->configuration(); LOG(VIMC, Debug) << "Requesting " << cfg.bufferCount << " buffers"; @@ -137,7 +141,8 @@ int PipelineHandlerVimc::allocateBuffers(Camera *camera, Stream *stream) return data->video_->exportBuffers(&stream->bufferPool()); } -int PipelineHandlerVimc::freeBuffers(Camera *camera, Stream *stream) +int PipelineHandlerVimc::freeBuffers(Camera *camera, + const std::set &streams) { VimcCameraData *data = cameraData(camera); return data->video_->releaseBuffers(); diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index 43550c0e0210..911d08448e69 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -193,10 +193,11 @@ PipelineHandler::~PipelineHandler() * \fn PipelineHandler::allocateBuffers() * \brief Allocate buffers for a stream * \param[in] camera The camera the \a stream belongs to - * \param[in] stream The stream to allocate buffers for + * \param[in] streams The set of streams to allocate buffers for * - * This method allocates buffers internally in the pipeline handler and - * associates them with the stream's buffer pool. + * This method allocates buffers internally in the pipeline handler for each + * stream in the \a streams buffer set, and associates them with the stream's + * buffer pool. * * The intended caller of this method is the Camera class. * @@ -207,9 +208,9 @@ PipelineHandler::~PipelineHandler() * \fn PipelineHandler::freeBuffers() * \brief Free all buffers associated with a stream * \param[in] camera The camera the \a stream belongs to - * \param[in] stream The stream to free buffers from + * \param[in] streams The set of streams to free buffers from * - * After a capture session has been stopped all buffers associated with the + * After a capture session has been stopped all buffers associated with each * stream shall be freed. * * The intended caller of this method is the Camera class. From patchwork Tue Apr 9 19:25: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: 959 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 07F6960DB7 for ; Tue, 9 Apr 2019 21:25:08 +0200 (CEST) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 80F9920000B; Tue, 9 Apr 2019 19:25:07 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 9 Apr 2019 21:25:40 +0200 Message-Id: <20190409192548.20325-5-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190409192548.20325-1-jacopo@jmondi.org> References: <20190409192548.20325-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 04/12] libcamera: ipu3: Add multiple stream memory management X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 09 Apr 2019 19:25:08 -0000 Perform allocation and setup of memory sharing between the CIO2 output and the ImgU input and allocate memory for each active stream. Reviewed-by: Laurent Pinchart --- src/libcamera/pipeline/ipu3/ipu3.cpp | 65 +++++++++++++++++++++------- 1 file changed, 49 insertions(+), 16 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 527213a8970a..f5d768f9f87f 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -91,6 +91,7 @@ public: BufferPool vfPool_; BufferPool statPool_; + BufferPool outPool_; }; class CIO2Device @@ -380,13 +381,23 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, return 0; } +/** + * \todo Clarify if 'viewfinder' and 'stat' nodes have to be set up and + * started even if not in use. As of now, if not properly configured and + * enabled, the ImgU processing pipeline stalls. + * + * In order to be able to start the 'viewfinder' and 'stat' nodes, we need + * memory to be reserved. + */ int PipelineHandlerIPU3::allocateBuffers(Camera *camera, const std::set &streams) { IPU3CameraData *data = cameraData(camera); - Stream *stream = *streams.begin(); + IPU3Stream *outStream = &data->outStream_; + IPU3Stream *vfStream = &data->vfStream_; CIO2Device *cio2 = &data->cio2_; ImgUDevice *imgu = data->imgu_; + int ret; /* Share buffers between CIO2 output and ImgU input. */ @@ -398,28 +409,49 @@ int PipelineHandlerIPU3::allocateBuffers(Camera *camera, 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. + * Use for the stat's internal pools the same number of buffer as + * for the input pool. + * \todo To be revised when we'll actually use the stat node. */ - unsigned int bufferCount = stream->bufferPool().count(); - - imgu->viewfinder_.pool->createBuffers(bufferCount); - ret = imgu->exportBuffers(&imgu->viewfinder_, imgu->viewfinder_.pool); - if (ret) - return ret; - + unsigned int bufferCount = pool->count(); imgu->stat_.pool->createBuffers(bufferCount); ret = imgu->exportBuffers(&imgu->stat_, imgu->stat_.pool); if (ret) return ret; + /* Allocate buffers for each active stream. */ + for (Stream *s : streams) { + IPU3Stream *stream = static_cast(s); + ImgUDevice::ImgUOutput *dev = stream->device_; + + ret = imgu->exportBuffers(dev, &stream->bufferPool()); + if (ret) + return ret; + } + + /* + * Allocate buffers also on non-active outputs; use the same number + * of buffers as the active ones. + */ + if (!outStream->active_) { + bufferCount = vfStream->bufferPool().count(); + outStream->device_->pool->createBuffers(bufferCount); + ret = imgu->exportBuffers(outStream->device_, + outStream->device_->pool); + if (ret) + return ret; + } + + if (!vfStream->active_) { + bufferCount = outStream->bufferPool().count(); + vfStream->device_->pool->createBuffers(bufferCount); + ret = imgu->exportBuffers(vfStream->device_, + vfStream->device_->pool); + if (ret) + return ret; + } + return 0; } @@ -780,6 +812,7 @@ int ImgUDevice::init(MediaDevice *media, unsigned int index) output_.pad = PAD_OUTPUT; output_.name = "output"; + output_.pool = &outPool_; viewfinder_.dev = V4L2Device::fromEntityName(media, name_ + " viewfinder"); From patchwork Tue Apr 9 19:25: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: 960 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8FA3C60DB7 for ; Tue, 9 Apr 2019 21:25:08 +0200 (CEST) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 2C6D9200008; Tue, 9 Apr 2019 19:25:08 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 9 Apr 2019 21:25:41 +0200 Message-Id: <20190409192548.20325-6-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190409192548.20325-1-jacopo@jmondi.org> References: <20190409192548.20325-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 05/12] libcamera: request: Expose the Stream to Buffers map 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, 09 Apr 2019 19:25:08 -0000 Add to the Request class a method to access the map to Stream to Buffer. Signed-off-by: Jacopo Mondi Reviewed-by: Niklas Söderlund Reviewed-by: Laurent Pinchart --- include/libcamera/request.h | 2 ++ src/libcamera/request.cpp | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/include/libcamera/request.h b/include/libcamera/request.h index 0dbd425115e8..2004312a2233 100644 --- a/include/libcamera/request.h +++ b/include/libcamera/request.h @@ -37,6 +37,8 @@ public: Status status() const { return status_; } + const std::map &bufferMap() const { return bufferMap_; } + private: friend class Camera; friend class PipelineHandler; diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp index e0e77e972411..46f9add98fde 100644 --- a/src/libcamera/request.cpp +++ b/src/libcamera/request.cpp @@ -106,6 +106,16 @@ Buffer *Request::findBuffer(Stream *stream) const * \return The request completion status */ +/** + * \fn Request::bufferMap() + * \brief Retrieve the request' stream to buffer map + * + * Return a reference to the map that associates each Stream part of the + * request to the Buffer the Stream output should be directed to. + * + * \return The map of Stream to Buffers + */ + /** * \brief Prepare the resources for the completion handler */ From patchwork Tue Apr 9 19:25: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: 961 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 26DD260DB7 for ; Tue, 9 Apr 2019 21:25:09 +0200 (CEST) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id B43A6200008; Tue, 9 Apr 2019 19:25:08 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 9 Apr 2019 21:25:42 +0200 Message-Id: <20190409192548.20325-7-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190409192548.20325-1-jacopo@jmondi.org> References: <20190409192548.20325-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 06/12] libcamera: ipu3: Queue requests for multiple streams X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 09 Apr 2019 19:25:09 -0000 Add support for queueing requests for multiple streams in the IPU3 pipeline handler class. The output video node should be queued with buffers even if not part of the requested streams. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 46 +++++++++++++++++++++------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index f5d768f9f87f..bb8d4ce644ca 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -146,6 +146,7 @@ public: std::string name_; ImgUDevice::ImgUOutput *device_; const StreamConfiguration *cfg_; + unsigned int bufferCount; }; class PipelineHandlerIPU3 : public PipelineHandler @@ -473,6 +474,9 @@ int PipelineHandlerIPU3::start(Camera *camera) ImgUDevice *imgu = data->imgu_; int ret; + if (!data->outStream_.active_) + data->outStream_.bufferCount = 0; + /* * Start the ImgU video devices, buffers will be queued to the * ImgU output and viewfinder when requests will be queued. @@ -513,20 +517,40 @@ void PipelineHandlerIPU3::stop(Camera *camera) int PipelineHandlerIPU3::queueRequest(Camera *camera, Request *request) { IPU3CameraData *data = cameraData(camera); - V4L2Device *output = data->imgu_->output_.dev; - IPU3Stream *stream = &data->outStream_; + IPU3Stream *output = &data->outStream_; + bool outputRequested = false; - /* Queue a buffer to the ImgU output for capture. */ - Buffer *buffer = request->findBuffer(stream); - if (!buffer) { - LOG(IPU3, Error) - << "Attempt to queue request with invalid stream"; - return -ENOENT; + for (auto const &bufferMap : request->bufferMap()) { + IPU3Stream *stream = static_cast(bufferMap.first); + Buffer *buffer = bufferMap.second; + + int ret = stream->device_->dev->queueBuffer(buffer); + if (ret) + continue; + + if (stream == output) + outputRequested = true; } - int ret = output->queueBuffer(buffer); - if (ret < 0) - return ret; + /* + * The output node should be queued with buffers even if not part + * of the request, otherwise the ImgU stalls. + * + * Use buffers from the stream's pool or the internal pool depending + * if the output stream has been configured or not. + */ + if (!outputRequested) { + BufferPool *pool = output->active_ ? &output->bufferPool() + : output->device_->pool; + Buffer *buffer = &pool->buffers()[output->bufferCount]; + unsigned int numBuffers = pool->count(); + + int ret = output->device_->dev->queueBuffer(buffer); + if (ret) + return ret; + + output->bufferCount = (output->bufferCount + 1) % numBuffers; + } PipelineHandler::queueRequest(camera, request); From patchwork Tue Apr 9 19:25: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: 962 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B55E460004 for ; Tue, 9 Apr 2019 21:25:09 +0200 (CEST) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 4CF9B20000B; Tue, 9 Apr 2019 19:25:09 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 9 Apr 2019 21:25:43 +0200 Message-Id: <20190409192548.20325-8-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190409192548.20325-1-jacopo@jmondi.org> References: <20190409192548.20325-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 07/12] libcamera: request: Add empty() method X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 09 Apr 2019 19:25:11 -0000 Add method to verify if a request has pending buffers yet to be completed or it is empty and ready from completion. Signed-off-by: Jacopo Mondi Reviewed-by: Niklas Söderlund --- include/libcamera/request.h | 2 ++ src/libcamera/request.cpp | 11 +++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/include/libcamera/request.h b/include/libcamera/request.h index 2004312a2233..37f9a3b27482 100644 --- a/include/libcamera/request.h +++ b/include/libcamera/request.h @@ -37,6 +37,8 @@ public: Status status() const { return status_; } + bool empty() const { return pending_.empty(); } + const std::map &bufferMap() const { return bufferMap_; } private: diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp index 46f9add98fde..3e10c995a6fa 100644 --- a/src/libcamera/request.cpp +++ b/src/libcamera/request.cpp @@ -106,6 +106,13 @@ Buffer *Request::findBuffer(Stream *stream) const * \return The request completion status */ +/** + * \fn Request::empty() + * \brief Retrieve if a request has buffers yet to be completed + * + * \return True if no buffer is pending for completion, false otherwise + */ + /** * \fn Request::bufferMap() * \brief Retrieve the request' stream to buffer map @@ -137,7 +144,7 @@ int Request::prepare() */ void Request::complete(Status status) { - ASSERT(pending_.empty()); + ASSERT(empty()); status_ = status; } @@ -159,7 +166,7 @@ bool Request::completeBuffer(Buffer *buffer) int ret = pending_.erase(buffer); ASSERT(ret == 1); - return pending_.empty(); + return empty(); } } /* namespace libcamera */ From patchwork Tue Apr 9 19:25:44 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 963 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 50FE660DBD for ; Tue, 9 Apr 2019 21:25:10 +0200 (CEST) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id D6FF4200008; Tue, 9 Apr 2019 19:25:09 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 9 Apr 2019 21:25:44 +0200 Message-Id: <20190409192548.20325-9-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190409192548.20325-1-jacopo@jmondi.org> References: <20190409192548.20325-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 08/12] libcamera: camera: Refuse empty requests 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, 09 Apr 2019 19:25:12 -0000 Requests that do not contain any Stream should not be forwarded to the pipeline handlers. Return -EINVAL if the request does not contain any Stream to capture from. Signed-off-by: Jacopo Mondi --- src/libcamera/camera.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp index cb392ca3b7e7..bd73ff69c3da 100644 --- a/src/libcamera/camera.cpp +++ b/src/libcamera/camera.cpp @@ -728,6 +728,7 @@ Request *Camera::createRequest() * \return 0 on success or a negative error code otherwise * \retval -ENODEV The camera has been disconnected from the system * \retval -EACCES The camera is not running so requests can't be queued + * \retval -EINVAL The request does not contain any stream to capture from */ int Camera::queueRequest(Request *request) { @@ -743,6 +744,9 @@ int Camera::queueRequest(Request *request) return ret; } + if (request->empty()) + return -EINVAL; + return pipe_->queueRequest(this, request); } From patchwork Tue Apr 9 19:25:45 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 964 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D216360DC2 for ; Tue, 9 Apr 2019 21:25:10 +0200 (CEST) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 6CF5020000B; Tue, 9 Apr 2019 19:25:10 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 9 Apr 2019 21:25:45 +0200 Message-Id: <20190409192548.20325-10-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190409192548.20325-1-jacopo@jmondi.org> References: <20190409192548.20325-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 09/12] libcamera: buffer: Store Request reference in Buffer 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, 09 Apr 2019 19:25:12 -0000 Add to the Buffer class methods to set and retrieve a reference to the Request instance this buffer is part of. As Buffers might outlive the Request they are associated with, the reference is only temporarly valid during the buffer completion interval (since when the buffer gets queued to Camera for processing, until it gets marked as completed). Signed-off-by: Jacopo Mondi --- include/libcamera/buffer.h | 5 +++++ src/libcamera/buffer.cpp | 39 +++++++++++++++++++++++++++++++++++++- src/libcamera/request.cpp | 4 ++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/include/libcamera/buffer.h b/include/libcamera/buffer.h index 0c844d126a27..10c46cd57ab0 100644 --- a/include/libcamera/buffer.h +++ b/include/libcamera/buffer.h @@ -13,6 +13,7 @@ namespace libcamera { class BufferPool; +class Request; class Plane final { @@ -53,6 +54,9 @@ public: Status status() const { return status_; } std::vector &planes() { return planes_; } + void setRequest(Request *req) { request_ = req; } + Request *request() const { return request_; } + private: friend class BufferPool; friend class PipelineHandler; @@ -67,6 +71,7 @@ private: Status status_; std::vector planes_; + Request *request_; }; class BufferPool final diff --git a/src/libcamera/buffer.cpp b/src/libcamera/buffer.cpp index e2d1cf04411e..68738b733ba6 100644 --- a/src/libcamera/buffer.cpp +++ b/src/libcamera/buffer.cpp @@ -196,7 +196,7 @@ void *Plane::mem() */ Buffer::Buffer() - : index_(-1) + : index_(-1), request_(nullptr) { } @@ -248,6 +248,43 @@ Buffer::Buffer() * \return The buffer status */ +/** + * \fn Buffer::setRequest() + * \brief Set the request this buffer belongs to + * + * Buffers are associated to Streams in a Request, which is then sent to the + * Camera for processing. This method stores in the Buffer a pointer to the + * Request this Buffer is part of, for later retrieval through the + * Buffer::request() method. + * + * Buffers are associated to requests at Request::prepare() time and said + * association is valid until the buffer does not complete at + * Request::completeBuffer() time. Before and after the buffer completion + * interval (the time between when the request is queued to the Camera, and + * the buffer is marked as 'complete' by pipeline handlers) the reference to + * Request is set to nullptr. + */ + +/** + * \fn Buffer::request() + * \brief Retrieve the request this buffer belongs to + * + * The intended callers of this method are buffer completion slots + * implemented in CameraData sub-classes which needs to associated a request + * to the just completed buffer, before calling Request::completeBuffer(). + * + * It is up to the caller of this function to deal with the case the buffer has + * been already marked as complete, and the reference to the Request has been + * invalidated and set to nullptr. + * + * See also Buffer::setRequest() for a more detailed explanation of the + * validity interval of the Request reference contained in a Buffer. + * + * \return The Request this Buffer belongs to or nullptr if the Buffer has + * not been queued to the Camera for processing yet or it has completed already. + * \sa Buffer::setRequest() + */ + /** * \brief Mark a buffer as cancel by setting its status to BufferCancelled */ diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp index 3e10c995a6fa..7d80c635fa92 100644 --- a/src/libcamera/request.cpp +++ b/src/libcamera/request.cpp @@ -130,6 +130,8 @@ int Request::prepare() { for (auto const &pair : bufferMap_) { Buffer *buffer = pair.second; + + buffer->setRequest(this); pending_.insert(buffer); } @@ -166,6 +168,8 @@ bool Request::completeBuffer(Buffer *buffer) int ret = pending_.erase(buffer); ASSERT(ret == 1); + buffer->setRequest(nullptr); + return empty(); } From patchwork Tue Apr 9 19:25:46 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 965 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 63B0F60DB8 for ; Tue, 9 Apr 2019 21:25:11 +0200 (CEST) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 00D1C200008; Tue, 9 Apr 2019 19:25:10 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 9 Apr 2019 21:25:46 +0200 Message-Id: <20190409192548.20325-11-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190409192548.20325-1-jacopo@jmondi.org> References: <20190409192548.20325-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 10/12] libcamera: ipu3: Connect viewfinder's BufferReady signal X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 09 Apr 2019 19:25:12 -0000 Connect the viewfinder buffer ready signal to the IPU3CameraData slot that complets the buffer first, and if not waiting for other buffers completes the request as well. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 43 ++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index bb8d4ce644ca..75ffdc56d157 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -182,7 +182,7 @@ private: { } - void imguOutputBufferReady(Buffer *buffer); + void imguCaptureBufferReady(Buffer *buffer); void imguInputBufferReady(Buffer *buffer); void cio2BufferReady(Buffer *buffer); @@ -722,7 +722,9 @@ int PipelineHandlerIPU3::registerCameras() data->imgu_->input_->bufferReady.connect(data.get(), &IPU3CameraData::imguInputBufferReady); data->imgu_->output_.dev->bufferReady.connect(data.get(), - &IPU3CameraData::imguOutputBufferReady); + &IPU3CameraData::imguCaptureBufferReady); + data->imgu_->viewfinder_.dev->bufferReady.connect(data.get(), + &IPU3CameraData::imguCaptureBufferReady); /* Initialize and register the Camera and its streams. */ @@ -769,12 +771,41 @@ void PipelineHandlerIPU3::IPU3CameraData::imguInputBufferReady(Buffer *buffer) * * Buffers completed from the ImgU output are directed to the application. */ -void PipelineHandlerIPU3::IPU3CameraData::imguOutputBufferReady(Buffer *buffer) +void PipelineHandlerIPU3::IPU3CameraData::imguCaptureBufferReady(Buffer *buffer) { - Request *request = queuedRequests_.front(); + Request *request = buffer->request(); + if (!request) + /* + * Completed buffers not part of a request are ignored + * (they most probably come from the output stream + * internal pool) + */ + return; + + if (!pipe_->completeBuffer(camera_, request, buffer)) + /* Request not completed yet, return here. */ + return; + + /* + * Complete requests in queuing order: if some other request is + * pending, post-pone completion. + */ + Request *front = queuedRequests_.front(); + if (front != request) + return; - pipe_->completeBuffer(camera_, request, buffer); - pipe_->completeRequest(camera_, request); + /* + * Complete the current request, and all the other pending ones, + * in queuing order. + */ + while (1) { + if (front->empty()) + pipe_->completeRequest(camera_, front); + else + break; + + front = queuedRequests_.front(); + } } /** From patchwork Tue Apr 9 19:25:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 966 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id EE23B60004 for ; Tue, 9 Apr 2019 21:25:11 +0200 (CEST) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 8BA4C20000B; Tue, 9 Apr 2019 19:25:11 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 9 Apr 2019 21:25:47 +0200 Message-Id: <20190409192548.20325-12-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190409192548.20325-1-jacopo@jmondi.org> References: <20190409192548.20325-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 11/12] libcamera: ipu3: Use roles in 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: Tue, 09 Apr 2019 19:25:12 -0000 Use and inspect the stream roles provided by the application to streamConfiguration() to assign streams to their intended roles and return a default configuration associated with them. Support a limited number of usages, as the viewfinder stream can optionally be used for capturing still images, but the main output stream cannot be used as viewfinder or for video recording purposes. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 105 ++++++++++++++++++++------- 1 file changed, 79 insertions(+), 26 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 75ffdc56d157..70a92783076f 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -227,36 +227,89 @@ CameraConfiguration PipelineHandlerIPU3::streamConfiguration(Camera *camera, const std::vector &usages) { - CameraConfiguration configs; IPU3CameraData *data = cameraData(camera); - StreamConfiguration config = {}; + CameraConfiguration configs; + std::vector availableStreams = { + &data->outStream_, + &data->vfStream_, + }; - /* - * 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; - - configs[&data->outStream_] = config; - LOG(IPU3, Debug) - << "Stream 'output' format set to " << config.width << "x" - << config.height << "-0x" << std::hex << std::setfill('0') - << std::setw(8) << config.pixelFormat; - - configs[&data->vfStream_] = config; - LOG(IPU3, Debug) - << "Stream 'viewfinder' format set to " << config.width << "x" - << config.height << "-0x" << std::hex << std::setfill('0') - << std::setw(8) << config.pixelFormat; + for (const StreamUsage &usage : usages) { + std::vector::iterator found; + enum StreamUsage::Role r = usage.role(); + StreamConfiguration config = {}; + IPU3Stream *stream = nullptr; + + std::vector::iterator s = availableStreams.begin(); + if (r == StreamUsage::Role::StillCapture) { + for (; s < availableStreams.end(); ++s) { + /* + * We can use the viewfinder stream in case + * the 'StillCapture' usage is required + * multiple times. + */ + if (*s == &data->outStream_) { + stream = &data->outStream_; + found = s; + break; + } else { + stream = &data->vfStream_; + found = s; + } + } + + /* + * 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 alignment requirements. + */ + config.width = 2560; + config.height = 1920; + } else if (r == StreamUsage::Role::Viewfinder || + r == StreamUsage::Role::VideoRecording) { + for (; s < availableStreams.end(); ++s) { + /* + * We can't use the 'output' stream for + * viewfinder or video capture usages. + */ + if (*s != &data->vfStream_) + continue; + + stream = &data->vfStream_; + found = s; + break; + } + + config.width = 640; + config.height = 480; + } + + if (stream == nullptr) + goto error; + + availableStreams.erase(found); + + config.pixelFormat = V4L2_PIX_FMT_NV12; + config.bufferCount = IPU3_BUFFER_COUNT; + + configs[stream] = config; + + LOG(IPU3, Debug) + << "Stream " << stream->name_ << " format set to " + << config.width << "x" << config.height + << "-0x" << std::hex << std::setfill('0') + << std::setw(8) << config.pixelFormat; + } return configs; + +error: + LOG(IPU3, Error) << "Requested stream roles not supported"; + return CameraConfiguration{}; } int PipelineHandlerIPU3::configureStreams(Camera *camera, From patchwork Tue Apr 9 19:25:48 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 967 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 848D760DBD for ; Tue, 9 Apr 2019 21:25:12 +0200 (CEST) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 2324D20000B; Tue, 9 Apr 2019 19:25:11 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 9 Apr 2019 21:25:48 +0200 Message-Id: <20190409192548.20325-13-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190409192548.20325-1-jacopo@jmondi.org> References: <20190409192548.20325-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 12/12] [HACK] still capture every 10 frames 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, 09 Apr 2019 19:25:12 -0000 Not for inclusion, just to demonstrate how an application could track its streams to their assigned usages. Signed-off-by: Jacopo Mondi --- src/cam/main.cpp | 46 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/src/cam/main.cpp b/src/cam/main.cpp index 46aba728393c..fce694bf26d5 100644 --- a/src/cam/main.cpp +++ b/src/cam/main.cpp @@ -28,6 +28,11 @@ std::map streamInfo; EventLoop *loop; BufferWriter *writer; +unsigned int streamCount = 0; +unsigned int outBuf = 0; +std::map streamMap; +CameraConfiguration config; + enum { OptCamera = 'c', OptCapture = 'C', @@ -129,6 +134,11 @@ static int prepareCameraConfig(CameraConfiguration *config) return -EINVAL; } + /* Associate each stream returned by the Camera with its role. */ + unsigned int i = 0; + for (auto *stream : *config) + streamMap[stream] = roles[i++].role(); + /* Apply configuration explicitly requested. */ CameraConfiguration::iterator it = config->begin(); for (auto const &value : streamOptions) { @@ -158,6 +168,7 @@ static int prepareCameraConfig(CameraConfiguration *config) static void requestComplete(Request *request, const std::map &buffers) { + std::map map; static uint64_t now, last = 0; double fps = 0.0; @@ -196,13 +207,37 @@ static void requestComplete(Request *request, const std::map return; } - request->setBuffers(buffers); + /* Viewfinder in every request. */ + for (auto &b : buffers) { + Stream *s = b.first; + if (streamMap[s] != StreamUsage::Role::Viewfinder) + continue; + + map[s] = b.second; + } + + /* Still capture every ten requests. */ + streamCount++; + if (!(streamCount % 10)) { + streamCount = 0; + for (Stream *stream : config) { + if (streamMap[stream] != StreamUsage::Role::StillCapture) + continue; + + map[stream] = + &stream->bufferPool().buffers()[outBuf]; + outBuf = (outBuf + 1) % + stream->bufferPool().count(); + break; + } + } + + request->setBuffers(map); camera->queueRequest(request); } static int capture() { - CameraConfiguration config; int ret; ret = prepareCameraConfig(&config); @@ -246,8 +281,13 @@ static int capture() } std::map map; - for (Stream *stream : config) + for (Stream *stream : config) { + if (streamMap[stream] != StreamUsage::Role::Viewfinder) + continue; + + /* Only require the viewfinder to begin with. */ map[stream] = &stream->bufferPool().buffers()[i]; + } ret = request->setBuffers(map); if (ret < 0) {