From patchwork Fri Apr 19 10:18:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1074 Return-Path: Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2ABFA60004 for ; Fri, 19 Apr 2019 12:17:52 +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 relay9-d.mail.gandi.net (Postfix) with ESMTPSA id B782FFF808; Fri, 19 Apr 2019 10:17:51 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Fri, 19 Apr 2019 12:18:32 +0200 Message-Id: <20190419101839.10337-2-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190419101839.10337-1-jacopo@jmondi.org> References: <20190419101839.10337-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v7 1/8] libcamera: stream: Document protected members 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: Fri, 19 Apr 2019 10:17:52 -0000 Since commit: 4e1dc9004fca ("libcamera: stream: Make Stream inheritable") the private members of the Stream class have been turned into protected, to allows subclasses to access them. As Doxygen generates documentation for protected members (but not for private memebers), add documentation to the stream class for the 'bufferMap_' and 'configuration_' members. Fixes: 4e1dc9004fca ("libcamera: stream: Make Stream inheritable") Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/libcamera/stream.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/libcamera/stream.cpp b/src/libcamera/stream.cpp index 85cd5256ee2f..aeb56fc1cadf 100644 --- a/src/libcamera/stream.cpp +++ b/src/libcamera/stream.cpp @@ -194,4 +194,22 @@ Stream::Stream() * \return The active configuration of the stream */ +/** + * \var Stream::bufferPool_ + * \brief The pool of buffers associated with the stream + * + * The stream buffer pool is populated by the Camera class after a succesfull + * stream configuration. + */ + +/** + * \var Stream::configuration_ + * \brief The stream configuration + * + * The configuration for the stream is set by any successful call to + * Camera::configureStreams() that includes the stream, and remains valid until + * the next call to Camera::configureStreams() regardless of if it includes the + * stream. + */ + } /* namespace libcamera */ From patchwork Fri Apr 19 10:18:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1075 Return-Path: Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D1A9160DBF for ; Fri, 19 Apr 2019 12:17:52 +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 relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 62550FF811; Fri, 19 Apr 2019 10:17:52 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Fri, 19 Apr 2019 12:18:33 +0200 Message-Id: <20190419101839.10337-3-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190419101839.10337-1-jacopo@jmondi.org> References: <20190419101839.10337-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v7 2/8] libcamera: camera: Reset basefield to decimal 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: Fri, 19 Apr 2019 10:17:53 -0000 When logging the camera configuration, the same ostringstream instance is used to assemble a message describing configuration of all the configured streams. After the first stream configuration has been assembled, the use of std::hex modifies the ostringstream basefield, causing all successive integers values inserted in the stream to be expressed as hexadecimals. Fix that by resetting the stream's basefield to decimal, before assembling a stream configuration description. Before this patch: INFO Camera camera.cpp:615 (0) 640x480-0x3231564e (1) 140xa0-0x3231564e After this patch: INFO Camera camera.cpp:616 (0) 640x480-0x3231564e (1) 320x160-0x3231564e Fixes: 9c9078133216 ("libcamera: camera: Log requested configuration in configureStreams()") Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/libcamera/camera.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp index bd381fa1cb56..4af3780d305e 100644 --- a/src/libcamera/camera.cpp +++ b/src/libcamera/camera.cpp @@ -605,6 +605,7 @@ int Camera::configureStreams(const CameraConfiguration &config) return -EINVAL; const StreamConfiguration &cfg = config[stream]; + msg << std::dec; msg << " (" << index << ") " << cfg.width << "x" << cfg.height << "-0x" << std::hex << std::setfill('0') << std::setw(8) << cfg.pixelFormat; From patchwork Fri Apr 19 10:18:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1076 Return-Path: Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7758E60DC7 for ; Fri, 19 Apr 2019 12:17:53 +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 relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 0406FFF802; Fri, 19 Apr 2019 10:17:52 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Fri, 19 Apr 2019 12:18:34 +0200 Message-Id: <20190419101839.10337-4-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190419101839.10337-1-jacopo@jmondi.org> References: <20190419101839.10337-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v7 3/8] 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: Fri, 19 Apr 2019 10:17:54 -0000 Sub-class the Stream class with an IPU3-specific implementation and create each IPU3 camera with two streams: 'output' and 'viewfinder' which represent the video streams 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, configure 'output', 'viewfinder' and 'stat' regardless of the user-requested active streams. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 186 +++++++++++++++++++-------- 1 file changed, 134 insertions(+), 52 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 64b4210b4ce3..9b2d96f22b2b 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -62,7 +62,7 @@ public: } int init(MediaDevice *media, unsigned int index); - int configureInput(const StreamConfiguration &config, + int configureInput(const Size &size, V4L2DeviceFormat *inputFormat); int configureOutput(ImgUOutput *output, const StreamConfiguration &config); @@ -112,7 +112,7 @@ public: } int init(const MediaDevice *media, unsigned int index); - int configure(const StreamConfiguration &config, + int configure(const Size &size, V4L2DeviceFormat *outputFormat); BufferPool *exportBuffers(); @@ -130,6 +130,20 @@ public: BufferPool pool_; }; +class IPU3Stream : public Stream +{ +public: + IPU3Stream() + : active_(false), device_(nullptr), cfg_(nullptr) + { + } + + bool active_; + std::string name_; + ImgUDevice::ImgUOutput *device_; + const StreamConfiguration *cfg_; +}; + class PipelineHandlerIPU3 : public PipelineHandler { public: @@ -170,7 +184,8 @@ private: CIO2Device cio2_; ImgUDevice *imgu_; - Stream stream_; + IPU3Stream outStream_; + IPU3Stream vfStream_; }; static constexpr unsigned int IPU3_BUFFER_COUNT = 4; @@ -209,7 +224,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 @@ -219,15 +234,24 @@ 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 '" << data->outStream_.name_ << "' 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 format set to " << config->width << "x" - << config->height << "-0x" << std::hex << std::setfill('0') - << std::setw(8) << config->pixelFormat; + << "Stream '" << data->vfStream_.name_ << "' set to " + << config.width << "x" << config.height << "-0x" + << std::hex << std::setfill('0') << std::setw(8) + << config.pixelFormat; return configs; } @@ -236,30 +260,53 @@ 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 sensorSize = {}; int ret; - /* - * 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; - } + data->outStream_.active_ = false; + data->vfStream_.active_ = false; + for (Stream *s : config) { + IPU3Stream *stream = static_cast(s); + const StreamConfiguration &cfg = config[stream]; - const Size &resolution = cio2->sensor_->resolution(); - if (cfg.width > resolution.width || - cfg.height > resolution.height) { - LOG(IPU3, Error) - << "Invalid stream size: larger than sensor resolution"; - 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; + } + + const Size &resolution = cio2->sensor_->resolution(); + if (cfg.width > resolution.width || + cfg.height > resolution.height) { + LOG(IPU3, Error) + << "Invalid stream size: larger than sensor resolution"; + return -EINVAL; + } + + /* + * Collect the maximum width and height: IPU3 can downscale + * only. + */ + if (cfg.width > sensorSize.width) + sensorSize.width = cfg.width; + if (cfg.height > sensorSize.height) + sensorSize.height = cfg.height; + + stream->cfg_ = &cfg; + stream->active_ = true; } /* @@ -275,24 +322,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(sensorSize, &cio2Format); if (ret) return ret; - ret = imgu->configureInput(cfg, &cio2Format); + ret = imgu->configureInput(sensorSize, &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 (Stream *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; @@ -407,7 +481,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->outStream_; /* Queue a buffer to the ImgU output for capture. */ Buffer *buffer = request->findBuffer(stream); @@ -558,7 +632,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); @@ -566,11 +643,16 @@ 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->outStream_.name_ = "output"; + data->vfStream_.device_ = &data->imgu_->viewfinder_; + data->vfStream_.name_ = "viewfinder"; /* * Connect video devices' 'bufferReady' signals to their @@ -721,12 +803,12 @@ int ImgUDevice::init(MediaDevice *media, unsigned int index) /** * \brief Configure the ImgU unit input - * \param[in] config The requested stream configuration + * \param[in] size The ImgU input frame size * \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 &size, V4L2DeviceFormat *inputFormat) { /* Configure the ImgU input video device with the requested sizes. */ @@ -764,8 +846,8 @@ int ImgUDevice::configureInput(const StreamConfiguration &config, << rect.toString(); V4L2SubdeviceFormat imguFormat = {}; - imguFormat.width = config.width; - imguFormat.height = config.height; + imguFormat.width = size.width; + imguFormat.height = size.height; imguFormat.mbus_code = MEDIA_BUS_FMT_FIXED; ret = imgu_->setFormat(PAD_INPUT, &imguFormat); @@ -1080,12 +1162,12 @@ int CIO2Device::init(const MediaDevice *media, unsigned int index) /** * \brief Configure the CIO2 unit - * \param[in] config The requested configuration + * \param[in] size The requested CIO2 output frame size * \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 &size, V4L2DeviceFormat *outputFormat) { V4L2SubdeviceFormat sensorFormat; @@ -1099,7 +1181,7 @@ int CIO2Device::configure(const StreamConfiguration &config, MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10 }, - Size(config.width, config.height)); + size); ret = sensor_->setFormat(&sensorFormat); if (ret) return ret; From patchwork Fri Apr 19 10:18:35 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1077 Return-Path: Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0C6B460DCD for ; Fri, 19 Apr 2019 12:17:54 +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 relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 9BFCFFF806; Fri, 19 Apr 2019 10:17:53 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Fri, 19 Apr 2019 12:18:35 +0200 Message-Id: <20190419101839.10337-5-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190419101839.10337-1-jacopo@jmondi.org> References: <20190419101839.10337-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v7 4/8] 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: Fri, 19 Apr 2019 10:17:55 -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, with the viewfinder stream able to capture both continuous video streams and still images, and the main output stream supporting still images images. This is an artificial limitation until we figure out the exact capabilities of the hardware. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 113 ++++++++++++++++++++------- 1 file changed, 83 insertions(+), 30 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 9b2d96f22b2b..45edc24b5d4c 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 #include @@ -222,38 +223,90 @@ CameraConfiguration PipelineHandlerIPU3::streamConfiguration(Camera *camera, const std::vector &usages) { - CameraConfiguration configs; IPU3CameraData *data = cameraData(camera); - StreamConfiguration config = {}; + CameraConfiguration cameraConfig; + std::set streams = { + &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 '" << data->outStream_.name_ << "' 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 '" << data->vfStream_.name_ << "' set to " - << config.width << "x" << config.height << "-0x" - << std::hex << std::setfill('0') << std::setw(8) - << config.pixelFormat; - - return configs; + for (const StreamUsage &usage : usages) { + std::vector::iterator found; + StreamUsage::Role role = usage.role(); + StreamConfiguration streamConfig = {}; + IPU3Stream *stream = nullptr; + + if (role == StreamUsage::Role::StillCapture) { + /* + * Don't allow viewfinder or video capture on the + * 'output stream. This is an artificial limitation + * until we figure out the capabilities of the + * hardware. + */ + if (streams.find(&data->outStream_) != streams.end()) + stream = &data->outStream_; + else if (streams.find(&data->vfStream_) != streams.end()) + stream = &data->vfStream_; + else + goto error; + + /* + * 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. + */ + streamConfig.width = 2560; + streamConfig.height = 1920; + } else if (role == StreamUsage::Role::Viewfinder || + role == StreamUsage::Role::VideoRecording) { + /* + * We can't use the 'output' stream for viewfinder or + * video capture usages. + */ + if (streams.find(&data->vfStream_) == streams.end()) + goto error; + + stream = &data->vfStream_; + + + /* + * Align the requested viewfinder size to the + * maximum available sensor resolution and to the + * IPU3 alignment constraints. + */ + const Size &res = data->cio2_.sensor_->resolution(); + unsigned int width = std::min(usage.size().width, + res.width); + unsigned int height = std::min(usage.size().height, + res.height); + streamConfig.width = width & ~7; + streamConfig.height = height & ~3; + } + + streams.erase(stream); + + streamConfig.pixelFormat = V4L2_PIX_FMT_NV12; + streamConfig.bufferCount = IPU3_BUFFER_COUNT; + + cameraConfig[stream] = streamConfig; + + LOG(IPU3, Debug) + << "Stream '" << stream->name_ << "' format set to " + << streamConfig.width << "x" << streamConfig.height + << "-0x" << std::hex << std::setfill('0') + << std::setw(8) << streamConfig.pixelFormat; + } + + return cameraConfig; + +error: + LOG(IPU3, Error) << "Requested stream roles not supported"; + + return CameraConfiguration{}; } int PipelineHandlerIPU3::configureStreams(Camera *camera, From patchwork Fri Apr 19 10:18:36 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1078 Return-Path: Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D539660DCE for ; Fri, 19 Apr 2019 12:17:54 +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 relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 32FE7FF80B; Fri, 19 Apr 2019 10:17:54 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Fri, 19 Apr 2019 12:18:36 +0200 Message-Id: <20190419101839.10337-6-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190419101839.10337-1-jacopo@jmondi.org> References: <20190419101839.10337-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v7 5/8] 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: Fri, 19 Apr 2019 10:17:55 -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 Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 64 +++++++++++++++++++++------- 1 file changed, 48 insertions(+), 16 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 45edc24b5d4c..fe671b95ed8e 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -93,6 +93,7 @@ public: BufferPool vfPool_; BufferPool statPool_; + BufferPool outPool_; }; class CIO2Device @@ -426,11 +427,20 @@ 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_; unsigned int bufferCount; @@ -445,28 +455,49 @@ int PipelineHandlerIPU3::allocateBuffers(Camera *camera, if (ret) goto error; - /* Export ImgU output buffers to the stream's pool. */ - ret = imgu->exportBuffers(&imgu->output_, &stream->bufferPool()); - if (ret) - goto error; - /* - * 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 pool the same number of buffer as + * for the input pool. + * \todo To be revised when we'll actually use the stat node. */ - bufferCount = stream->bufferPool().count(); - - imgu->viewfinder_.pool->createBuffers(bufferCount); - ret = imgu->exportBuffers(&imgu->viewfinder_, imgu->viewfinder_.pool); - if (ret) - goto error; - + bufferCount = pool->count(); imgu->stat_.pool->createBuffers(bufferCount); ret = imgu->exportBuffers(&imgu->stat_, imgu->stat_.pool); if (ret) goto error; + /* 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) + goto error; + } + + /* + * 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) + goto error; + } + + if (!vfStream->active_) { + bufferCount = outStream->bufferPool().count(); + vfStream->device_->pool->createBuffers(bufferCount); + ret = imgu->exportBuffers(vfStream->device_, + vfStream->device_->pool); + if (ret) + goto error; + } + return 0; error: @@ -831,6 +862,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 Fri Apr 19 10:18: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: 1079 Return-Path: Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A20B560DC0 for ; Fri, 19 Apr 2019 12:17:55 +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 relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 0A621FF80C; Fri, 19 Apr 2019 10:17:54 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Fri, 19 Apr 2019 12:18:37 +0200 Message-Id: <20190419101839.10337-7-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190419101839.10337-1-jacopo@jmondi.org> References: <20190419101839.10337-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v7 6/8] 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: Fri, 19 Apr 2019 10:17:55 -0000 Add support for queueing requests for multiple streams in the IPU3 pipeline handler class. Reviewed-by: Laurent Pinchart Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index fe671b95ed8e..8fa59157532e 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -563,25 +563,20 @@ 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_; + int error = 0; - /* 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 it : request->buffers()) { + IPU3Stream *stream = static_cast(it.first); + Buffer *buffer = it.second; - int ret = output->queueBuffer(buffer); - if (ret < 0) - return ret; + int ret = stream->device_->dev->queueBuffer(buffer); + if (ret < 0) + error = ret; + } PipelineHandler::queueRequest(camera, request); - return 0; + return error; } bool PipelineHandlerIPU3::match(DeviceEnumerator *enumerator) From patchwork Fri Apr 19 10:18: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: 1080 Return-Path: Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 397A660DC0 for ; Fri, 19 Apr 2019 12:17:56 +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 relay9-d.mail.gandi.net (Postfix) with ESMTPSA id C4B5BFF808; Fri, 19 Apr 2019 10:17:55 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Fri, 19 Apr 2019 12:18:38 +0200 Message-Id: <20190419101839.10337-8-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190419101839.10337-1-jacopo@jmondi.org> References: <20190419101839.10337-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v7 7/8] 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: Fri, 19 Apr 2019 10:17:56 -0000 The viewfinder and main output require identical logic for buffer and request completion. Connect the viewfinder bufferReady signal to the slot and handle requests for both main output and viewfinder there. Update the slot logic to complete the request only when the last buffer has completed, and make sure to complete requests in the same order they have been queued to the pipeline handler. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/libcamera/pipeline/ipu3/ipu3.cpp | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 8fa59157532e..1964603c591f 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -747,6 +747,8 @@ int PipelineHandlerIPU3::registerCameras() &IPU3CameraData::imguInputBufferReady); data->imgu_->output_.dev->bufferReady.connect(data.get(), &IPU3CameraData::imguOutputBufferReady); + data->imgu_->viewfinder_.dev->bufferReady.connect(data.get(), + &IPU3CameraData::imguOutputBufferReady); /* Create and register the Camera instance. */ std::string cameraName = cio2->sensor_->entity()->name() + " " @@ -792,10 +794,27 @@ void PipelineHandlerIPU3::IPU3CameraData::imguInputBufferReady(Buffer *buffer) */ void PipelineHandlerIPU3::IPU3CameraData::imguOutputBufferReady(Buffer *buffer) { - Request *request = queuedRequests_.front(); + Request *request = buffer->request(); + + if (!pipe_->completeBuffer(camera_, request, buffer)) + /* Request not completed yet, return here. */ + return; - pipe_->completeBuffer(camera_, request, buffer); - pipe_->completeRequest(camera_, request); + /* + * Complete requests in queuing order: if some other request is + * pending, postpone completion. + */ + if (request != queuedRequests_.front()) + return; + + /* Complete the pending requests in queuing order. */ + while (1) { + request = queuedRequests_.front(); + if (request->hasPendingBuffers()) + break; + + pipe_->completeRequest(camera_, request); + } } /** From patchwork Fri Apr 19 10:18:39 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1081 Return-Path: Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id CAC9760DC0 for ; Fri, 19 Apr 2019 12:17:56 +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 relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 60E10FF802; Fri, 19 Apr 2019 10:17:56 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Fri, 19 Apr 2019 12:18:39 +0200 Message-Id: <20190419101839.10337-9-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190419101839.10337-1-jacopo@jmondi.org> References: <20190419101839.10337-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v7 8/8] [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: Fri, 19 Apr 2019 10:17:57 -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) {