[libcamera-devel] [PATCH 3/3] android: Support initial set of EXIF metadata tags
Kieran Bingham
kieran.bingham at ideasonboard.com
Mon Aug 24 23:14:40 CEST 2020
Hi Umang,
On 24/08/2020 21:46, Umang Jain wrote:
> Support a initial set of EXIF metadata tags namely:
> Make, Model, Height, Width, Orientation and Timestamp.
> Each tag is set by a convenient high level helper API
> defined in exif.h.
>
> Signed-off-by: Umang Jain <email at uajain.com>
> ---
> src/android/camera_device.cpp | 8 +++++++
> src/android/jpeg/encoder_libjpeg.cpp | 12 ++++++++++
> src/android/jpeg/exif.cpp | 34 ++++++++++++++++++++++++++++
> src/android/jpeg/exif.h | 8 +++++++
I'd merge the helpers directly into the Exif object creation patch (and
take authorship on that if you like), or as an additional patch on it's
own after.
> 4 files changed, 62 insertions(+)
>
> diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp
> index bc5690e..fcf378a 100644
> --- a/src/android/camera_device.cpp
> +++ b/src/android/camera_device.cpp
> @@ -1435,6 +1435,14 @@ void CameraDevice::requestComplete(Request *request)
> }
>
> Exif exif;
> + /*
> + * \todo Discuss setMake String, maybe vendor ID?
> + * KB suggested to leave it to "libcamera" for now.
> + * setModel should use the 'model' property of the camera.
> + */
I think ultimately this will indeed need to come from some sort of
vendor tag. But I don't think we have those yet, so libcamera should be
fine for now ;-)
> + exif.setMake("Libcamera");
libcamera always has a lowercase 'l'.
> + exif.setModel("cameraModel");
Aha, are the patches for setting the model not integrated yet ?
That would indeed mean it's a todo for now, but hopefully that will be
usable really soon, so I hope that can be done before these patches get in.
> + exif.setOrientation(orientation_);
>
> int jpeg_size = encoder->encode(buffer, mapped.maps()[0], &exif);
> if (jpeg_size < 0) {
> diff --git a/src/android/jpeg/encoder_libjpeg.cpp b/src/android/jpeg/encoder_libjpeg.cpp
> index 0cd93b6..f84def9 100644
> --- a/src/android/jpeg/encoder_libjpeg.cpp
> +++ b/src/android/jpeg/encoder_libjpeg.cpp
> @@ -213,7 +213,19 @@ int EncoderLibJpeg::encode(const FrameBuffer *source,
> else
> compressRGB(&frame);
>
> + exif->setWidth(compress_.image_width);
> + exif->setHeight(compress_.image_height);
> + exif->setTimestamp(source->metadata().timestamp);
I hope all three of those could be obtained/determined in the layer
above, so we don't need to pass in the whole exif object, just the
generated span,
> +
> + Span<uint8_t> exif_data = exif->generate();
> +
So if you can do that in the camera_device.cpp, then we
> jpeg_finish_compress(&compress_);
>
> + if (exif->size())
> + /* Store Exif data in the JPEG_APP1 data block. */
> + jpeg_write_marker(&compress_, JPEG_APP0 + 1,
> + static_cast<const JOCTET *>(exif_data.data()),
> + exif_data.size());
> +
> return size;
> }
> diff --git a/src/android/jpeg/exif.cpp b/src/android/jpeg/exif.cpp
> index f6a9f5c..b7591d5 100644
> --- a/src/android/jpeg/exif.cpp
> +++ b/src/android/jpeg/exif.cpp
> @@ -160,6 +160,40 @@ int Exif::setString(ExifIfd ifd, ExifTag tag, ExifFormat format, const std::stri
> return 0;
> }
>
> +int Exif::setHeight(uint16_t height)
> +{
> + setShort(EXIF_IFD_0, EXIF_TAG_IMAGE_LENGTH, height);
> + setLong(EXIF_IFD_EXIF, EXIF_TAG_PIXEL_Y_DIMENSION, height);
> +
> + return 0;
> +}
> +
> +int Exif::setWidth(uint16_t width)
> +{
> + setShort(EXIF_IFD_0, EXIF_TAG_IMAGE_WIDTH, width);
> + setLong(EXIF_IFD_EXIF, EXIF_TAG_PIXEL_X_DIMENSION, width);
> +
> + return 0;
> +}
> +
> +int Exif::setTimestamp(const time_t timestamp)
> +{
> + std::string ts(std::ctime(×tamp));
> + int ret = setString(EXIF_IFD_0, EXIF_TAG_DATE_TIME, EXIF_FORMAT_ASCII, ts);
> + if(ret < 0)
> + return ret;
> +
> + ret = setString(EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_ORIGINAL, EXIF_FORMAT_ASCII, ts);
> + if(ret < 0)
> + return ret;
> +
> + ret = setString(EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_DIGITIZED, EXIF_FORMAT_ASCII, ts);
> + if(ret < 0)
> + return ret;
> +
> + return ret;
> +}
> +
> Span<uint8_t> Exif::generate()
> {
> if (exif_data_) {
> diff --git a/src/android/jpeg/exif.h b/src/android/jpeg/exif.h
> index 7df83c7..6a8f5f5 100644
> --- a/src/android/jpeg/exif.h
> +++ b/src/android/jpeg/exif.h
> @@ -11,6 +11,7 @@
>
> #include <libcamera/span.h>
>
> +#include <ctime>
> #include <string>
>
> class Exif
> @@ -24,6 +25,13 @@ public:
> int setString(ExifIfd ifd, ExifTag tag, ExifFormat format, const std::string &item);
> int setRational(ExifIfd ifd, ExifTag tag, uint32_t numerator, uint32_t denominator);
>
> + int setHeight(uint16_t height);
> + int setMake(const std::string &make) { return setString(EXIF_IFD_0, EXIF_TAG_MAKE, EXIF_FORMAT_ASCII, make); }
> + int setModel(const std::string &model) { return setString(EXIF_IFD_0, EXIF_TAG_MODEL, EXIF_FORMAT_ASCII, model); }
> + int setOrientation(int orientation) { return setShort(EXIF_IFD_0, EXIF_TAG_ORIENTATION, orientation); }
Even if they're short, I think these implementations would probably be
better in the .cpp so that all helpers are in the same place.
Orientation will potentially be more complex too, as I think there will
need to be a translation between the libcamera orientation value, and
the Exif orientation values.
I remember seeing some helpful comments in the USB HAL in CrOS/Camera2
for that.
> + int setTimestamp(const time_t timestamp);
> + int setWidth(uint16_t width);
I'd group by feature over sorting alphabetically, and keep setWidth,
setHeight together.
--
Kieran
> +
> libcamera::Span<uint8_t> generate();
> unsigned char *data() const { return exif_data_; }
> unsigned int size() const { return size_; }
>
--
Regards
--
Kieran
More information about the libcamera-devel
mailing list