From patchwork Tue Oct 27 21:24:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Umang Jain X-Patchwork-Id: 10272 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 7F615C3B5C for ; Tue, 27 Oct 2020 21:25:07 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4C28A62217; Tue, 27 Oct 2020 22:25:07 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=uajain.com header.i=@uajain.com header.b="H9Kgq3pn"; dkim-atps=neutral Received: from mail.uajain.com (static.126.159.217.95.clients.your-server.de [95.217.159.126]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7BA4F6216C for ; Tue, 27 Oct 2020 22:25:05 +0100 (CET) From: Umang Jain DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=uajain.com; s=mail; t=1603833905; bh=zZN38HVOZfCYW8HQqMLkBMj1+5ocwg133e5pxkpY7RU=; h=From:To:Cc:Subject:In-Reply-To:References; b=H9Kgq3pnC28ioRBVLBRs6vsy5BuTnER2dYtroYMQ5nCjIheKRHqfZaeX88bmn/fQb QJPzrq5ftM17T/s6cXwsWZ69uXe81KJlO86qPE1fewbCqNWEeJonBGQSdp9OJGzwEK tl8K7zL9HPB0R+mmJcgE+M8RqOZmedsZgsjrDyeUzvShTwxPmnJJFdRMgqsXSEFpad LHMFUBJ/v4/8RYM2l3XBsnOs01srfd2WJVkE/eCBRXFNsTMydRHjSHI/+1jMCzgCOw CDFG0BXjnFjMiiupXv+Tmgok6TuZ1koPkQyQNChft81SFuefbMIOgL7WPzTFM2Kvfv 9FPkJPdt9c2OA== To: libcamera-devel@lists.libcamera.org Date: Wed, 28 Oct 2020 02:54:47 +0530 Message-Id: <20201027212447.131431-4-email@uajain.com> In-Reply-To: <20201027212447.131431-1-email@uajain.com> References: <20201027212447.131431-1-email@uajain.com> Mime-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 3/3] android: jpeg: post_processor_jpeg: Embed thumbnail into Exif 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" Embed a Jpeg-encoded thumbnail into Exif metadata using the Thumbnailer class that got introduced. Introduce a helper function in Exif class for setting the thumbnail data. Set the EXIF_TAG_COMPRESSION to '6' to denote that the thumbnail is jpeg-compressed, as mentioned in Exif v2.31. Signed-off-by: Umang Jain Reviewed-by: Laurent Pinchart --- src/android/jpeg/exif.cpp | 24 ++++++++++++++++- src/android/jpeg/exif.h | 2 ++ src/android/jpeg/post_processor_jpeg.cpp | 34 ++++++++++++++++++++++++ src/android/jpeg/post_processor_jpeg.h | 8 +++++- 4 files changed, 66 insertions(+), 2 deletions(-) diff --git a/src/android/jpeg/exif.cpp b/src/android/jpeg/exif.cpp index d21534a..6ac52c6 100644 --- a/src/android/jpeg/exif.cpp +++ b/src/android/jpeg/exif.cpp @@ -75,8 +75,16 @@ Exif::~Exif() if (exifData_) free(exifData_); - if (data_) + if (data_) { + /* + * Reset thumbnail data to avoid getting double-freed by + * libexif. It is owned by the caller (i.e. PostProcessorJpeg). + */ + data_->data = nullptr; + data_->size = 0; + exif_data_unref(data_); + } if (mem_) exif_mem_unref(mem_); @@ -268,6 +276,20 @@ void Exif::setOrientation(int orientation) setShort(EXIF_IFD_0, EXIF_TAG_ORIENTATION, value); } +/* + * The thumbnail data should remain valid until the Exif object is destroyed. + * Failing to do so, might result in no thumbnail data being set even after a + * call to Exif::setThumbnail(). + */ +void Exif::setThumbnail(Span thumbnail, + uint16_t compression) +{ + data_->data = const_cast(thumbnail.data()); + data_->size = thumbnail.size(); + + setShort(EXIF_IFD_0, EXIF_TAG_COMPRESSION, compression); +} + [[nodiscard]] int Exif::generate() { if (exifData_) { diff --git a/src/android/jpeg/exif.h b/src/android/jpeg/exif.h index 12c27b6..6987b31 100644 --- a/src/android/jpeg/exif.h +++ b/src/android/jpeg/exif.h @@ -26,6 +26,8 @@ public: void setOrientation(int orientation); void setSize(const libcamera::Size &size); + void setThumbnail(libcamera::Span thumbnail, + uint16_t compression); void setTimestamp(time_t timestamp); libcamera::Span data() const { return { exifData_, size_ }; } diff --git a/src/android/jpeg/post_processor_jpeg.cpp b/src/android/jpeg/post_processor_jpeg.cpp index c56f1b2..a0db793 100644 --- a/src/android/jpeg/post_processor_jpeg.cpp +++ b/src/android/jpeg/post_processor_jpeg.cpp @@ -39,11 +39,41 @@ 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(); return encoder_->configure(inCfg); } +void PostProcessorJpeg::generateThumbnail(const FrameBuffer &source, + std::vector *thumbnail) +{ + /* Stores the raw scaled-down thumbnail bytes. */ + std::vector rawThumbnail; + + thumbnailer_.createThumbnail(source, &rawThumbnail); + + if (!rawThumbnail.empty()) { + thumbnail->resize(rawThumbnail.size()); + + int jpeg_size = thumbnailEncoder_.encode(rawThumbnail, + *thumbnail, { }); + thumbnail->resize(jpeg_size); + + LOG(JPEG, Debug) + << "Thumbnail compress returned " + << jpeg_size << " bytes"; + } +} + int PostProcessorJpeg::process(const FrameBuffer &source, Span destination, CameraMetadata *metadata) @@ -64,6 +94,10 @@ int PostProcessorJpeg::process(const FrameBuffer &source, * second, it is good enough. */ exif.setTimestamp(std::time(nullptr)); + std::vector thumbnail; + generateThumbnail(source, &thumbnail); + if(!thumbnail.empty()) + exif.setThumbnail(thumbnail, 6); if (exif.generate() != 0) LOG(JPEG, Error) << "Failed to generate valid EXIF data"; diff --git a/src/android/jpeg/post_processor_jpeg.h b/src/android/jpeg/post_processor_jpeg.h index 3706cec..5afa831 100644 --- a/src/android/jpeg/post_processor_jpeg.h +++ b/src/android/jpeg/post_processor_jpeg.h @@ -8,12 +8,13 @@ #define __ANDROID_POST_PROCESSOR_JPEG_H__ #include "../post_processor.h" +#include "encoder_libjpeg.h" +#include "thumbnailer.h" #include #include "libcamera/internal/buffer.h" -class Encoder; class CameraDevice; class PostProcessorJpeg : public PostProcessor @@ -28,9 +29,14 @@ public: CameraMetadata *metadata) override; private: + void generateThumbnail(const libcamera::FrameBuffer &source, + std::vector *thumbnail); + CameraDevice *const cameraDevice_; std::unique_ptr encoder_; libcamera::Size streamSize_; + EncoderLibJpeg thumbnailEncoder_; + Thumbnailer thumbnailer_; }; #endif /* __ANDROID_POST_PROCESSOR_JPEG_H__ */