mirror of
https://git.libcamera.org/libcamera/libcamera.git
synced 2025-07-16 08:55:06 +03:00
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:
parent
a6de3f0203
commit
ab72e6641c
5 changed files with 24 additions and 24 deletions
|
@ -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__ */
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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_;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue