[{"id":14784,"web_url":"https://patchwork.libcamera.org/comment/14784/","msgid":"<YBAY61GSBExHXI3H@pendragon.ideasonboard.com>","date":"2021-01-26T13:28:11","subject":"Re: [libcamera-devel] [PATCH v5 8/8] android: jpeg: Set thumbnail\n\tand JPEG quality based on request","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Paul,\n\nThank you for the patch.\n\nOn Tue, Jan 26, 2021 at 07:28:25PM +0900, Paul Elder wrote:\n> Set the thumbnail quality and the JPEG quality based on the android\n> request metadata.\n> \n> Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>\n> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n> \n> ---\n> No change in v5\n> Changes in v4:\n> - set jpeg quality to 95 by default\n> \n> New in v3\n> ---\n>  src/android/camera_device.cpp            |  4 +++-\n>  src/android/jpeg/encoder.h               |  3 ++-\n>  src/android/jpeg/encoder_libjpeg.cpp     | 10 ++++-----\n>  src/android/jpeg/encoder_libjpeg.h       |  8 ++++----\n>  src/android/jpeg/post_processor_jpeg.cpp | 26 +++++++++++-------------\n>  src/android/jpeg/post_processor_jpeg.h   |  1 +\n>  6 files changed, 27 insertions(+), 25 deletions(-)\n> \n> diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp\n> index d297bdf4..a0865911 100644\n> --- a/src/android/camera_device.cpp\n> +++ b/src/android/camera_device.cpp\n> @@ -708,7 +708,7 @@ std::tuple<uint32_t, uint32_t> CameraDevice::calculateStaticMetadataSize()\n>  \t * Currently: 53 entries, 782 bytes of static metadata\n>  \t */\n>  \tuint32_t numEntries = 53;\n> -\tuint32_t byteSize = 802;\n> +\tuint32_t byteSize = 810;\n>  \n>  \t/*\n>  \t * Calculate space occupation in bytes for dynamically built metadata\n> @@ -1272,6 +1272,8 @@ const camera_metadata_t *CameraDevice::getStaticMetadata()\n>  \t\tANDROID_JPEG_SIZE,\n>  \t\tANDROID_JPEG_QUALITY,\n>  \t\tANDROID_JPEG_ORIENTATION,\n> +\t\tANDROID_JPEG_THUMBNAIL_QUALITY,\n> +\t\tANDROID_JPEG_THUMBNAIL_SIZE,\n>  \t};\n>  \tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS,\n>  \t\t\t\t  availableResultKeys.data(),\n\nShould this be moved to patch 6/8 ? Apart from that all seems good.\n\n> diff --git a/src/android/jpeg/encoder.h b/src/android/jpeg/encoder.h\n> index 027233dc..8d449369 100644\n> --- a/src/android/jpeg/encoder.h\n> +++ b/src/android/jpeg/encoder.h\n> @@ -19,7 +19,8 @@ public:\n>  \tvirtual int configure(const libcamera::StreamConfiguration &cfg) = 0;\n>  \tvirtual int encode(const libcamera::FrameBuffer &source,\n>  \t\t\t   libcamera::Span<uint8_t> destination,\n> -\t\t\t   libcamera::Span<const uint8_t> exifData) = 0;\n> +\t\t\t   libcamera::Span<const uint8_t> exifData,\n> +\t\t\t   unsigned int quality) = 0;\n>  };\n>  \n>  #endif /* __ANDROID_JPEG_ENCODER_H__ */\n> diff --git a/src/android/jpeg/encoder_libjpeg.cpp b/src/android/jpeg/encoder_libjpeg.cpp\n> index aed919b9..f006e1d1 100644\n> --- a/src/android/jpeg/encoder_libjpeg.cpp\n> +++ b/src/android/jpeg/encoder_libjpeg.cpp\n> @@ -68,7 +68,6 @@ const struct JPEGPixelFormatInfo &findPixelInfo(const PixelFormat &format)\n>  } /* namespace */\n>  \n>  EncoderLibJpeg::EncoderLibJpeg()\n> -\t: quality_(95)\n>  {\n>  \t/* \\todo Expand error handling coverage with a custom handler. */\n>  \tcompress_.err = jpeg_std_error(&jerr_);\n> @@ -94,7 +93,6 @@ int EncoderLibJpeg::configure(const StreamConfiguration &cfg)\n>  \tcompress_.input_components = info.colorSpace == JCS_GRAYSCALE ? 1 : 3;\n>  \n>  \tjpeg_set_defaults(&compress_);\n> -\tjpeg_set_quality(&compress_, quality_, TRUE);\n>  \n>  \tpixelFormatInfo_ = &info.pixelFormatInfo;\n>  \n> @@ -180,7 +178,7 @@ void EncoderLibJpeg::compressNV(Span<const uint8_t> frame)\n>  }\n>  \n>  int EncoderLibJpeg::encode(const FrameBuffer &source, Span<uint8_t> dest,\n> -\t\t\t   Span<const uint8_t> exifData)\n> +\t\t\t   Span<const uint8_t> exifData, unsigned int quality)\n>  {\n>  \tMappedFrameBuffer frame(&source, PROT_READ);\n>  \tif (!frame.isValid()) {\n> @@ -189,15 +187,17 @@ int EncoderLibJpeg::encode(const FrameBuffer &source, Span<uint8_t> dest,\n>  \t\treturn frame.error();\n>  \t}\n>  \n> -\treturn encode(frame.maps()[0], dest, exifData);\n> +\treturn encode(frame.maps()[0], dest, exifData, quality);\n>  }\n>  \n>  int EncoderLibJpeg::encode(Span<const uint8_t> src, Span<uint8_t> dest,\n> -\t\t\t   Span<const uint8_t> exifData)\n> +\t\t\t   Span<const uint8_t> exifData, unsigned int quality)\n>  {\n>  \tunsigned char *destination = dest.data();\n>  \tunsigned long size = dest.size();\n>  \n> +\tjpeg_set_quality(&compress_, quality, TRUE);\n> +\n>  \t/*\n>  \t * The jpeg_mem_dest will reallocate if the required size is not\n>  \t * sufficient. That means the output won't be written to the correct\n> diff --git a/src/android/jpeg/encoder_libjpeg.h b/src/android/jpeg/encoder_libjpeg.h\n> index 070f56f8..838da772 100644\n> --- a/src/android/jpeg/encoder_libjpeg.h\n> +++ b/src/android/jpeg/encoder_libjpeg.h\n> @@ -23,10 +23,12 @@ public:\n>  \tint configure(const libcamera::StreamConfiguration &cfg) override;\n>  \tint encode(const libcamera::FrameBuffer &source,\n>  \t\t   libcamera::Span<uint8_t> destination,\n> -\t\t   libcamera::Span<const uint8_t> exifData) override;\n> +\t\t   libcamera::Span<const uint8_t> exifData,\n> +\t\t   unsigned int quality) override;\n>  \tint encode(libcamera::Span<const uint8_t> source,\n>  \t\t   libcamera::Span<uint8_t> destination,\n> -\t\t   libcamera::Span<const uint8_t> exifData);\n> +\t\t   libcamera::Span<const uint8_t> exifData,\n> +\t\t   unsigned int quality);\n>  \n>  private:\n>  \tvoid compressRGB(libcamera::Span<const uint8_t> frame);\n> @@ -35,8 +37,6 @@ private:\n>  \tstruct jpeg_compress_struct compress_;\n>  \tstruct jpeg_error_mgr jerr_;\n>  \n> -\tunsigned int quality_;\n> -\n>  \tconst libcamera::PixelFormatInfo *pixelFormatInfo_;\n>  \n>  \tbool nv_;\n> diff --git a/src/android/jpeg/post_processor_jpeg.cpp b/src/android/jpeg/post_processor_jpeg.cpp\n> index e990ba04..cac0087b 100644\n> --- a/src/android/jpeg/post_processor_jpeg.cpp\n> +++ b/src/android/jpeg/post_processor_jpeg.cpp\n> @@ -52,6 +52,7 @@ int PostProcessorJpeg::configure(const StreamConfiguration &inCfg,\n>  \n>  void PostProcessorJpeg::generateThumbnail(const FrameBuffer &source,\n>  \t\t\t\t\t  const Size &targetSize,\n> +\t\t\t\t\t  unsigned int quality,\n>  \t\t\t\t\t  std::vector<unsigned char> *thumbnail)\n>  {\n>  \t/* Stores the raw scaled-down thumbnail bytes. */\n> @@ -72,7 +73,7 @@ void PostProcessorJpeg::generateThumbnail(const FrameBuffer &source,\n>  \t\tthumbnail->resize(rawThumbnail.size());\n>  \n>  \t\tint jpeg_size = thumbnailEncoder_.encode(rawThumbnail,\n> -\t\t\t\t\t\t\t *thumbnail, {});\n> +\t\t\t\t\t\t\t *thumbnail, {}, quality);\n>  \t\tthumbnail->resize(jpeg_size);\n>  \n>  \t\tLOG(JPEG, Debug)\n> @@ -135,20 +136,18 @@ int PostProcessorJpeg::process(const FrameBuffer &source,\n>  \t\tSize thumbnailSize = { static_cast<uint32_t>(data[0]),\n>  \t\t\t\t       static_cast<uint32_t>(data[1]) };\n>  \n> +\t\tret = requestMetadata.getEntry(ANDROID_JPEG_THUMBNAIL_QUALITY, &entry);\n> +\t\tuint8_t quality = ret ? *entry.data.u8 : 95;\n> +\t\tresultMetadata->addEntry(ANDROID_JPEG_THUMBNAIL_QUALITY, &quality, 1);\n> +\n>  \t\tif (thumbnailSize != Size(0, 0)) {\n>  \t\t\tstd::vector<unsigned char> thumbnail;\n> -\t\t\tgenerateThumbnail(source, thumbnailSize, &thumbnail);\n> +\t\t\tgenerateThumbnail(source, thumbnailSize, quality, &thumbnail);\n>  \t\t\tif (!thumbnail.empty())\n>  \t\t\t\texif.setThumbnail(thumbnail, Exif::Compression::JPEG);\n>  \t\t}\n>  \n>  \t\tresultMetadata->addEntry(ANDROID_JPEG_THUMBNAIL_SIZE, data, 2);\n> -\n> -\t\t/* \\todo Use this quality as a parameter to the encoder */\n> -\t\tret = requestMetadata.getEntry(ANDROID_JPEG_THUMBNAIL_QUALITY, &entry);\n> -\t\tif (ret)\n> -\t\t\tresultMetadata->addEntry(ANDROID_JPEG_THUMBNAIL_QUALITY,\n> -\t\t\t\t\t\t entry.data.u8, 1);\n>  \t}\n>  \n>  \tret = requestMetadata.getEntry(ANDROID_JPEG_GPS_COORDINATES, &entry);\n> @@ -169,7 +168,11 @@ int PostProcessorJpeg::process(const FrameBuffer &source,\n>  \tif (exif.generate() != 0)\n>  \t\tLOG(JPEG, Error) << \"Failed to generate valid EXIF data\";\n>  \n> -\tint jpeg_size = encoder_->encode(source, destination, exif.data());\n> +\tret = requestMetadata.getEntry(ANDROID_JPEG_QUALITY, &entry);\n> +\tconst uint8_t quality = ret ? *entry.data.u8 : 95;\n> +\tresultMetadata->addEntry(ANDROID_JPEG_QUALITY, &quality, 1);\n> +\n> +\tint jpeg_size = encoder_->encode(source, destination, exif.data(), quality);\n>  \tif (jpeg_size < 0) {\n>  \t\tLOG(JPEG, Error) << \"Failed to encode stream image\";\n>  \t\treturn jpeg_size;\n> @@ -197,10 +200,5 @@ int PostProcessorJpeg::process(const FrameBuffer &source,\n>  \t/* Update the JPEG result Metadata. */\n>  \tresultMetadata->addEntry(ANDROID_JPEG_SIZE, &jpeg_size, 1);\n>  \n> -\t/* \\todo Configure JPEG encoder with this */\n> -\tret = requestMetadata.getEntry(ANDROID_JPEG_QUALITY, &entry);\n> -\tconst uint8_t jpegQuality = ret ? *entry.data.u8 : 95;\n> -\tresultMetadata->addEntry(ANDROID_JPEG_QUALITY, &jpegQuality, 1);\n> -\n>  \treturn 0;\n>  }\n> diff --git a/src/android/jpeg/post_processor_jpeg.h b/src/android/jpeg/post_processor_jpeg.h\n> index 660b79b4..d2dfa450 100644\n> --- a/src/android/jpeg/post_processor_jpeg.h\n> +++ b/src/android/jpeg/post_processor_jpeg.h\n> @@ -32,6 +32,7 @@ public:\n>  private:\n>  \tvoid generateThumbnail(const libcamera::FrameBuffer &source,\n>  \t\t\t       const libcamera::Size &targetSize,\n> +\t\t\t       unsigned int quality,\n>  \t\t\t       std::vector<unsigned char> *thumbnail);\n>  \n>  \tCameraDevice *const cameraDevice_;","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id C4192BD808\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 26 Jan 2021 13:28:33 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 58B2F682EC;\n\tTue, 26 Jan 2021 14:28:33 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 228FB682EC\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 26 Jan 2021 14:28:32 +0100 (CET)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 5211C2C1;\n\tTue, 26 Jan 2021 14:28:30 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"Dn3rk7GM\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1611667710;\n\tbh=CvguvCR3N5VselXtzI8Mlbb6efOwp+Re1PeT29djqZc=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=Dn3rk7GMlq5R3zvsg0qTLlbdS0WhrUTZdlGTkYyv+qZwWV7DC5krV2cjjUmYoIaIW\n\tuSTSNEuEUEB2qI/QP9ZwNU8yKIy9oSQjGz9UWDiYTmocYjmsW+BofytidFQlX25p4Z\n\tQVNKHtW+OvlGj84mQ+KStfF4Pvl82Tciy5JNiW5w=","Date":"Tue, 26 Jan 2021 15:28:11 +0200","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Paul Elder <paul.elder@ideasonboard.com>","Message-ID":"<YBAY61GSBExHXI3H@pendragon.ideasonboard.com>","References":"<20210126102825.147026-1-paul.elder@ideasonboard.com>\n\t<20210126102825.147026-9-paul.elder@ideasonboard.com>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<20210126102825.147026-9-paul.elder@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v5 8/8] android: jpeg: Set thumbnail\n\tand JPEG quality based on request","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Cc":"libcamera-devel@lists.libcamera.org","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]