From patchwork Wed Aug 11 12:40:15 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hirokazu Honda X-Patchwork-Id: 13306 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 48BFEC3242 for ; Wed, 11 Aug 2021 12:40:35 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id DF4C96888F; Wed, 11 Aug 2021 14:40:34 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="kkHIv9xN"; dkim-atps=neutral Received: from mail-pj1-x102e.google.com (mail-pj1-x102e.google.com [IPv6:2607:f8b0:4864:20::102e]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id AA6906884D for ; Wed, 11 Aug 2021 14:40:33 +0200 (CEST) Received: by mail-pj1-x102e.google.com with SMTP id hv22-20020a17090ae416b0290178c579e424so4587628pjb.3 for ; Wed, 11 Aug 2021 05:40:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=7KSQpt515bp2ZRdRFLOpnhZCNt2r9Wb+3ftNdr4TIMA=; b=kkHIv9xNK009p3ansmvWn/+iW6ipCnTdqL3quEfGxLqL7Z3XrOMo11XpvcChsX6hzZ b9QVpwPsUtV7Df44dLO/BEV7Q9v4KBG/saN8L/MSrq1M/tx+tPjDzjLNIDsTduPh7+Ir yUKcrQeUo6e6OQx3p9LYg1+FJR8wkIWqGrc3E= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=7KSQpt515bp2ZRdRFLOpnhZCNt2r9Wb+3ftNdr4TIMA=; b=YFh7i4xT2pzmTNTJHdAxugyjUj2bFLv9Mqy2Uxu/tTB8eRlJnhVwLV8KMwxRBXKQKa icTKKBPVrCP//q9GqVK+IEj8U7wKure6AB8c/wDTq2WjKcumeXo0DO8rjkjsfe9CLEsS uiyQnK0c2N8f96KOEhnAI681MENGvleV6nH/cJEe2d4hg3+ZkL/2am0lMAeeWPzWl2lC R2R2J05MG2pQ33/Y7zPv1Rrjri6aTUfQP+UA5da/JEa69b1bml0xcXuNmN04OL58ZIvy Ip/LnaAZJNYBIchl5lge+5Zkd5adrqspc9F1VNX1Fjw2KH2qEwhzLqLCJbWwIdxneWeX uW2A== X-Gm-Message-State: AOAM531RtGFxNjtx5LR3YxqsiJZHG+ZMcYl7BSs6KdSsXFkSrzen8KTT IzYsFWvGP/bxLD95GyCF8Pi1/aQtqkGlSw== X-Google-Smtp-Source: ABdhPJw9Aup2jFjCmI8wOd8N3UaVggincMC6Of0XL4y8N0/4IWcmRH8RH0oRPSxYUpLOctQAjI+gpw== X-Received: by 2002:a63:2217:: with SMTP id i23mr820672pgi.448.1628685631929; Wed, 11 Aug 2021 05:40:31 -0700 (PDT) Received: from hiroh2.tok.corp.google.com ([2401:fa00:8f:203:ba11:c25e:242c:485d]) by smtp.gmail.com with ESMTPSA id p30sm15722876pfh.116.2021.08.11.05.40.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Aug 2021 05:40:31 -0700 (PDT) From: Hirokazu Honda To: libcamera-devel@lists.libcamera.org Date: Wed, 11 Aug 2021 21:40:15 +0900 Message-Id: <20210811124015.2116188-6-hiroh@chromium.org> X-Mailer: git-send-email 2.32.0.605.g8dce9f2422-goog In-Reply-To: <20210811124015.2116188-1-hiroh@chromium.org> References: <20210811124015.2116188-1-hiroh@chromium.org> MIME-Version: 1.0 Subject: [libcamera-devel] [RFC PATCH 5/5] WIP: android: jpeg: Use maps() and clean up 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" WIP Signed-off-by: Hirokazu Honda --- src/android/jpeg/encoder.h | 7 +++-- src/android/jpeg/encoder_libjpeg.cpp | 32 ++++++--------------- src/android/jpeg/encoder_libjpeg.h | 10 ++----- src/android/jpeg/post_processor_jpeg.cpp | 21 ++++++++++---- src/android/jpeg/thumbnailer.cpp | 36 ++++++++++++++++++++---- src/android/jpeg/thumbnailer.h | 4 ++- src/libcamera/mapped_framebuffer.cpp | 2 ++ 7 files changed, 66 insertions(+), 46 deletions(-) diff --git a/src/android/jpeg/encoder.h b/src/android/jpeg/encoder.h index a28522f4..2b9b8fca 100644 --- a/src/android/jpeg/encoder.h +++ b/src/android/jpeg/encoder.h @@ -8,17 +8,18 @@ #define __ANDROID_JPEG_ENCODER_H__ #include - -#include #include +#include "libcamera/internal/framebuffer.h" +#include "libcamera/internal/mapped_framebuffer.h" + class Encoder { public: virtual ~Encoder() = default; virtual int configure(const libcamera::StreamConfiguration &cfg) = 0; - virtual int encode(const libcamera::FrameBuffer &source, + virtual int encode(const libcamera::MappedFrameBuffer &source, libcamera::Span destination, libcamera::Span exifData, unsigned int quality) = 0; diff --git a/src/android/jpeg/encoder_libjpeg.cpp b/src/android/jpeg/encoder_libjpeg.cpp index a7a63601..188aabdb 100644 --- a/src/android/jpeg/encoder_libjpeg.cpp +++ b/src/android/jpeg/encoder_libjpeg.cpp @@ -94,7 +94,6 @@ int EncoderLibJpeg::configure(const StreamConfiguration &cfg) compress_.input_components = info.colorSpace == JCS_GRAYSCALE ? 1 : 3; jpeg_set_defaults(&compress_); - pixelFormatInfo_ = &info.pixelFormatInfo; nv_ = pixelFormatInfo_->numPlanes() == 2; @@ -103,9 +102,9 @@ int EncoderLibJpeg::configure(const StreamConfiguration &cfg) return 0; } -void EncoderLibJpeg::compressRGB(Span frame) +void EncoderLibJpeg::compressRGB(const libcamera::MappedFrameBuffer &frame) { - unsigned char *src = const_cast(frame.data()); + unsigned char *src = const_cast(frame.maps()[0].data()); /* \todo Stride information should come from buffer configuration. */ unsigned int stride = pixelFormatInfo_->stride(compress_.image_width, 0); @@ -121,7 +120,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 libcamera::MappedFrameBuffer &frame) { uint8_t tmprowbuf[compress_.image_width * 3]; @@ -143,8 +142,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 = frame.maps()[0].data(); + const unsigned char *src_c = frame.maps()[1].data(); JSAMPROW row_pointer[1]; row_pointer[0] = &tmprowbuf[0]; @@ -152,7 +151,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; @@ -178,20 +177,7 @@ void EncoderLibJpeg::compressNV(Span frame) } } -int EncoderLibJpeg::encode(const FrameBuffer &source, Span dest, - Span exifData, unsigned int quality) -{ - MappedFrameBuffer frame(&source, MappedFrameBuffer::MapFlag::Read); - if (!frame.isValid()) { - LOG(JPEG, Error) << "Failed to map FrameBuffer : " - << strerror(frame.error()); - return frame.error(); - } - - return encode(frame.maps()[0], dest, exifData, quality); -} - -int EncoderLibJpeg::encode(Span src, Span dest, +int EncoderLibJpeg::encode(const MappedFrameBuffer &source, Span dest, Span exifData, unsigned int quality) { unsigned char *destination = dest.data(); @@ -221,9 +207,9 @@ int EncoderLibJpeg::encode(Span src, Span dest, << "x" << compress_.image_height; if (nv_) - compressNV(src); + compressNV(source); else - compressRGB(src); + compressRGB(source); jpeg_finish_compress(&compress_); diff --git a/src/android/jpeg/encoder_libjpeg.h b/src/android/jpeg/encoder_libjpeg.h index 61fbd1a6..588756aa 100644 --- a/src/android/jpeg/encoder_libjpeg.h +++ b/src/android/jpeg/encoder_libjpeg.h @@ -20,18 +20,14 @@ public: ~EncoderLibJpeg(); int configure(const libcamera::StreamConfiguration &cfg) override; - int encode(const libcamera::FrameBuffer &source, + int encode(const libcamera::MappedFrameBuffer &source, libcamera::Span destination, libcamera::Span exifData, unsigned int quality) override; - int encode(libcamera::Span source, - libcamera::Span destination, - libcamera::Span exifData, - unsigned int quality); private: - void compressRGB(libcamera::Span frame); - void compressNV(libcamera::Span frame); + void compressRGB(const libcamera::MappedFrameBuffer &frame); + void compressNV(const libcamera::MappedFrameBuffer &frame); 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 3160a784..354e4fdd 100644 --- a/src/android/jpeg/post_processor_jpeg.cpp +++ b/src/android/jpeg/post_processor_jpeg.cpp @@ -56,8 +56,7 @@ void PostProcessorJpeg::generateThumbnail(const FrameBuffer &source, std::vector *thumbnail) { /* Stores the raw scaled-down thumbnail bytes. */ - std::vector rawThumbnail; - + std::unique_ptr rawThumbnail; thumbnailer_.createThumbnail(source, targetSize, &rawThumbnail); StreamConfiguration thCfg; @@ -65,14 +64,17 @@ void PostProcessorJpeg::generateThumbnail(const FrameBuffer &source, thCfg.pixelFormat = thumbnailer_.pixelFormat(); int ret = thumbnailEncoder_.configure(thCfg); - if (!rawThumbnail.empty() && !ret) { + if (rawThumbnail && !ret) { /* * \todo Avoid value-initialization of all elements of the * vector. */ - thumbnail->resize(rawThumbnail.size()); + size_t thumbnail_size = 0; + for (const MappedBuffer::Plane &plane : rawThumbnail->maps()) + thumbnail_size += plane.size(); + thumbnail->resize(thumbnail_size); - int jpeg_size = thumbnailEncoder_.encode(rawThumbnail, + int jpeg_size = thumbnailEncoder_.encode(*rawThumbnail, *thumbnail, {}, quality); thumbnail->resize(jpeg_size); @@ -177,7 +179,14 @@ int PostProcessorJpeg::process(const FrameBuffer &source, const uint8_t quality = ret ? *entry.data.u8 : 95; resultMetadata->addEntry(ANDROID_JPEG_QUALITY, quality); - int jpeg_size = encoder_->encode(source, destination->plane(0), + MappedFrameBuffer mapped(&source, MappedFrameBuffer::MapFlag::Read); + if (!mapped.isValid()) { + LOG(JPEG, Error) << "Failed to map FrameBuffer : " + << strerror(mapped.error()); + return mapped.error(); + } + + int jpeg_size = encoder_->encode(mapped, destination->plane(0), exif.data(), quality); if (jpeg_size < 0) { LOG(JPEG, Error) << "Failed to encode stream image"; diff --git a/src/android/jpeg/thumbnailer.cpp b/src/android/jpeg/thumbnailer.cpp index 79d83926..e8fa9f84 100644 --- a/src/android/jpeg/thumbnailer.cpp +++ b/src/android/jpeg/thumbnailer.cpp @@ -8,6 +8,7 @@ #include "thumbnailer.h" #include +#include #include @@ -17,6 +18,24 @@ using namespace libcamera; LOG_DEFINE_CATEGORY(Thumbnailer) +namespace { +class MappedThumbnailBuffer : public MappedFrameBuffer +{ +public: + MappedThumbnailBuffer(std::vector buffer, + const std::vector> &planes) + : MappedFrameBuffer(nullptr, MapFlag::Read), + buffer_(std::move(buffer)) + { + planes_ = planes; + } + +private: + std::vector buffer_; +}; + +} // namespace + Thumbnailer::Thumbnailer() : valid_(false) { @@ -39,7 +58,7 @@ void Thumbnailer::configure(const Size &sourceSize, PixelFormat pixelFormat) void Thumbnailer::createThumbnail(const FrameBuffer &source, const Size &targetSize, - std::vector *destination) + std::unique_ptr *destination) { MappedFrameBuffer frame(&source, MappedFrameBuffer::MapFlag::Read); if (!frame.isValid()) { @@ -63,14 +82,19 @@ void Thumbnailer::createThumbnail(const FrameBuffer &source, /* Image scaling block implementing nearest-neighbour algorithm. */ unsigned char *src = static_cast(frame.maps()[0].data()); - unsigned char *srcC = src + sh * sw; + unsigned char *srcC = static_cast(frame.maps()[1].data()); unsigned char *srcCb, *srcCr; unsigned char *dstY, *srcY; - size_t dstSize = (th * tw) + ((th / 2) * tw); - destination->resize(dstSize); - unsigned char *dst = destination->data(); - unsigned char *dstC = dst + th * tw; + std::vector buffer(th * tw + (th / 2) * tw); + std::vector> dstPlanes = { + { buffer.data(), th * tw }, + { buffer.data() + th * tw, (th / 2) * tw } + }; + unsigned char *dst = static_cast(dstPlanes[0].data()); + unsigned char *dstC = static_cast(dstPlanes[1].data()); + *destination = std::make_unique(std::move(buffer), + dstPlanes); for (unsigned int y = 0; y < th; y += 2) { unsigned int sourceY = (sh * y + th / 2) / th; diff --git a/src/android/jpeg/thumbnailer.h b/src/android/jpeg/thumbnailer.h index 4d086c49..9c938588 100644 --- a/src/android/jpeg/thumbnailer.h +++ b/src/android/jpeg/thumbnailer.h @@ -11,6 +11,7 @@ #include #include "libcamera/internal/formats.h" +#include "libcamera/internal/mapped_framebuffer.h" class Thumbnailer { @@ -21,7 +22,8 @@ public: libcamera::PixelFormat pixelFormat); void createThumbnail(const libcamera::FrameBuffer &source, const libcamera::Size &targetSize, - std::vector *dest); + std::unique_ptr *dest); + const libcamera::PixelFormat &pixelFormat() const { return pixelFormat_; } private: diff --git a/src/libcamera/mapped_framebuffer.cpp b/src/libcamera/mapped_framebuffer.cpp index 5d5b02f1..e5647127 100644 --- a/src/libcamera/mapped_framebuffer.cpp +++ b/src/libcamera/mapped_framebuffer.cpp @@ -177,6 +177,8 @@ MappedBuffer::~MappedBuffer() */ MappedFrameBuffer::MappedFrameBuffer(const FrameBuffer *buffer, MapFlags flags) { + if (!buffer) + return; ASSERT(!buffer->planes().empty()); planes_.reserve(buffer->planes().size());