From patchwork Mon Sep 6 22:56:07 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13667 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id A6D6FBE175 for ; Mon, 6 Sep 2021 22:57:01 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id BFD5C69170; Tue, 7 Sep 2021 00:57:00 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="jCqBJnO/"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 458BE60253 for ; Tue, 7 Sep 2021 00:56:59 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 8C362891; Tue, 7 Sep 2021 00:56:58 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969018; bh=pC+gqSk8VFETXj3WCksnBoLMDUBsNbccZli0wVQuRv0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jCqBJnO/doWDS4RClt5VKuRwRG753xZGre5IXLxSFWJxOs2npBIxwtj88sAlxNAKb KfpO1X56f7mFVf+/iL/tmGTMHfPfBkP4xr7Gel2hE5IxmC9uiM2gKck+MYwo6uv1/f xmqdfud/+VGJlsZvyppfTOwhlQIO2p04T7zl2pSM= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:07 +0300 Message-Id: <20210906225636.14683-1-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 01/30] libcamera: base: utils: Use size_t for index in utils::enumerate() X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The index generated by utils::enumerate() is an iteration counter, which should thus be positive. Use std::size_t instead of the difference_type of the container. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Reviewed-by: Jean-Michel Hautbois Reviewed-by: Paul Elder Reviewed-by: Hirokazu Honda --- include/libcamera/base/utils.h | 4 ++-- test/utils.cpp | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/libcamera/base/utils.h b/include/libcamera/base/utils.h index 52301254c2eb..2b761436a99f 100644 --- a/include/libcamera/base/utils.h +++ b/include/libcamera/base/utils.h @@ -246,7 +246,7 @@ private: public: using difference_type = typename std::iterator_traits::difference_type; - using value_type = std::pair; + using value_type = std::pair; using pointer = value_type *; using reference = value_type &; using iterator_category = std::input_iterator_tag; @@ -275,7 +275,7 @@ public: private: Base current_; - difference_type pos_; + std::size_t pos_; }; template diff --git a/test/utils.cpp b/test/utils.cpp index d7f810e95e7a..d65467b5102c 100644 --- a/test/utils.cpp +++ b/test/utils.cpp @@ -77,8 +77,8 @@ protected: int testEnumerate() { - std::vector integers{ 1, 2, 3, 4, 5 }; - int i = 0; + std::vector integers{ 1, 2, 3, 4, 5 }; + unsigned int i = 0; for (auto [index, value] : utils::enumerate(integers)) { if (index != i || value != i + 1) { @@ -93,12 +93,12 @@ protected: ++i; } - if (integers != std::vector{ 0, 1, 2, 3, 4 }) { + if (integers != std::vector{ 0, 1, 2, 3, 4 }) { cerr << "Failed to modify container in enumerated range loop" << endl; return TestFail; } - Span span{ integers }; + Span span{ integers }; i = 0; for (auto [index, value] : utils::enumerate(span)) { @@ -112,7 +112,7 @@ protected: ++i; } - const int array[] = { 0, 2, 4, 6, 8 }; + const unsigned int array[] = { 0, 2, 4, 6, 8 }; i = 0; for (auto [index, value] : utils::enumerate(array)) { From patchwork Mon Sep 6 22:56:08 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13668 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 0A34EBE175 for ; Mon, 6 Sep 2021 22:57:04 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 842CB69174; Tue, 7 Sep 2021 00:57:01 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="evgzIiaW"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7A23769167 for ; Tue, 7 Sep 2021 00:56:59 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id EEA60993; Tue, 7 Sep 2021 00:56:58 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969019; bh=uLkB9Y9I1Q8pO5WttL2JG13L9GNHJ16SgH6o+Osv5LE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=evgzIiaWssesMIWVcdrDz1b5LFnoWuf/w6l5g7QX/RLas70oMQI1SrX8LSSM2Q9v/ sGmFK6FW1iy/1wF4J21MwhViWxxfljj4GUEapBD1WxD9ehjsLfBjIEguwH4qBxcSN7 CqCEbARZHDG9GWpdwulFAG4kBf/Hc0JMKdioTPSA= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:08 +0300 Message-Id: <20210906225636.14683-2-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 02/30] libcamera: file_descriptor: Add a function to retrieve the inode X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The inode is useful to check if two file descriptors refer to the same file. Add a function to retrieve it. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Reviewed-by: Jean-Michel Hautbois Reviewed-by: Paul Elder Reviewed-by: Hirokazu Honda --- Changes since v1: - Use isValid() instead of open-coding it - Print a message on error --- include/libcamera/file_descriptor.h | 3 +++ src/libcamera/file_descriptor.cpp | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/include/libcamera/file_descriptor.h b/include/libcamera/file_descriptor.h index d514aac7697b..988f9b7a3d25 100644 --- a/include/libcamera/file_descriptor.h +++ b/include/libcamera/file_descriptor.h @@ -8,6 +8,7 @@ #define __LIBCAMERA_FILE_DESCRIPTOR_H__ #include +#include namespace libcamera { @@ -27,6 +28,8 @@ public: int fd() const { return fd_ ? fd_->fd() : -1; } FileDescriptor dup() const; + ino_t inode() const; + private: class Descriptor { diff --git a/src/libcamera/file_descriptor.cpp b/src/libcamera/file_descriptor.cpp index 9f9ebc81f738..0409c3e1758c 100644 --- a/src/libcamera/file_descriptor.cpp +++ b/src/libcamera/file_descriptor.cpp @@ -8,6 +8,8 @@ #include #include +#include +#include #include #include @@ -221,6 +223,30 @@ FileDescriptor FileDescriptor::dup() const return FileDescriptor(fd()); } +/** + * \brief Retrieve the file descriptor inode + * + * \todo Should this move to the File class ? + * + * \return The file descriptor inode on success, or 0 on error + */ +ino_t FileDescriptor::inode() const +{ + if (!isValid()) + return 0; + + struct stat st; + int ret = fstat(fd_->fd(), &st); + if (ret < 0) { + ret = -errno; + LOG(FileDescriptor, Fatal) + << "Failed to fstat() fd: " << strerror(-ret); + return 0; + } + + return st.st_ino; +} + FileDescriptor::Descriptor::Descriptor(int fd, bool duplicate) { if (!duplicate) { From patchwork Mon Sep 6 22:56:09 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13669 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 7712CBE175 for ; Mon, 6 Sep 2021 22:57:05 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 195106916F; Tue, 7 Sep 2021 00:57:02 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="EhlKHqd0"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C1F5769168 for ; Tue, 7 Sep 2021 00:56:59 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 55CDBB75; Tue, 7 Sep 2021 00:56:59 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969019; bh=GvyVu/+Dib2xdPt60f1UUnJZMF7C3U4Kc1CLyECl0Hs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=EhlKHqd01kF8snMhUsHaoyNF4whRg4RU7V96zxEGWsPYoQjk9oNvok7uZazRy8uuC btZUHah2791nx6A+UI+y88BueTgqDOgBIiYDzxe3RislNA+N9lw/v/Y+OSlrSaM41F buupdxHXzviuL1bD+kbAXQ8H0ZKE0xaIobN1Nl1Y= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:09 +0300 Message-Id: <20210906225636.14683-3-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 03/30] libcamera: v4l2_videodevice: Drop toV4L2PixelFormat() X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The V4L2VideoDevice::toV4L2PixelFormat() function is incorrectly implemented, as it will pick a multi-planar format if the device supports the multi-planar API, even if only single-planar formats are supported. This currently works because the implementation calls V4L2PixelFormat::fromPixelFormat(), which ignores the multiplanar argument and always returns a single-planar format. Fixing this isn't trivial. As we don't need to support multi-planar V4L2 formats at this point, drop the function instead of pretending everything is fine, and call V4L2PixelFormat::fromPixelFormat() directly from pipeline handlers. As the single-planar case is the most common, set the multiplanar argument to false by default to avoid long lines. Signed-off-by: Laurent Pinchart Reviewed-by: Jean-Michel Hautbois Reviewed-by: Kieran Bingham Reviewed-by: Hirokazu Honda --- include/libcamera/internal/v4l2_pixelformat.h | 2 +- include/libcamera/internal/v4l2_videodevice.h | 2 -- src/libcamera/pipeline/ipu3/imgu.cpp | 2 +- .../pipeline/raspberrypi/raspberrypi.cpp | 8 ++++---- src/libcamera/pipeline/rkisp1/rkisp1_path.cpp | 6 +++--- src/libcamera/pipeline/simple/converter.cpp | 8 ++++---- src/libcamera/pipeline/simple/simple.cpp | 4 ++-- src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 6 +++--- src/libcamera/pipeline/vimc/vimc.cpp | 8 ++++---- src/libcamera/v4l2_videodevice.cpp | 17 ----------------- test/libtest/buffer_source.cpp | 3 +-- 11 files changed, 23 insertions(+), 43 deletions(-) diff --git a/include/libcamera/internal/v4l2_pixelformat.h b/include/libcamera/internal/v4l2_pixelformat.h index 9bfd81ad6651..560c5c53c0c3 100644 --- a/include/libcamera/internal/v4l2_pixelformat.h +++ b/include/libcamera/internal/v4l2_pixelformat.h @@ -38,7 +38,7 @@ public: PixelFormat toPixelFormat() const; static V4L2PixelFormat fromPixelFormat(const PixelFormat &pixelFormat, - bool multiplanar); + bool multiplanar = false); private: uint32_t fourcc_; diff --git a/include/libcamera/internal/v4l2_videodevice.h b/include/libcamera/internal/v4l2_videodevice.h index 7a145f608a5b..087ad067e37e 100644 --- a/include/libcamera/internal/v4l2_videodevice.h +++ b/include/libcamera/internal/v4l2_videodevice.h @@ -212,8 +212,6 @@ public: static std::unique_ptr fromEntityName(const MediaDevice *media, const std::string &entity); - V4L2PixelFormat toV4L2PixelFormat(const PixelFormat &pixelFormat); - protected: std::string logPrefix() const override; diff --git a/src/libcamera/pipeline/ipu3/imgu.cpp b/src/libcamera/pipeline/ipu3/imgu.cpp index 317e482a1498..3e1ef645ec93 100644 --- a/src/libcamera/pipeline/ipu3/imgu.cpp +++ b/src/libcamera/pipeline/ipu3/imgu.cpp @@ -575,7 +575,7 @@ int ImgUDevice::configureVideoDevice(V4L2VideoDevice *dev, unsigned int pad, return 0; *outputFormat = {}; - outputFormat->fourcc = dev->toV4L2PixelFormat(formats::NV12); + outputFormat->fourcc = V4L2PixelFormat::fromPixelFormat(formats::NV12); outputFormat->size = cfg.size; outputFormat->planesCount = 2; diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp index b2674ac02109..0bdfa7273ce0 100644 --- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp +++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp @@ -440,14 +440,14 @@ CameraConfiguration::Status RPiCameraConfiguration::validate() V4L2VideoDevice::Formats fmts = dev->formats(); - if (fmts.find(V4L2PixelFormat::fromPixelFormat(cfgPixFmt, false)) == fmts.end()) { + if (fmts.find(V4L2PixelFormat::fromPixelFormat(cfgPixFmt)) == fmts.end()) { /* If we cannot find a native format, use a default one. */ cfgPixFmt = formats::NV12; status = Adjusted; } V4L2DeviceFormat format; - format.fourcc = dev->toV4L2PixelFormat(cfg.pixelFormat); + format.fourcc = V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat); format.size = cfg.size; int ret = dev->tryFormat(&format); @@ -647,7 +647,7 @@ int PipelineHandlerRPi::configure(Camera *camera, CameraConfiguration *config) RPi::Stream *stream = i == maxIndex ? &data->isp_[Isp::Output0] : &data->isp_[Isp::Output1]; - V4L2PixelFormat fourcc = stream->dev()->toV4L2PixelFormat(cfg.pixelFormat); + V4L2PixelFormat fourcc = V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat); format.size = cfg.size; format.fourcc = fourcc; @@ -688,7 +688,7 @@ int PipelineHandlerRPi::configure(Camera *camera, CameraConfiguration *config) maxSize = Size(320, 240); format = {}; format.size = maxSize; - format.fourcc = V4L2PixelFormat::fromPixelFormat(formats::YUV420, false); + format.fourcc = V4L2PixelFormat::fromPixelFormat(formats::YUV420); ret = data->isp_[Isp::Output0].dev()->setFormat(&format); if (ret) { LOG(RPI, Error) diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp index 25f482eb8d8e..f8d471204d2e 100644 --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp @@ -80,7 +80,7 @@ CameraConfiguration::Status RkISP1Path::validate(StreamConfiguration *cfg) cfg->bufferCount = RKISP1_BUFFER_COUNT; V4L2DeviceFormat format; - format.fourcc = video_->toV4L2PixelFormat(cfg->pixelFormat); + format.fourcc = V4L2PixelFormat::fromPixelFormat(cfg->pixelFormat); format.size = cfg->size; int ret = video_->tryFormat(&format); @@ -146,7 +146,7 @@ int RkISP1Path::configure(const StreamConfiguration &config, const PixelFormatInfo &info = PixelFormatInfo::info(config.pixelFormat); V4L2DeviceFormat outputFormat; - outputFormat.fourcc = video_->toV4L2PixelFormat(config.pixelFormat); + outputFormat.fourcc = V4L2PixelFormat::fromPixelFormat(config.pixelFormat); outputFormat.size = config.size; outputFormat.planesCount = info.numPlanes(); @@ -155,7 +155,7 @@ int RkISP1Path::configure(const StreamConfiguration &config, return ret; if (outputFormat.size != config.size || - outputFormat.fourcc != video_->toV4L2PixelFormat(config.pixelFormat)) { + outputFormat.fourcc != V4L2PixelFormat::fromPixelFormat(config.pixelFormat)) { LOG(RkISP1, Error) << "Unable to configure capture in " << config.toString(); return -EINVAL; diff --git a/src/libcamera/pipeline/simple/converter.cpp b/src/libcamera/pipeline/simple/converter.cpp index b5e34c4cd0c5..9cbc6ee30ce4 100644 --- a/src/libcamera/pipeline/simple/converter.cpp +++ b/src/libcamera/pipeline/simple/converter.cpp @@ -46,7 +46,7 @@ int SimpleConverter::Stream::configure(const StreamConfiguration &inputCfg, const StreamConfiguration &outputCfg) { V4L2PixelFormat videoFormat = - m2m_->output()->toV4L2PixelFormat(inputCfg.pixelFormat); + V4L2PixelFormat::fromPixelFormat(inputCfg.pixelFormat); V4L2DeviceFormat format; format.fourcc = videoFormat; @@ -71,7 +71,7 @@ int SimpleConverter::Stream::configure(const StreamConfiguration &inputCfg, } /* Set the pixel format and size on the output. */ - videoFormat = m2m_->capture()->toV4L2PixelFormat(outputCfg.pixelFormat); + videoFormat = V4L2PixelFormat::fromPixelFormat(outputCfg.pixelFormat); format = {}; format.fourcc = videoFormat; format.size = outputCfg.size; @@ -210,7 +210,7 @@ std::vector SimpleConverter::formats(PixelFormat input) * enumerate the conversion capabilities on its output (V4L2 capture). */ V4L2DeviceFormat v4l2Format; - v4l2Format.fourcc = m2m_->output()->toV4L2PixelFormat(input); + v4l2Format.fourcc = V4L2PixelFormat::fromPixelFormat(input); v4l2Format.size = { 1, 1 }; int ret = m2m_->output()->setFormat(&v4l2Format); @@ -281,7 +281,7 @@ SimpleConverter::strideAndFrameSize(const PixelFormat &pixelFormat, const Size &size) { V4L2DeviceFormat format; - format.fourcc = m2m_->capture()->toV4L2PixelFormat(pixelFormat); + format.fourcc = V4L2PixelFormat::fromPixelFormat(pixelFormat); format.size = size; int ret = m2m_->capture()->tryFormat(&format); diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp index cadaf5d030ab..701fb4be0b71 100644 --- a/src/libcamera/pipeline/simple/simple.cpp +++ b/src/libcamera/pipeline/simple/simple.cpp @@ -826,7 +826,7 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate() return Invalid; } else { V4L2DeviceFormat format; - format.fourcc = data_->video_->toV4L2PixelFormat(cfg.pixelFormat); + format.fourcc = V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat); format.size = cfg.size; int ret = data_->video_->tryFormat(&format); @@ -915,7 +915,7 @@ int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c) return ret; /* Configure the video node. */ - V4L2PixelFormat videoFormat = video->toV4L2PixelFormat(pipeConfig->captureFormat); + V4L2PixelFormat videoFormat = V4L2PixelFormat::fromPixelFormat(pipeConfig->captureFormat); V4L2DeviceFormat captureFormat; captureFormat.fourcc = videoFormat; diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp index 973ecd5b835e..264f5370cf32 100644 --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp @@ -151,7 +151,7 @@ CameraConfiguration::Status UVCCameraConfiguration::validate() cfg.bufferCount = 4; V4L2DeviceFormat format; - format.fourcc = data_->video_->toV4L2PixelFormat(cfg.pixelFormat); + format.fourcc = V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat); format.size = cfg.size; int ret = data_->video_->tryFormat(&format); @@ -207,7 +207,7 @@ int PipelineHandlerUVC::configure(Camera *camera, CameraConfiguration *config) int ret; V4L2DeviceFormat format; - format.fourcc = data->video_->toV4L2PixelFormat(cfg.pixelFormat); + format.fourcc = V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat); format.size = cfg.size; ret = data->video_->setFormat(&format); @@ -215,7 +215,7 @@ int PipelineHandlerUVC::configure(Camera *camera, CameraConfiguration *config) return ret; if (format.size != cfg.size || - format.fourcc != data->video_->toV4L2PixelFormat(cfg.pixelFormat)) + format.fourcc != V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat)) return -EINVAL; cfg.setStream(&data->stream_); diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp index baeb6a7e6fa6..e453091da4b2 100644 --- a/src/libcamera/pipeline/vimc/vimc.cpp +++ b/src/libcamera/pipeline/vimc/vimc.cpp @@ -170,7 +170,7 @@ CameraConfiguration::Status VimcCameraConfiguration::validate() cfg.bufferCount = 4; V4L2DeviceFormat format; - format.fourcc = data_->video_->toV4L2PixelFormat(cfg.pixelFormat); + format.fourcc = V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat); format.size = cfg.size; int ret = data_->video_->tryFormat(&format); @@ -274,7 +274,7 @@ int PipelineHandlerVimc::configure(Camera *camera, CameraConfiguration *config) return ret; V4L2DeviceFormat format; - format.fourcc = data->video_->toV4L2PixelFormat(cfg.pixelFormat); + format.fourcc = V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat); format.size = cfg.size; ret = data->video_->setFormat(&format); @@ -282,7 +282,7 @@ int PipelineHandlerVimc::configure(Camera *camera, CameraConfiguration *config) return ret; if (format.size != cfg.size || - format.fourcc != data->video_->toV4L2PixelFormat(cfg.pixelFormat)) + format.fourcc != V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat)) return -EINVAL; /* @@ -597,7 +597,7 @@ int VimcCameraData::allocateMockIPABuffers() constexpr unsigned int kBufCount = 2; V4L2DeviceFormat format; - format.fourcc = video_->toV4L2PixelFormat(formats::BGR888); + format.fourcc = V4L2PixelFormat::fromPixelFormat(formats::BGR888); format.size = Size (160, 120); int ret = video_->setFormat(&format); diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp index 4e1c2b7cef5e..84ccb97495f5 100644 --- a/src/libcamera/v4l2_videodevice.cpp +++ b/src/libcamera/v4l2_videodevice.cpp @@ -1687,23 +1687,6 @@ V4L2VideoDevice::fromEntityName(const MediaDevice *media, return std::make_unique(mediaEntity); } -/** - * \brief Convert \a PixelFormat to its corresponding V4L2 FourCC - * \param[in] pixelFormat The PixelFormat to convert - * - * For multiplanar formats, the V4L2 format variant (contiguous or - * non-contiguous planes) is selected automatically based on the capabilities - * of the video device. If the video device supports the V4L2 multiplanar API, - * non-contiguous formats are preferred. - * - * \return The V4L2_PIX_FMT_* pixel format code corresponding to \a pixelFormat - */ -V4L2PixelFormat V4L2VideoDevice::toV4L2PixelFormat(const PixelFormat &pixelFormat) -{ - return V4L2PixelFormat::fromPixelFormat(pixelFormat, - caps_.isMultiplanar()); -} - /** * \class V4L2M2MDevice * \brief Memory-to-Memory video device diff --git a/test/libtest/buffer_source.cpp b/test/libtest/buffer_source.cpp index 73563f2fc39d..64e7376ad575 100644 --- a/test/libtest/buffer_source.cpp +++ b/test/libtest/buffer_source.cpp @@ -70,8 +70,7 @@ int BufferSource::allocate(const StreamConfiguration &config) } format.size = config.size; - format.fourcc = V4L2PixelFormat::fromPixelFormat(config.pixelFormat, - false); + format.fourcc = V4L2PixelFormat::fromPixelFormat(config.pixelFormat); if (video->setFormat(&format)) { std::cout << "Failed to set format on output device" << std::endl; return TestFail; From patchwork Mon Sep 6 22:56:10 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13670 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id DBDAABE175 for ; Mon, 6 Sep 2021 22:57:06 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7BAB669181; Tue, 7 Sep 2021 00:57:05 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="N8e2qa+q"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 29B8B6916A for ; Tue, 7 Sep 2021 00:57:00 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B57FE891; Tue, 7 Sep 2021 00:56:59 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969019; bh=b7gPBp850bZHu3787Wvt9wPxGmz/eKhWf5qntMcqV4c=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=N8e2qa+qOE3HnQZSO5VJmfyNAJl+wkOIPYKM5yt04OXaKByVNdbLRHQbFQtKmYJ9U jgHEzgpgvterCF4K8YhZzYoEj22TNAooDfItosw6BC+nAoNdwjd8GN0803bcLGfIdv N4U4ZsvHaeXqkgzr0+4MlYqqMHAfX3OvEuAMTDdA= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:10 +0300 Message-Id: <20210906225636.14683-4-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 04/30] libcamera: Use V4L2PixelFormat::fromPixelFormat() X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Replace manual looked for V4L2 pixel format in the PixelFormatInfo with the V4L2PixelFormat::fromPixelFormat() helper function. This prepares for multi-planar support that will modify how V4L2 pixel formats are stored in PixelFormatInfo. Signed-off-by: Laurent Pinchart Reviewed-by: Jean-Michel Hautbois Reviewed-by: Hirokazu Honda Reviewed-by: Kieran Bingham --- src/libcamera/pipeline/ipu3/cio2.cpp | 4 +--- src/v4l2/v4l2_camera_proxy.cpp | 9 +++------ 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/cio2.cpp b/src/libcamera/pipeline/ipu3/cio2.cpp index 9cedcb5b2879..dc62ab197acb 100644 --- a/src/libcamera/pipeline/ipu3/cio2.cpp +++ b/src/libcamera/pipeline/ipu3/cio2.cpp @@ -203,9 +203,7 @@ int CIO2Device::configure(const Size &size, V4L2DeviceFormat *outputFormat) if (itInfo == mbusCodesToPixelFormat.end()) return -EINVAL; - const PixelFormatInfo &info = PixelFormatInfo::info(itInfo->second); - - outputFormat->fourcc = info.v4l2Format; + outputFormat->fourcc = V4L2PixelFormat::fromPixelFormat(itInfo->second); outputFormat->size = sensorFormat.size; outputFormat->planesCount = 1; diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 07b1a90aa32f..d926a7b77083 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -164,12 +164,11 @@ bool V4L2CameraProxy::validateMemoryType(uint32_t memory) void V4L2CameraProxy::setFmtFromConfig(const StreamConfiguration &streamConfig) { - const PixelFormatInfo &info = PixelFormatInfo::info(streamConfig.pixelFormat); const Size &size = streamConfig.size; v4l2PixFormat_.width = size.width; v4l2PixFormat_.height = size.height; - v4l2PixFormat_.pixelformat = info.v4l2Format; + v4l2PixFormat_.pixelformat = V4L2PixelFormat::fromPixelFormat(streamConfig.pixelFormat); v4l2PixFormat_.field = V4L2_FIELD_NONE; v4l2PixFormat_.bytesperline = streamConfig.stride; v4l2PixFormat_.sizeimage = streamConfig.frameSize; @@ -276,7 +275,7 @@ int V4L2CameraProxy::vidioc_enum_fmt(V4L2CameraFile *file, struct v4l2_fmtdesc * /* \todo Add map from format to description. */ utils::strlcpy(reinterpret_cast(arg->description), "Video Format Description", sizeof(arg->description)); - arg->pixelformat = PixelFormatInfo::info(format).v4l2Format; + arg->pixelformat = V4L2PixelFormat::fromPixelFormat(format); memset(arg->reserved, 0, sizeof(arg->reserved)); @@ -311,11 +310,9 @@ int V4L2CameraProxy::tryFormat(struct v4l2_format *arg) return -EINVAL; } - const PixelFormatInfo &info = PixelFormatInfo::info(config.pixelFormat); - arg->fmt.pix.width = config.size.width; arg->fmt.pix.height = config.size.height; - arg->fmt.pix.pixelformat = info.v4l2Format; + arg->fmt.pix.pixelformat = V4L2PixelFormat::fromPixelFormat(config.pixelFormat); arg->fmt.pix.field = V4L2_FIELD_NONE; arg->fmt.pix.bytesperline = config.stride; arg->fmt.pix.sizeimage = config.frameSize; From patchwork Mon Sep 6 22:56:11 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13671 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 4741ABE175 for ; Mon, 6 Sep 2021 22:57:08 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 264EE69174; Tue, 7 Sep 2021 00:57:06 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="lldtFaNX"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 871A769167 for ; Tue, 7 Sep 2021 00:57:00 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 1CA1F993; Tue, 7 Sep 2021 00:57:00 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969020; bh=XwTyR0ihZRafzf8OwECTqWs0cCxDtW0RjPSL/y2Pt8I=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=lldtFaNXfS3508oclGVSOBrhaOkImA0/y2GZqU4YFO0ojp7cQrhrzNhVQQuFv4PPG 2Jpn3Gg7v/VUAUIUUiZS9gsSAxWUv60VHKUzyw0NZeMp/TD8GNhPGgN/J/qZ5yOLdr cZwmH4kq2wGo4ekHenP3/TsgOi7WmxqqGYUlm5fI= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:11 +0300 Message-Id: <20210906225636.14683-5-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 05/30] libcamera: formats: Move plane info structure to PixelFormatInfo X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Move the PixelFormatPlaneInfo structure within the PixelFormatInfo class definition and rename it to Plane, to align the naming scheme with other parts of libcamera, such as FrameBuffer::Plane or FrameMetadata::Plane. Signed-off-by: Laurent Pinchart Reviewed-by: Jean-Michel Hautbois Reviewed-by: Hirokazu Honda Reviewed-by: Kieran Bingham --- include/libcamera/internal/formats.h | 13 ++++++------- src/libcamera/formats.cpp | 12 ++++++------ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/include/libcamera/internal/formats.h b/include/libcamera/internal/formats.h index 51a8a6b8b0ae..a07de6bc6020 100644 --- a/include/libcamera/internal/formats.h +++ b/include/libcamera/internal/formats.h @@ -19,12 +19,6 @@ namespace libcamera { -struct PixelFormatPlaneInfo -{ - unsigned int bytesPerGroup; - unsigned int verticalSubSampling; -}; - class PixelFormatInfo { public: @@ -34,6 +28,11 @@ public: ColourEncodingRAW, }; + struct Plane { + unsigned int bytesPerGroup; + unsigned int verticalSubSampling; + }; + bool isValid() const { return format.isValid(); } static const PixelFormatInfo &info(const PixelFormat &format); @@ -58,7 +57,7 @@ public: unsigned int pixelsPerGroup; - std::array planes; + std::array planes; }; } /* namespace libcamera */ diff --git a/src/libcamera/formats.cpp b/src/libcamera/formats.cpp index 603d88619fe0..c993960eb982 100644 --- a/src/libcamera/formats.cpp +++ b/src/libcamera/formats.cpp @@ -24,15 +24,15 @@ namespace libcamera { LOG_DEFINE_CATEGORY(Formats) /** - * \class PixelFormatPlaneInfo + * \class PixelFormatInfo::Plane * \brief Information about a single plane of a pixel format * - * \var PixelFormatPlaneInfo::bytesPerGroup + * \var PixelFormatInfo::Plane::bytesPerGroup * \brief The number of bytes that a pixel group consumes * * \sa PixelFormatInfo::pixelsPerGroup * - * \var PixelFormatPlaneInfo::verticalSubSampling + * \var PixelFormatInfo::Plane::verticalSubSampling * \brief Vertical subsampling multiplier * * This value is the ratio between the number of rows of pixels in the frame @@ -87,7 +87,7 @@ LOG_DEFINE_CATEGORY(Formats) * * A pixel group is defined as the minimum number of pixels (including padding) * necessary in a row when the image has only one column of effective pixels. - * pixelsPerGroup refers to this value. PixelFormatPlaneInfo::bytesPerGroup, + * pixelsPerGroup refers to this value. PixelFormatInfo::Plane::bytesPerGroup, * then, refers to the number of bytes that a pixel group consumes. This * definition of a pixel group allows simple calculation of stride, as * ceil(width / pixelsPerGroup) * bytesPerGroup. These values are determined @@ -122,7 +122,7 @@ LOG_DEFINE_CATEGORY(Formats) * \var PixelFormatInfo::planes * \brief Information about pixels for each plane * - * \sa PixelFormatPlaneInfo + * \sa PixelFormatInfo::Plane */ /** @@ -869,7 +869,7 @@ unsigned int PixelFormatInfo::numPlanes() const { unsigned int count = 0; - for (const PixelFormatPlaneInfo &p : planes) { + for (const Plane &p : planes) { if (p.bytesPerGroup == 0) break; From patchwork Mon Sep 6 22:56:12 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13672 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 423A1BE175 for ; Mon, 6 Sep 2021 22:57:09 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id EF02669180; Tue, 7 Sep 2021 00:57:06 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="ttWRg0kd"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id F13EC6916A for ; Tue, 7 Sep 2021 00:57:00 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 7A860891; Tue, 7 Sep 2021 00:57:00 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969020; bh=gPr5UjzG2uC9IWNT501744MbdukW6WqdEIsA0DPdpWY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ttWRg0kdQwN7Be3HJ9v2pu0cphby7HE/SNqmml99Pe+92ISISeG67vjT+yaQNdQlz DbdM1kw4wE40qkzgmyhANzwxxoRw+EGsWI6VEz+g1r9oYqKEmtshJ7is0fOeP5R8q7 yw9qIH9DdPJG76lbocxDv0+AutlRCbTO/QtxdUIk= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:12 +0300 Message-Id: <20210906225636.14683-6-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 06/30] libcamera: formats: Add planeSize() helpers to PixelFormatInfo X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add two helpers functions to the PixelFormatInfo class to compute the byte size of a given plane, taking the frame size, the stride, the alignment constraints and the vertical subsampling into account. Use the new functions through the code base to replace manual implementations. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Reviewed-by: Hirokazu Honda --- Changes since v1: - Factor out duplicated code --- include/libcamera/internal/formats.h | 4 ++ src/android/mm/generic_camera_buffer.cpp | 11 +--- src/android/yuv/post_processor_yuv.cpp | 10 ++- src/libcamera/formats.cpp | 77 +++++++++++++++++++----- src/libcamera/v4l2_videodevice.cpp | 6 +- 5 files changed, 74 insertions(+), 34 deletions(-) diff --git a/include/libcamera/internal/formats.h b/include/libcamera/internal/formats.h index a07de6bc6020..b2869c93e960 100644 --- a/include/libcamera/internal/formats.h +++ b/include/libcamera/internal/formats.h @@ -41,6 +41,10 @@ public: unsigned int stride(unsigned int width, unsigned int plane, unsigned int align = 1) const; + unsigned int planeSize(const Size &size, unsigned int plane, + unsigned int align = 1) const; + unsigned int planeSize(unsigned int height, unsigned int plane, + unsigned int stride) const; unsigned int frameSize(const Size &size, unsigned int align = 1) const; unsigned int frameSize(const Size &size, const std::array &strides) const; diff --git a/src/android/mm/generic_camera_buffer.cpp b/src/android/mm/generic_camera_buffer.cpp index 22efc4d4b13a..93aa5821e470 100644 --- a/src/android/mm/generic_camera_buffer.cpp +++ b/src/android/mm/generic_camera_buffer.cpp @@ -108,16 +108,9 @@ CameraBuffer::Private::Private([[maybe_unused]] CameraBuffer *cameraBuffer, unsigned int offset = 0; for (unsigned int i = 0; i < numPlanes; ++i) { - /* - * \todo Remove if this plane size computation function is - * added to PixelFormatInfo. - */ - const unsigned int vertSubSample = info.planes[i].verticalSubSampling; - const unsigned int stride = info.stride(size.width, i, 1u); - const unsigned int planeSize = - stride * ((size.height + vertSubSample - 1) / vertSubSample); + const unsigned int planeSize = info.planeSize(size, i); - planeInfo_[i].stride = stride; + planeInfo_[i].stride = info.stride(size.width, i, 1u); planeInfo_[i].offset = offset; planeInfo_[i].size = planeSize; diff --git a/src/android/yuv/post_processor_yuv.cpp b/src/android/yuv/post_processor_yuv.cpp index 6952fc38b0ef..7b3b49609cb1 100644 --- a/src/android/yuv/post_processor_yuv.cpp +++ b/src/android/yuv/post_processor_yuv.cpp @@ -134,11 +134,9 @@ void PostProcessorYuv::calculateLengths(const StreamConfiguration &inCfg, sourceStride_[i] = inCfg.stride; destinationStride_[i] = nv12Info.stride(destinationSize_.width, i, 1); - const unsigned int vertSubSample = - nv12Info.planes[i].verticalSubSampling; - sourceLength_[i] = sourceStride_[i] * - ((sourceSize_.height + vertSubSample - 1) / vertSubSample); - destinationLength_[i] = destinationStride_[i] * - ((destinationSize_.height + vertSubSample - 1) / vertSubSample); + sourceLength_[i] = nv12Info.planeSize(sourceSize_.height, i, + sourceStride_[i]); + destinationLength_[i] = nv12Info.planeSize(destinationSize_.height, i, + destinationStride_[i]); } } diff --git a/src/libcamera/formats.cpp b/src/libcamera/formats.cpp index c993960eb982..ce0081a8a3d1 100644 --- a/src/libcamera/formats.cpp +++ b/src/libcamera/formats.cpp @@ -11,6 +11,7 @@ #include #include +#include #include @@ -801,32 +802,80 @@ unsigned int PixelFormatInfo::stride(unsigned int width, unsigned int plane, } /** - * \brief Compute the number of bytes necessary to store a frame + * \brief Compute the number of bytes necessary to store a plane of a frame * \param[in] size The size of the frame, in pixels + * \param[in] plane The plane index * \param[in] align The stride alignment, in bytes (1 for default alignment) * - * The frame is computed by adding the product of the line stride and the frame - * height for all planes, taking subsampling and other format characteristics - * into account. Additional stride alignment constraints may be specified - * through the \a align parameter, and will apply to all planes. For more - * complex stride constraints, use the frameSize() overloaded version that takes - * an array of stride values. + * The plane size is computed by multiplying the line stride and the frame + * height, taking subsampling and other format characteristics into account. + * Stride alignment constraints may be specified through the \a align parameter. * * \sa stride() * + * \return The number of bytes necessary to store the plane, or 0 if the + * PixelFormatInfo instance is not valid or the plane number isn't valid for the + * format + */ +unsigned int PixelFormatInfo::planeSize(const Size &size, unsigned int plane, + unsigned int align) const +{ + unsigned int stride = PixelFormatInfo::stride(size.width, plane, align); + if (!stride) + return 0; + + return planeSize(size.height, plane, stride); +} + +/** + * \brief Compute the number of bytes necessary to store a plane of a frame + * \param[in] height The height of the frame, in pixels + * \param[in] plane The plane index + * \param[in] stride The plane stride, in bytes + * + * The plane size is computed by multiplying the line stride and the frame + * height, taking subsampling and other format characteristics into account. + * Stride alignment constraints may be specified through the \a align parameter. + * + * \return The number of bytes necessary to store the plane, or 0 if the + * PixelFormatInfo instance is not valid or the plane number isn't valid for the + * format + */ +unsigned int PixelFormatInfo::planeSize(unsigned int height, unsigned int plane, + unsigned int stride) const +{ + unsigned int vertSubSample = planes[plane].verticalSubSampling; + if (!vertSubSample) + return 0; + + /* stride * ceil(height / verticalSubSampling) */ + return stride * ((height + vertSubSample - 1) / vertSubSample); +} + +/** + * \brief Compute the number of bytes necessary to store a frame + * \param[in] size The size of the frame, in pixels + * \param[in] align The stride alignment, in bytes (1 for default alignment) + * + * The frame size is computed by adding the size of all planes, as computed by + * planeSize(), using the specified alignment constraints for all planes. For + * more complex stride constraints, use the frameSize() overloaded version that + * takes an array of stride values. + * + * \sa planeSize() + * * \return The number of bytes necessary to store the frame, or 0 if the * PixelFormatInfo instance is not valid */ unsigned int PixelFormatInfo::frameSize(const Size &size, unsigned int align) const { - /* stride * ceil(height / verticalSubSampling) */ unsigned int sum = 0; - for (unsigned int i = 0; i < 3; i++) { - unsigned int vertSubSample = planes[i].verticalSubSampling; - if (!vertSubSample) - continue; - sum += stride(size.width, i, align) - * ((size.height + vertSubSample - 1) / vertSubSample); + + for (const auto &[i, plane] : utils::enumerate(planes)) { + if (plane.bytesPerGroup == 0) + break; + + sum += planeSize(size, i, align); } return sum; diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp index 84ccb97495f5..1c4e6fbf7fe7 100644 --- a/src/libcamera/v4l2_videodevice.cpp +++ b/src/libcamera/v4l2_videodevice.cpp @@ -1337,11 +1337,7 @@ std::unique_ptr V4L2VideoDevice::createBuffer(unsigned int index) planes[i].offset = offset; /* \todo Take the V4L2 stride into account */ - const unsigned int vertSubSample = - info.planes[i].verticalSubSampling; - planes[i].length = - info.stride(format_.size.width, i, 1u) * - ((format_.size.height + vertSubSample - 1) / vertSubSample); + planes[i].length = info.planeSize(format_.size, i); offset += planes[i].length; } } From patchwork Mon Sep 6 22:56:13 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13673 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 618DABE175 for ; Mon, 6 Sep 2021 22:57:10 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7C89669181; Tue, 7 Sep 2021 00:57:09 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="EgIFEEOE"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D9E7569168 for ; Tue, 7 Sep 2021 00:57:01 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id D4AF3993; Tue, 7 Sep 2021 00:57:00 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969021; bh=y3efOrE2gmByasjOZMIQivO7wSsltS2IB1+OKsbLtcM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=EgIFEEOE/S64joWy90qwU2gmB6fU6aHkyHAL0svDdQIjxPZtjrziC/7IvNTbd5CEi iz6BBi7Dt4M467zg8BXtIfGFm9pl+3m8d6SLbzcWXzUn/o7MKuyknxn9LLKGHcrGWI AF/tTLhKVyE6bcHKFY0T/nQMB/oQy7VRHGNj6XMQ= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:13 +0300 Message-Id: <20210906225636.14683-7-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 07/30] libcamera: formats: Support V4L2 non-contiguous formats X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" V4L2 describes multi-planar formats with different 4CCs depending on whether or not the planes are stored contiguously in memory. Support this when translating between PixelFormat and V4L2PixelFormat. Signed-off-by: Laurent Pinchart Reviewed-by: Hirokazu Honda Reviewed-by: Jean-Michel Hautbois --- Changes since v1: - Replace the v4l2Format array with a structure --- include/libcamera/internal/formats.h | 5 +- src/libcamera/formats.cpp | 284 +++++++++++++++++++++------ src/libcamera/v4l2_pixelformat.cpp | 11 +- 3 files changed, 240 insertions(+), 60 deletions(-) diff --git a/include/libcamera/internal/formats.h b/include/libcamera/internal/formats.h index b2869c93e960..5ebc68f91cda 100644 --- a/include/libcamera/internal/formats.h +++ b/include/libcamera/internal/formats.h @@ -54,7 +54,10 @@ public: /* \todo Add support for non-contiguous memory planes */ const char *name; PixelFormat format; - V4L2PixelFormat v4l2Format; + struct { + V4L2PixelFormat single; + V4L2PixelFormat multi; + } v4l2Formats; unsigned int bitsPerPixel; enum ColourEncoding colourEncoding; bool packed; diff --git a/src/libcamera/formats.cpp b/src/libcamera/formats.cpp index ce0081a8a3d1..5bbb12347ac8 100644 --- a/src/libcamera/formats.cpp +++ b/src/libcamera/formats.cpp @@ -55,8 +55,15 @@ LOG_DEFINE_CATEGORY(Formats) * \var PixelFormatInfo::format * \brief The PixelFormat described by this instance * - * \var PixelFormatInfo::v4l2Format - * \brief The V4L2 pixel format corresponding to the PixelFormat + * \var PixelFormatInfo::v4l2Formats + * \brief The V4L2 pixel formats corresponding to the PixelFormat + * + * Multiple V4L2 formats may exist for one PixelFormat when the format uses + * multiple planes, as V4L2 defines separate 4CCs for contiguous and separate + * planes formats. The two entries in the array store the contiguous and + * non-contiguous V4L2 formats respectively. If the PixelFormat isn't a + * multiplanar format, or if no corresponding non-contiguous V4L2 format + * exists, the second entry is invalid. * * \var PixelFormatInfo::bitsPerPixel * \brief The average number of bits per pixel @@ -149,7 +156,10 @@ const std::map pixelFormatInfo{ { formats::RGB565, { .name = "RGB565", .format = formats::RGB565, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_RGB565), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_RGB565), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, .packed = false, @@ -159,7 +169,10 @@ const std::map pixelFormatInfo{ { formats::RGB565_BE, { .name = "RGB565_BE", .format = formats::RGB565_BE, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_RGB565X), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_RGB565X), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, .packed = false, @@ -169,7 +182,10 @@ const std::map pixelFormatInfo{ { formats::BGR888, { .name = "BGR888", .format = formats::BGR888, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_RGB24), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_RGB24), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 24, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, .packed = false, @@ -179,7 +195,10 @@ const std::map pixelFormatInfo{ { formats::RGB888, { .name = "RGB888", .format = formats::RGB888, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_BGR24), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_BGR24), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 24, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, .packed = false, @@ -189,7 +208,10 @@ const std::map pixelFormatInfo{ { formats::XRGB8888, { .name = "XRGB8888", .format = formats::XRGB8888, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_XBGR32), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_XBGR32), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 32, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, .packed = false, @@ -199,7 +221,10 @@ const std::map pixelFormatInfo{ { formats::XBGR8888, { .name = "XBGR8888", .format = formats::XBGR8888, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_RGBX32), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_RGBX32), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 32, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, .packed = false, @@ -209,7 +234,10 @@ const std::map pixelFormatInfo{ { formats::BGRX8888, { .name = "BGRX8888", .format = formats::BGRX8888, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_XRGB32), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_XRGB32), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 32, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, .packed = false, @@ -219,7 +247,10 @@ const std::map pixelFormatInfo{ { formats::ABGR8888, { .name = "ABGR8888", .format = formats::ABGR8888, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_RGBA32), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_RGBA32), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 32, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, .packed = false, @@ -229,7 +260,10 @@ const std::map pixelFormatInfo{ { formats::ARGB8888, { .name = "ARGB8888", .format = formats::ARGB8888, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_ABGR32), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_ABGR32), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 32, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, .packed = false, @@ -239,7 +273,10 @@ const std::map pixelFormatInfo{ { formats::BGRA8888, { .name = "BGRA8888", .format = formats::BGRA8888, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_ARGB32), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_ARGB32), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 32, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, .packed = false, @@ -249,7 +286,10 @@ const std::map pixelFormatInfo{ { formats::RGBA8888, { .name = "RGBA8888", .format = formats::RGBA8888, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_BGRA32), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_BGRA32), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 32, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, .packed = false, @@ -261,7 +301,10 @@ const std::map pixelFormatInfo{ { formats::YUYV, { .name = "YUYV", .format = formats::YUYV, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_YUYV), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_YUYV), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, .packed = false, @@ -271,7 +314,10 @@ const std::map pixelFormatInfo{ { formats::YVYU, { .name = "YVYU", .format = formats::YVYU, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_YVYU), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_YVYU), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, .packed = false, @@ -281,7 +327,10 @@ const std::map pixelFormatInfo{ { formats::UYVY, { .name = "UYVY", .format = formats::UYVY, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_UYVY), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_UYVY), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, .packed = false, @@ -291,7 +340,10 @@ const std::map pixelFormatInfo{ { formats::VYUY, { .name = "VYUY", .format = formats::VYUY, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_VYUY), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_VYUY), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, .packed = false, @@ -303,7 +355,10 @@ const std::map pixelFormatInfo{ { formats::NV12, { .name = "NV12", .format = formats::NV12, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_NV12), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_NV12), + .multi = V4L2PixelFormat(V4L2_PIX_FMT_NV12M), + }, .bitsPerPixel = 12, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, .packed = false, @@ -313,7 +368,10 @@ const std::map pixelFormatInfo{ { formats::NV21, { .name = "NV21", .format = formats::NV21, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_NV21), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_NV21), + .multi = V4L2PixelFormat(V4L2_PIX_FMT_NV21M), + }, .bitsPerPixel = 12, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, .packed = false, @@ -323,7 +381,10 @@ const std::map pixelFormatInfo{ { formats::NV16, { .name = "NV16", .format = formats::NV16, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_NV16), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_NV16), + .multi = V4L2PixelFormat(V4L2_PIX_FMT_NV16M), + }, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, .packed = false, @@ -333,7 +394,10 @@ const std::map pixelFormatInfo{ { formats::NV61, { .name = "NV61", .format = formats::NV61, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_NV61), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_NV61), + .multi = V4L2PixelFormat(V4L2_PIX_FMT_NV61M), + }, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, .packed = false, @@ -343,7 +407,10 @@ const std::map pixelFormatInfo{ { formats::NV24, { .name = "NV24", .format = formats::NV24, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_NV24), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_NV24), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 24, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, .packed = false, @@ -353,7 +420,10 @@ const std::map pixelFormatInfo{ { formats::NV42, { .name = "NV42", .format = formats::NV42, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_NV42), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_NV42), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 24, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, .packed = false, @@ -363,7 +433,10 @@ const std::map pixelFormatInfo{ { formats::YUV420, { .name = "YUV420", .format = formats::YUV420, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_YUV420), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_YUV420), + .multi = V4L2PixelFormat(V4L2_PIX_FMT_YUV420M), + }, .bitsPerPixel = 12, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, .packed = false, @@ -373,7 +446,10 @@ const std::map pixelFormatInfo{ { formats::YVU420, { .name = "YVU420", .format = formats::YVU420, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_YVU420), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_YVU420), + .multi = V4L2PixelFormat(V4L2_PIX_FMT_YVU420M), + }, .bitsPerPixel = 12, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, .packed = false, @@ -383,7 +459,10 @@ const std::map pixelFormatInfo{ { formats::YUV422, { .name = "YUV422", .format = formats::YUV422, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_YUV422P), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_YUV422P), + .multi = V4L2PixelFormat(V4L2_PIX_FMT_YUV422M), + }, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, .packed = false, @@ -395,7 +474,10 @@ const std::map pixelFormatInfo{ { formats::R8, { .name = "R8", .format = formats::R8, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_GREY), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_GREY), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 8, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, .packed = false, @@ -407,7 +489,10 @@ const std::map pixelFormatInfo{ { formats::SBGGR8, { .name = "SBGGR8", .format = formats::SBGGR8, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SBGGR8), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_SBGGR8), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 8, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = false, @@ -417,7 +502,10 @@ const std::map pixelFormatInfo{ { formats::SGBRG8, { .name = "SGBRG8", .format = formats::SGBRG8, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SGBRG8), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_SGBRG8), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 8, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = false, @@ -427,7 +515,10 @@ const std::map pixelFormatInfo{ { formats::SGRBG8, { .name = "SGRBG8", .format = formats::SGRBG8, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SGRBG8), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_SGRBG8), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 8, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = false, @@ -437,7 +528,10 @@ const std::map pixelFormatInfo{ { formats::SRGGB8, { .name = "SRGGB8", .format = formats::SRGGB8, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SRGGB8), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_SRGGB8), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 8, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = false, @@ -447,7 +541,10 @@ const std::map pixelFormatInfo{ { formats::SBGGR10, { .name = "SBGGR10", .format = formats::SBGGR10, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SBGGR10), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_SBGGR10), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 10, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = false, @@ -457,7 +554,10 @@ const std::map pixelFormatInfo{ { formats::SGBRG10, { .name = "SGBRG10", .format = formats::SGBRG10, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SGBRG10), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_SGBRG10), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 10, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = false, @@ -467,7 +567,10 @@ const std::map pixelFormatInfo{ { formats::SGRBG10, { .name = "SGRBG10", .format = formats::SGRBG10, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SGRBG10), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_SGRBG10), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 10, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = false, @@ -477,7 +580,10 @@ const std::map pixelFormatInfo{ { formats::SRGGB10, { .name = "SRGGB10", .format = formats::SRGGB10, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SRGGB10), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_SRGGB10), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 10, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = false, @@ -487,7 +593,10 @@ const std::map pixelFormatInfo{ { formats::SBGGR10_CSI2P, { .name = "SBGGR10_CSI2P", .format = formats::SBGGR10_CSI2P, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SBGGR10P), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_SBGGR10P), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 10, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = true, @@ -497,7 +606,10 @@ const std::map pixelFormatInfo{ { formats::SGBRG10_CSI2P, { .name = "SGBRG10_CSI2P", .format = formats::SGBRG10_CSI2P, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SGBRG10P), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_SGBRG10P), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 10, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = true, @@ -507,7 +619,10 @@ const std::map pixelFormatInfo{ { formats::SGRBG10_CSI2P, { .name = "SGRBG10_CSI2P", .format = formats::SGRBG10_CSI2P, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SGRBG10P), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_SGRBG10P), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 10, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = true, @@ -517,7 +632,10 @@ const std::map pixelFormatInfo{ { formats::SRGGB10_CSI2P, { .name = "SRGGB10_CSI2P", .format = formats::SRGGB10_CSI2P, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SRGGB10P), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_SRGGB10P), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 10, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = true, @@ -527,7 +645,10 @@ const std::map pixelFormatInfo{ { formats::SBGGR12, { .name = "SBGGR12", .format = formats::SBGGR12, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SBGGR12), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_SBGGR12), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 12, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = false, @@ -537,7 +658,10 @@ const std::map pixelFormatInfo{ { formats::SGBRG12, { .name = "SGBRG12", .format = formats::SGBRG12, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SGBRG12), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_SGBRG12), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 12, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = false, @@ -547,7 +671,10 @@ const std::map pixelFormatInfo{ { formats::SGRBG12, { .name = "SGRBG12", .format = formats::SGRBG12, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SGRBG12), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_SGRBG12), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 12, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = false, @@ -557,7 +684,10 @@ const std::map pixelFormatInfo{ { formats::SRGGB12, { .name = "SRGGB12", .format = formats::SRGGB12, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SRGGB12), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_SRGGB12), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 12, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = false, @@ -567,7 +697,10 @@ const std::map pixelFormatInfo{ { formats::SBGGR12_CSI2P, { .name = "SBGGR12_CSI2P", .format = formats::SBGGR12_CSI2P, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SBGGR12P), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_SBGGR12P), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 12, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = true, @@ -577,7 +710,10 @@ const std::map pixelFormatInfo{ { formats::SGBRG12_CSI2P, { .name = "SGBRG12_CSI2P", .format = formats::SGBRG12_CSI2P, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SGBRG12P), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_SGBRG12P), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 12, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = true, @@ -587,7 +723,10 @@ const std::map pixelFormatInfo{ { formats::SGRBG12_CSI2P, { .name = "SGRBG12_CSI2P", .format = formats::SGRBG12_CSI2P, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SGRBG12P), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_SGRBG12P), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 12, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = true, @@ -597,7 +736,10 @@ const std::map pixelFormatInfo{ { formats::SRGGB12_CSI2P, { .name = "SRGGB12_CSI2P", .format = formats::SRGGB12_CSI2P, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SRGGB12P), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_SRGGB12P), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 12, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = true, @@ -607,7 +749,10 @@ const std::map pixelFormatInfo{ { formats::SBGGR16, { .name = "SBGGR16", .format = formats::SBGGR16, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SBGGR16), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_SBGGR16), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = false, @@ -617,7 +762,10 @@ const std::map pixelFormatInfo{ { formats::SGBRG16, { .name = "SGBRG16", .format = formats::SGBRG16, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SGBRG16), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_SGBRG16), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = false, @@ -627,7 +775,10 @@ const std::map pixelFormatInfo{ { formats::SGRBG16, { .name = "SGRBG16", .format = formats::SGRBG16, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SGRBG16), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_SGRBG16), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = false, @@ -637,7 +788,10 @@ const std::map pixelFormatInfo{ { formats::SRGGB16, { .name = "SRGGB16", .format = formats::SRGGB16, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SRGGB16), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_SRGGB16), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = false, @@ -647,7 +801,10 @@ const std::map pixelFormatInfo{ { formats::SBGGR10_IPU3, { .name = "SBGGR10_IPU3", .format = formats::SBGGR10_IPU3, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SBGGR10), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SBGGR10), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 10, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = true, @@ -658,7 +815,10 @@ const std::map pixelFormatInfo{ { formats::SGBRG10_IPU3, { .name = "SGBRG10_IPU3", .format = formats::SGBRG10_IPU3, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SGBRG10), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SGBRG10), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 10, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = true, @@ -668,7 +828,10 @@ const std::map pixelFormatInfo{ { formats::SGRBG10_IPU3, { .name = "SGRBG10_IPU3", .format = formats::SGRBG10_IPU3, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SGRBG10), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SGRBG10), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 10, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = true, @@ -678,7 +841,10 @@ const std::map pixelFormatInfo{ { formats::SRGGB10_IPU3, { .name = "SRGGB10_IPU3", .format = formats::SRGGB10_IPU3, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SRGGB10), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SRGGB10), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 10, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, .packed = true, @@ -690,7 +856,10 @@ const std::map pixelFormatInfo{ { formats::MJPEG, { .name = "MJPEG", .format = formats::MJPEG, - .v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_MJPEG), + .v4l2Formats = { + .single = V4L2PixelFormat(V4L2_PIX_FMT_MJPEG), + .multi = V4L2PixelFormat(), + }, .bitsPerPixel = 0, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, .packed = false, @@ -736,7 +905,8 @@ const PixelFormatInfo &PixelFormatInfo::info(const V4L2PixelFormat &format) { const auto &info = std::find_if(pixelFormatInfo.begin(), pixelFormatInfo.end(), [format](auto pair) { - return pair.second.v4l2Format == format; + return pair.second.v4l2Formats.single == format || + pair.second.v4l2Formats.multi == format; }); if (info == pixelFormatInfo.end()) return pixelFormatInfoInvalid; diff --git a/src/libcamera/v4l2_pixelformat.cpp b/src/libcamera/v4l2_pixelformat.cpp index 93fc4446cc64..d1f3a42f3de2 100644 --- a/src/libcamera/v4l2_pixelformat.cpp +++ b/src/libcamera/v4l2_pixelformat.cpp @@ -67,12 +67,19 @@ const std::map vpf2pf{ /* YUV planar formats. */ { V4L2PixelFormat(V4L2_PIX_FMT_NV16), formats::NV16 }, + { V4L2PixelFormat(V4L2_PIX_FMT_NV16M), formats::NV16 }, { V4L2PixelFormat(V4L2_PIX_FMT_NV61), formats::NV61 }, + { V4L2PixelFormat(V4L2_PIX_FMT_NV61M), formats::NV61 }, { V4L2PixelFormat(V4L2_PIX_FMT_NV12), formats::NV12 }, + { V4L2PixelFormat(V4L2_PIX_FMT_NV12M), formats::NV12 }, { V4L2PixelFormat(V4L2_PIX_FMT_NV21), formats::NV21 }, + { V4L2PixelFormat(V4L2_PIX_FMT_NV21M), formats::NV21 }, { V4L2PixelFormat(V4L2_PIX_FMT_YUV420), formats::YUV420 }, + { V4L2PixelFormat(V4L2_PIX_FMT_YUV420M), formats::YUV420 }, { V4L2PixelFormat(V4L2_PIX_FMT_YVU420), formats::YVU420 }, + { V4L2PixelFormat(V4L2_PIX_FMT_YVU420M), formats::YVU420 }, { V4L2PixelFormat(V4L2_PIX_FMT_YUV422P), formats::YUV422 }, + { V4L2PixelFormat(V4L2_PIX_FMT_YUV422M), formats::YUV422 }, /* Greyscale formats. */ { V4L2PixelFormat(V4L2_PIX_FMT_GREY), formats::R8 }, @@ -202,13 +209,13 @@ PixelFormat V4L2PixelFormat::toPixelFormat() const * \return The V4L2PixelFormat corresponding to \a pixelFormat */ V4L2PixelFormat V4L2PixelFormat::fromPixelFormat(const PixelFormat &pixelFormat, - [[maybe_unused]] bool multiplanar) + bool multiplanar) { const PixelFormatInfo &info = PixelFormatInfo::info(pixelFormat); if (!info.isValid()) return V4L2PixelFormat(); - return info.v4l2Format; + return multiplanar ? info.v4l2Formats.multi : info.v4l2Formats.single; } } /* namespace libcamera */ From patchwork Mon Sep 6 22:56:14 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13674 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 2DA3EBE175 for ; Mon, 6 Sep 2021 22:57:12 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id A18BB69173; Tue, 7 Sep 2021 00:57:11 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="NFRhYtJw"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5DB5269179 for ; Tue, 7 Sep 2021 00:57:02 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id DF00A891; Tue, 7 Sep 2021 00:57:01 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969022; bh=BP7jcFFYwrn3GfvDVNOgjisyswRcA2wt/qRxgsZa9L8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=NFRhYtJwqOtCLxB1y/7nYkWjPmtNOrAJbsqFG9h8R3rzbsPQ6VpNOYVSvalXRAX6i phM9Li+sa+QxUeOtZFXdSRR2ibb/efYkG09cOveXjrJqVMcmwVnICyDnakrxIm2v+B abyuyeeskKMlBORDO78/DazmOwf97U1eLhouC3Dk= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:14 +0300 Message-Id: <20210906225636.14683-8-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 08/30] libcamera: framebuffer: Move planes check to constructor X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The FrameBuffer::planes() function checks that planes are correctly initialized with an offset. This can be done at construction time instead, as the planes are constant. The backtrace generated by the assertion will show where the faulty frame buffer is created instead of where it is used, easing debugging. As the runtime overhead is reduced, there's no real need to drop the assertion in the future anymore, it can be useful to ensure that the planes are correctly populated by the caller. Drop the comment that calls for removing the check. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Reviewed-by: Hirokazu Honda --- include/libcamera/framebuffer.h | 9 +-------- src/libcamera/framebuffer.cpp | 2 ++ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/include/libcamera/framebuffer.h b/include/libcamera/framebuffer.h index d5aeff00387b..fd68ed0a139d 100644 --- a/include/libcamera/framebuffer.h +++ b/include/libcamera/framebuffer.h @@ -51,14 +51,7 @@ public: FrameBuffer(const std::vector &planes, unsigned int cookie = 0); - const std::vector &planes() const - { - /* \todo Remove the assertions after sufficient testing */ - for (const auto &plane : planes_) - assert(plane.offset != Plane::kInvalidOffset); - return planes_; - } - + const std::vector &planes() const { return planes_; } Request *request() const; const FrameMetadata &metadata() const { return metadata_; } diff --git a/src/libcamera/framebuffer.cpp b/src/libcamera/framebuffer.cpp index c99f5b15e6ff..ad63a34a83bf 100644 --- a/src/libcamera/framebuffer.cpp +++ b/src/libcamera/framebuffer.cpp @@ -199,6 +199,8 @@ FrameBuffer::FrameBuffer(const std::vector &planes, unsigned int cookie) : Extensible(std::make_unique()), planes_(planes), cookie_(cookie) { + for (const auto &plane : planes_) + ASSERT(plane.offset != Plane::kInvalidOffset); } /** From patchwork Mon Sep 6 22:56:15 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13675 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id C7258BE175 for ; Mon, 6 Sep 2021 22:57:13 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 642236917C; Tue, 7 Sep 2021 00:57:13 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="pw2gJD/h"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B2CCF69171 for ; Tue, 7 Sep 2021 00:57:02 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 47A4A993; Tue, 7 Sep 2021 00:57:02 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969022; bh=yQzDE330FE4bfpnJvwkRVv4LxSn+BVXbC0iceJxsrrI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=pw2gJD/hgz5l7c+gtXrTYQ8OBZEQJfcD8IVEwNoqIZsVAKnRG0invFvAg5ww81TLA mG28IVIYEgljgMnyU+sepEXmuQBhdhPxwX0H04Yn5kEW/En7XSKftv4QoLzWOk+WKY 5o+vYC18wHtLLBoNbyFQPYesG+VHcQ90O/iVwvtw= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:15 +0300 Message-Id: <20210906225636.14683-9-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 09/30] libcamera: framebuffer: Add a function to check if planes are contiguous X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Multi-planar frame buffers can store their planes contiguously in memory, or split them in discontiguous memory areas. Add a private function to check in which of these two categories the frame buffer belongs. This will be used to correctly handle the differences between the V4L2 single and multi planar APIs. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Reviewed-by: Hirokazu Honda --- Changes v1: - Merge both loops in FrameBuffer::FrameBuffer() --- include/libcamera/internal/framebuffer.h | 2 ++ src/libcamera/framebuffer.cpp | 45 ++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/include/libcamera/internal/framebuffer.h b/include/libcamera/internal/framebuffer.h index 606aed2b4782..cd33c295466e 100644 --- a/include/libcamera/internal/framebuffer.h +++ b/include/libcamera/internal/framebuffer.h @@ -21,9 +21,11 @@ public: Private(); void setRequest(Request *request) { request_ = request; } + bool isContiguous() const { return isContiguous_; } private: Request *request_; + bool isContiguous_; }; } /* namespace libcamera */ diff --git a/src/libcamera/framebuffer.cpp b/src/libcamera/framebuffer.cpp index ad63a34a83bf..e71c2ffae034 100644 --- a/src/libcamera/framebuffer.cpp +++ b/src/libcamera/framebuffer.cpp @@ -106,7 +106,7 @@ LOG_DEFINE_CATEGORY(Buffer) */ FrameBuffer::Private::Private() - : request_(nullptr) + : request_(nullptr), isContiguous_(true) { } @@ -120,6 +120,17 @@ FrameBuffer::Private::Private() * handlers, it is called by the pipeline handlers themselves. */ +/** + * \fn FrameBuffer::Private::isContiguous() + * \brief Check if the frame buffer stores planes contiguously in memory + * + * Multi-planar frame buffers can store their planes contiguously in memory, or + * split them into discontiguous memory areas. This function checks in which of + * these two categories the frame buffer belongs. + * + * \return True if the planes are stored contiguously in memory, false otherwise + */ + /** * \class FrameBuffer * \brief Frame buffer data and its associated dynamic metadata @@ -199,8 +210,38 @@ FrameBuffer::FrameBuffer(const std::vector &planes, unsigned int cookie) : Extensible(std::make_unique()), planes_(planes), cookie_(cookie) { - for (const auto &plane : planes_) + unsigned int offset = 0; + bool isContiguous = true; + ino_t inode = 0; + + for (const auto &plane : planes_) { ASSERT(plane.offset != Plane::kInvalidOffset); + + if (plane.offset != offset) { + isContiguous = false; + break; + } + + /* + * Two different dmabuf file descriptors may still refer to the + * same dmabuf instance. Check this using inodes. + */ + if (plane.fd.fd() != planes_[0].fd.fd()) { + if (!inode) + inode = planes_[0].fd.inode(); + if (plane.fd.inode() != inode) { + isContiguous = false; + break; + } + } + + offset += plane.length; + } + + LOG(Buffer, Debug) + << "Buffer is " << (isContiguous ? "not " : "") << "contiguous"; + + _d()->isContiguous_ = isContiguous; } /** From patchwork Mon Sep 6 22:56:16 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13676 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 0E68ABE175 for ; Mon, 6 Sep 2021 22:57:15 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 966A46916D; Tue, 7 Sep 2021 00:57:14 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="EgbkBjFn"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 177146917A for ; Tue, 7 Sep 2021 00:57:03 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id AB877B75; Tue, 7 Sep 2021 00:57:02 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969022; bh=yKy+10GjDbrM8APjEW8E8CZpYga7jglPDb7x0BCWsUc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=EgbkBjFnIqo9ahAcx7zCA1asx1YfMDrBO9QN/AUzNR0DQsc+Wc5dA56Ju9lS0+j0C XxYfGERUEy79vvlaay06F+VQjBceiXQb/SoLPEgzQinoBrqcbq7W0t7HFvg3VOOQ/c Z4x68KTTjkfpSuQAghf0YvOrkwIFD416NW0M40vY= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:16 +0300 Message-Id: <20210906225636.14683-10-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 10/30] libcamera: v4l2_videodevice: Cache PixelFormatInfo X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Cache the PixelFormatInfo instead of looking it up in every call to createBuffer(). This prepares for usage of the info in queueBuffer(), to avoid a looking every time a buffer is queued. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Reviewed-by: Hirokazu Honda --- Changes since v1: - Add a comment to explain why formatInfo_ isn't guaranteed to be valid --- include/libcamera/internal/v4l2_videodevice.h | 1 + src/libcamera/v4l2_videodevice.cpp | 28 +++++++++++++------ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/include/libcamera/internal/v4l2_videodevice.h b/include/libcamera/internal/v4l2_videodevice.h index 087ad067e37e..efe34d47e72b 100644 --- a/include/libcamera/internal/v4l2_videodevice.h +++ b/include/libcamera/internal/v4l2_videodevice.h @@ -241,6 +241,7 @@ private: V4L2Capability caps_; V4L2DeviceFormat format_; + const PixelFormatInfo *formatInfo_; enum v4l2_buf_type bufferType_; enum v4l2_memory memoryType_; diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp index 1c4e6fbf7fe7..1483181a0856 100644 --- a/src/libcamera/v4l2_videodevice.cpp +++ b/src/libcamera/v4l2_videodevice.cpp @@ -482,8 +482,8 @@ const std::string V4L2DeviceFormat::toString() const * \param[in] deviceNode The file-system path to the video device node */ V4L2VideoDevice::V4L2VideoDevice(const std::string &deviceNode) - : V4L2Device(deviceNode), cache_(nullptr), fdBufferNotifier_(nullptr), - streaming_(false) + : V4L2Device(deviceNode), formatInfo_(nullptr), cache_(nullptr), + fdBufferNotifier_(nullptr), streaming_(false) { /* * We default to an MMAP based CAPTURE video device, however this will @@ -586,6 +586,8 @@ int V4L2VideoDevice::open() return ret; } + formatInfo_ = &PixelFormatInfo::info(format_.fourcc); + return 0; } @@ -681,6 +683,8 @@ int V4L2VideoDevice::open(int handle, enum v4l2_buf_type type) return ret; } + formatInfo_ = &PixelFormatInfo::info(format_.fourcc); + return 0; } @@ -695,6 +699,8 @@ void V4L2VideoDevice::close() releaseBuffers(); delete fdBufferNotifier_; + formatInfo_ = nullptr; + V4L2Device::close(); } @@ -787,6 +793,8 @@ int V4L2VideoDevice::setFormat(V4L2DeviceFormat *format) return ret; format_ = *format; + formatInfo_ = &PixelFormatInfo::info(format_.fourcc); + return 0; } @@ -1325,19 +1333,23 @@ std::unique_ptr V4L2VideoDevice::createBuffer(unsigned int index) planes.push_back(std::move(plane)); } - const auto &info = PixelFormatInfo::info(format_.fourcc); - if (info.isValid() && info.numPlanes() != numPlanes) { + /* + * The format info is not guaranteed to be valid, as there are no + * PixelFormatInfo for metadata formats, so check it first. + */ + if (formatInfo_->isValid() && formatInfo_->numPlanes() != numPlanes) { ASSERT(numPlanes == 1u); - const size_t numColorPlanes = info.numPlanes(); - planes.resize(numColorPlanes); + + planes.resize(formatInfo_->numPlanes()); const FileDescriptor &fd = planes[0].fd; size_t offset = 0; - for (size_t i = 0; i < numColorPlanes; ++i) { + + for (size_t i = 0; i < planes.size(); ++i) { planes[i].fd = fd; planes[i].offset = offset; /* \todo Take the V4L2 stride into account */ - planes[i].length = info.planeSize(format_.size, i); + planes[i].length = formatInfo_->planeSize(format_.size, i); offset += planes[i].length; } } From patchwork Mon Sep 6 22:56:17 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13677 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 17FACBE175 for ; Mon, 6 Sep 2021 22:57:17 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 87AEB69171; Tue, 7 Sep 2021 00:57:16 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="FDFPJ/vN"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7C3CB6916D for ; Tue, 7 Sep 2021 00:57:03 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 116FE993; Tue, 7 Sep 2021 00:57:03 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969023; bh=XJQIoEiIryeoez7TWTX9unKSFLX6i1uryjTsFB9b6io=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=FDFPJ/vN8mQymv75ukj0Vf4OvJLoT6jfyjDGqVZ0BbjbvVBH1ydT0LI1cwEHfgoae X49A+BNlsX89YXZHDLWKgOhtj1lVVNlJH/OPjB6RIF7Ejr0WqqgGNeqDLidN3b9naY 3oHKsVcVBW2B8cX75mzZm8t6WqQVa9wuC5UyoJDo= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:17 +0300 Message-Id: <20210906225636.14683-11-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 11/30] libcamera: v4l2_videodevice: Document plane handling in createBuffer() X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The V4L2VideoDevice::createBuffer() calculates offsets manually when using a multi-planar pixel format and a single-planar V4L2 format. The process isn't trivial, document it. Signed-off-by: Laurent Pinchart Reviewed-by: Jean-Michel Hautbois Reviewed-by: Hirokazu Honda Reviewed-by: Kieran Bingham --- src/libcamera/v4l2_videodevice.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp index 1483181a0856..88535f5a07c7 100644 --- a/src/libcamera/v4l2_videodevice.cpp +++ b/src/libcamera/v4l2_videodevice.cpp @@ -1334,10 +1334,19 @@ std::unique_ptr V4L2VideoDevice::createBuffer(unsigned int index) } /* + * If we have a multi-planar format with a V4L2 single-planar buffer, + * split the single V4L2 plane into multiple FrameBuffer planes by + * computing the offsets manually. + * * The format info is not guaranteed to be valid, as there are no * PixelFormatInfo for metadata formats, so check it first. */ if (formatInfo_->isValid() && formatInfo_->numPlanes() != numPlanes) { + /* + * There's no valid situation where the number of colour planes + * differs from the number of V4L2 planes and the V4L2 buffer + * has more than one plane. + */ ASSERT(numPlanes == 1u); planes.resize(formatInfo_->numPlanes()); From patchwork Mon Sep 6 22:56:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13678 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 43A5ABE175 for ; Mon, 6 Sep 2021 22:57:19 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id EC1356917F; Tue, 7 Sep 2021 00:57:18 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="cVrO9yZn"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id DC5916916C for ; Tue, 7 Sep 2021 00:57:03 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 6E19F891; Tue, 7 Sep 2021 00:57:03 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969023; bh=zVgGXo4m+aHg7nB3jjUEoAJGed4MOav0IDCcFOskuzc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=cVrO9yZniPMh9O2zR8iE7xIKON8XRnb+YJQ6binm3q/AJj0C81vF+VoFMQ4NbmwtK cUwlm9lRsvXlnmsOorwOZnKFNOego106SJaXRD8z3usNGWthq2KrB1SvBSSTUzUr2P JwEtUxOQCyF7YxqpxkgqZGJvOxnU6pD7ef5dfwGM= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:18 +0300 Message-Id: <20210906225636.14683-12-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 12/30] libcamera: v4l2_videodevice: Take stride into account to compute offsets X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" When creating FrameBuffer instances, the V4L2VideoDevice computes plane offsets using minimal stride for the format. This doesn't always produce a valid result when the device requires padding at the end of lines. Fix it by computing offsets using the stride reported by V4L2. Signed-off-by: Laurent Pinchart Reviewed-by: Jean-Michel Hautbois Reviewed-by: Hirokazu Honda Reviewed-by: Kieran Bingham --- src/libcamera/v4l2_videodevice.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp index 88535f5a07c7..c6c9263c49e9 100644 --- a/src/libcamera/v4l2_videodevice.cpp +++ b/src/libcamera/v4l2_videodevice.cpp @@ -1354,11 +1354,21 @@ std::unique_ptr V4L2VideoDevice::createBuffer(unsigned int index) size_t offset = 0; for (size_t i = 0; i < planes.size(); ++i) { + /* + * The stride is reported by V4L2 for the first plane + * only. Compute the stride of the other planes by + * taking the horizontal subsampling factor into + * account, which is equal to the bytesPerGroup ratio of + * the planes. + */ + unsigned int stride = format_.planes[0].bpl + * formatInfo_->planes[i].bytesPerGroup + / formatInfo_->planes[0].bytesPerGroup; + planes[i].fd = fd; planes[i].offset = offset; - - /* \todo Take the V4L2 stride into account */ - planes[i].length = formatInfo_->planeSize(format_.size, i); + planes[i].length = formatInfo_->planeSize(format_.size.height, + i, stride); offset += planes[i].length; } } From patchwork Mon Sep 6 22:56:19 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13679 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 77E78BE175 for ; Mon, 6 Sep 2021 22:57:20 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 05F746916E; Tue, 7 Sep 2021 00:57:20 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="RI11skCM"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 44D3B6916E for ; Tue, 7 Sep 2021 00:57:04 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id D0589993; Tue, 7 Sep 2021 00:57:03 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969024; bh=XxS7cI+sDkbVoE77PdIrZtkm4p8tHhFJ4OQ3455RPQM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RI11skCMZULKvV/Xchf8TbPLgc5Gf+hcFwT8U41wbD+BiVDZLpTieI+uKYkzOtJQz tNma1TB6Adphb0+7ZM6SkgkH0zWe99z1uQdpYqgwdrie2Y2RtLAGLoT9ge/BckO05a x0KTEC/H7UZj9sE7CjqoXqg01npGeBjOc1iAvRa8= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:19 +0300 Message-Id: <20210906225636.14683-13-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 13/30] libcamera: v4l2_videodevice: Coalesce planes when queuing buffer X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" When queueing a buffer to a V4L2VideoDevice, the number of planes in the FrameBuffer may not match the number of V4L2 buffer planes if the PixelFormat is multi-planar (has multiple colour planes) and the V4L2 format is single-planar (has a single buffer plane). In this case, we need to coalesce all FrameBuffer planes into a single V4L2 buffer plane. Do so, and add validity checks to reject frame buffers that can't be described using a single V4L2 buffer plane. This change prepares for proper multi-planar support, but isn't expected to result in a change of behaviour with existing pipeline handlers, as none of them queue an output buffer with multiple FrameBuffer planes or use non-contiguous buffers for either capture or output. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Reviewed-by: Hirokazu Honda --- Changes since v2: - Ensure that the queued frame buffer has enough planes Changes since v1: - Make numV4l2Planes const - Use format_.planesCount --- src/libcamera/v4l2_videodevice.cpp | 72 +++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 10 deletions(-) diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp index c6c9263c49e9..6c1ca9bb0a5c 100644 --- a/src/libcamera/v4l2_videodevice.cpp +++ b/src/libcamera/v4l2_videodevice.cpp @@ -22,10 +22,12 @@ #include #include +#include #include #include "libcamera/internal/formats.h" +#include "libcamera/internal/framebuffer.h" #include "libcamera/internal/media_device.h" #include "libcamera/internal/media_object.h" @@ -1496,10 +1498,25 @@ int V4L2VideoDevice::queueBuffer(FrameBuffer *buffer) bool multiPlanar = V4L2_TYPE_IS_MULTIPLANAR(buf.type); const std::vector &planes = buffer->planes(); + const unsigned int numV4l2Planes = format_.planesCount; + + /* + * Ensure that the frame buffer has enough planes, and that they're + * contiguous if the V4L2 format requires them to be. + */ + if (planes.size() < numV4l2Planes) { + LOG(V4L2, Error) << "Frame buffer has too few planes"; + return -EINVAL; + } + + if (planes.size() != numV4l2Planes && !buffer->_d()->isContiguous()) { + LOG(V4L2, Error) << "Device format requires contiguous buffer"; + return -EINVAL; + } if (buf.memory == V4L2_MEMORY_DMABUF) { if (multiPlanar) { - for (unsigned int p = 0; p < planes.size(); ++p) + for (unsigned int p = 0; p < numV4l2Planes; ++p) v4l2Planes[p].m.fd = planes[p].fd.fd(); } else { buf.m.fd = planes[0].fd.fd(); @@ -1507,23 +1524,58 @@ int V4L2VideoDevice::queueBuffer(FrameBuffer *buffer) } if (multiPlanar) { - buf.length = planes.size(); + buf.length = numV4l2Planes; buf.m.planes = v4l2Planes; } if (V4L2_TYPE_IS_OUTPUT(buf.type)) { const FrameMetadata &metadata = buffer->metadata(); - if (multiPlanar) { - unsigned int nplane = 0; - for (const FrameMetadata::Plane &plane : metadata.planes) { - v4l2Planes[nplane].bytesused = plane.bytesused; - v4l2Planes[nplane].length = buffer->planes()[nplane].length; - nplane++; + if (numV4l2Planes != planes.size()) { + /* + * If we have a multi-planar buffer with a V4L2 + * single-planar format, coalesce all planes. The length + * and number of bytes used may only differ in the last + * plane as any other situation can't be represented. + */ + unsigned int bytesused = 0; + unsigned int length = 0; + + for (auto [i, plane] : utils::enumerate(planes)) { + bytesused += metadata.planes[i].bytesused; + length += plane.length; + + if (i != planes.size() - 1 && bytesused != length) { + LOG(V4L2, Error) + << "Holes in multi-planar buffer not supported"; + return -EINVAL; + } + } + + if (multiPlanar) { + v4l2Planes[0].bytesused = bytesused; + v4l2Planes[0].length = length; + } else { + buf.bytesused = bytesused; + buf.length = length; + } + } else if (multiPlanar) { + /* + * If we use the multi-planar API, fill in the planes. + * The number of planes in the frame buffer and in the + * V4L2 buffer is guaranteed to be equal at this point. + */ + for (auto [i, plane] : utils::enumerate(planes)) { + v4l2Planes[i].bytesused = metadata.planes[i].bytesused; + v4l2Planes[i].length = plane.length; } } else { - if (metadata.planes.size()) - buf.bytesused = metadata.planes[0].bytesused; + /* + * Single-planar API with a single plane in the buffer + * is trivial to handle. + */ + buf.bytesused = metadata.planes[0].bytesused; + buf.length = planes[0].length; } buf.sequence = metadata.sequence; From patchwork Mon Sep 6 22:56:20 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13681 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 4E308BE175 for ; Mon, 6 Sep 2021 22:57:31 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 319AF69171; Tue, 7 Sep 2021 00:57:30 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="aStOT6hq"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A114B6916B for ; Tue, 7 Sep 2021 00:57:04 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 39FA6891; Tue, 7 Sep 2021 00:57:04 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969024; bh=ri+vEUSyTxOTaM1OW0ENfWYzF390moPZsaFA9314zvQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=aStOT6hqzNWOeCklJ3ZMe5QdOz/u/aA9WFp3RwGbswKwSzeuYzMfmkidkVA5dzCNY Ye/rzISOqvaFzec63Ok71+IYdf8DB5VWHMCRbuqeD9mxWcyOCn3e58w6gp5KG88yWL lM+LNEWqtn7p//TKBXXp5d6By2K3JaIdc/gWKi8c= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:20 +0300 Message-Id: <20210906225636.14683-14-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 14/30] libcamera: v4l2_videodevice: Split planes when dequeuing buffer X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" When dequeueing a buffer from a V4L2VideoDevice, the number of planes in the FrameBuffer may not match the number of V4L2 buffer planes if the PixelFormat is multi-planar (has multiple colour planes) and the V4L2 format is single-planar (has a single buffer plane). In this case, we need to split the single V4L2 buffer plane into FrameBuffer planes. Do so, and add checks to reject invalid V4L2 buffers in case of a driver issue. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Reviewed-by: Hirokazu Honda --- Changes since v1: - Reduce indentation --- src/libcamera/v4l2_videodevice.cpp | 53 +++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp index 6c1ca9bb0a5c..2e458fcc22e0 100644 --- a/src/libcamera/v4l2_videodevice.cpp +++ b/src/libcamera/v4l2_videodevice.cpp @@ -7,6 +7,7 @@ #include "libcamera/internal/v4l2_videodevice.h" +#include #include #include #include @@ -1669,12 +1670,54 @@ FrameBuffer *V4L2VideoDevice::dequeueBuffer() buffer->metadata_.timestamp = buf.timestamp.tv_sec * 1000000000ULL + buf.timestamp.tv_usec * 1000ULL; - buffer->metadata_.planes.clear(); - if (multiPlanar) { - for (unsigned int nplane = 0; nplane < buf.length; nplane++) - buffer->metadata_.planes.push_back({ planes[nplane].bytesused }); + if (V4L2_TYPE_IS_OUTPUT(buf.type)) + return buffer; + + unsigned int numV4l2Planes = multiPlanar ? buf.length : 1; + FrameMetadata &metadata = buffer->metadata_; + metadata.planes.clear(); + + if (numV4l2Planes != buffer->planes().size()) { + /* + * If we have a multi-planar buffer with a V4L2 + * single-planar format, split the V4L2 buffer across + * the buffer planes. Only the last plane may have less + * bytes used than its length. + */ + if (numV4l2Planes != 1) { + LOG(V4L2, Error) + << "Invalid number of planes (" << numV4l2Planes + << " != " << buffer->planes().size() << ")"; + + metadata.status = FrameMetadata::FrameError; + return buffer; + } + + unsigned int bytesused = multiPlanar ? planes[0].bytesused + : buf.bytesused; + + for (auto [i, plane] : utils::enumerate(buffer->planes())) { + if (!bytesused) { + LOG(V4L2, Error) + << "Dequeued buffer is too small"; + + metadata.status = FrameMetadata::FrameError; + return buffer; + } + + metadata.planes.push_back({ std::min(plane.length, bytesused) }); + bytesused -= metadata.planes.back().bytesused; + } + } else if (multiPlanar) { + /* + * If we use the multi-planar API, fill in the planes. + * The number of planes in the frame buffer and in the + * V4L2 buffer is guaranteed to be equal at this point. + */ + for (unsigned int i = 0; i < numV4l2Planes; ++i) + metadata.planes.push_back({ planes[i].bytesused }); } else { - buffer->metadata_.planes.push_back({ buf.bytesused }); + metadata.planes.push_back({ buf.bytesused }); } return buffer; From patchwork Mon Sep 6 22:56:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13680 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 9B2FDBE175 for ; Mon, 6 Sep 2021 22:57:28 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5278F6916D; Tue, 7 Sep 2021 00:57:28 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="ENcI9wVQ"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 08E596917E for ; Tue, 7 Sep 2021 00:57:05 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 96A64993; Tue, 7 Sep 2021 00:57:04 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969024; bh=QZnxsi0f7lzKbL9ewSoqOoSOZ2Ze5awXmXVvtbDofVs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ENcI9wVQO1+6wHJbYsk+nQGSG5Jm4cG1iT/jI20lObMJAVq0+QMguSlxzQS968vua +4vnsH44KxNlH38CVdQ6hRW83feyU5BDMRmKApbc2w4SyxZrtlqkp18xVE3i1N+R35 CeT4NGZXTxM2DryjXoQ2FobpfOEGt+ew+RmEz/oo= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:21 +0300 Message-Id: <20210906225636.14683-15-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 15/30] libcamera: v4l2_videodevice: Use utils::enumerate() X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Replace a manual counter with the utils::enumerate() utility function. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Reviewed-by: Hirokazu Honda --- src/libcamera/v4l2_videodevice.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp index 2e458fcc22e0..281f3f13fc9c 100644 --- a/src/libcamera/v4l2_videodevice.cpp +++ b/src/libcamera/v4l2_videodevice.cpp @@ -1356,7 +1356,7 @@ std::unique_ptr V4L2VideoDevice::createBuffer(unsigned int index) const FileDescriptor &fd = planes[0].fd; size_t offset = 0; - for (size_t i = 0; i < planes.size(); ++i) { + for (auto [i, plane] : utils::enumerate(planes)) { /* * The stride is reported by V4L2 for the first plane * only. Compute the stride of the other planes by @@ -1368,11 +1368,11 @@ std::unique_ptr V4L2VideoDevice::createBuffer(unsigned int index) * formatInfo_->planes[i].bytesPerGroup / formatInfo_->planes[0].bytesPerGroup; - planes[i].fd = fd; - planes[i].offset = offset; - planes[i].length = formatInfo_->planeSize(format_.size.height, - i, stride); - offset += planes[i].length; + plane.fd = fd; + plane.offset = offset; + plane.length = formatInfo_->planeSize(format_.size.height, + i, stride); + offset += plane.length; } } From patchwork Mon Sep 6 22:56:22 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13683 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 7DFC4BE175 for ; Mon, 6 Sep 2021 22:57:41 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id A349869176; Tue, 7 Sep 2021 00:57:40 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="VhmXhv56"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 659A86917B for ; Tue, 7 Sep 2021 00:57:05 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id F190A891; Tue, 7 Sep 2021 00:57:04 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969025; bh=FQRh8jtBYRQJEcnoB04QAkbbvLALlkPZpcwtBAk8UnY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=VhmXhv56SkWQwQhQ8L2VrvH8gFlpoONpUX/PQN/qCUC4M/q6Da2LvuaQVwxPpOECE RTqs9HHRHox1wrzjPKJujFYrUpmY69y1rujiBvoiXq8AHzDDrKEx0qVUc06rHQMknI SRwq1427i2m522/6d6zAwl0r1kn4iQff5+XyHcUk= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:22 +0300 Message-Id: <20210906225636.14683-16-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 16/30] libcamera: framebuffer: Allocate metadata planes at construction time X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The metadata planes are allocated by V4L2VideoDevice when dequeuing a buffer. This causes the metadata planes to only be allocated after a buffer gets dequeued, and doesn't provide any strong guarantee that their number matches the number of FrameBuffer planes. The lack of this invariant makes the FrameBuffer class fragile. As a first step towards fixing this, allocate the metadata planes when the FrameBuffer is constructed. The FrameMetadata API should be further improved by preventing a change in the number of planes. Signed-off-by: Laurent Pinchart Reviewed-by: Jean-Michel Hautbois Reviewed-by: Hirokazu Honda --- Changes since v1: - Return buffer with state set to FrameError on error --- src/libcamera/framebuffer.cpp | 2 ++ src/libcamera/v4l2_videodevice.cpp | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/libcamera/framebuffer.cpp b/src/libcamera/framebuffer.cpp index e71c2ffae034..e4f8419a9063 100644 --- a/src/libcamera/framebuffer.cpp +++ b/src/libcamera/framebuffer.cpp @@ -210,6 +210,8 @@ FrameBuffer::FrameBuffer(const std::vector &planes, unsigned int cookie) : Extensible(std::make_unique()), planes_(planes), cookie_(cookie) { + metadata_.planes.resize(planes_.size()); + unsigned int offset = 0; bool isContiguous = true; ino_t inode = 0; diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp index 281f3f13fc9c..81209e485c24 100644 --- a/src/libcamera/v4l2_videodevice.cpp +++ b/src/libcamera/v4l2_videodevice.cpp @@ -1675,7 +1675,6 @@ FrameBuffer *V4L2VideoDevice::dequeueBuffer() unsigned int numV4l2Planes = multiPlanar ? buf.length : 1; FrameMetadata &metadata = buffer->metadata_; - metadata.planes.clear(); if (numV4l2Planes != buffer->planes().size()) { /* @@ -1705,8 +1704,9 @@ FrameBuffer *V4L2VideoDevice::dequeueBuffer() return buffer; } - metadata.planes.push_back({ std::min(plane.length, bytesused) }); - bytesused -= metadata.planes.back().bytesused; + metadata.planes[i].bytesused = + std::min(plane.length, bytesused); + bytesused -= metadata.planes[i].bytesused; } } else if (multiPlanar) { /* @@ -1715,9 +1715,9 @@ FrameBuffer *V4L2VideoDevice::dequeueBuffer() * V4L2 buffer is guaranteed to be equal at this point. */ for (unsigned int i = 0; i < numV4l2Planes; ++i) - metadata.planes.push_back({ planes[i].bytesused }); + metadata.planes[i].bytesused = planes[i].bytesused; } else { - metadata.planes.push_back({ buf.bytesused }); + metadata.planes[0].bytesused = buf.bytesused; } return buffer; From patchwork Mon Sep 6 22:56:23 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13682 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id BD6E3BE175 for ; Mon, 6 Sep 2021 22:57:39 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6EC6869171; Tue, 7 Sep 2021 00:57:39 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="bakz1pxg"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C52E469182 for ; Tue, 7 Sep 2021 00:57:05 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 5C1F1993; Tue, 7 Sep 2021 00:57:05 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969025; bh=OS1O0tqbLsxuQcAay/xY3KHSGZHAVM3Y+ccvdrM7954=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bakz1pxgPFJXji2UgF+ExoV3v4ntr73LsSWu4uyuxXX/39lyEAw3JWzrrmDkaDYSQ kGjBG3hr8bxpdvwPNKH0EYzq6i4QsFs8XePc9+bXaPV/TYpKPJKtY61uo95EPAFvfc 0CyWCfbnFuJJutdZb5/mA05wuhIoSHoKK1vuAsL0= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:23 +0300 Message-Id: <20210906225636.14683-17-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 17/30] libcamera: framebuffer: Prevent modifying the number of metadata planes X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The number of metadata planes should always match the number of frame buffer planes. Enforce this by making the vector private and providing accessor functions. As this changes the public API, update all in-tree users accordingly. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Reviewed-by: Jean-Michel Hautbois Reviewed-by: Hirokazu Honda --- include/libcamera/framebuffer.h | 10 +++++++++- src/cam/camera_session.cpp | 4 ++-- src/cam/file_sink.cpp | 2 +- src/libcamera/framebuffer.cpp | 12 +++++++++--- src/libcamera/v4l2_videodevice.cpp | 14 +++++++------- src/qcam/main_window.cpp | 2 +- src/qcam/viewfinder_gl.cpp | 2 +- src/qcam/viewfinder_qt.cpp | 2 +- src/v4l2/v4l2_camera_proxy.cpp | 2 +- 9 files changed, 32 insertions(+), 18 deletions(-) diff --git a/include/libcamera/framebuffer.h b/include/libcamera/framebuffer.h index fd68ed0a139d..7f2f176af691 100644 --- a/include/libcamera/framebuffer.h +++ b/include/libcamera/framebuffer.h @@ -13,6 +13,7 @@ #include #include +#include #include @@ -34,7 +35,14 @@ struct FrameMetadata { Status status; unsigned int sequence; uint64_t timestamp; - std::vector planes; + + Span planes() { return planes_; } + Span planes() const { return planes_; } + +private: + friend class FrameBuffer; + + std::vector planes_; }; class FrameBuffer final : public Extensible diff --git a/src/cam/camera_session.cpp b/src/cam/camera_session.cpp index 60d640f2b15c..32a373a99b72 100644 --- a/src/cam/camera_session.cpp +++ b/src/cam/camera_session.cpp @@ -374,9 +374,9 @@ void CameraSession::processRequest(Request *request) << " bytesused: "; unsigned int nplane = 0; - for (const FrameMetadata::Plane &plane : metadata.planes) { + for (const FrameMetadata::Plane &plane : metadata.planes()) { info << plane.bytesused; - if (++nplane < metadata.planes.size()) + if (++nplane < metadata.planes().size()) info << "/"; } } diff --git a/src/cam/file_sink.cpp b/src/cam/file_sink.cpp index 0b529e3eb767..0fc7d621f50b 100644 --- a/src/cam/file_sink.cpp +++ b/src/cam/file_sink.cpp @@ -110,7 +110,7 @@ void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer) for (unsigned int i = 0; i < buffer->planes().size(); ++i) { const FrameBuffer::Plane &plane = buffer->planes()[i]; - const FrameMetadata::Plane &meta = buffer->metadata().planes[i]; + const FrameMetadata::Plane &meta = buffer->metadata().planes()[i]; uint8_t *data = planeData_[&plane]; unsigned int length = std::min(meta.bytesused, plane.length); diff --git a/src/libcamera/framebuffer.cpp b/src/libcamera/framebuffer.cpp index e4f8419a9063..d44a98babd05 100644 --- a/src/libcamera/framebuffer.cpp +++ b/src/libcamera/framebuffer.cpp @@ -91,8 +91,14 @@ LOG_DEFINE_CATEGORY(Buffer) */ /** - * \var FrameMetadata::planes - * \brief Array of per-plane metadata + * \fn FrameMetadata::planes() + * \copydoc FrameMetadata::planes() const + */ + +/** + * \fn FrameMetadata::planes() const + * \brief Retrieve the array of per-plane metadata + * \return The array of per-plane metadata */ /** @@ -210,7 +216,7 @@ FrameBuffer::FrameBuffer(const std::vector &planes, unsigned int cookie) : Extensible(std::make_unique()), planes_(planes), cookie_(cookie) { - metadata_.planes.resize(planes_.size()); + metadata_.planes_.resize(planes_.size()); unsigned int offset = 0; bool isContiguous = true; diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp index 81209e485c24..837a59d9bae2 100644 --- a/src/libcamera/v4l2_videodevice.cpp +++ b/src/libcamera/v4l2_videodevice.cpp @@ -1543,7 +1543,7 @@ int V4L2VideoDevice::queueBuffer(FrameBuffer *buffer) unsigned int length = 0; for (auto [i, plane] : utils::enumerate(planes)) { - bytesused += metadata.planes[i].bytesused; + bytesused += metadata.planes()[i].bytesused; length += plane.length; if (i != planes.size() - 1 && bytesused != length) { @@ -1567,7 +1567,7 @@ int V4L2VideoDevice::queueBuffer(FrameBuffer *buffer) * V4L2 buffer is guaranteed to be equal at this point. */ for (auto [i, plane] : utils::enumerate(planes)) { - v4l2Planes[i].bytesused = metadata.planes[i].bytesused; + v4l2Planes[i].bytesused = metadata.planes()[i].bytesused; v4l2Planes[i].length = plane.length; } } else { @@ -1575,7 +1575,7 @@ int V4L2VideoDevice::queueBuffer(FrameBuffer *buffer) * Single-planar API with a single plane in the buffer * is trivial to handle. */ - buf.bytesused = metadata.planes[0].bytesused; + buf.bytesused = metadata.planes()[0].bytesused; buf.length = planes[0].length; } @@ -1704,9 +1704,9 @@ FrameBuffer *V4L2VideoDevice::dequeueBuffer() return buffer; } - metadata.planes[i].bytesused = + metadata.planes()[i].bytesused = std::min(plane.length, bytesused); - bytesused -= metadata.planes[i].bytesused; + bytesused -= metadata.planes()[i].bytesused; } } else if (multiPlanar) { /* @@ -1715,9 +1715,9 @@ FrameBuffer *V4L2VideoDevice::dequeueBuffer() * V4L2 buffer is guaranteed to be equal at this point. */ for (unsigned int i = 0; i < numV4l2Planes; ++i) - metadata.planes[i].bytesused = planes[i].bytesused; + metadata.planes()[i].bytesused = planes[i].bytesused; } else { - metadata.planes[0].bytesused = buf.bytesused; + metadata.planes()[0].bytesused = buf.bytesused; } return buffer; diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index 1536b2b5bd66..ac853e360aea 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -756,7 +756,7 @@ void MainWindow::processViewfinder(FrameBuffer *buffer) qDebug().noquote() << QString("seq: %1").arg(metadata.sequence, 6, 10, QLatin1Char('0')) - << "bytesused:" << metadata.planes[0].bytesused + << "bytesused:" << metadata.planes()[0].bytesused << "timestamp:" << metadata.timestamp << "fps:" << Qt::fixed << qSetRealNumberPrecision(2) << fps; diff --git a/src/qcam/viewfinder_gl.cpp b/src/qcam/viewfinder_gl.cpp index 40226601f9fd..d2ef036974f4 100644 --- a/src/qcam/viewfinder_gl.cpp +++ b/src/qcam/viewfinder_gl.cpp @@ -125,7 +125,7 @@ void ViewFinderGL::render(libcamera::FrameBuffer *buffer, /* * \todo Get the stride from the buffer instead of computing it naively */ - stride_ = buffer->metadata().planes[0].bytesused / size_.height(); + stride_ = buffer->metadata().planes()[0].bytesused / size_.height(); update(); buffer_ = buffer; } diff --git a/src/qcam/viewfinder_qt.cpp b/src/qcam/viewfinder_qt.cpp index efa1d412584b..a0bf99b0b522 100644 --- a/src/qcam/viewfinder_qt.cpp +++ b/src/qcam/viewfinder_qt.cpp @@ -87,7 +87,7 @@ void ViewFinderQt::render(libcamera::FrameBuffer *buffer, } unsigned char *memory = mem.data(); - size_t size = buffer->metadata().planes[0].bytesused; + size_t size = buffer->metadata().planes()[0].bytesused; { QMutexLocker locker(&mutex_); diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index d926a7b77083..07d2250bb846 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -211,7 +211,7 @@ void V4L2CameraProxy::updateBuffers() switch (fmd.status) { case FrameMetadata::FrameSuccess: - buf.bytesused = fmd.planes[0].bytesused; + buf.bytesused = fmd.planes()[0].bytesused; buf.field = V4L2_FIELD_NONE; buf.timestamp.tv_sec = fmd.timestamp / 1000000000; buf.timestamp.tv_usec = fmd.timestamp % 1000000; From patchwork Mon Sep 6 22:56:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13685 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 9C873BE175 for ; Mon, 6 Sep 2021 22:57:45 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5AD1F69168; Tue, 7 Sep 2021 00:57:45 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="WvhxN2YR"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2BBA869184 for ; Tue, 7 Sep 2021 00:57:06 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B8623891; Tue, 7 Sep 2021 00:57:05 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969025; bh=72iPAvQlOWqo1OLDSL3+qXDCX4aKEck7EYVkLGusbzU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=WvhxN2YRTfmd15zqqEjLFU03stx3+Iq8fOwmIwiBz5BuDqRfNUnk5fVN3JeQr6tyY srgill7pG3gsiDi/YE4LWsQXk/Lxcy7D3FXcdnJ9pCzm44VPLJSu5gp/V7yau3EvXz 5kI7YjczAgzEyCpst6NHuOPUJTqWzTaoAgW4oB3U= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:24 +0300 Message-Id: <20210906225636.14683-18-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 18/30] android: camera_device: Don't assume all planes use the same fd X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Now that libcamera correctly supports frame buffers with different dmabuf for each plane, remove the assumption that a single dmabuf is used. Signed-off-by: Laurent Pinchart Reviewed-by: Jean-Michel Hautbois Reviewed-by: Kieran Bingham --- src/android/camera_device.cpp | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp index 8ca76719a50f..c64064106ccc 100644 --- a/src/android/camera_device.cpp +++ b/src/android/camera_device.cpp @@ -749,25 +749,6 @@ FrameBuffer *CameraDevice::createFrameBuffer(const buffer_handle_t camera3buffer libcamera::PixelFormat pixelFormat, const libcamera::Size &size) { - FileDescriptor fd; - /* - * This assumes all the planes are in the same dmabuf. - * - * \todo Verify that this assumption holds, fstat() can be used to check - * if two fds refer to the same dmabuf. - */ - for (int i = 0; i < camera3buffer->numFds; i++) { - if (camera3buffer->data[i] != -1) { - fd = FileDescriptor(camera3buffer->data[i]); - break; - } - } - - if (!fd.isValid()) { - LOG(HAL, Fatal) << "No valid fd"; - return nullptr; - } - CameraBuffer buf(camera3buffer, pixelFormat, size, PROT_READ); if (!buf.isValid()) { LOG(HAL, Fatal) << "Failed to create CameraBuffer"; @@ -776,6 +757,12 @@ FrameBuffer *CameraDevice::createFrameBuffer(const buffer_handle_t camera3buffer std::vector planes(buf.numPlanes()); for (size_t i = 0; i < buf.numPlanes(); ++i) { + FileDescriptor fd{ camera3buffer->data[i] }; + if (!fd.isValid()) { + LOG(HAL, Fatal) << "No valid fd"; + return nullptr; + } + planes[i].fd = fd; planes[i].offset = buf.offset(i); planes[i].length = buf.size(i); From patchwork Mon Sep 6 22:56:25 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13684 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 1D1ECBE175 for ; Mon, 6 Sep 2021 22:57:45 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id DF9C369173; Tue, 7 Sep 2021 00:57:44 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="FmSXmhvi"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A694569172 for ; Tue, 7 Sep 2021 00:57:06 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 2EBE2993; Tue, 7 Sep 2021 00:57:06 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969026; bh=o5n0xDiA7QFYxvIj9O7llgm2HJtAZLE5xgDJcgsnrl4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=FmSXmhviy2gI6QOpi3ze3CEVEZh4Wv2xzTReQtNkJnmBb8dU5UZr54s/g31BBqUju S2f8T1iJhuDTDiniBwjWTVbjcv0GmZEthaQJkm3UVJ0vLWCEITBmIqou4fo72ZSVX9 3Fzk+PGoUKm+G+7YbTXOAs4UTrUqvpyMAirnKepE= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:25 +0300 Message-Id: <20210906225636.14683-19-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 19/30] android: jpeg: Use stride instead of image width for line address X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" When calculating the luma line address, the image width is used instead of the stride. Without padding at the end of the line the the values should be identical, but this is conceptually incorrect in any case. Fix it. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Reviewed-by: Jean-Michel Hautbois --- src/android/jpeg/encoder_libjpeg.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/android/jpeg/encoder_libjpeg.cpp b/src/android/jpeg/encoder_libjpeg.cpp index b8b01e20a001..807a0949a8fc 100644 --- a/src/android/jpeg/encoder_libjpeg.cpp +++ b/src/android/jpeg/encoder_libjpeg.cpp @@ -152,7 +152,7 @@ void EncoderLibJpeg::compressNV(Span frame) for (unsigned int y = 0; y < compress_.image_height; y++) { unsigned char *dst = &tmprowbuf[0]; - const unsigned char *src_y = src + y * compress_.image_width; + const unsigned char *src_y = src + y * y_stride; const unsigned char *src_cb = src_c + (y / vertSubSample) * c_stride + cb_pos; const unsigned char *src_cr = src_c + (y / vertSubSample) * c_stride + cr_pos; From patchwork Mon Sep 6 22:56:26 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13687 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id E8A9FBE175 for ; Mon, 6 Sep 2021 22:57:46 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 76E846917D; Tue, 7 Sep 2021 00:57:46 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="cbmxTP8u"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 02B1969188 for ; Tue, 7 Sep 2021 00:57:07 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 8DEBD891; Tue, 7 Sep 2021 00:57:06 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969026; bh=tjiiRI3BhiGDkMgKGuwJ9IXOMBt/szvtvdXEWcpeWqM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=cbmxTP8un3UbJ/QrOa++ZNshivknoipMBRedXnnA2Knut3K2hzQSTqi0KyRqMBVe7 uCZLkC1rlNNMz+kYn9q0kdMu6mUdQV2uXAoZhGQ+qhyPaNfITPlFImSrB3RoEGqzi3 YLspJZYj40YAJLumPFu3gXc1sBQ3hwMxg9gVDrug= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:26 +0300 Message-Id: <20210906225636.14683-20-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 20/30] android: jpeg: Support multi-planar buffers X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The JPEG post-processor uses MappedFrameBuffer to access pixel data, but only uses data from the first plane. Pass the vector of planes to the encode() function to correctly handle multi-planar formats (currently limited to NV12). Signed-off-by: Laurent Pinchart Acked-by: Umang Jain Tested-by: Umang Jain Reviewed-by: Hirokazu Honda Reviewed-by: Kieran Bingham --- src/android/jpeg/encoder_libjpeg.cpp | 17 +++++++++-------- src/android/jpeg/encoder_libjpeg.h | 8 +++++--- src/android/jpeg/post_processor_jpeg.cpp | 2 +- src/android/jpeg/thumbnailer.cpp | 4 ++-- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/android/jpeg/encoder_libjpeg.cpp b/src/android/jpeg/encoder_libjpeg.cpp index 807a0949a8fc..d0b1da5016d2 100644 --- a/src/android/jpeg/encoder_libjpeg.cpp +++ b/src/android/jpeg/encoder_libjpeg.cpp @@ -103,9 +103,9 @@ int EncoderLibJpeg::configure(const StreamConfiguration &cfg) return 0; } -void EncoderLibJpeg::compressRGB(Span frame) +void EncoderLibJpeg::compressRGB(const std::vector> &planes) { - unsigned char *src = const_cast(frame.data()); + unsigned char *src = const_cast(planes[0].data()); /* \todo Stride information should come from buffer configuration. */ unsigned int stride = pixelFormatInfo_->stride(compress_.image_width, 0); @@ -121,7 +121,7 @@ void EncoderLibJpeg::compressRGB(Span frame) * Compress the incoming buffer from a supported NV format. * This naively unpacks the semi-planar NV12 to a YUV888 format for libjpeg. */ -void EncoderLibJpeg::compressNV(Span frame) +void EncoderLibJpeg::compressNV(const std::vector> &planes) { uint8_t tmprowbuf[compress_.image_width * 3]; @@ -143,8 +143,8 @@ void EncoderLibJpeg::compressNV(Span frame) unsigned int cb_pos = nvSwap_ ? 1 : 0; unsigned int cr_pos = nvSwap_ ? 0 : 1; - const unsigned char *src = frame.data(); - const unsigned char *src_c = src + y_stride * compress_.image_height; + const unsigned char *src = planes[0].data(); + const unsigned char *src_c = planes[1].data(); JSAMPROW row_pointer[1]; row_pointer[0] = &tmprowbuf[0]; @@ -188,11 +188,12 @@ int EncoderLibJpeg::encode(const FrameBuffer &source, Span dest, return frame.error(); } - return encode(frame.planes()[0], dest, exifData, quality); + return encode(frame.planes(), dest, exifData, quality); } -int EncoderLibJpeg::encode(Span src, Span dest, - Span exifData, unsigned int quality) +int EncoderLibJpeg::encode(const std::vector> &src, + Span dest, Span exifData, + unsigned int quality) { unsigned char *destination = dest.data(); unsigned long size = dest.size(); diff --git a/src/android/jpeg/encoder_libjpeg.h b/src/android/jpeg/encoder_libjpeg.h index 61fbd1a69278..45ffbd7fae5d 100644 --- a/src/android/jpeg/encoder_libjpeg.h +++ b/src/android/jpeg/encoder_libjpeg.h @@ -9,6 +9,8 @@ #include "encoder.h" +#include + #include "libcamera/internal/formats.h" #include @@ -24,14 +26,14 @@ public: libcamera::Span destination, libcamera::Span exifData, unsigned int quality) override; - int encode(libcamera::Span source, + int encode(const std::vector> &planes, libcamera::Span destination, libcamera::Span exifData, unsigned int quality); private: - void compressRGB(libcamera::Span frame); - void compressNV(libcamera::Span frame); + void compressRGB(const std::vector> &planes); + void compressNV(const std::vector> &planes); struct jpeg_compress_struct compress_; struct jpeg_error_mgr jerr_; diff --git a/src/android/jpeg/post_processor_jpeg.cpp b/src/android/jpeg/post_processor_jpeg.cpp index 3160a784419c..68d74842925d 100644 --- a/src/android/jpeg/post_processor_jpeg.cpp +++ b/src/android/jpeg/post_processor_jpeg.cpp @@ -72,7 +72,7 @@ void PostProcessorJpeg::generateThumbnail(const FrameBuffer &source, */ thumbnail->resize(rawThumbnail.size()); - int jpeg_size = thumbnailEncoder_.encode(rawThumbnail, + int jpeg_size = thumbnailEncoder_.encode({ rawThumbnail }, *thumbnail, {}, quality); thumbnail->resize(jpeg_size); diff --git a/src/android/jpeg/thumbnailer.cpp b/src/android/jpeg/thumbnailer.cpp index 043c7b33f06a..2c341535de9e 100644 --- a/src/android/jpeg/thumbnailer.cpp +++ b/src/android/jpeg/thumbnailer.cpp @@ -62,8 +62,8 @@ void Thumbnailer::createThumbnail(const FrameBuffer &source, ASSERT(tw % 2 == 0 && th % 2 == 0); /* Image scaling block implementing nearest-neighbour algorithm. */ - unsigned char *src = static_cast(frame.planes()[0].data()); - unsigned char *srcC = src + sh * sw; + unsigned char *src = frame.planes()[0].data(); + unsigned char *srcC = frame.planes()[1].data(); unsigned char *srcCb, *srcCr; unsigned char *dstY, *srcY; From patchwork Mon Sep 6 22:56:27 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13688 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id A29C3BE175 for ; Mon, 6 Sep 2021 22:57:47 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4718369168; Tue, 7 Sep 2021 00:57:47 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="uVr1WLsK"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 61C1B69187 for ; Tue, 7 Sep 2021 00:57:07 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id EB221993; Tue, 7 Sep 2021 00:57:06 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969027; bh=71I3HIVpN19PnV02rVKuqjH2ieN+1GD/UXroLqS/oyE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=uVr1WLsKXUytSqJZllrEj6RuUoQFVAURHOoA9J94d8zcRihf9DfzgkAxoKXpSJSnU 3fjqR8oheuq5wfHX0pcqsee4Srsj9CbCxANOU4P3Xnp6mBMUwSgML50BZCe7J9Q472 50ebDUemGLLMiuz0P63AHsg79Jz3Y39LekKditds= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:27 +0300 Message-Id: <20210906225636.14683-21-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 21/30] cam: Add Image class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The new Image class represents a multi-planar image with direct access to pixel data. It currently duplicates the function of the MappedFrameBuffer class which is internal to libcamera, and will serve as a design playground to improve the API until it is considered ready to be made part of the libcamera public API. Signed-off-by: Laurent Pinchart Reviewed-by: Hirokazu Honda Reviewed-by: Kieran Bingham --- src/cam/image.cpp | 107 ++++++++++++++++++++++++++++++++++++++++++++ src/cam/image.h | 52 +++++++++++++++++++++ src/cam/meson.build | 1 + 3 files changed, 160 insertions(+) create mode 100644 src/cam/image.cpp create mode 100644 src/cam/image.h diff --git a/src/cam/image.cpp b/src/cam/image.cpp new file mode 100644 index 000000000000..7ae5f52dccb4 --- /dev/null +++ b/src/cam/image.cpp @@ -0,0 +1,107 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2021, Google Inc. + * + * image.cpp - Multi-planar image with access to pixel data + */ + +#include "image.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace libcamera; + +std::unique_ptr Image::fromFrameBuffer(const FrameBuffer *buffer, MapMode mode) +{ + std::unique_ptr image{ new Image() }; + + assert(!buffer->planes().empty()); + + int mmapFlags = 0; + + if (mode & MapMode::ReadOnly) + mmapFlags |= PROT_READ; + + if (mode & MapMode::WriteOnly) + mmapFlags |= PROT_WRITE; + + struct MappedBufferInfo { + uint8_t *address = nullptr; + size_t mapLength = 0; + size_t dmabufLength = 0; + }; + std::map mappedBuffers; + + for (const FrameBuffer::Plane &plane : buffer->planes()) { + const int fd = plane.fd.fd(); + if (mappedBuffers.find(fd) == mappedBuffers.end()) { + const size_t length = lseek(fd, 0, SEEK_END); + mappedBuffers[fd] = MappedBufferInfo{ nullptr, 0, length }; + } + + const size_t length = mappedBuffers[fd].dmabufLength; + + if (plane.offset > length || + plane.offset + plane.length > length) { + std::cerr << "plane is out of buffer: buffer length=" + << length << ", plane offset=" << plane.offset + << ", plane length=" << plane.length + << std::endl; + return nullptr; + } + size_t &mapLength = mappedBuffers[fd].mapLength; + mapLength = std::max(mapLength, + static_cast(plane.offset + plane.length)); + } + + for (const FrameBuffer::Plane &plane : buffer->planes()) { + const int fd = plane.fd.fd(); + auto &info = mappedBuffers[fd]; + if (!info.address) { + void *address = mmap(nullptr, info.mapLength, mmapFlags, + MAP_SHARED, fd, 0); + if (address == MAP_FAILED) { + int error = -errno; + std::cerr << "Failed to mmap plane: " + << strerror(-error) << std::endl; + return nullptr; + } + + info.address = static_cast(address); + image->maps_.emplace_back(info.address, info.mapLength); + } + + image->planes_.emplace_back(info.address + plane.offset, plane.length); + } + + return image; +} + +Image::Image() = default; + +Image::~Image() +{ + for (Span &map : maps_) + munmap(map.data(), map.size()); +} + +unsigned int Image::numPlanes() const +{ + return planes_.size(); +} + +Span Image::data(unsigned int plane) +{ + return planes_[plane]; +} + +Span Image::data(unsigned int plane) const +{ + return planes_[plane]; +} diff --git a/src/cam/image.h b/src/cam/image.h new file mode 100644 index 000000000000..1ce5f84e5f9e --- /dev/null +++ b/src/cam/image.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2021, Google Inc. + * + * image.h - Multi-planar image with access to pixel data + */ +#ifndef __CAM_IMAGE_H__ +#define __CAM_IMAGE_H__ + +#include +#include +#include + +#include +#include +#include + +#include + +class Image +{ +public: + enum class MapMode { + ReadOnly = 1 << 0, + WriteOnly = 1 << 1, + ReadWrite = ReadOnly | WriteOnly, + }; + + static std::unique_ptr fromFrameBuffer(const libcamera::FrameBuffer *buffer, + MapMode mode); + + ~Image(); + + unsigned int numPlanes() const; + + libcamera::Span data(unsigned int plane); + libcamera::Span data(unsigned int plane) const; + +private: + LIBCAMERA_DISABLE_COPY(Image) + + Image(); + + std::vector> maps_; + std::vector> planes_; +}; + +namespace libcamera { +LIBCAMERA_FLAGS_ENABLE_OPERATORS(Image::MapMode) +} + +#endif /* __CAM_IMAGE_H__ */ diff --git a/src/cam/meson.build b/src/cam/meson.build index ea36aaa5c514..e8e2ae57d3f4 100644 --- a/src/cam/meson.build +++ b/src/cam/meson.build @@ -14,6 +14,7 @@ cam_sources = files([ 'event_loop.cpp', 'file_sink.cpp', 'frame_sink.cpp', + 'image.cpp', 'main.cpp', 'options.cpp', 'stream_options.cpp', From patchwork Mon Sep 6 22:56:28 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13689 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 2CC4EBE175 for ; Mon, 6 Sep 2021 22:57:48 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id DE00569180; Tue, 7 Sep 2021 00:57:47 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="IcYJjze+"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C435F6917D for ; Tue, 7 Sep 2021 00:57:07 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 5A184B75; Tue, 7 Sep 2021 00:57:07 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969027; bh=9LYXnKijRFq02UZEC0V6piQFmCHLvjmAkL0qY8FYUGk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=IcYJjze+hTZoJet9CodqqPDcIPJ3XNAitZ2ZzRE+5qgTqDn2mPYF7Jil6Wyz+ZbvF sDn+WZnckQoXw+w079VqsGNAoVeAE6+1tfWj2HNXmQ5IHgJiZeTvaltB4zSSNUjDE7 YcPLjqdky96l4FDB3g39Pd6wTI5dN2ndumsTtvhU= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:28 +0300 Message-Id: <20210906225636.14683-22-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 22/30] cam: file_sink: Use Image class to access pixel data X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Replace the manual implementation of frame buffer mapping with the Image class to improve code sharing. Signed-off-by: Laurent Pinchart Reviewed-by: Jean-Michel Hautbois Reviewed-by: Hirokazu Honda Reviewed-by: Kieran Bingham --- src/cam/file_sink.cpp | 42 +++++++++++++----------------------------- src/cam/file_sink.h | 6 ++++-- 2 files changed, 17 insertions(+), 31 deletions(-) diff --git a/src/cam/file_sink.cpp b/src/cam/file_sink.cpp index 0fc7d621f50b..3c2e565b27a2 100644 --- a/src/cam/file_sink.cpp +++ b/src/cam/file_sink.cpp @@ -5,17 +5,18 @@ * file_sink.cpp - File Sink */ +#include #include #include #include #include #include -#include #include #include #include "file_sink.h" +#include "image.h" using namespace libcamera; @@ -26,12 +27,6 @@ FileSink::FileSink(const std::string &pattern) FileSink::~FileSink() { - for (auto &iter : mappedBuffers_) { - void *memory = iter.second.first; - unsigned int length = iter.second.second; - munmap(memory, length); - } - mappedBuffers_.clear(); } int FileSink::configure(const libcamera::CameraConfiguration &config) @@ -51,23 +46,11 @@ int FileSink::configure(const libcamera::CameraConfiguration &config) void FileSink::mapBuffer(FrameBuffer *buffer) { - /* \todo use MappedFrameBuffer. */ - for (const FrameBuffer::Plane &plane : buffer->planes()) { - const int fd = plane.fd.fd(); - if (mappedBuffers_.find(fd) == mappedBuffers_.end()) { - /** - * \todo Should we try to only map the portions of the - * dmabuf that are used by planes ? - */ - size_t length = lseek(fd, 0, SEEK_END); - void *memory = mmap(NULL, plane.length, PROT_READ, - MAP_SHARED, fd, 0); - mappedBuffers_[fd] = std::make_pair(memory, length); - } + std::unique_ptr image = + Image::fromFrameBuffer(buffer, Image::MapMode::ReadOnly); + assert(image != nullptr); - void *memory = mappedBuffers_[fd].first; - planeData_[&plane] = static_cast(memory) + plane.offset; - } + mappedBuffers_[buffer] = std::move(image); } bool FileSink::processRequest(Request *request) @@ -108,19 +91,20 @@ void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer) return; } + Image *image = mappedBuffers_[buffer].get(); + for (unsigned int i = 0; i < buffer->planes().size(); ++i) { - const FrameBuffer::Plane &plane = buffer->planes()[i]; const FrameMetadata::Plane &meta = buffer->metadata().planes()[i]; - uint8_t *data = planeData_[&plane]; - unsigned int length = std::min(meta.bytesused, plane.length); + Span data = image->data(i); + unsigned int length = std::min(meta.bytesused, data.size()); - if (meta.bytesused > plane.length) + if (meta.bytesused > data.size()) std::cerr << "payload size " << meta.bytesused - << " larger than plane size " << plane.length + << " larger than plane size " << data.size() << std::endl; - ret = ::write(fd, data, length); + ret = ::write(fd, data.data(), length); if (ret < 0) { ret = -errno; std::cerr << "write error: " << strerror(-ret) diff --git a/src/cam/file_sink.h b/src/cam/file_sink.h index c12325d955c5..335be93b8732 100644 --- a/src/cam/file_sink.h +++ b/src/cam/file_sink.h @@ -8,12 +8,15 @@ #define __CAM_FILE_SINK_H__ #include +#include #include #include #include "frame_sink.h" +class Image; + class FileSink : public FrameSink { public: @@ -32,8 +35,7 @@ private: std::map streamNames_; std::string pattern_; - std::map> mappedBuffers_; - std::map planeData_; + std::map> mappedBuffers_; }; #endif /* __CAM_FILE_SINK_H__ */ From patchwork Mon Sep 6 22:56:29 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13686 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 4935EBE175 for ; Mon, 6 Sep 2021 22:57:46 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id DDC2569174; Tue, 7 Sep 2021 00:57:45 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="DRqXsUMT"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2FB6969175 for ; Tue, 7 Sep 2021 00:57:08 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B4E3B891; Tue, 7 Sep 2021 00:57:07 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969027; bh=bqyQIZd68Xh74j2UCky+WnVOGaSWdFIBWkZ5Es1xQRg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=DRqXsUMTDvSNIKKg3sr98rKOaFe0sSHzyS9uXYhCoNhm3JlE+XtSh5XLWjSkd+MRH dz4BM0Ff51kelN0fPFaRvD9+zYCav06tVmF2ve+z2Jie+TYjqO9xZ6RCheFNCFON02 Vp04x9oV7UpTWkNlnElH+W/lFaT67HWBTO3mFn2U= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:29 +0300 Message-Id: <20210906225636.14683-23-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 23/30] cam: drm: Support per-plane stride values X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The stride is not always identical for all planes for multi-planar formats. Semi-planar YUV formats without horizontal subsampling often have a chroma stride equal to twice the luma stride, and tri-planar YUV formats with a 1/2 horizontal subsampling often have a chroma stride equal to half the luma stride. This isn't correctly taken into account when creating a DRM frame buffer, as the same stride is set for all planes. libcamera doesn't report per-plane stride values yet, but uses chroma strides that match the above description for all currently supported platforms. Calculation the chrome strides appropriately in the KMSSink class, and pass them to DRM::createFrameBuffer(). Signed-off-by: Laurent Pinchart Reviewed-by: Jean-Michel Hautbois Reviewed-by: Kieran Bingham --- src/cam/drm.cpp | 7 +++---- src/cam/drm.h | 5 ++++- src/cam/kms_sink.cpp | 28 +++++++++++++++++++++++++++- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/cam/drm.cpp b/src/cam/drm.cpp index da317e27cb19..ac47b8bd3287 100644 --- a/src/cam/drm.cpp +++ b/src/cam/drm.cpp @@ -595,12 +595,12 @@ const Object *Device::object(uint32_t id) std::unique_ptr Device::createFrameBuffer( const libcamera::FrameBuffer &buffer, const libcamera::PixelFormat &format, - const libcamera::Size &size, unsigned int stride) + const libcamera::Size &size, + const std::array &strides) { std::unique_ptr fb{ new FrameBuffer(this) }; uint32_t handles[4] = {}; - uint32_t pitches[4] = {}; uint32_t offsets[4] = {}; int ret; @@ -623,13 +623,12 @@ std::unique_ptr Device::createFrameBuffer( fb->planes_.push_back({ handle }); handles[i] = handle; - pitches[i] = stride; offsets[i] = 0; /* TODO */ ++i; } ret = drmModeAddFB2(fd_, size.width, size.height, format.fourcc(), handles, - pitches, offsets, &fb->id_, 0); + strides.data(), offsets, &fb->id_, 0); if (ret < 0) { ret = -errno; std::cerr diff --git a/src/cam/drm.h b/src/cam/drm.h index ee2304025208..00f7e798b771 100644 --- a/src/cam/drm.h +++ b/src/cam/drm.h @@ -7,9 +7,11 @@ #ifndef __CAM_DRM_H__ #define __CAM_DRM_H__ +#include #include #include #include +#include #include #include @@ -298,7 +300,8 @@ public: std::unique_ptr createFrameBuffer( const libcamera::FrameBuffer &buffer, const libcamera::PixelFormat &format, - const libcamera::Size &size, unsigned int stride); + const libcamera::Size &size, + const std::array &strides); libcamera::Signal requestComplete; diff --git a/src/cam/kms_sink.cpp b/src/cam/kms_sink.cpp index 8c0b79c63922..658192efc105 100644 --- a/src/cam/kms_sink.cpp +++ b/src/cam/kms_sink.cpp @@ -7,10 +7,12 @@ #include "kms_sink.h" +#include #include #include #include #include +#include #include #include @@ -65,8 +67,32 @@ KMSSink::KMSSink(const std::string &connectorName) void KMSSink::mapBuffer(libcamera::FrameBuffer *buffer) { + std::array strides = {}; + + /* \todo Should libcamera report per-plane strides ? */ + unsigned int uvStrideMultiplier; + + switch (format_) { + case libcamera::formats::NV24: + case libcamera::formats::NV42: + uvStrideMultiplier = 4; + break; + case libcamera::formats::YUV420: + case libcamera::formats::YVU420: + case libcamera::formats::YUV422: + uvStrideMultiplier = 1; + break; + default: + uvStrideMultiplier = 2; + break; + } + + strides[0] = stride_; + for (unsigned int i = 1; i < buffer->planes().size(); ++i) + strides[i] = stride_ * uvStrideMultiplier / 2; + std::unique_ptr drmBuffer = - dev_.createFrameBuffer(*buffer, format_, size_, stride_); + dev_.createFrameBuffer(*buffer, format_, size_, strides); if (!drmBuffer) return; From patchwork Mon Sep 6 22:56:30 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13690 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id EB6E0BE175 for ; Mon, 6 Sep 2021 22:57:48 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id A54B169174; Tue, 7 Sep 2021 00:57:48 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="NWpTdV8/"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9713B69170 for ; Tue, 7 Sep 2021 00:57:08 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 2092FB75; Tue, 7 Sep 2021 00:57:08 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969028; bh=BXti2I2EJ1iwmJVBwUsY40z4tz8z+d/4S8F8jRvmlTo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=NWpTdV8/CazNQH9hKFtnzbvdTJjTobBC3ydCf6Jhb/RG6D5smYFYsebckvIzyd+Ge 29ENwRDqkG63MYk/iFuWYf7MDFyLdQn4ZDcemmiL31I+JubIuQar9eZlklwCGhgAKg s+n1Sv65kyTEavEOigtp8usPe9DTaJT0Qkcsojig= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:30 +0300 Message-Id: <20210906225636.14683-24-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 24/30] cam: drm: Set per-plane offsets when creating DRM frame buffer X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Now that libcamera supports per-plane offsets, pass the values to drmModeAddFB2(). Signed-off-by: Laurent Pinchart Reviewed-by: Jean-Michel Hautbois Reviewed-by: Kieran Bingham --- src/cam/drm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cam/drm.cpp b/src/cam/drm.cpp index ac47b8bd3287..d5a75d039fd8 100644 --- a/src/cam/drm.cpp +++ b/src/cam/drm.cpp @@ -623,7 +623,7 @@ std::unique_ptr Device::createFrameBuffer( fb->planes_.push_back({ handle }); handles[i] = handle; - offsets[i] = 0; /* TODO */ + offsets[i] = plane.offset; ++i; } From patchwork Mon Sep 6 22:56:31 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13691 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 75252BE175 for ; Mon, 6 Sep 2021 22:57:49 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 3401C6917E; Tue, 7 Sep 2021 00:57:49 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="PrNYx+b9"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E9F6A69167 for ; Tue, 7 Sep 2021 00:57:08 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 87204891; Tue, 7 Sep 2021 00:57:08 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969028; bh=KGEkV/+jB/Kl24eWKUk1fHAkY97gdEaD0mhGkRoNyns=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=PrNYx+b94uUkhwggRNpMu9xf4GB7ZRgpzSdw/V2WQBtI9BLUzR7VYkmG1Z4Uet6AT xNuQ24AmVGnVJ2QdtgWSYaWpiFp8Au0DYkVB7L3Hh8g0vjRW1DVtHBhBB0iOG9K7n5 IEd3H1qVmkTbXlLo5xE+vZxOAaREV+K5DjK2GfWs= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:31 +0300 Message-Id: <20210906225636.14683-25-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 25/30] cam: drm: Avoid importing the same dmabuf multiple times X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" When creating a DRM frame buffer, the dmabufs for the planes are imported as GEM objects. For multi-planar formats, all planes may use the same dmabuf, which results in multiple imports. This doesn't cause any issue at import time, as DRM detects this situation and returns the same GEM object. However, when destroying the frame buffer, the same GEM object ends up being closed multiple times, which generates an error. Fix this by avoiding multiple imports of the same dmabuf for the same frame buffer. While the issue may theoretically occur with identical dmabufs for different frame buffers, this is quite unlikely and is thus not addressed. Signed-off-by: Laurent Pinchart Reviewed-by: Jean-Michel Hautbois Reviewed-by: Kieran Bingham --- src/cam/drm.cpp | 29 +++++++++++++++++------------ src/cam/drm.h | 2 +- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/cam/drm.cpp b/src/cam/drm.cpp index d5a75d039fd8..f25300913a7f 100644 --- a/src/cam/drm.cpp +++ b/src/cam/drm.cpp @@ -283,9 +283,9 @@ FrameBuffer::FrameBuffer(Device *dev) FrameBuffer::~FrameBuffer() { - for (FrameBuffer::Plane &plane : planes_) { + for (const auto &plane : planes_) { struct drm_gem_close gem_close = { - .handle = plane.handle, + .handle = plane.second.handle, .pad = 0, }; int ret; @@ -605,22 +605,27 @@ std::unique_ptr Device::createFrameBuffer( int ret; const std::vector &planes = buffer.planes(); - fb->planes_.reserve(planes.size()); unsigned int i = 0; for (const libcamera::FrameBuffer::Plane &plane : planes) { + int fd = plane.fd.fd(); uint32_t handle; - ret = drmPrimeFDToHandle(fd_, plane.fd.fd(), &handle); - if (ret < 0) { - ret = -errno; - std::cerr - << "Unable to import framebuffer dmabuf: " - << strerror(-ret) << std::endl; - return nullptr; - } + auto iter = fb->planes_.find(fd); + if (iter == fb->planes_.end()) { + ret = drmPrimeFDToHandle(fd_, plane.fd.fd(), &handle); + if (ret < 0) { + ret = -errno; + std::cerr + << "Unable to import framebuffer dmabuf: " + << strerror(-ret) << std::endl; + return nullptr; + } - fb->planes_.push_back({ handle }); + fb->planes_[fd] = { handle }; + } else { + handle = iter->second.handle; + } handles[i] = handle; offsets[i] = plane.offset; diff --git a/src/cam/drm.h b/src/cam/drm.h index 00f7e798b771..0b88f9a33912 100644 --- a/src/cam/drm.h +++ b/src/cam/drm.h @@ -242,7 +242,7 @@ private: FrameBuffer(Device *dev); - std::vector planes_; + std::map planes_; }; class AtomicRequest From patchwork Mon Sep 6 22:56:32 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13692 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 0DC58BE175 for ; Mon, 6 Sep 2021 22:57:50 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C9D5169189; Tue, 7 Sep 2021 00:57:49 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="W26jC5AG"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6CCB269178 for ; Tue, 7 Sep 2021 00:57:09 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E5D22993; Tue, 7 Sep 2021 00:57:08 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969029; bh=cSKnrdogwcNGPHLRhmFzlEpzq2IKVZJt43uev+8QhGU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=W26jC5AGmwDwcmcZKpen2mc3QpwW+EQa55GZEhyTbrlBXLFY2l9e55NofNDV4A6U0 ty9BCID3kqP2Pyhqxd2caDc7FBozKIZVssOHKYkCS6xu9g+EHE3mKmrpBixomLf2t5 ej6ortP265QaAe92epjDGpioegARTes8V7H5l2do= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:32 +0300 Message-Id: <20210906225636.14683-26-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 26/30] qcam: Print bytesused for all planes X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Fix the debug message that prints frame metadata to print the number of bytes used for each plane, not just the first one. Signed-off-by: Laurent Pinchart Reviewed-by: Jean-Michel Hautbois Reviewed-by: Kieran Bingham --- src/qcam/main_window.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index ac853e360aea..0a00b1001570 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -754,9 +755,13 @@ void MainWindow::processViewfinder(FrameBuffer *buffer) fps = lastBufferTime_ && fps ? 1000000000.0 / fps : 0.0; lastBufferTime_ = metadata.timestamp; + QStringList bytesused; + for (const FrameMetadata::Plane &plane : metadata.planes()) + bytesused << QString::number(plane.bytesused); + qDebug().noquote() << QString("seq: %1").arg(metadata.sequence, 6, 10, QLatin1Char('0')) - << "bytesused:" << metadata.planes()[0].bytesused + << "bytesused:" << bytesused.join("/") << "timestamp:" << metadata.timestamp << "fps:" << Qt::fixed << qSetRealNumberPrecision(2) << fps; From patchwork Mon Sep 6 22:56:33 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13693 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id B35E9BE175 for ; Mon, 6 Sep 2021 22:57:50 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6888F69168; Tue, 7 Sep 2021 00:57:50 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="IYy/keTp"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B7C9A6918E for ; Tue, 7 Sep 2021 00:57:09 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 52530891; Tue, 7 Sep 2021 00:57:09 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969029; bh=FQyMhKOgdpFBah23uV5iA8J43CwjXu3uyYsE0tW5buY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=IYy/keTpUyxqEEzGXzorhpTFKLExh4wPHG3RjADb4IAR8ZhImtZo65mHK4zl7yhMc W2HuVjn9HY8bbEC2GosWcZijKmMyEMZgYTSZkPFVMHTYyOmGl+z0HBjsfa8zuRBjeF /s6xUBq2mvOtAktzydjhjoTdAARD175poWAsTtvs= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:33 +0300 Message-Id: <20210906225636.14683-27-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 27/30] qcam: Use Image class to access pixel data X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Replace the manual implementation of frame buffer mapping with the Image class to improve code sharing. The ViewFinder API is updated to take an Image pointer in the render() function to prepare for multi-planar buffer support. Signed-off-by: Laurent Pinchart Reviewed-by: Jean-Michel Hautbois Reviewed-by: Kieran Bingham --- src/qcam/main_window.cpp | 31 ++++++++----------------------- src/qcam/main_window.h | 4 ++-- src/qcam/meson.build | 1 + src/qcam/viewfinder.h | 6 +++--- src/qcam/viewfinder_gl.cpp | 7 ++++--- src/qcam/viewfinder_gl.h | 2 +- src/qcam/viewfinder_qt.cpp | 6 +++--- src/qcam/viewfinder_qt.h | 2 +- 8 files changed, 23 insertions(+), 36 deletions(-) diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index 0a00b1001570..168dd5ce30e3 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -7,10 +7,9 @@ #include "main_window.h" +#include #include #include -#include -#include #include #include @@ -29,6 +28,7 @@ #include #include +#include "../cam/image.h" #include "dng_writer.h" #ifndef QT_NO_OPENGL #include "viewfinder_gl.h" @@ -473,15 +473,10 @@ int MainWindow::startCapture() for (const std::unique_ptr &buffer : allocator_->buffers(stream)) { /* Map memory buffers and cache the mappings. */ - const FrameBuffer::Plane &plane = buffer->planes().front(); - size_t length = lseek(plane.fd.fd(), 0, SEEK_END); - void *memory = mmap(NULL, length, PROT_READ, MAP_SHARED, - plane.fd.fd(), 0); - - mappedBuffers_[buffer.get()] = { static_cast(memory), - plane.length }; - planeData_[buffer.get()] = { static_cast(memory) + plane.offset, - plane.length }; + std::unique_ptr image = + Image::fromFrameBuffer(buffer.get(), Image::MapMode::ReadOnly); + assert(image != nullptr); + mappedBuffers_[buffer.get()] = std::move(image); /* Store buffers on the free list. */ freeBuffers_[stream].enqueue(buffer.get()); @@ -543,12 +538,7 @@ error_disconnect: error: requests_.clear(); - for (auto &iter : mappedBuffers_) { - const Span &buffer = iter.second; - munmap(buffer.data(), buffer.size()); - } mappedBuffers_.clear(); - planeData_.clear(); freeBuffers_.clear(); @@ -580,12 +570,7 @@ void MainWindow::stopCapture() camera_->requestCompleted.disconnect(this); - for (auto &iter : mappedBuffers_) { - const Span &buffer = iter.second; - munmap(buffer.data(), buffer.size()); - } mappedBuffers_.clear(); - planeData_.clear(); requests_.clear(); freeQueue_.clear(); @@ -682,7 +667,7 @@ void MainWindow::processRaw(FrameBuffer *buffer, "DNG Files (*.dng)"); if (!filename.isEmpty()) { - uint8_t *memory = planeData_[buffer].data(); + uint8_t *memory = mappedBuffers_[buffer]->data(0).data(); DNGWriter::write(filename.toStdString().c_str(), camera_.get(), rawStream_->configuration(), metadata, buffer, memory); @@ -766,7 +751,7 @@ void MainWindow::processViewfinder(FrameBuffer *buffer) << "fps:" << Qt::fixed << qSetRealNumberPrecision(2) << fps; /* Render the frame on the viewfinder. */ - viewfinder_->render(buffer, planeData_[buffer]); + viewfinder_->render(buffer, mappedBuffers_[buffer].get()); } void MainWindow::queueRequest(FrameBuffer *buffer) diff --git a/src/qcam/main_window.h b/src/qcam/main_window.h index 28244bca58b2..a16bea09eadc 100644 --- a/src/qcam/main_window.h +++ b/src/qcam/main_window.h @@ -34,6 +34,7 @@ using namespace libcamera; class QAction; class QComboBox; +class Image; class HotplugEvent; enum { @@ -106,8 +107,7 @@ private: FrameBufferAllocator *allocator_; std::unique_ptr config_; - std::map> mappedBuffers_; - std::map> planeData_; + std::map> mappedBuffers_; /* Capture state, buffers queue and statistics */ bool isCapturing_; diff --git a/src/qcam/meson.build b/src/qcam/meson.build index 7d3621c93d41..c46f463130cd 100644 --- a/src/qcam/meson.build +++ b/src/qcam/meson.build @@ -15,6 +15,7 @@ endif qcam_enabled = true qcam_sources = files([ + '../cam/image.cpp', '../cam/options.cpp', '../cam/stream_options.cpp', 'format_converter.cpp', diff --git a/src/qcam/viewfinder.h b/src/qcam/viewfinder.h index 42d40f1f33f0..fb462835fb5f 100644 --- a/src/qcam/viewfinder.h +++ b/src/qcam/viewfinder.h @@ -11,11 +11,11 @@ #include #include -#include - #include #include +class Image; + class ViewFinder { public: @@ -24,7 +24,7 @@ public: virtual const QList &nativeFormats() const = 0; virtual int setFormat(const libcamera::PixelFormat &format, const QSize &size) = 0; - virtual void render(libcamera::FrameBuffer *buffer, libcamera::Span mem) = 0; + virtual void render(libcamera::FrameBuffer *buffer, Image *image) = 0; virtual void stop() = 0; virtual QImage getCurrentImage() = 0; diff --git a/src/qcam/viewfinder_gl.cpp b/src/qcam/viewfinder_gl.cpp index d2ef036974f4..87e4fe03cb8d 100644 --- a/src/qcam/viewfinder_gl.cpp +++ b/src/qcam/viewfinder_gl.cpp @@ -13,6 +13,8 @@ #include +#include "../cam/image.h" + static const QList supportedFormats{ /* YUV - packed (single plane) */ libcamera::formats::UYVY, @@ -110,8 +112,7 @@ QImage ViewFinderGL::getCurrentImage() return grabFramebuffer(); } -void ViewFinderGL::render(libcamera::FrameBuffer *buffer, - libcamera::Span mem) +void ViewFinderGL::render(libcamera::FrameBuffer *buffer, Image *image) { if (buffer->planes().size() != 1) { qWarning() << "Multi-planar buffers are not supported"; @@ -121,7 +122,7 @@ void ViewFinderGL::render(libcamera::FrameBuffer *buffer, if (buffer_) renderComplete(buffer_); - data_ = mem.data(); + data_ = image->data(0).data(); /* * \todo Get the stride from the buffer instead of computing it naively */ diff --git a/src/qcam/viewfinder_gl.h b/src/qcam/viewfinder_gl.h index 3334549e0be4..7cd8ef3316b9 100644 --- a/src/qcam/viewfinder_gl.h +++ b/src/qcam/viewfinder_gl.h @@ -39,7 +39,7 @@ public: const QList &nativeFormats() const override; int setFormat(const libcamera::PixelFormat &format, const QSize &size) override; - void render(libcamera::FrameBuffer *buffer, libcamera::Span mem) override; + void render(libcamera::FrameBuffer *buffer, Image *image) override; void stop() override; QImage getCurrentImage() override; diff --git a/src/qcam/viewfinder_qt.cpp b/src/qcam/viewfinder_qt.cpp index a0bf99b0b522..fef6d53eef5e 100644 --- a/src/qcam/viewfinder_qt.cpp +++ b/src/qcam/viewfinder_qt.cpp @@ -19,6 +19,7 @@ #include +#include "../cam/image.h" #include "format_converter.h" static const QMap nativeFormats @@ -78,15 +79,14 @@ int ViewFinderQt::setFormat(const libcamera::PixelFormat &format, return 0; } -void ViewFinderQt::render(libcamera::FrameBuffer *buffer, - libcamera::Span mem) +void ViewFinderQt::render(libcamera::FrameBuffer *buffer, Image *image) { if (buffer->planes().size() != 1) { qWarning() << "Multi-planar buffers are not supported"; return; } - unsigned char *memory = mem.data(); + unsigned char *memory = image->data(0).data(); size_t size = buffer->metadata().planes()[0].bytesused; { diff --git a/src/qcam/viewfinder_qt.h b/src/qcam/viewfinder_qt.h index 1a569b9cee6e..6b48ef48a7d1 100644 --- a/src/qcam/viewfinder_qt.h +++ b/src/qcam/viewfinder_qt.h @@ -32,7 +32,7 @@ public: const QList &nativeFormats() const override; int setFormat(const libcamera::PixelFormat &format, const QSize &size) override; - void render(libcamera::FrameBuffer *buffer, libcamera::Span mem) override; + void render(libcamera::FrameBuffer *buffer, Image *image) override; void stop() override; QImage getCurrentImage() override; From patchwork Mon Sep 6 22:56:34 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13694 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 4F606BE175 for ; Mon, 6 Sep 2021 22:57:51 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 03E9F69185; Tue, 7 Sep 2021 00:57:51 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="cBvLb4kf"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2F2236918A for ; Tue, 7 Sep 2021 00:57:10 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id ACB44993; Tue, 7 Sep 2021 00:57:09 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969029; bh=mjp6bsNyrmQYd+BbqSpInOVicnd2/UieEMCHU/KAj4g=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=cBvLb4kfbJWZkxpC22qvt40OtzHLlDyPKC7ft1aRh0BlskJL7OhhuZwLBVe9f7mc9 29hhH417R4kx4LTjSPSUMyqV2DlXHexXk/au/mulFHwqGRUWeDElMlLxqo0rp3K1Kk NkhsZCwnMH/SqZKm5MkgnnAhyos46xRuthg/wz6s= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:34 +0300 Message-Id: <20210906225636.14683-28-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 28/30] qcam: viewfinder_gl: Support multi-planar buffers X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Now that the ViewFinderGL receives an Image, it can trivially support multi-planar buffers. Signed-off-by: Laurent Pinchart Reviewed-by: Jean-Michel Hautbois Reviewed-by: Kieran Bingham --- src/qcam/viewfinder_gl.cpp | 38 +++++++++++++++++--------------------- src/qcam/viewfinder_gl.h | 2 +- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/qcam/viewfinder_gl.cpp b/src/qcam/viewfinder_gl.cpp index 87e4fe03cb8d..32232faa2ad8 100644 --- a/src/qcam/viewfinder_gl.cpp +++ b/src/qcam/viewfinder_gl.cpp @@ -56,7 +56,7 @@ static const QList supportedFormats{ }; ViewFinderGL::ViewFinderGL(QWidget *parent) - : QOpenGLWidget(parent), buffer_(nullptr), data_(nullptr), + : QOpenGLWidget(parent), buffer_(nullptr), image_(nullptr), vertexBuffer_(QOpenGLBuffer::VertexBuffer) { } @@ -102,6 +102,7 @@ void ViewFinderGL::stop() if (buffer_) { renderComplete(buffer_); buffer_ = nullptr; + image_ = nullptr; } } @@ -114,15 +115,10 @@ QImage ViewFinderGL::getCurrentImage() void ViewFinderGL::render(libcamera::FrameBuffer *buffer, Image *image) { - if (buffer->planes().size() != 1) { - qWarning() << "Multi-planar buffers are not supported"; - return; - } - if (buffer_) renderComplete(buffer_); - data_ = image->data(0).data(); + image_ = image; /* * \todo Get the stride from the buffer instead of computing it naively */ @@ -489,7 +485,7 @@ void ViewFinderGL::doRender() 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, - data_); + image_->data(0).data()); shaderProgram_.setUniformValue(textureUniformY_, 0); /* Activate texture UV/VU */ @@ -503,7 +499,7 @@ void ViewFinderGL::doRender() 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, - data_ + size_.width() * size_.height()); + image_->data(1).data()); shaderProgram_.setUniformValue(textureUniformU_, 1); break; @@ -519,7 +515,7 @@ void ViewFinderGL::doRender() 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, - data_); + image_->data(0).data()); shaderProgram_.setUniformValue(textureUniformY_, 0); /* Activate texture U */ @@ -533,7 +529,7 @@ void ViewFinderGL::doRender() 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, - data_ + size_.width() * size_.height()); + image_->data(1).data()); shaderProgram_.setUniformValue(textureUniformU_, 1); /* Activate texture V */ @@ -547,7 +543,7 @@ void ViewFinderGL::doRender() 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, - data_ + size_.width() * size_.height() * 5 / 4); + image_->data(2).data()); shaderProgram_.setUniformValue(textureUniformV_, 2); break; @@ -563,7 +559,7 @@ void ViewFinderGL::doRender() 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, - data_); + image_->data(0).data()); shaderProgram_.setUniformValue(textureUniformY_, 0); /* Activate texture V */ @@ -577,7 +573,7 @@ void ViewFinderGL::doRender() 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, - data_ + size_.width() * size_.height()); + image_->data(1).data()); shaderProgram_.setUniformValue(textureUniformV_, 2); /* Activate texture U */ @@ -591,7 +587,7 @@ void ViewFinderGL::doRender() 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, - data_ + size_.width() * size_.height() * 5 / 4); + image_->data(2).data()); shaderProgram_.setUniformValue(textureUniformU_, 1); break; @@ -602,7 +598,7 @@ void ViewFinderGL::doRender() /* * Packed YUV formats are stored in a RGBA texture to match the * OpenGL texel size with the 4 bytes repeating pattern in YUV. - * The texture width is thus half of the image with. + * The texture width is thus half of the image_ with. */ glActiveTexture(GL_TEXTURE0); configureTexture(*textures_[0]); @@ -614,7 +610,7 @@ void ViewFinderGL::doRender() 0, GL_RGBA, GL_UNSIGNED_BYTE, - data_); + image_->data(0).data()); shaderProgram_.setUniformValue(textureUniformY_, 0); /* @@ -642,7 +638,7 @@ void ViewFinderGL::doRender() 0, GL_RGBA, GL_UNSIGNED_BYTE, - data_); + image_->data(0).data()); shaderProgram_.setUniformValue(textureUniformY_, 0); break; @@ -658,7 +654,7 @@ void ViewFinderGL::doRender() 0, GL_RGB, GL_UNSIGNED_BYTE, - data_); + image_->data(0).data()); shaderProgram_.setUniformValue(textureUniformY_, 0); break; @@ -689,7 +685,7 @@ void ViewFinderGL::doRender() 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, - data_); + image_->data(0).data()); shaderProgram_.setUniformValue(textureUniformY_, 0); shaderProgram_.setUniformValue(textureUniformBayerFirstRed_, firstRed_); @@ -714,7 +710,7 @@ void ViewFinderGL::paintGL() << "create fragment shader failed."; } - if (data_) { + if (image_) { glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); diff --git a/src/qcam/viewfinder_gl.h b/src/qcam/viewfinder_gl.h index 7cd8ef3316b9..72a60ecb9159 100644 --- a/src/qcam/viewfinder_gl.h +++ b/src/qcam/viewfinder_gl.h @@ -67,7 +67,7 @@ private: libcamera::PixelFormat format_; QSize size_; unsigned int stride_; - unsigned char *data_; + Image *image_; /* Shaders */ QOpenGLShaderProgram shaderProgram_; From patchwork Mon Sep 6 22:56:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13695 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id DFC03BE175 for ; Mon, 6 Sep 2021 22:57:51 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 9041A69183; Tue, 7 Sep 2021 00:57:51 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="X5r24nes"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8AE416918F for ; Tue, 7 Sep 2021 00:57:10 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 1F1D3891; Tue, 7 Sep 2021 00:57:10 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969030; bh=n1xRmqPZP79JZhVkH8ut6hJd9fcaLnQmjUZPiPaLC0k=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=X5r24nesUBJW5oeDP6feW0FjNFU7b6GsvipmMR2uw+V/1hiGhmW/8rJ32YUzusGOB CP3QsgO7x5drFk7QEZErIldZ1sNcqFRhGxHUbUL2QEZFH6HvWUB6L7Dz0oeQOdba9k F9WdV7FGcGhMnQ2/tIqhnMfk2rs2h14Nuu2cAKbE= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:35 +0300 Message-Id: <20210906225636.14683-29-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 29/30] qcam: viewfinder_qt: Support multi-planar buffers X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Now that the ViewFinderQt receives an Image, move the Converter API to take an Image as well, and enable multi-planar buffer support. Signed-off-by: Laurent Pinchart Reviewed-by: Jean-Michel Hautbois Reviewed-by: Kieran Bingham --- src/qcam/format_converter.cpp | 18 +++++++++++------- src/qcam/format_converter.h | 9 +++++---- src/qcam/viewfinder_qt.cpp | 14 +++++--------- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/qcam/format_converter.cpp b/src/qcam/format_converter.cpp index 973966f6afc1..673ad33e141d 100644 --- a/src/qcam/format_converter.cpp +++ b/src/qcam/format_converter.cpp @@ -13,6 +13,8 @@ #include +#include "../cam/image.h" + #define RGBSHIFT 8 #ifndef MAX #define MAX(a,b) ((a)>(b)?(a):(b)) @@ -154,12 +156,11 @@ int FormatConverter::configure(const libcamera::PixelFormat &format, return 0; } -void FormatConverter::convert(const unsigned char *src, size_t size, - QImage *dst) +void FormatConverter::convert(const Image *src, size_t size, QImage *dst) { switch (formatFamily_) { case MJPEG: - dst->loadFromData(src, size, "JPEG"); + dst->loadFromData(src->data(0).data(), size, "JPEG"); break; case YUV: convertYUV(src, dst->bits()); @@ -183,13 +184,14 @@ static void yuv_to_rgb(int y, int u, int v, int *r, int *g, int *b) *b = CLIP(( 298 * c + 516 * d + 128) >> RGBSHIFT); } -void FormatConverter::convertNV(const unsigned char *src, unsigned char *dst) +void FormatConverter::convertNV(const Image *srcImage, unsigned char *dst) { unsigned int c_stride = width_ * (2 / horzSubSample_); unsigned int c_inc = horzSubSample_ == 1 ? 2 : 0; unsigned int cb_pos = nvSwap_ ? 1 : 0; unsigned int cr_pos = nvSwap_ ? 0 : 1; - const unsigned char *src_c = src + width_ * height_; + const unsigned char *src = srcImage->data(0).data(); + const unsigned char *src_c = srcImage->data(1).data(); int r, g, b; for (unsigned int y = 0; y < height_; y++) { @@ -223,8 +225,9 @@ void FormatConverter::convertNV(const unsigned char *src, unsigned char *dst) } } -void FormatConverter::convertRGB(const unsigned char *src, unsigned char *dst) +void FormatConverter::convertRGB(const Image *srcImage, unsigned char *dst) { + const unsigned char *src = srcImage->data(0).data(); unsigned int x, y; int r, g, b; @@ -245,8 +248,9 @@ void FormatConverter::convertRGB(const unsigned char *src, unsigned char *dst) } } -void FormatConverter::convertYUV(const unsigned char *src, unsigned char *dst) +void FormatConverter::convertYUV(const Image *srcImage, unsigned char *dst) { + const unsigned char *src = srcImage->data(0).data(); unsigned int src_x, src_y, dst_x, dst_y; unsigned int src_stride; unsigned int dst_stride; diff --git a/src/qcam/format_converter.h b/src/qcam/format_converter.h index e389b24a69f7..2220a62b5f11 100644 --- a/src/qcam/format_converter.h +++ b/src/qcam/format_converter.h @@ -13,6 +13,7 @@ #include +class Image; class QImage; class FormatConverter @@ -20,7 +21,7 @@ class FormatConverter public: int configure(const libcamera::PixelFormat &format, const QSize &size); - void convert(const unsigned char *src, size_t size, QImage *dst); + void convert(const Image *src, size_t size, QImage *dst); private: enum FormatFamily { @@ -30,9 +31,9 @@ private: YUV, }; - void convertNV(const unsigned char *src, unsigned char *dst); - void convertRGB(const unsigned char *src, unsigned char *dst); - void convertYUV(const unsigned char *src, unsigned char *dst); + void convertNV(const Image *src, unsigned char *dst); + void convertRGB(const Image *src, unsigned char *dst); + void convertYUV(const Image *src, unsigned char *dst); libcamera::PixelFormat format_; unsigned int width_; diff --git a/src/qcam/viewfinder_qt.cpp b/src/qcam/viewfinder_qt.cpp index fef6d53eef5e..0d357d860014 100644 --- a/src/qcam/viewfinder_qt.cpp +++ b/src/qcam/viewfinder_qt.cpp @@ -7,6 +7,7 @@ #include "viewfinder_qt.h" +#include #include #include @@ -81,12 +82,6 @@ int ViewFinderQt::setFormat(const libcamera::PixelFormat &format, void ViewFinderQt::render(libcamera::FrameBuffer *buffer, Image *image) { - if (buffer->planes().size() != 1) { - qWarning() << "Multi-planar buffers are not supported"; - return; - } - - unsigned char *memory = image->data(0).data(); size_t size = buffer->metadata().planes()[0].bytesused; { @@ -103,8 +98,9 @@ void ViewFinderQt::render(libcamera::FrameBuffer *buffer, Image *image) * \todo Get the stride from the buffer instead of * computing it naively */ - image_ = QImage(memory, size_.width(), size_.height(), - size / size_.height(), + assert(buffer->planes().size() == 1); + image_ = QImage(image->data(0).data(), size_.width(), + size_.height(), size / size_.height(), ::nativeFormats[format_]); std::swap(buffer, buffer_); } else { @@ -112,7 +108,7 @@ void ViewFinderQt::render(libcamera::FrameBuffer *buffer, Image *image) * Otherwise, convert the format and release the frame * buffer immediately. */ - converter_.convert(memory, size, &image_); + converter_.convert(image, size, &image_); } } From patchwork Mon Sep 6 22:56:36 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13696 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 66998BE175 for ; Mon, 6 Sep 2021 22:57:52 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 280E36917A; Tue, 7 Sep 2021 00:57:52 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="ZqFylIcb"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E5ADE69168 for ; Tue, 7 Sep 2021 00:57:10 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 7E3FF993; Tue, 7 Sep 2021 00:57:10 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630969030; bh=uk/1IISMeHUL+xlquqyQPEOm8yec0VB/3HEvPxfYe94=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ZqFylIcbzVkCiYQZgDiXfcArn/KfHCOMB9dpmHBEhP/cywo6rDDzPboYcdfYFc8jI Oa1lbrK7bcepZcDRRN3krixYHzZZGY327x4/ygpv5OoTfoWk562WoMefUgynufr1/Z 3PAt3/iS26Ynis2SvgDOBcQmEIj3DqODOPd/mUw0= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 01:56:36 +0300 Message-Id: <20210906225636.14683-30-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> References: <20210906225420.13275-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 30/30] v4l2: Sum bytesused for all planes when dequeuing buffer X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The V4L2 compatibility layer supports the single-planar API only, and thuss expose a single V4L2 buffer plane to applications, regardless of the number of planes in the FrameBuffer. For multi-planar frame buffers, the bytesused value isn't correct as it only takes the first plane into account. Fix it by summing the bytesused values for all FrameBuffer planes. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Reviewed-by: Jean-Michel Hautbois --- src/v4l2/v4l2_camera_proxy.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 07d2250bb846..aeffef26c5bf 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -211,7 +212,11 @@ void V4L2CameraProxy::updateBuffers() switch (fmd.status) { case FrameMetadata::FrameSuccess: - buf.bytesused = fmd.planes()[0].bytesused; + buf.bytesused = std::accumulate(fmd.planes().begin(), + fmd.planes().end(), 0, + [](unsigned int total, const auto &plane) { + return total + plane.bytesused; + }); buf.field = V4L2_FIELD_NONE; buf.timestamp.tv_sec = fmd.timestamp / 1000000000; buf.timestamp.tv_usec = fmd.timestamp % 1000000;