From patchwork Tue Sep 7 15:44:41 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13725 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 6F369BE175 for ; Tue, 7 Sep 2021 15:45:07 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id CD1A160252; Tue, 7 Sep 2021 17:45: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="GU0G2FPP"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0718260251 for ; Tue, 7 Sep 2021 17:45: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 772A424F for ; Tue, 7 Sep 2021 17:45:04 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1631029504; bh=eq08UapOkJQAmbYjCNFjChyajMyKbqL68F7mZpHwUaE=; h=From:To:Subject:Date:In-Reply-To:References:From; b=GU0G2FPPSnI7Zw9dTAK+hJir5MOqcsgsF9UrX6Cc+xBQzlX3FkA8G7sH2LBNqLPFf JuA8uRXz7N8h0gyiJrHUykQfjkIAjB0YFpgKO8o7wRE9EY6kPyv2AGGaoyRMq6FG21 g6Q0VQhDP1vM1TnidTzJABUCpckDm1LjcZzHjGt0= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 18:44:41 +0300 Message-Id: <20210907154441.10993-1-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225636.14683-3-laurent.pinchart@ideasonboard.com> References: <20210906225636.14683-3-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3.1 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 --- Changes since v3: - Update documentation --- Documentation/guides/pipeline-handler.rst | 7 +++---- 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 +-- 12 files changed, 26 insertions(+), 47 deletions(-) diff --git a/Documentation/guides/pipeline-handler.rst b/Documentation/guides/pipeline-handler.rst index 54c8e7f1f553..c0fb71478a09 100644 --- a/Documentation/guides/pipeline-handler.rst +++ b/Documentation/guides/pipeline-handler.rst @@ -970,8 +970,7 @@ with the fourcc and size attributes to apply directly to the capture device node. The fourcc attribute is a `V4L2PixelFormat`_ and differs from the ``libcamera::PixelFormat``. Converting the format requires knowledge of the plane configuration for multiplanar formats, so you must explicitly convert it -using the helper ``V4L2VideoDevice::toV4L2PixelFormat()`` provided by the -V4L2VideoDevice instance of which the format will be applied on. +using the helper ``V4L2PixelFormat::fromPixelFormat()``. .. _V4L2DeviceFormat: http://libcamera.org/api-html/classlibcamera_1_1V4L2DeviceFormat.html .. _V4L2PixelFormat: http://libcamera.org/api-html/classlibcamera_1_1V4L2PixelFormat.html @@ -981,7 +980,7 @@ Add the following code beneath the code from above: .. code-block:: cpp V4L2DeviceFormat format = {}; - format.fourcc = data->video_->toV4L2PixelFormat(cfg.pixelFormat); + format.fourcc = V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat); format.size = cfg.size; Set the video device format defined above using the @@ -1001,7 +1000,7 @@ Continue the implementation with the following code: return ret; if (format.size != cfg.size || - format.fourcc != data->video_->toV4L2PixelFormat(cfg.pixelFormat)) + format.fourcc != V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat)) return -EINVAL; Finally, store and set stream-specific data reflecting the state of the stream. 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 Tue Sep 7 15:45: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: 13726 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 D6C4FBE175 for ; Tue, 7 Sep 2021 15:45:40 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id A576F60251; Tue, 7 Sep 2021 17:45: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="QmCTIL2/"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 33EB860251 for ; Tue, 7 Sep 2021 17:45:39 +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 D26E124F for ; Tue, 7 Sep 2021 17:45:38 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1631029539; bh=Lsfo+IBj6wF6c+BtwxgXBPUqK82cqzQqBH9sGc8LXnM=; h=From:To:Subject:Date:In-Reply-To:References:From; b=QmCTIL2/mNWuLMAjft2dlxETuhRfI1u6+TyNPLe4PXbUeYNPL8SVNpxYRfmjPXfFu 9j1YnKJLnV1dDnDZbMAKtQgIyVi8RNRH1htRcekeP4kEM8lCiVT0DydeZ8/HAONAPm yQbGBqOsASB+2a+Laa3JzeY03bLRsLkx1UQB+y/8= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 18:45:17 +0300 Message-Id: <20210907154517.11140-1-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225636.14683-5-laurent.pinchart@ideasonboard.com> References: <20210906225636.14683-5-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3.1 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 Reviewed-by: Paul Elder --- Changes since v3: - Use \struct instead of \class - Move the comment block to the right place --- include/libcamera/internal/formats.h | 13 +++++----- src/libcamera/formats.cpp | 38 ++++++++++++++-------------- 2 files changed, 25 insertions(+), 26 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..1e5c8a0c36dc 100644 --- a/src/libcamera/formats.cpp +++ b/src/libcamera/formats.cpp @@ -23,22 +23,6 @@ namespace libcamera { LOG_DEFINE_CATEGORY(Formats) -/** - * \class PixelFormatPlaneInfo - * \brief Information about a single plane of a pixel format - * - * \var PixelFormatPlaneInfo::bytesPerGroup - * \brief The number of bytes that a pixel group consumes - * - * \sa PixelFormatInfo::pixelsPerGroup - * - * \var PixelFormatPlaneInfo::verticalSubSampling - * \brief Vertical subsampling multiplier - * - * This value is the ratio between the number of rows of pixels in the frame - * to the number of rows of pixels in the plane. - */ - /** * \class PixelFormatInfo * \brief Information about pixel formats @@ -87,7 +71,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 +106,7 @@ LOG_DEFINE_CATEGORY(Formats) * \var PixelFormatInfo::planes * \brief Information about pixels for each plane * - * \sa PixelFormatPlaneInfo + * \sa PixelFormatInfo::Plane */ /** @@ -139,6 +123,22 @@ LOG_DEFINE_CATEGORY(Formats) * \brief RAW colour encoding */ +/** + * \struct PixelFormatInfo::Plane + * \brief Information about a single plane of a pixel format + * + * \var PixelFormatInfo::Plane::bytesPerGroup + * \brief The number of bytes that a pixel group consumes + * + * \sa PixelFormatInfo::pixelsPerGroup + * + * \var PixelFormatInfo::Plane::verticalSubSampling + * \brief Vertical subsampling multiplier + * + * This value is the ratio between the number of rows of pixels in the frame + * to the number of rows of pixels in the plane. + */ + namespace { const PixelFormatInfo pixelFormatInfoInvalid{}; @@ -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 Tue Sep 7 15:45:38 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13727 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 582F0BE175 for ; Tue, 7 Sep 2021 15:46:03 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 14C546916D; Tue, 7 Sep 2021 17:46:03 +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="MXSeADA/"; 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 CCFF760251 for ; Tue, 7 Sep 2021 17:46: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 6F32B24F for ; Tue, 7 Sep 2021 17:46:00 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1631029560; bh=RzzAHeTQRy09sCO0oyZDnSzsJ03TiRC9oGqd/zRJ4tA=; h=From:To:Subject:Date:In-Reply-To:References:From; b=MXSeADA/m7H2V61wiJvJfYelP4EgEMSGF6EeZp2DbzSzc4yWFjy+B5CE43guTL8yD EQ+micVnPgnZsQ3dH3L4V6R1nmi4xxU3ssp/kyyri5UhA3auGBOVIowIUrKaYQckid 1AcZblkT1hiiwppbJgMENpP+sYafNs4DY9HDt2rM= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 18:45:38 +0300 Message-Id: <20210907154538.11231-1-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225636.14683-17-laurent.pinchart@ideasonboard.com> References: <20210906225636.14683-17-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3.1 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 --- Changes since v3: - Update documentation --- Documentation/guides/application-developer.rst | 4 ++-- 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 +- 10 files changed, 34 insertions(+), 20 deletions(-) diff --git a/Documentation/guides/application-developer.rst b/Documentation/guides/application-developer.rst index 462efe2411fc..84e522c01c85 100644 --- a/Documentation/guides/application-developer.rst +++ b/Documentation/guides/application-developer.rst @@ -427,10 +427,10 @@ the Frame sequence number and details of the planes. std::cout << " seq: " << std::setw(6) << std::setfill('0') << metadata.sequence << " bytesused: "; unsigned int nplane = 0; - for (const FrameMetadata::Plane &plane : metadata.planes) + for (const FrameMetadata::Plane &plane : metadata.planes()) { std::cout << plane.bytesused; - if (++nplane < metadata.planes.size()) std::cout << "/"; + if (++nplane < metadata.planes().size()) std::cout << "/"; } std::cout << std::endl; 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 Tue Sep 7 15:46:06 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13728 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 E15ADBE175 for ; Tue, 7 Sep 2021 15:46:29 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id B15A16916C; Tue, 7 Sep 2021 17:46:29 +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="aGrOsGj6"; 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 8E69460251 for ; Tue, 7 Sep 2021 17:46:28 +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 3013924F for ; Tue, 7 Sep 2021 17:46:28 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1631029588; bh=HRSUvzVUzrrhgJyZd4eTtvJJ2KJab/rLeRs0TwHwUf8=; h=From:To:Subject:Date:In-Reply-To:References:From; b=aGrOsGj6PwlpByGwiBOLeuR9QCBXup/ik7dIzoAloUL8cZS3PCVRX9pm3arn0qRFe EQKEO7saP8Pwgl+p5eromh7P/xCh1SObfaCnARaG5oC7Jf38VnE5obfHjennc42nVs AmwpaC8ioMOsCSQFNZOBOPhBLR0sB7Y7+kYMZS8g= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 18:46:06 +0300 Message-Id: <20210907154606.11350-1-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225636.14683-20-laurent.pinchart@ideasonboard.com> References: <20210906225636.14683-20-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3.1 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 --- Changes since v3: - Add assertions to check the number of planes --- src/android/jpeg/encoder_libjpeg.cpp | 19 +++++++++++-------- src/android/jpeg/encoder_libjpeg.h | 8 +++++--- src/android/jpeg/post_processor_jpeg.cpp | 2 +- src/android/jpeg/thumbnailer.cpp | 5 +++-- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/android/jpeg/encoder_libjpeg.cpp b/src/android/jpeg/encoder_libjpeg.cpp index 807a0949a8fc..21a3b33dd92c 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(); @@ -220,6 +221,8 @@ int EncoderLibJpeg::encode(Span src, Span dest, LOG(JPEG, Debug) << "JPEG Encode Starting:" << compress_.image_width << "x" << compress_.image_height; + ASSERT(src.size() == pixelFormatInfo_->numPlanes()); + if (nv_) compressNV(src); else 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..1fab80724f3c 100644 --- a/src/android/jpeg/thumbnailer.cpp +++ b/src/android/jpeg/thumbnailer.cpp @@ -59,11 +59,12 @@ void Thumbnailer::createThumbnail(const FrameBuffer &source, const unsigned int tw = targetSize.width; const unsigned int th = targetSize.height; + ASSERT(frame.planes().size() == 2); 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 Tue Sep 7 15:46: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: 13729 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 5C11BBE175 for ; Tue, 7 Sep 2021 15:46:52 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 19D6F60252; Tue, 7 Sep 2021 17:46: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="qBuP+BYZ"; 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 522BE60251 for ; Tue, 7 Sep 2021 17:46:50 +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 E818F24F for ; Tue, 7 Sep 2021 17:46:49 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1631029610; bh=dlhy2oG9v90m6JQVS4Nj1HOrSLVeESltVD1zNa13JDg=; h=From:To:Subject:Date:In-Reply-To:References:From; b=qBuP+BYZC2KODDVQE4X1TQ0GH40H02ps336pNTfQApj1tfE/XD3fyMkbVB9N9dZu7 u4wML/jupkR4wTCitFrbEwQRgiCPflKeLi81ay/yNxl/7PBfziyJg42xo9JRmkmzLw 3ZNR8s6ex23ZugYlWNULKpR/yXPqDVO8XuABcwRA= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 18:46:28 +0300 Message-Id: <20210907154628.11440-1-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225636.14683-21-laurent.pinchart@ideasonboard.com> References: <20210906225636.14683-21-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3.1 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 --- Changes since v3: - Added assertions --- src/cam/image.cpp | 109 ++++++++++++++++++++++++++++++++++++++++++++ src/cam/image.h | 52 +++++++++++++++++++++ src/cam/meson.build | 1 + 3 files changed, 162 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..6085fa7ba9d7 --- /dev/null +++ b/src/cam/image.cpp @@ -0,0 +1,109 @@ +/* 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) +{ + assert(plane <= planes_.size()); + return planes_[plane]; +} + +Span Image::data(unsigned int plane) const +{ + assert(plane <= planes_.size()); + 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 Tue Sep 7 15:46:50 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13730 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 C5503BE175 for ; Tue, 7 Sep 2021 15:47:13 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7AB1F6916C; Tue, 7 Sep 2021 17:47: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="huqKIkoi"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9E69060251 for ; Tue, 7 Sep 2021 17:47:12 +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 4665224F for ; Tue, 7 Sep 2021 17:47:12 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1631029632; bh=AUuLfCYRU01TSxzU8FZREzpvFLvu8rxBgqn5SoJxuPA=; h=From:To:Subject:Date:In-Reply-To:References:From; b=huqKIkoi8Gi+LYN32hbstWnPkcrgBXY70hLt6TqWeHeSCNFWJpA6OVZDwoRHQA8AL 7u8BrWur4qvkBfqxf6NliBUyrU1CN0XW6yIxSI3gzlhxDd81hZX6MZ0CKwE83s7w5P ZH76NtPGH+UgN4UcDsJojaSS9b+NDjelCwaxmdK0= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 7 Sep 2021 18:46:50 +0300 Message-Id: <20210907154650.11507-1-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906225636.14683-26-laurent.pinchart@ideasonboard.com> References: <20210906225636.14683-26-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3.1 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 --- Changes since v3: - Separate bytesused for planes with comma instead of slash --- src/qcam/main_window.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index ac853e360aea..129aeb0b6b2e 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,10 +755,14 @@ 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 - << "timestamp:" << metadata.timestamp + << "bytesused: {" << bytesused.join(", ") + << "} timestamp:" << metadata.timestamp << "fps:" << Qt::fixed << qSetRealNumberPrecision(2) << fps; /* Render the frame on the viewfinder. */