/* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ //#define LOG_NDEBUG 0 #define LOG_TAG "GCH_HalCameraMetadata" #define ATRACE_TAG ATRACE_TAG_CAMERA #include #include #include #include "hal_camera_metadata.h" namespace android { namespace google_camera_hal { std::unique_ptr HalCameraMetadata::Create( camera_metadata_t* metadata) { if (metadata == nullptr) { ALOGE("%s: metadata cannot be nullptr.", __FUNCTION__); return nullptr; } auto hal_metadata = std::unique_ptr(new HalCameraMetadata(metadata)); if (hal_metadata == nullptr) { ALOGE("%s: Creating HalCameraMetadata failed.", __FUNCTION__); return nullptr; } return hal_metadata; } std::unique_ptr HalCameraMetadata::Create( size_t entry_capacity, size_t data_capacity) { camera_metadata_t* metadata = allocate_camera_metadata(entry_capacity, data_capacity); if (metadata == nullptr) { ALOGE("%s: Allocating camera metadata failed.", __FUNCTION__); return nullptr; } auto hal_metadata = Create(metadata); if (hal_metadata == nullptr) { free_camera_metadata(metadata); return nullptr; } return hal_metadata; } std::unique_ptr HalCameraMetadata::Clone( const camera_metadata_t* metadata) { if (metadata == nullptr) { ALOGE("%s: metadata cannot be nullptr.", __FUNCTION__); return nullptr; } camera_metadata_t* cloned_metadata = clone_camera_metadata(metadata); if (cloned_metadata == nullptr) { ALOGE("%s: Cloning camera metadata failed.", __FUNCTION__); return nullptr; } auto hal_metadata = Create(cloned_metadata); if (hal_metadata == nullptr) { free_camera_metadata(cloned_metadata); return nullptr; } return hal_metadata; } std::unique_ptr HalCameraMetadata::Clone( const HalCameraMetadata* hal_metadata) { if (hal_metadata == nullptr) { return nullptr; } return Clone(hal_metadata->metadata_); } HalCameraMetadata::~HalCameraMetadata() { std::unique_lock lock(metadata_lock_); if (metadata_ != nullptr) { free_camera_metadata(metadata_); } } HalCameraMetadata::HalCameraMetadata(camera_metadata_t* metadata) : metadata_(metadata) { } camera_metadata_t* HalCameraMetadata::ReleaseCameraMetadata() { std::unique_lock lock(metadata_lock_); camera_metadata_t* metadata = metadata_; metadata_ = nullptr; return metadata; } const camera_metadata_t* HalCameraMetadata::GetRawCameraMetadata() const { return metadata_; } size_t HalCameraMetadata::GetCameraMetadataSize() const { std::unique_lock lock(metadata_lock_); if (metadata_ == nullptr) { return 0; } return get_camera_metadata_size(metadata_); } status_t HalCameraMetadata::ResizeIfNeeded(size_t extra_entries, size_t extra_data) { bool resize = false; size_t current_entry_cap = get_camera_metadata_entry_capacity(metadata_); size_t new_entry_count = get_camera_metadata_entry_count(metadata_) + extra_entries; if (new_entry_count > current_entry_cap) { new_entry_count = new_entry_count * 2; resize = true; } else { new_entry_count = current_entry_cap; } size_t current_data_count = get_camera_metadata_data_count(metadata_); size_t current_data_cap = get_camera_metadata_data_capacity(metadata_); size_t new_data_count = current_data_count + extra_data; if (new_data_count > current_data_cap) { new_data_count = new_data_count * 2; resize = true; } else { new_data_count = current_data_cap; } if (resize) { camera_metadata_t* metadata = metadata_; metadata_ = allocate_camera_metadata(new_entry_count, new_data_count); if (metadata_ == nullptr) { ALOGE("%s: Can't allocate larger metadata buffer", __FUNCTION__); metadata_ = metadata; return NO_MEMORY; } append_camera_metadata(metadata_, metadata); free_camera_metadata(metadata); } return OK; } status_t HalCameraMetadata::SetMetadataRaw(uint32_t tag, const void* data, size_t data_count) { status_t res; int type = get_camera_metadata_tag_type(tag); if (type == -1) { ALOGE("%s: Tag %d not found", __FUNCTION__, tag); return BAD_VALUE; } // Safety check - ensure that data isn't pointing to this metadata, since // that would get invalidated if a resize is needed size_t buffer_size = get_camera_metadata_size(metadata_); uintptr_t buffer_addr = reinterpret_cast(metadata_); uintptr_t data_addr = reinterpret_cast(data); if (data_addr > buffer_addr && data_addr < (buffer_addr + buffer_size)) { ALOGE("%s: Update attempted with data from the same metadata buffer!", __FUNCTION__); return INVALID_OPERATION; } size_t size = calculate_camera_metadata_entry_data_size(type, data_count); res = ResizeIfNeeded(/*extra_entries=*/1, size); if (res != OK) { ALOGE("%s: Resize fail", __FUNCTION__); return res; } camera_metadata_entry_t entry; res = find_camera_metadata_entry(metadata_, tag, &entry); if (res == NAME_NOT_FOUND) { res = add_camera_metadata_entry(metadata_, tag, data, data_count); } else if (res == OK) { res = update_camera_metadata_entry(metadata_, entry.index, data, data_count, nullptr); } return res; } bool HalCameraMetadata::IsTypeValid(uint32_t tag, int32_t expected_type) { int32_t type = get_camera_metadata_tag_type(tag); if (type == -1) { ALOGE("%s: Unknown tag 0x%x.", __FUNCTION__, tag); return false; } if (type != expected_type) { ALOGE("%s: mismatched type (%d) from tag 0x%x. Expected type is %d", __FUNCTION__, type, tag, expected_type); return false; } return true; } status_t HalCameraMetadata::Set(uint32_t tag, const uint8_t* data, uint32_t data_count) { std::unique_lock lock(metadata_lock_); if (metadata_ == nullptr) { ALOGE("%s: metadata_ is nullptr", __FUNCTION__); return INVALID_OPERATION; } if (IsTypeValid(tag, TYPE_BYTE) == false) { return INVALID_OPERATION; } return SetMetadataRaw(tag, reinterpret_cast(data), data_count); } status_t HalCameraMetadata::Set(uint32_t tag, const int32_t* data, uint32_t data_count) { std::unique_lock lock(metadata_lock_); if (metadata_ == nullptr) { ALOGE("%s: metadata_ is nullptr", __FUNCTION__); return INVALID_OPERATION; } if (IsTypeValid(tag, TYPE_INT32) == false) { return INVALID_OPERATION; } return SetMetadataRaw(tag, reinterpret_cast(data), data_count); } status_t HalCameraMetadata::Set(uint32_t tag, const float* data, uint32_t data_count) { std::unique_lock lock(metadata_lock_); if (metadata_ == nullptr) { ALOGE("%s: metadata_ is nullptr", __FUNCTION__); return INVALID_OPERATION; } if (IsTypeValid(tag, TYPE_FLOAT) == false) { return INVALID_OPERATION; } return SetMetadataRaw(tag, reinterpret_cast(data), data_count); } status_t HalCameraMetadata::Set(uint32_t tag, const int64_t* data, uint32_t data_count) { std::unique_lock lock(metadata_lock_); if (metadata_ == nullptr) { ALOGE("%s: metadata_ is nullptr", __FUNCTION__); return INVALID_OPERATION; } if (IsTypeValid(tag, TYPE_INT64) == false) { return INVALID_OPERATION; } return SetMetadataRaw(tag, reinterpret_cast(data), data_count); } status_t HalCameraMetadata::Set(uint32_t tag, const double* data, uint32_t data_count) { std::unique_lock lock(metadata_lock_); if (metadata_ == nullptr) { ALOGE("%s: metadata_ is nullptr", __FUNCTION__); return INVALID_OPERATION; } if (IsTypeValid(tag, TYPE_DOUBLE) == false) { return INVALID_OPERATION; } return SetMetadataRaw(tag, reinterpret_cast(data), data_count); } status_t HalCameraMetadata::Set(uint32_t tag, const camera_metadata_rational_t* data, uint32_t data_count) { std::unique_lock lock(metadata_lock_); if (metadata_ == nullptr) { ALOGE("%s: metadata_ is nullptr", __FUNCTION__); return INVALID_OPERATION; } if (IsTypeValid(tag, TYPE_RATIONAL) == false) { return INVALID_OPERATION; } return SetMetadataRaw(tag, reinterpret_cast(data), data_count); } status_t HalCameraMetadata::Set(uint32_t tag, const std::string& string) { std::unique_lock lock(metadata_lock_); if (metadata_ == nullptr) { ALOGE("%s: metadata_ is nullptr", __FUNCTION__); return INVALID_OPERATION; } if (IsTypeValid(tag, TYPE_BYTE) == false) { return INVALID_OPERATION; } // string length +1 for null-terminated character. return SetMetadataRaw(tag, reinterpret_cast(string.c_str()), string.length() + 1); } status_t HalCameraMetadata::Set(const camera_metadata_ro_entry& entry) { status_t res; int32_t type = get_camera_metadata_tag_type(entry.tag); switch (type) { case TYPE_BYTE: res = Set(entry.tag, entry.data.u8, entry.count); break; case TYPE_INT32: res = Set(entry.tag, entry.data.i32, entry.count); break; case TYPE_FLOAT: res = Set(entry.tag, entry.data.f, entry.count); break; case TYPE_INT64: res = Set(entry.tag, entry.data.i64, entry.count); break; case TYPE_DOUBLE: res = Set(entry.tag, entry.data.d, entry.count); break; case TYPE_RATIONAL: res = Set(entry.tag, entry.data.r, entry.count); break; default: ALOGE("%s: Unknown type in tag 0x%x.", __FUNCTION__, entry.tag); res = BAD_TYPE; break; } return res; } status_t HalCameraMetadata::Get(uint32_t tag, camera_metadata_ro_entry* entry) const { if (entry == nullptr) { ALOGE("%s: entry is nullptr", __FUNCTION__); return BAD_VALUE; } std::unique_lock lock(metadata_lock_); return find_camera_metadata_ro_entry(metadata_, tag, entry); } status_t HalCameraMetadata::GetByIndex(camera_metadata_ro_entry* entry, size_t entry_index) const { if (entry == nullptr) { ALOGE("%s: entry is nullptr", __FUNCTION__); return BAD_VALUE; } std::unique_lock lock(metadata_lock_); size_t entry_count = get_camera_metadata_entry_count(metadata_); if (entry_index >= entry_count) { ALOGE("%s: entry_index (%zu) >= entry_count(%zu)", __FUNCTION__, entry_index, entry_count); return BAD_VALUE; } return get_camera_metadata_ro_entry(metadata_, entry_index, entry); } status_t HalCameraMetadata::Erase(const std::unordered_set& tags) { std::unique_lock lock(metadata_lock_); camera_metadata_ro_entry_t entry; status_t res; // Metadata entries to copy over; entries whose tag IDs aren't in 'tags' std::vector entry_indices; size_t data_count = get_camera_metadata_data_count(metadata_); size_t entry_count = get_camera_metadata_entry_count(metadata_); size_t data_count_removed = 0; for (size_t entry_index = 0; entry_index < entry_count; entry_index++) { res = get_camera_metadata_ro_entry(metadata_, entry_index, &entry); if (res != OK) { ALOGE("%s: Error getting entry at index %zu: %s %d", __FUNCTION__, entry_index, strerror(-res), res); continue; } // See if the entry at the current index has a tag ID in the list of IDs // that we'd like to remove if (tags.find(entry.tag) != tags.end()) { data_count_removed += calculate_camera_metadata_entry_data_size(entry.type, entry.count); } else { entry_indices.push_back(entry_index); } } if (data_count_removed > data_count) { // Sanity; this should never happen unless there is an implementation error ALOGE("%s: Error! Cannot remove %zu bytes of data when there is only %zu", __FUNCTION__, data_count_removed, data_count); return UNKNOWN_ERROR; } else if (data_count_removed == 0) { // Nothing to remove return OK; } size_t new_data_count = (data_count - data_count_removed); size_t new_entry_count = entry_indices.size(); // Calculate the new capacity; multiply by 2 to allow room for metadata growth size_t entry_capacity = (2 * new_entry_count); size_t data_capacity = (2 * new_data_count); // Allocate a new buffer with the smaller size camera_metadata_t* orig_metadata = metadata_; metadata_ = allocate_camera_metadata(entry_capacity, data_capacity); if (metadata_ == nullptr) { ALOGE("%s: Can't allocate new metadata buffer", __FUNCTION__); metadata_ = orig_metadata; return NO_MEMORY; } IF_ALOGV() { ALOGV( "%s: data capacity [%zu --> %zu], data count [%zu --> %zu], entry " "capacity: [%zu --> %zu] entry count: [%zu --> %zu]", __FUNCTION__, get_camera_metadata_data_capacity(orig_metadata), data_capacity, data_count, new_data_count, get_camera_metadata_entry_capacity(orig_metadata), entry_capacity, entry_count, new_entry_count); } // Loop through the original metadata buffer and add all to the new buffer, // except for those indices which were removed for (size_t entry_index : entry_indices) { res = CopyEntry(orig_metadata, metadata_, entry_index); if (res != OK) { ALOGE("%s: Error adding entry at index %zu failed: %s %d", __FUNCTION__, entry_index, strerror(-res), res); free_camera_metadata(metadata_); metadata_ = orig_metadata; return res; } } free_camera_metadata(orig_metadata); return OK; } status_t HalCameraMetadata::Erase(uint32_t tag) { std::unique_lock lock(metadata_lock_); camera_metadata_entry_t entry; status_t res = find_camera_metadata_entry(metadata_, tag, &entry); if (res == NAME_NOT_FOUND) { return OK; } else if (res != OK) { ALOGE("%s: Error finding entry (0x%x): %s %d", __FUNCTION__, tag, strerror(-res), res); return res; } res = delete_camera_metadata_entry(metadata_, entry.index); if (res != OK) { ALOGE("%s: Error deleting entry (0x%x): %s %d", __FUNCTION__, tag, strerror(-res), res); } return res; } void HalCameraMetadata::PrintData(const uint8_t* data, int32_t type, int32_t count, uint32_t indentation) { const uint32_t kDumpSizePerLine = 100; static int32_t values_per_line[NUM_TYPES] = { [TYPE_BYTE] = 16, [TYPE_INT32] = 4, [TYPE_FLOAT] = 8, [TYPE_INT64] = 2, [TYPE_DOUBLE] = 4, [TYPE_RATIONAL] = 2, }; int32_t max_type_count = sizeof(values_per_line) / sizeof(int32_t); if (type >= max_type_count) { ALOGE("%s: unsupported type: %d", __FUNCTION__, type); return; } size_t type_size = camera_metadata_type_size[type]; char string[kDumpSizePerLine]; uint32_t string_offset; int32_t lines = count / values_per_line[type]; if (count % values_per_line[type] != 0) { lines++; } int32_t index = 0; int32_t j = 0, k = 0; for (j = 0; j < lines; j++) { string_offset = 0; string_offset += snprintf(&string[string_offset], (sizeof(string) - string_offset), "%*s[ ", indentation + 4, ""); for (k = 0; k < values_per_line[type] && count > 0; k++, count--, index += type_size) { switch (type) { case TYPE_BYTE: { string_offset += snprintf(&string[string_offset], (sizeof(string) - string_offset), "%hhu ", *(data + index)); break; } case TYPE_INT32: { string_offset += snprintf(&string[string_offset], (sizeof(string) - string_offset), "%d ", *reinterpret_cast(data + index)); break; } case TYPE_FLOAT: { string_offset += snprintf(&string[string_offset], (sizeof(string) - string_offset), "%0.8f ", *reinterpret_cast(data + index)); break; } case TYPE_INT64: { string_offset += snprintf( &string[string_offset], (sizeof(string) - string_offset), "%" PRId64 " ", *reinterpret_cast(data + index)); break; } case TYPE_DOUBLE: { string_offset += snprintf( &string[string_offset], (sizeof(string) - string_offset), "%0.8f ", *reinterpret_cast(data + index)); break; } case TYPE_RATIONAL: { int32_t numerator = *(int32_t*)(data + index); int32_t denominator = *(int32_t*)(data + index + 4); string_offset += snprintf(&string[string_offset], (sizeof(string) - string_offset), "(%d / %d) ", numerator, denominator); break; } default: { break; } } } string_offset += snprintf(&string[string_offset], (sizeof(string) - string_offset), "]"); ALOGI("%s:%s", __FUNCTION__, string); } } void HalCameraMetadata::Dump(int32_t fd, MetadataDumpVerbosity verbosity, uint32_t indentation) const { std::unique_lock lock(metadata_lock_); if (fd >= 0) { dump_indented_camera_metadata(metadata_, fd, static_cast(verbosity), indentation); } else { if (metadata_ == nullptr) { ALOGE("%s: metadata_ is nullptr", __FUNCTION__); return; } size_t entry_count = get_camera_metadata_entry_count(metadata_); for (uint32_t i = 0; i < entry_count; i++) { camera_metadata_ro_entry_t entry; status_t res = get_camera_metadata_ro_entry(metadata_, i, &entry); if (res != OK) { ALOGE("%s: get_camera_metadata_ro_entry (%d) fail", __FUNCTION__, i); continue; } const char *tag_name, *tag_section; tag_section = get_local_camera_metadata_section_name(entry.tag, metadata_); if (tag_section == nullptr) { tag_section = "unknownSection"; } tag_name = get_local_camera_metadata_tag_name(entry.tag, metadata_); if (tag_name == nullptr) { tag_name = "unknownTag"; } const char* type_name; if (entry.type >= NUM_TYPES) { type_name = "unknown"; } else { type_name = camera_metadata_type_names[entry.type]; } ALOGI("%s: (%d) %s.%s (%05x): %s[%zu] ", __FUNCTION__, i, tag_section, tag_name, entry.tag, type_name, entry.count); if (verbosity < MetadataDumpVerbosity::kTagEntryWith16Data) { continue; } if (entry.type >= NUM_TYPES) { continue; } const uint8_t* data = entry.data.u8; int32_t count = entry.count; if (verbosity < MetadataDumpVerbosity::kAllInformation && count > 16) { count = 16; } PrintData(data, entry.type, count, indentation); } } } status_t HalCameraMetadata::Append( std::unique_ptr hal_metadata) { if (hal_metadata == nullptr) { ALOGE("%s: hal_metadata is nullptr", __FUNCTION__); return BAD_VALUE; } return Append(hal_metadata->ReleaseCameraMetadata()); } status_t HalCameraMetadata::Append(const camera_metadata_t* metadata) { if (metadata == nullptr) { ALOGE("%s: metadata is nullptr", __FUNCTION__); return BAD_VALUE; } std::unique_lock lock(metadata_lock_); size_t extra_entries = get_camera_metadata_entry_count(metadata); size_t extra_data = get_camera_metadata_data_count(metadata); status_t res = ResizeIfNeeded(extra_entries, extra_data); if (res != OK) { ALOGE("%s: Resize fail", __FUNCTION__); return res; } return append_camera_metadata(metadata_, metadata); } size_t HalCameraMetadata::GetEntryCount() const { std::unique_lock lock(metadata_lock_); return (metadata_ == nullptr) ? 0 : get_camera_metadata_entry_count(metadata_); } status_t HalCameraMetadata::CopyEntry(const camera_metadata_t* src, camera_metadata_t* dest, size_t entry_index) const { if (src == nullptr || dest == nullptr) { ALOGE("%s: src (%p) or dest(%p) is nullptr", __FUNCTION__, src, dest); return BAD_VALUE; } camera_metadata_ro_entry entry; status_t res = get_camera_metadata_ro_entry(src, entry_index, &entry); if (res != OK) { ALOGE("%s: failed to get entry index %zu", __FUNCTION__, entry_index); return res; } res = add_camera_metadata_entry(dest, entry.tag, entry.data.u8, entry.count); if (res != OK) { ALOGE("%s: failed to add entry index %zu", __FUNCTION__, entry_index); return res; } return OK; } } // namespace google_camera_hal } // namespace android