mirror of
https://git.libcamera.org/libcamera/libcamera.git
synced 2025-07-15 00:19:44 +03:00
android: jpeg: Support an initial set of EXIF metadata tags
Create a Exif object with various metadata tags set, just before the encoder starts to encode the frame. The object is passed directly as libcamera::Span<> to make sure EXIF tags can be set in a single place i.e. in CameraDevice and the encoder only has the job to write the data in the final output. Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Signed-off-by: Umang Jain <email@uajain.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
This commit is contained in:
parent
c3d1329b93
commit
6f09a619cc
6 changed files with 88 additions and 4 deletions
|
@ -24,6 +24,7 @@
|
||||||
#include "system/graphics.h"
|
#include "system/graphics.h"
|
||||||
|
|
||||||
#include "jpeg/encoder_libjpeg.h"
|
#include "jpeg/encoder_libjpeg.h"
|
||||||
|
#include "jpeg/exif.h"
|
||||||
|
|
||||||
using namespace libcamera;
|
using namespace libcamera;
|
||||||
|
|
||||||
|
@ -1439,7 +1440,23 @@ void CameraDevice::requestComplete(Request *request)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int jpeg_size = encoder->encode(buffer, mapped.maps()[0]);
|
/* Set EXIF metadata for various tags. */
|
||||||
|
Exif exif;
|
||||||
|
/* \todo Set Make and Model from external vendor tags. */
|
||||||
|
exif.setMake("libcamera");
|
||||||
|
exif.setModel("cameraModel");
|
||||||
|
exif.setOrientation(orientation_);
|
||||||
|
exif.setSize(cameraStream->size);
|
||||||
|
/*
|
||||||
|
* We set the frame's EXIF timestamp as the time of encode.
|
||||||
|
* Since the precision we need for EXIF timestamp is only one
|
||||||
|
* second, it is good enough.
|
||||||
|
*/
|
||||||
|
exif.setTimestamp(std::time(nullptr));
|
||||||
|
if (exif.generate() != 0)
|
||||||
|
LOG(HAL, Error) << "Failed to generate valid EXIF data";
|
||||||
|
|
||||||
|
int jpeg_size = encoder->encode(buffer, mapped.maps()[0], exif.data());
|
||||||
if (jpeg_size < 0) {
|
if (jpeg_size < 0) {
|
||||||
LOG(HAL, Error) << "Failed to encode stream image";
|
LOG(HAL, Error) << "Failed to encode stream image";
|
||||||
status = CAMERA3_BUFFER_STATUS_ERROR;
|
status = CAMERA3_BUFFER_STATUS_ERROR;
|
||||||
|
|
|
@ -18,7 +18,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,
|
||||||
const libcamera::Span<uint8_t> &destination) = 0;
|
const libcamera::Span<uint8_t> &destination,
|
||||||
|
const libcamera::Span<const uint8_t> &exifData) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __ANDROID_JPEG_ENCODER_H__ */
|
#endif /* __ANDROID_JPEG_ENCODER_H__ */
|
||||||
|
|
|
@ -180,7 +180,8 @@ void EncoderLibJpeg::compressNV(const libcamera::MappedBuffer *frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
int EncoderLibJpeg::encode(const FrameBuffer *source,
|
int EncoderLibJpeg::encode(const FrameBuffer *source,
|
||||||
const libcamera::Span<uint8_t> &dest)
|
const libcamera::Span<uint8_t> &dest,
|
||||||
|
const libcamera::Span<const uint8_t> &exifData)
|
||||||
{
|
{
|
||||||
MappedFrameBuffer frame(source, PROT_READ);
|
MappedFrameBuffer frame(source, PROT_READ);
|
||||||
if (!frame.isValid()) {
|
if (!frame.isValid()) {
|
||||||
|
@ -204,6 +205,12 @@ int EncoderLibJpeg::encode(const FrameBuffer *source,
|
||||||
|
|
||||||
jpeg_start_compress(&compress_, TRUE);
|
jpeg_start_compress(&compress_, TRUE);
|
||||||
|
|
||||||
|
if (exifData.size())
|
||||||
|
/* Store Exif data in the JPEG_APP1 data block. */
|
||||||
|
jpeg_write_marker(&compress_, JPEG_APP0 + 1,
|
||||||
|
static_cast<const JOCTET *>(exifData.data()),
|
||||||
|
exifData.size());
|
||||||
|
|
||||||
LOG(JPEG, Debug) << "JPEG Encode Starting:" << compress_.image_width
|
LOG(JPEG, Debug) << "JPEG Encode Starting:" << compress_.image_width
|
||||||
<< "x" << compress_.image_height;
|
<< "x" << compress_.image_height;
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,8 @@ 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,
|
||||||
const libcamera::Span<uint8_t> &destination) override;
|
const libcamera::Span<uint8_t> &destination,
|
||||||
|
const libcamera::Span<const uint8_t> &exifData) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void compressRGB(const libcamera::MappedBuffer *frame);
|
void compressRGB(const libcamera::MappedBuffer *frame);
|
||||||
|
|
|
@ -168,6 +168,56 @@ void Exif::setString(ExifIfd ifd, ExifTag tag, ExifFormat format, const std::str
|
||||||
exif_entry_unref(entry);
|
exif_entry_unref(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Exif::setMake(const std::string &make)
|
||||||
|
{
|
||||||
|
setString(EXIF_IFD_0, EXIF_TAG_MAKE, EXIF_FORMAT_ASCII, make);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Exif::setModel(const std::string &model)
|
||||||
|
{
|
||||||
|
setString(EXIF_IFD_0, EXIF_TAG_MODEL, EXIF_FORMAT_ASCII, model);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Exif::setSize(const Size &size)
|
||||||
|
{
|
||||||
|
setLong(EXIF_IFD_EXIF, EXIF_TAG_PIXEL_Y_DIMENSION, size.height);
|
||||||
|
setLong(EXIF_IFD_EXIF, EXIF_TAG_PIXEL_X_DIMENSION, size.width);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Exif::setTimestamp(time_t timestamp)
|
||||||
|
{
|
||||||
|
char str[20];
|
||||||
|
std::strftime(str, sizeof(str), "%Y:%m:%d %H:%M:%S",
|
||||||
|
std::localtime(×tamp));
|
||||||
|
std::string ts(str);
|
||||||
|
|
||||||
|
setString(EXIF_IFD_0, EXIF_TAG_DATE_TIME, EXIF_FORMAT_ASCII, ts);
|
||||||
|
setString(EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_ORIGINAL, EXIF_FORMAT_ASCII, ts);
|
||||||
|
setString(EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_DIGITIZED, EXIF_FORMAT_ASCII, ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Exif::setOrientation(int orientation)
|
||||||
|
{
|
||||||
|
int value;
|
||||||
|
switch (orientation) {
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
value = 1;
|
||||||
|
break;
|
||||||
|
case 90:
|
||||||
|
value = 8;
|
||||||
|
break;
|
||||||
|
case 180:
|
||||||
|
value = 3;
|
||||||
|
break;
|
||||||
|
case 270:
|
||||||
|
value = 6;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
setShort(EXIF_IFD_0, EXIF_TAG_ORIENTATION, value);
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] int Exif::generate()
|
[[nodiscard]] int Exif::generate()
|
||||||
{
|
{
|
||||||
if (exifData_) {
|
if (exifData_) {
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include <libexif/exif-data.h>
|
#include <libexif/exif-data.h>
|
||||||
|
|
||||||
|
#include <libcamera/geometry.h>
|
||||||
#include <libcamera/span.h>
|
#include <libcamera/span.h>
|
||||||
|
|
||||||
class Exif
|
class Exif
|
||||||
|
@ -20,6 +21,13 @@ public:
|
||||||
Exif();
|
Exif();
|
||||||
~Exif();
|
~Exif();
|
||||||
|
|
||||||
|
void setMake(const std::string &make);
|
||||||
|
void setModel(const std::string &model);
|
||||||
|
|
||||||
|
void setOrientation(int orientation);
|
||||||
|
void setSize(const libcamera::Size &size);
|
||||||
|
void setTimestamp(time_t timestamp);
|
||||||
|
|
||||||
libcamera::Span<const uint8_t> data() const { return { exifData_, size_ }; }
|
libcamera::Span<const uint8_t> data() const { return { exifData_, size_ }; }
|
||||||
[[nodiscard]] int generate();
|
[[nodiscard]] int generate();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue