From patchwork Mon Jan 25 07:14:44 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 10986 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 CCC00C0F2B for ; Mon, 25 Jan 2021 07:15:15 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 99336682A9; Mon, 25 Jan 2021 08:15:15 +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="lY/aCDV7"; 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 97E89682A0 for ; Mon, 25 Jan 2021 08:15:13 +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 B562E3E; Mon, 25 Jan 2021 08:15:11 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1611558913; bh=IgR5UJ+G7jjzMoUsI1li5ipV+GDLBayA4KDWz1rWgvA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=lY/aCDV77nJu54TCIvR403vw1d6X1iwXYVO6e2LdGZPPGUjdhO3Uim1LuCqKn51vJ YW3WkOvujiazUcCkxd0AKhz06i5ARybOBGQwiNNGpcmYB1AXNek2l3JZa0PS8ATAuJ 7yhBvUqJCUwtL+YPNvU68ZsOqGqA7LHTxlpjsL48= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Mon, 25 Jan 2021 16:14:44 +0900 Message-Id: <20210125071444.26252-9-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20210125071444.26252-1-paul.elder@ideasonboard.com> References: <20210125071444.26252-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 8/8] android: jpeg: Set thumbnail and JPEG quality based on request 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" Set the thumbnail quality and the JPEG quality based on the android request metadata. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart Reviewed-by: Jacopo Mondi --- Changes in v4: - set jpeg quality to 95 by default New in v3 --- src/android/jpeg/encoder.h | 3 ++- src/android/jpeg/encoder_libjpeg.cpp | 10 ++++----- src/android/jpeg/encoder_libjpeg.h | 8 ++++---- src/android/jpeg/post_processor_jpeg.cpp | 26 +++++++++++------------- src/android/jpeg/post_processor_jpeg.h | 1 + 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/android/jpeg/encoder.h b/src/android/jpeg/encoder.h index 027233dc..8d449369 100644 --- a/src/android/jpeg/encoder.h +++ b/src/android/jpeg/encoder.h @@ -19,7 +19,8 @@ public: virtual int configure(const libcamera::StreamConfiguration &cfg) = 0; virtual int encode(const libcamera::FrameBuffer &source, libcamera::Span destination, - libcamera::Span exifData) = 0; + libcamera::Span exifData, + unsigned int quality) = 0; }; #endif /* __ANDROID_JPEG_ENCODER_H__ */ diff --git a/src/android/jpeg/encoder_libjpeg.cpp b/src/android/jpeg/encoder_libjpeg.cpp index aed919b9..f006e1d1 100644 --- a/src/android/jpeg/encoder_libjpeg.cpp +++ b/src/android/jpeg/encoder_libjpeg.cpp @@ -68,7 +68,6 @@ const struct JPEGPixelFormatInfo &findPixelInfo(const PixelFormat &format) } /* namespace */ EncoderLibJpeg::EncoderLibJpeg() - : quality_(95) { /* \todo Expand error handling coverage with a custom handler. */ compress_.err = jpeg_std_error(&jerr_); @@ -94,7 +93,6 @@ int EncoderLibJpeg::configure(const StreamConfiguration &cfg) compress_.input_components = info.colorSpace == JCS_GRAYSCALE ? 1 : 3; jpeg_set_defaults(&compress_); - jpeg_set_quality(&compress_, quality_, TRUE); pixelFormatInfo_ = &info.pixelFormatInfo; @@ -180,7 +178,7 @@ void EncoderLibJpeg::compressNV(Span frame) } int EncoderLibJpeg::encode(const FrameBuffer &source, Span dest, - Span exifData) + Span exifData, unsigned int quality) { MappedFrameBuffer frame(&source, PROT_READ); if (!frame.isValid()) { @@ -189,15 +187,17 @@ int EncoderLibJpeg::encode(const FrameBuffer &source, Span dest, return frame.error(); } - return encode(frame.maps()[0], dest, exifData); + return encode(frame.maps()[0], dest, exifData, quality); } int EncoderLibJpeg::encode(Span src, Span dest, - Span exifData) + Span exifData, unsigned int quality) { unsigned char *destination = dest.data(); unsigned long size = dest.size(); + jpeg_set_quality(&compress_, quality, TRUE); + /* * The jpeg_mem_dest will reallocate if the required size is not * sufficient. That means the output won't be written to the correct diff --git a/src/android/jpeg/encoder_libjpeg.h b/src/android/jpeg/encoder_libjpeg.h index 070f56f8..838da772 100644 --- a/src/android/jpeg/encoder_libjpeg.h +++ b/src/android/jpeg/encoder_libjpeg.h @@ -23,10 +23,12 @@ public: int configure(const libcamera::StreamConfiguration &cfg) override; int encode(const libcamera::FrameBuffer &source, libcamera::Span destination, - libcamera::Span exifData) override; + libcamera::Span exifData, + unsigned int quality) override; int encode(libcamera::Span source, libcamera::Span destination, - libcamera::Span exifData); + libcamera::Span exifData, + unsigned int quality); private: void compressRGB(libcamera::Span frame); @@ -35,8 +37,6 @@ private: struct jpeg_compress_struct compress_; struct jpeg_error_mgr jerr_; - unsigned int quality_; - const libcamera::PixelFormatInfo *pixelFormatInfo_; bool nv_; diff --git a/src/android/jpeg/post_processor_jpeg.cpp b/src/android/jpeg/post_processor_jpeg.cpp index d35fe361..f52a791a 100644 --- a/src/android/jpeg/post_processor_jpeg.cpp +++ b/src/android/jpeg/post_processor_jpeg.cpp @@ -51,6 +51,7 @@ int PostProcessorJpeg::configure(const StreamConfiguration &inCfg, void PostProcessorJpeg::generateThumbnail(const FrameBuffer &source, const Size &targetSize, + unsigned int quality, std::vector *thumbnail) { /* Stores the raw scaled-down thumbnail bytes. */ @@ -71,7 +72,7 @@ void PostProcessorJpeg::generateThumbnail(const FrameBuffer &source, thumbnail->resize(rawThumbnail.size()); int jpeg_size = thumbnailEncoder_.encode(rawThumbnail, - *thumbnail, {}); + *thumbnail, {}, quality); thumbnail->resize(jpeg_size); LOG(JPEG, Debug) @@ -133,20 +134,18 @@ int PostProcessorJpeg::process(const FrameBuffer &source, Size thumbnailSize = { static_cast(data[0]), static_cast(data[1]) }; + ret = requestMetadata.getEntry(ANDROID_JPEG_THUMBNAIL_QUALITY, &entry); + uint8_t quality = ret ? *entry.data.u8 : 95; + resultMetadata->addEntry(ANDROID_JPEG_THUMBNAIL_QUALITY, &quality, 1); + if (thumbnailSize != Size(0, 0)) { std::vector thumbnail; - generateThumbnail(source, thumbnailSize, &thumbnail); + generateThumbnail(source, thumbnailSize, quality, &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); @@ -167,7 +166,11 @@ int PostProcessorJpeg::process(const FrameBuffer &source, if (exif.generate() != 0) LOG(JPEG, Error) << "Failed to generate valid EXIF data"; - int jpeg_size = encoder_->encode(source, destination, exif.data()); + ret = requestMetadata.getEntry(ANDROID_JPEG_QUALITY, &entry); + const uint8_t quality = ret ? *entry.data.u8 : 95; + resultMetadata->addEntry(ANDROID_JPEG_QUALITY, &quality, 1); + + int jpeg_size = encoder_->encode(source, destination, exif.data(), quality); if (jpeg_size < 0) { LOG(JPEG, Error) << "Failed to encode stream image"; return jpeg_size; @@ -195,10 +198,5 @@ int PostProcessorJpeg::process(const FrameBuffer &source, /* Update the JPEG result Metadata. */ resultMetadata->addEntry(ANDROID_JPEG_SIZE, &jpeg_size, 1); - /* \todo Configure JPEG encoder with this */ - ret = requestMetadata.getEntry(ANDROID_JPEG_QUALITY, &entry); - const uint32_t jpegQuality = ret ? *entry.data.u8 : 95; - resultMetadata->addEntry(ANDROID_JPEG_QUALITY, &jpegQuality, 1); - return 0; } diff --git a/src/android/jpeg/post_processor_jpeg.h b/src/android/jpeg/post_processor_jpeg.h index 660b79b4..d2dfa450 100644 --- a/src/android/jpeg/post_processor_jpeg.h +++ b/src/android/jpeg/post_processor_jpeg.h @@ -32,6 +32,7 @@ public: private: void generateThumbnail(const libcamera::FrameBuffer &source, const libcamera::Size &targetSize, + unsigned int quality, std::vector *thumbnail); CameraDevice *const cameraDevice_;