[libcamera-devel] [PATCH v3 1/3] android: camera_metadata: Auto-resize CameraMetadata

Hirokazu Honda hiroh at chromium.org
Thu May 13 05:26:29 CEST 2021


Hi Paul, thank you for the patch.

On Wed, May 12, 2021 at 7:25 PM Paul Elder <paul.elder at ideasonboard.com>
wrote:

> Previously we had to manually declare the size of CameraMetadata on
> allocation, and its count could not be changed after construction.
> Change CameraMetadata's behavior so that the user can simply add or
> update entries, and the CameraMetadata will auto-resize (double the
> size) as necessary. Also remove everything involved with calculating
> the initial size for any CameraMetadata instances.
>
> Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>
>
> ---
> Changes in v3:
> - dependency on "FULL hardware level fixes" removed
> - split addEntry and updateEntry
>   - i think the lookup on every (merged) addEntry isn't worth it, since
>     the user probably knows if they need to add or update
> - add auto-resize (and corresponding check) to updateEntry as well
> - add the templates and overloads to updateEntry as well
> - increase the default size for the static metadata to be above what we
>   had before
> - valid_ is now used to indicate a failed addEntry/updateEntry in
>   addition to metadata_ == nullptr. this way the user doesn't have to
>   check the return value of every single addEntry/updateEntry call, and
>   can just check valid_ at the end
> - print resize when it happens
> - updateEntry resizes if the new data size is greater than the old data
>
> Question: I think on failure of addEntry/updateEntry the metadata could
> still be "valid", it's just that the content isn't what the user
> expects. Should we keep valid_ as I've repurposed it here in v3, or
> should we add another flag?
>
> Changes in v2:
> - add overloading of addEntry
> - better logging with the separation of core code vs template code
> - addEntry failure makes the metadata invalid
>
> The main feature of v2 is the overloading of addEntry. I have three
> overloads and the main one:
> - tag, single piece of data (reference)
> - tag, vector (v3: s/span/vector/)
> - tag, data pointer, count
> - tag, data pointer, count, size of one instance of the data
>
> The last one is the main one, and is not templated. The first two are
> nice and convenient, because now we can do things like:
>
> uint32_t orientation = 0;
> resultMetadata->addEntry(ANDROID_JPEG_ORIENTATION, orientation);
>
> and
>
> std::vector<uint32_t> availableStates = { SOME_STATE_1, SOME_STATE_2 };
> metadata->addEntry(ANDROID_AVAILABLE_STATES, availableStates);
>
> The third is for when android metadata is copied directly from another
> piece of android metadata. This is very common, and wasn't very nice
> having to wrap everything in a Span. All the old calls are
> backward-compatible using this overload.
> ---
>  src/android/camera_device.cpp   | 47 +-----------------
>  src/android/camera_device.h     |  1 -
>  src/android/camera_metadata.cpp | 84 +++++++++++++++++++++++++++++----
>  src/android/camera_metadata.h   | 44 ++++++++++++++++-
>  4 files changed, 117 insertions(+), 59 deletions(-)
>
> diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp
> index 7d4d0feb..74f6915c 100644
> --- a/src/android/camera_device.cpp
> +++ b/src/android/camera_device.cpp
> @@ -773,43 +773,6 @@ void CameraDevice::setCallbacks(const
> camera3_callback_ops_t *callbacks)
>         callbacks_ = callbacks;
>  }
>
> -std::tuple<uint32_t, uint32_t> CameraDevice::calculateStaticMetadataSize()
> -{
> -       /*
> -        * \todo Keep this in sync with the actual number of entries.
> -        * Currently: 54 entries, 874 bytes of static metadata
> -        */
> -       uint32_t numEntries = 54;
> -       uint32_t byteSize = 874;
> -
> -       /*
> -        * Calculate space occupation in bytes for dynamically built
> metadata
> -        * entries.
> -        *
> -        * Each stream configuration entry requires 48 bytes:
> -        * 4 32bits integers for
> ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS
> -        * 4 64bits integers for
> ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS
> -        */
> -       byteSize += streamConfigurations_.size() * 48;
> -
> -       /*
> -        * 2 32bits integers for each HAL_PIXEL_FORMAT_BLOB for thumbnail
> sizes
> -        * 2 32bits integers for the (0, 0) thumbnail size
> -        *
> -        * This is a worst case estimates as different configurations with
> the
> -        * same aspect ratio will generate the same size.
> -        */
> -       for (const auto &entry : streamConfigurations_) {
> -               if (entry.androidFormat != HAL_PIXEL_FORMAT_BLOB)
> -                       continue;
> -
> -               byteSize += 8;
> -       }
> -       byteSize += 8;
> -
> -       return std::make_tuple(numEntries, byteSize);
> -}
> -
>  /*
>   * Return static information for the camera.
>   */
> @@ -818,15 +781,7 @@ const camera_metadata_t
> *CameraDevice::getStaticMetadata()
>         if (staticMetadata_)
>                 return staticMetadata_->get();
>
> -       /*
> -        * The here reported metadata are enough to implement a basic
> capture
> -        * example application, but a real camera implementation will
> require
> -        * more.
> -        */
> -       uint32_t numEntries;
> -       uint32_t byteSize;
> -       std::tie(numEntries, byteSize) = calculateStaticMetadataSize();
> -       staticMetadata_ = std::make_unique<CameraMetadata>(numEntries,
> byteSize);
> +       staticMetadata_ = std::make_unique<CameraMetadata>(64, 1024);
>         if (!staticMetadata_->isValid()) {
>                 LOG(HAL, Error) << "Failed to allocate static metadata";
>                 staticMetadata_.reset();
> diff --git a/src/android/camera_device.h b/src/android/camera_device.h
> index 23457e47..ae162a45 100644
> --- a/src/android/camera_device.h
> +++ b/src/android/camera_device.h
> @@ -98,7 +98,6 @@ private:
>         std::vector<libcamera::Size>
>         getRawResolutions(const libcamera::PixelFormat &pixelFormat);
>
> -       std::tuple<uint32_t, uint32_t> calculateStaticMetadataSize();
>         libcamera::FrameBuffer *createFrameBuffer(const buffer_handle_t
> camera3buffer);
>         void notifyShutter(uint32_t frameNumber, uint64_t timestamp);
>         void notifyError(uint32_t frameNumber, camera3_stream_t *stream);
> diff --git a/src/android/camera_metadata.cpp
> b/src/android/camera_metadata.cpp
> index 6f1bcdbe..6394fd74 100644
> --- a/src/android/camera_metadata.cpp
> +++ b/src/android/camera_metadata.cpp
> @@ -63,14 +63,67 @@ bool CameraMetadata::getEntry(uint32_t tag,
> camera_metadata_ro_entry_t *entry) c
>         return true;
>  }
>
> -bool CameraMetadata::addEntry(uint32_t tag, const void *data, size_t
> count)
> +/*
> + * \brief Resize the metadata container, if necessary
> + * \param[in] count Number of entries to add to the container
> + * \param[in] size Total size of entries to add, in bytes
> + * \return True if resize was successful or unnecessary, false otherwise
> + */
> +bool CameraMetadata::resize(size_t count, size_t size)
>  {
>         if (!valid_)
>                 return false;
>
> -       if (!add_camera_metadata_entry(metadata_, tag, data, count))
> +       if (!count && !size)
>                 return true;
>
> +       size_t currentEntryCount =
> get_camera_metadata_entry_count(metadata_);
> +       size_t currentEntryCapacity =
> get_camera_metadata_entry_capacity(metadata_);
> +       size_t newEntryCapacity = currentEntryCapacity < currentEntryCount
> + count ?
> +                                 currentEntryCapacity * 2 :
> currentEntryCapacity;
> +
> +       size_t currentDataCount =
> get_camera_metadata_data_count(metadata_);
> +       size_t currentDataCapacity =
> get_camera_metadata_data_capacity(metadata_);
> +       size_t newDataCapacity = currentDataCapacity < currentDataCount +
> size ?
> +                                currentDataCapacity * 2 :
> currentDataCapacity;
> +
> +       if (newEntryCapacity > currentEntryCapacity ||
> +           newDataCapacity > currentDataCapacity) {
> +               camera_metadata_t *oldMetadata = metadata_;
> +               metadata_ = allocate_camera_metadata(newEntryCapacity,
> newDataCapacity);
> +               if (!metadata_) {
> +                       metadata_ = oldMetadata;
> +                       return false;
> +               }
> +
> +               LOG(CameraMetadata, Info)
> +                       << "Resized: old entry capacity " <<
> currentEntryCapacity
> +                       << ", old data capacity " << currentDataCapacity
> +                       << ", new entry capacity " << newEntryCapacity
> +                       << ", new data capacity " << newDataCapacity;
> +
> +               append_camera_metadata(metadata_, oldMetadata);
> +               free_camera_metadata(oldMetadata);
> +       }
> +
> +       return true;
> +}
> +
> +void CameraMetadata::addEntry(uint32_t tag, const void *data, size_t
> count,
> +                             size_t sizeofT)
> +{
> +       if (!valid_)
> +               return;
> +
> +       if (!resize(1, count * sizeofT)) {
> +               LOG(CameraMetadata, Error) << "Failed to resize";
> +               valid_ = false;
> +               return;
> +       }
> +
> +       if (!add_camera_metadata_entry(metadata_, tag, data, count))
> +               return;
> +
>         const char *name = get_camera_metadata_tag_name(tag);
>         if (name)
>                 LOG(CameraMetadata, Error)
> @@ -80,14 +133,13 @@ bool CameraMetadata::addEntry(uint32_t tag, const
> void *data, size_t count)
>                         << "Failed to add unknown tag " << tag;
>
>         valid_ = false;
> -
> -       return false;
>  }
>
> -bool CameraMetadata::updateEntry(uint32_t tag, const void *data, size_t
> count)
> +void CameraMetadata::updateEntry(uint32_t tag, const void *data, size_t
> count,
> +                                size_t sizeofT)
>  {
>         if (!valid_)
> -               return false;
> +               return;
>
>         camera_metadata_entry_t entry;
>         int ret = find_camera_metadata_entry(metadata_, tag, &entry);
> @@ -96,7 +148,20 @@ bool CameraMetadata::updateEntry(uint32_t tag, const
> void *data, size_t count)
>                 LOG(CameraMetadata, Error)
>                         << "Failed to update tag "
>                         << (name ? name : "<unknown>") << ": not present";
> -               return false;
> +               return;
> +       }
> +
> +       size_t oldSize =
> +               calculate_camera_metadata_entry_data_size(entry.type,
> +                                                         entry.count);
> +       size_t newSize =
> +               calculate_camera_metadata_entry_data_size(entry.type,
> +                                                         count * sizeofT);
>

I am confused by this.
calculate_camera_metadata_entry_data_size() looks up the size of one
element for the type and computes the required size multiplying by the
count.
That is, newSize seems to be sizeofT * count * sizeofT.
Am I missing something?

+       size_t sizeIncrement = newSize - oldSize > 0 ? newSize - oldSize :
> 0;
> +       if (!resize(0, count * sizeIncrement)) {
> +               LOG(CameraMetadata, Error) << "Failed to resize";
> +               valid_ = false;
> +               return;
>         }
>
>         ret = update_camera_metadata_entry(metadata_, entry.index, data,
> @@ -105,10 +170,9 @@ bool CameraMetadata::updateEntry(uint32_t tag, const
> void *data, size_t count)
>                 const char *name = get_camera_metadata_tag_name(tag);
>                 LOG(CameraMetadata, Error)
>                         << "Failed to update tag " << (name ? name :
> "<unknown>");
> -               return false;
> -       }
>
> -       return true;
> +               valid_ = false;
> +       }
>  }
>
>  camera_metadata_t *CameraMetadata::get()
> diff --git a/src/android/camera_metadata.h b/src/android/camera_metadata.h
> index d653e2f0..aa875fe4 100644
> --- a/src/android/camera_metadata.h
> +++ b/src/android/camera_metadata.h
> @@ -8,6 +8,7 @@
>  #define __ANDROID_CAMERA_METADATA_H__
>
>  #include <stdint.h>
> +#include <vector>
>
>  #include <system/camera_metadata.h>
>
> @@ -23,9 +24,48 @@ public:
>         CameraMetadata &operator=(const CameraMetadata &other);
>
>         bool isValid() const { return valid_; }
> +       bool resize(size_t count, size_t size);
>         bool getEntry(uint32_t tag, camera_metadata_ro_entry_t *entry)
> const;
> -       bool addEntry(uint32_t tag, const void *data, size_t data_count);
> -       bool updateEntry(uint32_t tag, const void *data, size_t
> data_count);
> +
> +       template<typename T,
> +                std::enable_if_t<std::is_arithmetic_v<T>> * = nullptr>
> +       void addEntry(uint32_t tag, const T &data)
> +       {
> +               addEntry(tag, &data, 1, sizeof(T));
> +       }
> +
> +       template<typename T>
> +       void addEntry(uint32_t tag, std::vector<T> &data)
> +       {
> +               addEntry(tag, data.data(), data.size(), sizeof(T));
> +       }
> +
>

s/std::vector<T>/Span<const T>/
ditto to updateEntry().

We can use a row array, for example, for aeAvailableAntiBandingModes.

-Hiro

+       template<typename T>
> +       void addEntry(uint32_t tag, const T *data, size_t count)
> +       {
> +               addEntry(tag, data, count, sizeof(T));
> +       }
> +
> +       template<typename T>
> +       void updateEntry(uint32_t tag, const T &data)
> +       {
> +               updateEntry(tag, &data, 1, sizeof(T));
> +       }
> +
> +       template<typename T>
> +       void updateEntry(uint32_t tag, std::vector<T> &data)
> +       {
> +               updateEntry(tag, data.data(), data.size(), sizeof(T));
> +       }
> +
> +       template<typename T>
> +       void updateEntry(uint32_t tag, const T *data, size_t count)
> +       {
> +               updateEntry(tag, data, count, sizeof(T));
> +       }
> +
> +       void addEntry(uint32_t tag, const void *data, size_t count, size_t
> sizeofT);
> +       void updateEntry(uint32_t tag, const void *data, size_t count,
> size_t sizeofT);
>
>         camera_metadata_t *get();
>         const camera_metadata_t *get() const;
> --
> 2.27.0
>
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel at lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.libcamera.org/pipermail/libcamera-devel/attachments/20210513/17bdee6f/attachment-0001.htm>


More information about the libcamera-devel mailing list