android: jpeg: Set thumbnail and JPEG quality based on request

Set the thumbnail quality and the JPEG quality based on the android
request metadata.

Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
This commit is contained in:
Paul Elder 2021-01-23 14:08:35 +09:00
parent a6de3f0203
commit ab72e6641c
5 changed files with 24 additions and 24 deletions

View file

@ -19,7 +19,8 @@ public:
virtual int configure(const libcamera::StreamConfiguration &cfg) = 0; virtual int configure(const libcamera::StreamConfiguration &cfg) = 0;
virtual int encode(const libcamera::FrameBuffer &source, virtual int encode(const libcamera::FrameBuffer &source,
libcamera::Span<uint8_t> destination, 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__ */ #endif /* __ANDROID_JPEG_ENCODER_H__ */

View file

@ -68,7 +68,6 @@ const struct JPEGPixelFormatInfo &findPixelInfo(const PixelFormat &format)
} /* namespace */ } /* namespace */
EncoderLibJpeg::EncoderLibJpeg() EncoderLibJpeg::EncoderLibJpeg()
: quality_(95)
{ {
/* \todo Expand error handling coverage with a custom handler. */ /* \todo Expand error handling coverage with a custom handler. */
compress_.err = jpeg_std_error(&jerr_); 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; compress_.input_components = info.colorSpace == JCS_GRAYSCALE ? 1 : 3;
jpeg_set_defaults(&compress_); jpeg_set_defaults(&compress_);
jpeg_set_quality(&compress_, quality_, TRUE);
pixelFormatInfo_ = &info.pixelFormatInfo; 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, 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); MappedFrameBuffer frame(&source, PROT_READ);
if (!frame.isValid()) { if (!frame.isValid()) {
@ -189,15 +187,17 @@ int EncoderLibJpeg::encode(const FrameBuffer &source, Span<uint8_t> dest,
return frame.error(); 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, 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 char *destination = dest.data();
unsigned long size = dest.size(); unsigned long size = dest.size();
jpeg_set_quality(&compress_, quality, TRUE);
/* /*
* The jpeg_mem_dest will reallocate if the required size is not * The jpeg_mem_dest will reallocate if the required size is not
* sufficient. That means the output won't be written to the correct * sufficient. That means the output won't be written to the correct

View file

@ -23,10 +23,12 @@ public:
int configure(const libcamera::StreamConfiguration &cfg) override; int configure(const libcamera::StreamConfiguration &cfg) override;
int encode(const libcamera::FrameBuffer &source, int encode(const libcamera::FrameBuffer &source,
libcamera::Span<uint8_t> destination, 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, int encode(libcamera::Span<const uint8_t> source,
libcamera::Span<uint8_t> destination, libcamera::Span<uint8_t> destination,
libcamera::Span<const uint8_t> exifData); libcamera::Span<const uint8_t> exifData,
unsigned int quality);
private: private:
void compressRGB(libcamera::Span<const uint8_t> frame); void compressRGB(libcamera::Span<const uint8_t> frame);
@ -35,8 +37,6 @@ private:
struct jpeg_compress_struct compress_; struct jpeg_compress_struct compress_;
struct jpeg_error_mgr jerr_; struct jpeg_error_mgr jerr_;
unsigned int quality_;
const libcamera::PixelFormatInfo *pixelFormatInfo_; const libcamera::PixelFormatInfo *pixelFormatInfo_;
bool nv_; bool nv_;

View file

@ -52,6 +52,7 @@ int PostProcessorJpeg::configure(const StreamConfiguration &inCfg,
void PostProcessorJpeg::generateThumbnail(const FrameBuffer &source, void PostProcessorJpeg::generateThumbnail(const FrameBuffer &source,
const Size &targetSize, const Size &targetSize,
unsigned int quality,
std::vector<unsigned char> *thumbnail) std::vector<unsigned char> *thumbnail)
{ {
/* Stores the raw scaled-down thumbnail bytes. */ /* Stores the raw scaled-down thumbnail bytes. */
@ -72,7 +73,7 @@ void PostProcessorJpeg::generateThumbnail(const FrameBuffer &source,
thumbnail->resize(rawThumbnail.size()); thumbnail->resize(rawThumbnail.size());
int jpeg_size = thumbnailEncoder_.encode(rawThumbnail, int jpeg_size = thumbnailEncoder_.encode(rawThumbnail,
*thumbnail, {}); *thumbnail, {}, quality);
thumbnail->resize(jpeg_size); thumbnail->resize(jpeg_size);
LOG(JPEG, Debug) LOG(JPEG, Debug)
@ -135,20 +136,18 @@ int PostProcessorJpeg::process(const FrameBuffer &source,
Size thumbnailSize = { static_cast<uint32_t>(data[0]), Size thumbnailSize = { static_cast<uint32_t>(data[0]),
static_cast<uint32_t>(data[1]) }; 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)) { if (thumbnailSize != Size(0, 0)) {
std::vector<unsigned char> thumbnail; std::vector<unsigned char> thumbnail;
generateThumbnail(source, thumbnailSize, &thumbnail); generateThumbnail(source, thumbnailSize, quality, &thumbnail);
if (!thumbnail.empty()) if (!thumbnail.empty())
exif.setThumbnail(thumbnail, Exif::Compression::JPEG); exif.setThumbnail(thumbnail, Exif::Compression::JPEG);
} }
resultMetadata->addEntry(ANDROID_JPEG_THUMBNAIL_SIZE, data, 2); 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); ret = requestMetadata.getEntry(ANDROID_JPEG_GPS_COORDINATES, &entry);
@ -169,7 +168,11 @@ int PostProcessorJpeg::process(const FrameBuffer &source,
if (exif.generate() != 0) if (exif.generate() != 0)
LOG(JPEG, Error) << "Failed to generate valid EXIF data"; 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) { if (jpeg_size < 0) {
LOG(JPEG, Error) << "Failed to encode stream image"; LOG(JPEG, Error) << "Failed to encode stream image";
return jpeg_size; return jpeg_size;
@ -197,10 +200,5 @@ int PostProcessorJpeg::process(const FrameBuffer &source,
/* Update the JPEG result Metadata. */ /* Update the JPEG result Metadata. */
resultMetadata->addEntry(ANDROID_JPEG_SIZE, &jpeg_size, 1); 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; return 0;
} }

View file

@ -32,6 +32,7 @@ public:
private: private:
void generateThumbnail(const libcamera::FrameBuffer &source, void generateThumbnail(const libcamera::FrameBuffer &source,
const libcamera::Size &targetSize, const libcamera::Size &targetSize,
unsigned int quality,
std::vector<unsigned char> *thumbnail); std::vector<unsigned char> *thumbnail);
CameraDevice *const cameraDevice_; CameraDevice *const cameraDevice_;