[{"id":14726,"web_url":"https://patchwork.libcamera.org/comment/14726/","msgid":"<YAvxNj6+I+/qfcCe@pendragon.ideasonboard.com>","date":"2021-01-23T09:49:42","subject":"Re: [libcamera-devel] [PATCH v3 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 Sat, Jan 23, 2021 at 02:17:04PM +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> \n> ---\n> New in v3\n> ---\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 | 25 ++++++++++++------------\n>  src/android/jpeg/post_processor_jpeg.h   |  1 +\n>  5 files changed, 25 insertions(+), 22 deletions(-)\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 e5e42d39..8b1801b9 100644\n> --- a/src/android/jpeg/post_processor_jpeg.cpp\n> +++ b/src/android/jpeg/post_processor_jpeg.cpp\n> @@ -49,6 +49,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> @@ -69,7 +70,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> @@ -131,19 +132,20 @@ 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\tif (ret)\n> +\t\t\tresultMetadata->addEntry(ANDROID_JPEG_THUMBNAIL_QUALITY, entry.data.u8, 1);\n\nThis should be set to 95 if ANDROID_JPEG_THUMBNAIL_QUALITY isn't\nspecified as that's the value we use below.\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> +\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,\n> +\t\t\t\t\t  ret ? *entry.data.u8 : 95, &thumbnail);\n\n\t\t\tgenerateThumbnail(source, thumbnailSize, quality,\n\t\t\t\t\t  &thumbnail);\n\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, entry.data.u8, 1);\n>  \t}\n>  \n>  \tret = requestMetadata.getEntry(ANDROID_JPEG_GPS_COORDINATES, &entry);\n> @@ -164,7 +166,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 uint32_t jpeg_quality = ret ? *entry.data.u8 : 95;\n\ns/jpeg_quality/jpegQuality/ (or just quality).\n\nThis should be a uint8_t otherwise you'll pass the wrong pointer to\n->addEntry() and it will fail on big-endian machines.\n\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\n> +\tresultMetadata->addEntry(ANDROID_JPEG_QUALITY, &jpeg_quality, 1);\n> +\n> +\tint jpeg_size = encoder_->encode(source, destination, exif.data(), jpeg_quality);\n>  \tif (jpeg_size < 0) {\n>  \t\tLOG(JPEG, Error) << \"Failed to encode stream image\";\n>  \t\treturn jpeg_size;\n> @@ -192,10 +198,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 uint32_t jpeg_quality = ret ? *entry.data.u8 : 95;\n> -\tresultMetadata->addEntry(ANDROID_JPEG_QUALITY, &jpeg_quality, 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 089FDC0F2B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSat, 23 Jan 2021 09:50:04 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 7B2DD68293;\n\tSat, 23 Jan 2021 10:50:03 +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 5C10B6827C\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat, 23 Jan 2021 10:50:02 +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 BC75A3E;\n\tSat, 23 Jan 2021 10:50:01 +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=\"GHKpqPtR\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1611395401;\n\tbh=aBDCuLb+e+RXKUb7tzaFCTrNb4uorBwKs3vA9oR9DtA=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=GHKpqPtR/2CBNyUtbpgwWzJHXeSqIi1OAGvkqJNJvC5Clr+dqTp5GW0wmVlTOV3R3\n\t3UUuq38EaaFCrQ711lin+Bia0XprKfosb6sTpVLPOMeajAQFO45J0iyPBT2l86sczM\n\tQMx647LIXgbXt94Mv7tK68dMVg+Qxc443jrFSDfs=","Date":"Sat, 23 Jan 2021 11:49:42 +0200","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Paul Elder <paul.elder@ideasonboard.com>","Message-ID":"<YAvxNj6+I+/qfcCe@pendragon.ideasonboard.com>","References":"<20210123051704.188117-1-paul.elder@ideasonboard.com>\n\t<20210123051704.188117-9-paul.elder@ideasonboard.com>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<20210123051704.188117-9-paul.elder@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v3 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>"}}]