mirror of
https://git.libcamera.org/libcamera/libcamera.git
synced 2025-07-13 15:29:45 +03:00
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:
parent
abfabdd6e7
commit
1264628d3c
5 changed files with 44 additions and 43 deletions
|
@ -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(),
|
||||
|
@ -1918,7 +1920,7 @@ CameraDevice::getResultMetadata(Camera3RequestDescriptor *descriptor,
|
|||
|
||||
/*
|
||||
* \todo Keep this in sync with the actual number of entries.
|
||||
* Currently: 38 entries, 147 bytes
|
||||
* Currently: 40 entries, 156 bytes
|
||||
*
|
||||
* Reserve more space for the JPEG metadata set by the post-processor.
|
||||
* Currently:
|
||||
|
@ -1928,10 +1930,12 @@ CameraDevice::getResultMetadata(Camera3RequestDescriptor *descriptor,
|
|||
* ANDROID_JPEG_SIZE (int32_t) = 4 bytes
|
||||
* ANDROID_JPEG_QUALITY (byte) = 1 byte
|
||||
* ANDROID_JPEG_ORIENTATION (int32_t) = 4 bytes
|
||||
* Total bytes for JPEG metadata: 73
|
||||
* ANDROID_JPEG_THUMBNAIL_QUALITY (byte) = 1 byte
|
||||
* ANDROID_JPEG_THUMBNAIL_SIZE (int32 x 2) = 8 bytes
|
||||
* Total bytes for JPEG metadata: 82
|
||||
*/
|
||||
std::unique_ptr<CameraMetadata> resultMetadata =
|
||||
std::make_unique<CameraMetadata>(38, 147);
|
||||
std::make_unique<CameraMetadata>(40, 156);
|
||||
if (!resultMetadata->isValid()) {
|
||||
LOG(HAL, Error) << "Failed to allocate static metadata";
|
||||
return nullptr;
|
||||
|
|
|
@ -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";
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ public:
|
|||
|
||||
private:
|
||||
void generateThumbnail(const libcamera::FrameBuffer &source,
|
||||
const libcamera::Size &targetSize,
|
||||
std::vector<unsigned char> *thumbnail);
|
||||
|
||||
CameraDevice *const cameraDevice_;
|
||||
|
|
|
@ -32,30 +32,11 @@ void Thumbnailer::configure(const Size &sourceSize, PixelFormat pixelFormat)
|
|||
return;
|
||||
}
|
||||
|
||||
targetSize_ = computeThumbnailSize();
|
||||
|
||||
valid_ = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* The Exif specification recommends the width of the thumbnail to be a
|
||||
* multiple of 16 (section 4.8.1). Hence, compute the corresponding height
|
||||
* keeping the aspect ratio same as of the source.
|
||||
*/
|
||||
Size Thumbnailer::computeThumbnailSize() const
|
||||
{
|
||||
unsigned int targetHeight;
|
||||
constexpr unsigned int kTargetWidth = 160;
|
||||
|
||||
targetHeight = kTargetWidth * sourceSize_.height / sourceSize_.width;
|
||||
|
||||
if (targetHeight & 1)
|
||||
targetHeight++;
|
||||
|
||||
return Size(kTargetWidth, targetHeight);
|
||||
}
|
||||
|
||||
void Thumbnailer::createThumbnail(const FrameBuffer &source,
|
||||
const Size &targetSize,
|
||||
std::vector<unsigned char> *destination)
|
||||
{
|
||||
MappedFrameBuffer frame(&source, PROT_READ);
|
||||
|
@ -73,8 +54,8 @@ void Thumbnailer::createThumbnail(const FrameBuffer &source,
|
|||
|
||||
const unsigned int sw = sourceSize_.width;
|
||||
const unsigned int sh = sourceSize_.height;
|
||||
const unsigned int tw = targetSize_.width;
|
||||
const unsigned int th = targetSize_.height;
|
||||
const unsigned int tw = targetSize.width;
|
||||
const unsigned int th = targetSize.height;
|
||||
|
||||
ASSERT(tw % 2 == 0 && th % 2 == 0);
|
||||
|
||||
|
|
|
@ -20,15 +20,13 @@ public:
|
|||
void configure(const libcamera::Size &sourceSize,
|
||||
libcamera::PixelFormat pixelFormat);
|
||||
void createThumbnail(const libcamera::FrameBuffer &source,
|
||||
const libcamera::Size &targetSize,
|
||||
std::vector<unsigned char> *dest);
|
||||
const libcamera::Size &size() const { return targetSize_; }
|
||||
const libcamera::PixelFormat &pixelFormat() const { return pixelFormat_; }
|
||||
|
||||
private:
|
||||
libcamera::Size computeThumbnailSize() const;
|
||||
|
||||
libcamera::PixelFormat pixelFormat_;
|
||||
libcamera::Size sourceSize_;
|
||||
libcamera::Size targetSize_;
|
||||
|
||||
bool valid_;
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue