[libcamera-devel] [PATCH v5 8/8] android: jpeg: Set thumbnail and JPEG quality based on request
Paul Elder
paul.elder at ideasonboard.com
Tue Jan 26 11:28:25 CET 2021
Set the thumbnail quality and the JPEG quality based on the android
request metadata.
Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo at jmondi.org>
---
No change in v5
Changes in v4:
- set jpeg quality to 95 by default
New in v3
---
src/android/camera_device.cpp | 4 +++-
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 +
6 files changed, 27 insertions(+), 25 deletions(-)
diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp
index d297bdf4..a0865911 100644
--- a/src/android/camera_device.cpp
+++ b/src/android/camera_device.cpp
@@ -708,7 +708,7 @@ std::tuple<uint32_t, uint32_t> CameraDevice::calculateStaticMetadataSize()
* Currently: 53 entries, 782 bytes of static metadata
*/
uint32_t numEntries = 53;
- uint32_t byteSize = 802;
+ uint32_t byteSize = 810;
/*
* Calculate space occupation in bytes for dynamically built metadata
@@ -1272,6 +1272,8 @@ const camera_metadata_t *CameraDevice::getStaticMetadata()
ANDROID_JPEG_SIZE,
ANDROID_JPEG_QUALITY,
ANDROID_JPEG_ORIENTATION,
+ ANDROID_JPEG_THUMBNAIL_QUALITY,
+ ANDROID_JPEG_THUMBNAIL_SIZE,
};
staticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS,
availableResultKeys.data(),
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 e990ba04..cac0087b 100644
--- a/src/android/jpeg/post_processor_jpeg.cpp
+++ b/src/android/jpeg/post_processor_jpeg.cpp
@@ -52,6 +52,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. */
@@ -72,7 +73,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)
@@ -135,20 +136,18 @@ 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);
+ 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, 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);
@@ -169,7 +168,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;
@@ -197,10 +200,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 uint8_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<unsigned char> *thumbnail);
CameraDevice *const cameraDevice_;
--
2.27.0
More information about the libcamera-devel
mailing list