[libcamera-devel] [PATCH v3 8/8] android: jpeg: Set thumbnail and JPEG quality based on request
Laurent Pinchart
laurent.pinchart at ideasonboard.com
Sat Jan 23 10:49:42 CET 2021
Hi Paul,
Thank you for the patch.
On Sat, Jan 23, 2021 at 02:17:04PM +0900, Paul Elder wrote:
> Set the thumbnail quality and the JPEG quality based on the android
> request metadata.
>
> Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>
>
> ---
> 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 | 25 ++++++++++++------------
> src/android/jpeg/post_processor_jpeg.h | 1 +
> 5 files changed, 25 insertions(+), 22 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<uint8_t> destination,
> - libcamera::Span<const uint8_t> exifData) = 0;
> + libcamera::Span<const uint8_t> 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<const uint8_t> frame)
> }
>
> int EncoderLibJpeg::encode(const FrameBuffer &source, Span<uint8_t> dest,
> - Span<const uint8_t> exifData)
> + Span<const uint8_t> exifData, unsigned int quality)
> {
> MappedFrameBuffer frame(&source, PROT_READ);
> if (!frame.isValid()) {
> @@ -189,15 +187,17 @@ int EncoderLibJpeg::encode(const FrameBuffer &source, Span<uint8_t> dest,
> return frame.error();
> }
>
> - return encode(frame.maps()[0], dest, exifData);
> + return encode(frame.maps()[0], dest, exifData, quality);
> }
>
> int EncoderLibJpeg::encode(Span<const uint8_t> src, Span<uint8_t> dest,
> - Span<const uint8_t> exifData)
> + Span<const uint8_t> 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<uint8_t> destination,
> - libcamera::Span<const uint8_t> exifData) override;
> + libcamera::Span<const uint8_t> exifData,
> + unsigned int quality) override;
> int encode(libcamera::Span<const uint8_t> source,
> libcamera::Span<uint8_t> destination,
> - libcamera::Span<const uint8_t> exifData);
> + libcamera::Span<const uint8_t> exifData,
> + unsigned int quality);
>
> private:
> void compressRGB(libcamera::Span<const uint8_t> 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 e5e42d39..8b1801b9 100644
> --- a/src/android/jpeg/post_processor_jpeg.cpp
> +++ b/src/android/jpeg/post_processor_jpeg.cpp
> @@ -49,6 +49,7 @@ int PostProcessorJpeg::configure(const StreamConfiguration &inCfg,
>
> void PostProcessorJpeg::generateThumbnail(const FrameBuffer &source,
> const Size &targetSize,
> + unsigned int quality,
> std::vector<unsigned char> *thumbnail)
> {
> /* Stores the raw scaled-down thumbnail bytes. */
> @@ -69,7 +70,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)
> @@ -131,19 +132,20 @@ int PostProcessorJpeg::process(const FrameBuffer &source,
> Size thumbnailSize = { static_cast<uint32_t>(data[0]),
> static_cast<uint32_t>(data[1]) };
>
> + ret = requestMetadata.getEntry(ANDROID_JPEG_THUMBNAIL_QUALITY, &entry);
> + if (ret)
> + resultMetadata->addEntry(ANDROID_JPEG_THUMBNAIL_QUALITY, entry.data.u8, 1);
This should be set to 95 if ANDROID_JPEG_THUMBNAIL_QUALITY isn't
specified as that's the value we use below.
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<unsigned char> thumbnail;
> - generateThumbnail(source, thumbnailSize, &thumbnail);
> + generateThumbnail(source, thumbnailSize,
> + ret ? *entry.data.u8 : 95, &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);
> @@ -164,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 uint32_t jpeg_quality = ret ? *entry.data.u8 : 95;
s/jpeg_quality/jpegQuality/ (or just quality).
This should be a uint8_t otherwise you'll pass the wrong pointer to
->addEntry() and it will fail on big-endian machines.
Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> + resultMetadata->addEntry(ANDROID_JPEG_QUALITY, &jpeg_quality, 1);
> +
> + int jpeg_size = encoder_->encode(source, destination, exif.data(), jpeg_quality);
> if (jpeg_size < 0) {
> LOG(JPEG, Error) << "Failed to encode stream image";
> return jpeg_size;
> @@ -192,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 jpeg_quality = ret ? *entry.data.u8 : 95;
> - resultMetadata->addEntry(ANDROID_JPEG_QUALITY, &jpeg_quality, 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<unsigned char> *thumbnail);
>
> CameraDevice *const cameraDevice_;
--
Regards,
Laurent Pinchart
More information about the libcamera-devel
mailing list