android: jpeg: Configure thumbnailer based on request metadata

Configure the thumbnailer based on the thumbnail parameters given by the
android request metadata. Only the thumbnail encoder needs to be
configured, and since it is only used at post-processing time, move the
configuration out of the post-processor constructor and into the
processing step.

Also set the following android result metadata tags:
- ANDROID_JPEG_THUMBNAIL_SIZE
- ANDROID_JPEG_THUMBNAIL_QUALITY

Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
This commit is contained in:
Paul Elder 2021-01-23 13:56:01 +09:00
parent abfabdd6e7
commit 1264628d3c
5 changed files with 44 additions and 43 deletions

View file

@ -44,12 +44,6 @@ int PostProcessorJpeg::configure(const StreamConfiguration &inCfg,
streamSize_ = outCfg.size;
thumbnailer_.configure(inCfg.size, inCfg.pixelFormat);
StreamConfiguration thCfg = inCfg;
thCfg.size = thumbnailer_.size();
if (thumbnailEncoder_.configure(thCfg) != 0) {
LOG(JPEG, Error) << "Failed to configure thumbnail encoder";
return -EINVAL;
}
encoder_ = std::make_unique<EncoderLibJpeg>();
@ -57,14 +51,20 @@ int PostProcessorJpeg::configure(const StreamConfiguration &inCfg,
}
void PostProcessorJpeg::generateThumbnail(const FrameBuffer &source,
const Size &targetSize,
std::vector<unsigned char> *thumbnail)
{
/* Stores the raw scaled-down thumbnail bytes. */
std::vector<unsigned char> rawThumbnail;
thumbnailer_.createThumbnail(source, &rawThumbnail);
thumbnailer_.createThumbnail(source, targetSize, &rawThumbnail);
if (!rawThumbnail.empty()) {
StreamConfiguration thCfg;
thCfg.size = targetSize;
thCfg.pixelFormat = thumbnailer_.pixelFormat();
int ret = thumbnailEncoder_.configure(thCfg);
if (!rawThumbnail.empty() && !ret) {
/*
* \todo Avoid value-initialization of all elements of the
* vector.
@ -129,6 +129,28 @@ int PostProcessorJpeg::process(const FrameBuffer &source,
entry.data.i64, 1);
}
ret = requestMetadata.getEntry(ANDROID_JPEG_THUMBNAIL_SIZE, &entry);
if (ret) {
const int32_t *data = entry.data.i32;
Size thumbnailSize = { static_cast<uint32_t>(data[0]),
static_cast<uint32_t>(data[1]) };
if (thumbnailSize != Size(0, 0)) {
std::vector<unsigned char> thumbnail;
generateThumbnail(source, thumbnailSize, &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);
if (ret) {
exif.setGPSLocation(entry.data.d);
@ -144,11 +166,6 @@ int PostProcessorJpeg::process(const FrameBuffer &source,
entry.data.u8, entry.count);
}
std::vector<unsigned char> thumbnail;
generateThumbnail(source, &thumbnail);
if (!thumbnail.empty())
exif.setThumbnail(thumbnail, Exif::Compression::JPEG);
if (exif.generate() != 0)
LOG(JPEG, Error) << "Failed to generate valid EXIF data";