From patchwork Sat Jan 23 05:17:02 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 10971 X-Patchwork-Delegate: paul.elder@ideasonboard.com 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 55176C0F2B for ; Sat, 23 Jan 2021 05:17:29 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 1F6F968277; Sat, 23 Jan 2021 06:17:29 +0100 (CET) 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="lmlnKElu"; 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 89AF66030D for ; Sat, 23 Jan 2021 06:17:27 +0100 (CET) Received: from pyrite.rasen.tech (unknown [IPv6:2400:4051:61:600:2c71:1b79:d06d:5032]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 17123813; Sat, 23 Jan 2021 06:17:25 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1611379047; bh=q9Uu+V7CSqF7jZM5ayXtIdkotoiQdam0sPajR8Q9J74=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=lmlnKEluCNdi9lsCLplQgGKFrrpN1adom8aN+E5VJCgeIxNZeoiflngoUcecevdbr jsnTXZ0drxIeXwzdQXMlLIpN76WVL+6uKVOniBUmW+Wf9mFzZX/Z4WMBOuTrodtp+1 wnX1fV59a0oCk4J/dSbJQN1e689ONrNaBYSzk+Ks= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Sat, 23 Jan 2021 14:17:02 +0900 Message-Id: <20210123051704.188117-7-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20210123051704.188117-1-paul.elder@ideasonboard.com> References: <20210123051704.188117-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 6/8] android: jpeg: Configure thumbnailer based on request metadata 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" Configure the thumbnailer based on the thumbnail parameters given by the android request metadata. Only the thumbnail encoder needs to be configured, and since it is only used at post-processing time, move the configuration out of the post-processor constructor and into the processing step. Also set the following android result metadata tags: - ANDROID_JPEG_THUMBNAIL_SIZE - ANDROID_JPEG_THUMBNAIL_QUALITY Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- New in v3 - split from "android: Set result metadata and EXIF fields based on request" --- src/android/jpeg/post_processor_jpeg.cpp | 40 +++++++++++++++++------- src/android/jpeg/post_processor_jpeg.h | 1 + src/android/jpeg/thumbnailer.cpp | 25 ++------------- src/android/jpeg/thumbnailer.h | 4 +-- 4 files changed, 34 insertions(+), 36 deletions(-) diff --git a/src/android/jpeg/post_processor_jpeg.cpp b/src/android/jpeg/post_processor_jpeg.cpp index b325a06a..e5e42d39 100644 --- a/src/android/jpeg/post_processor_jpeg.cpp +++ b/src/android/jpeg/post_processor_jpeg.cpp @@ -41,12 +41,6 @@ int PostProcessorJpeg::configure(const StreamConfiguration &inCfg, streamSize_ = outCfg.size; thumbnailer_.configure(inCfg.size, inCfg.pixelFormat); - StreamConfiguration thCfg = inCfg; - thCfg.size = thumbnailer_.size(); - if (thumbnailEncoder_.configure(thCfg) != 0) { - LOG(JPEG, Error) << "Failed to configure thumbnail encoder"; - return -EINVAL; - } encoder_ = std::make_unique(); @@ -54,14 +48,20 @@ int PostProcessorJpeg::configure(const StreamConfiguration &inCfg, } void PostProcessorJpeg::generateThumbnail(const FrameBuffer &source, + const Size &targetSize, std::vector *thumbnail) { /* Stores the raw scaled-down thumbnail bytes. */ std::vector rawThumbnail; - thumbnailer_.createThumbnail(source, &rawThumbnail); + thumbnailer_.createThumbnail(source, targetSize, &rawThumbnail); + + StreamConfiguration thCfg; + thCfg.size = targetSize; + thCfg.pixelFormat = thumbnailer_.pixelFormat(); + int ret = thumbnailEncoder_.configure(thCfg); - if (!rawThumbnail.empty()) { + if (!rawThumbnail.empty() && !ret) { /* * \todo Avoid value-initialization of all elements of the * vector. @@ -125,10 +125,26 @@ int PostProcessorJpeg::process(const FrameBuffer &source, entry.data.i64, 1); } - std::vector thumbnail; - generateThumbnail(source, &thumbnail); - if (!thumbnail.empty()) - exif.setThumbnail(thumbnail, Exif::Compression::JPEG); + ret = requestMetadata.getEntry(ANDROID_JPEG_THUMBNAIL_SIZE, &entry); + if (ret) { + const int32_t *data = entry.data.i32; + Size thumbnailSize = { static_cast(data[0]), + static_cast(data[1]) }; + + if (thumbnailSize != Size(0, 0)) { + std::vector thumbnail; + generateThumbnail(source, thumbnailSize, &thumbnail); + if (!thumbnail.empty()) + exif.setThumbnail(thumbnail, Exif::Compression::JPEG); + } + + resultMetadata->addEntry(ANDROID_JPEG_THUMBNAIL_SIZE, data, 2); + + /* \todo Use this quality as a parameter to the encoder */ + ret = requestMetadata.getEntry(ANDROID_JPEG_THUMBNAIL_QUALITY, &entry); + if (ret) + resultMetadata->addEntry(ANDROID_JPEG_THUMBNAIL_QUALITY, entry.data.u8, 1); + } ret = requestMetadata.getEntry(ANDROID_JPEG_GPS_COORDINATES, &entry); if (ret) { diff --git a/src/android/jpeg/post_processor_jpeg.h b/src/android/jpeg/post_processor_jpeg.h index d721d1b9..660b79b4 100644 --- a/src/android/jpeg/post_processor_jpeg.h +++ b/src/android/jpeg/post_processor_jpeg.h @@ -31,6 +31,7 @@ public: private: void generateThumbnail(const libcamera::FrameBuffer &source, + const libcamera::Size &targetSize, std::vector *thumbnail); CameraDevice *const cameraDevice_; diff --git a/src/android/jpeg/thumbnailer.cpp b/src/android/jpeg/thumbnailer.cpp index 5374538a..f709d343 100644 --- a/src/android/jpeg/thumbnailer.cpp +++ b/src/android/jpeg/thumbnailer.cpp @@ -32,30 +32,11 @@ void Thumbnailer::configure(const Size &sourceSize, PixelFormat pixelFormat) return; } - targetSize_ = computeThumbnailSize(); - valid_ = true; } -/* - * The Exif specification recommends the width of the thumbnail to be a - * multiple of 16 (section 4.8.1). Hence, compute the corresponding height - * keeping the aspect ratio same as of the source. - */ -Size Thumbnailer::computeThumbnailSize() const -{ - unsigned int targetHeight; - constexpr unsigned int kTargetWidth = 160; - - targetHeight = kTargetWidth * sourceSize_.height / sourceSize_.width; - - if (targetHeight & 1) - targetHeight++; - - return Size(kTargetWidth, targetHeight); -} - void Thumbnailer::createThumbnail(const FrameBuffer &source, + const Size &targetSize, std::vector *destination) { MappedFrameBuffer frame(&source, PROT_READ); @@ -73,8 +54,8 @@ void Thumbnailer::createThumbnail(const FrameBuffer &source, const unsigned int sw = sourceSize_.width; const unsigned int sh = sourceSize_.height; - const unsigned int tw = targetSize_.width; - const unsigned int th = targetSize_.height; + const unsigned int tw = targetSize.width; + const unsigned int th = targetSize.height; ASSERT(tw % 2 == 0 && th % 2 == 0); diff --git a/src/android/jpeg/thumbnailer.h b/src/android/jpeg/thumbnailer.h index 98f11833..bbd9832d 100644 --- a/src/android/jpeg/thumbnailer.h +++ b/src/android/jpeg/thumbnailer.h @@ -20,15 +20,15 @@ public: void configure(const libcamera::Size &sourceSize, libcamera::PixelFormat pixelFormat); void createThumbnail(const libcamera::FrameBuffer &source, + const libcamera::Size &targetSize, std::vector *dest); - const libcamera::Size &size() const { return targetSize_; } + const libcamera::PixelFormat &pixelFormat() const { return pixelFormat_; } private: libcamera::Size computeThumbnailSize() const; libcamera::PixelFormat pixelFormat_; libcamera::Size sourceSize_; - libcamera::Size targetSize_; bool valid_; };