/* * Copyright (C) 2023 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 FAILURE_DEBUG_PREFIX "exif" #include #if defined(__LP64__) #include using Timestamp = time_t; #define TIMESTAMP_TO_TM(timestamp, tm) gmtime_r(timestamp, tm) #else #include using Timestamp = time64_t; #define TIMESTAMP_TO_TM(timestamp, tm) gmtime64_r(timestamp, tm) #endif #include #include #include #include "exif.h" #include "debug.h" namespace android { namespace hardware { namespace camera { namespace provider { namespace implementation { namespace exif { namespace { struct ExifMemDeleter { void operator()(ExifMem* allocator) const { exif_mem_unref(allocator); } }; typedef std::unique_ptr ExifMemPtr; ExifEntry* allocateEntry(ExifMem* mem, const ExifTag tag, const ExifFormat format, const size_t numComponents) { ExifEntry* e = exif_entry_new_mem(mem); const size_t size = numComponents * exif_format_get_size(format); e->data = static_cast(exif_mem_alloc(mem, size)); e->size = size; e->tag = tag; e->components = numComponents; e->format = format; return e; } void appendEntry(ExifData* edata, ExifMem* mem, const ExifIfd ifd, const ExifTag tag) { ExifEntry* e = exif_entry_new_mem(mem); exif_entry_initialize(e, tag); exif_content_add_entry(edata->ifd[ifd], e); exif_entry_unref(e); } void appendEntryU8(ExifData* edata, ExifMem* mem, const ExifIfd ifd, const ExifTag tag, const uint8_t value) { ExifEntry* e = allocateEntry(mem, tag, EXIF_FORMAT_BYTE, 1); *e->data = value; exif_content_add_entry(edata->ifd[ifd], e); exif_entry_unref(e); } void appendEntryU16(ExifData* edata, ExifMem* mem, const ExifIfd ifd, const ExifTag tag, const uint16_t value) { ExifEntry* e = allocateEntry(mem, tag, EXIF_FORMAT_SHORT, 1); exif_set_short(e->data, exif_data_get_byte_order(edata), value); exif_content_add_entry(edata->ifd[ifd], e); exif_entry_unref(e); } void appendEntryU32(ExifData* edata, ExifMem* mem, const ExifIfd ifd, const ExifTag tag, const uint32_t value) { ExifEntry* e = allocateEntry(mem, tag, EXIF_FORMAT_LONG, 1); exif_set_long(e->data, exif_data_get_byte_order(edata), value); exif_content_add_entry(edata->ifd[ifd], e); exif_entry_unref(e); } void appendEntryR32(ExifData* edata, ExifMem* mem, const ExifIfd ifd, const ExifTag tag, const ExifRational* src, size_t n) { ExifEntry* e = allocateEntry(mem, tag, EXIF_FORMAT_RATIONAL, n); for (uint8_t* dst = e->data; n > 0; --n, ++src, dst += sizeof(ExifRational)) { exif_set_rational(dst, exif_data_get_byte_order(edata), *src); } exif_content_add_entry(edata->ifd[ifd], e); exif_entry_unref(e); } void appendEntryR32(ExifData* edata, ExifMem* mem, const ExifIfd ifd, const ExifTag tag, const uint32_t num, const uint32_t dem) { const ExifRational value = { num, dem }; appendEntryR32(edata, mem, ifd, tag, &value, 1); } void appendEntryS(ExifData* edata, ExifMem* mem, const ExifIfd ifd, const ExifTag tag, const char* value, const size_t size, const ExifFormat format) { ExifEntry* e = allocateEntry(mem, tag, format, size); memcpy(e->data, value, size); exif_content_add_entry(edata->ifd[ifd], e); exif_entry_unref(e); } std::tuple convertDegToDegMmSs(double v) { const uint32_t ideg = floor(v); v = (v - ideg) * 60; const uint32_t minutes = floor(v); v = (v - minutes) * 60; const uint32_t secondsM = round(v * 1000000); return {ideg, minutes, secondsM}; } struct tm convertT64ToTm(const int64_t t) { Timestamp t2 = t; struct tm result; TIMESTAMP_TO_TM(&t2, &result); return result; } } // namespace ExifDataPtr createExifData(const CameraMetadata& metadata, const Rect size) { const camera_metadata_t* const rawMetadata = reinterpret_cast(metadata.metadata.data()); camera_metadata_ro_entry_t metadataEntry; ExifMemPtr allocator(exif_mem_new_default()); ExifDataPtr exifData(exif_data_new_mem(allocator.get())); exif_data_set_option(exifData.get(), EXIF_DATA_OPTION_FOLLOW_SPECIFICATION); exif_data_set_data_type(exifData.get(), EXIF_DATA_TYPE_COMPRESSED); exif_data_set_byte_order(exifData.get(), EXIF_BYTE_ORDER_INTEL); exif_data_fix(exifData.get()); { const std::string v = base::GetProperty("ro.product.manufacturer", ""); appendEntryS(exifData.get(), allocator.get(), EXIF_IFD_0, EXIF_TAG_MAKE, v.c_str(), v.size() + 1, EXIF_FORMAT_ASCII); } { const std::string v = base::GetProperty("ro.product.model", ""); appendEntryS(exifData.get(), allocator.get(), EXIF_IFD_0, EXIF_TAG_MODEL, v.c_str(), v.size() + 1, EXIF_FORMAT_ASCII); } { struct tm now; { time_t t = time(nullptr); localtime_r(&t, &now); } char timeStr[20]; const int len = snprintf(timeStr, sizeof(timeStr), "%04d:%02d:%02d %02d:%02d:%02d", now.tm_year + 1900, now.tm_mon + 1, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec) + 1; appendEntryS(exifData.get(), allocator.get(), EXIF_IFD_0, EXIF_TAG_DATE_TIME, timeStr, len, EXIF_FORMAT_ASCII); appendEntryS(exifData.get(), allocator.get(), EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_ORIGINAL, timeStr, len, EXIF_FORMAT_ASCII); appendEntryS(exifData.get(), allocator.get(), EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_DIGITIZED, timeStr, len, EXIF_FORMAT_ASCII); } { char ddd[4]; const int len = snprintf(ddd, sizeof(ddd), "%03d", 0); appendEntryS(exifData.get(), allocator.get(), EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME, ddd, len, EXIF_FORMAT_ASCII); appendEntryS(exifData.get(), allocator.get(), EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME_ORIGINAL, ddd, len, EXIF_FORMAT_ASCII); appendEntryS(exifData.get(), allocator.get(), EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME_DIGITIZED, ddd, len, EXIF_FORMAT_ASCII); } if ((size.width > 0) && (size.height > 0)) { appendEntryU32(exifData.get(), allocator.get(), EXIF_IFD_EXIF, EXIF_TAG_PIXEL_X_DIMENSION, size.width); appendEntryU32(exifData.get(), allocator.get(), EXIF_IFD_EXIF, EXIF_TAG_PIXEL_Y_DIMENSION, size.width); } if (!find_camera_metadata_ro_entry(rawMetadata, ANDROID_JPEG_ORIENTATION, &metadataEntry)) { unsigned v; switch (metadataEntry.data.i32[0]) { default: case 0: v = 1; break; case 90: v = 6; break; case 180: v = 3; break; case 270: v = 8; break; } appendEntryU16(exifData.get(), allocator.get(), EXIF_IFD_0, EXIF_TAG_ORIENTATION, v); } if (!find_camera_metadata_ro_entry(rawMetadata, ANDROID_LENS_APERTURE, &metadataEntry)) { const float v = metadataEntry.data.f[0]; appendEntryR32(exifData.get(), allocator.get(), EXIF_IFD_EXIF, EXIF_TAG_FNUMBER, uint32_t(v * 1000U), 1000U); } if (!find_camera_metadata_ro_entry(rawMetadata, ANDROID_LENS_FOCAL_LENGTH, &metadataEntry)) { const float v = metadataEntry.data.f[0]; appendEntryR32(exifData.get(), allocator.get(), EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH, uint32_t(v * 1000U), 1000U); } if (!find_camera_metadata_ro_entry(rawMetadata, ANDROID_FLASH_MODE, &metadataEntry)) { const unsigned v = (metadataEntry.data.i32[0] == ANDROID_FLASH_MODE_OFF) ? 0 : 1; appendEntryU16(exifData.get(), allocator.get(), EXIF_IFD_EXIF, EXIF_TAG_FLASH, v); } if (!find_camera_metadata_ro_entry(rawMetadata, ANDROID_SENSOR_EXPOSURE_TIME, &metadataEntry)) { int64_t num = metadataEntry.data.i64[0]; uint32_t dem = 1000000000U; while (num > std::numeric_limits::max()) { num /= 10; dem /= 10; } appendEntryR32(exifData.get(), allocator.get(), EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_TIME, uint32_t(num), dem); } if (!find_camera_metadata_ro_entry(rawMetadata, ANDROID_SENSOR_SENSITIVITY, &metadataEntry)) { appendEntryU16(exifData.get(), allocator.get(), EXIF_IFD_EXIF, EXIF_TAG_ISO_SPEED_RATINGS, metadataEntry.data.i32[0]); } if (!find_camera_metadata_ro_entry(rawMetadata, ANDROID_CONTROL_AWB_MODE, &metadataEntry)) { const unsigned v = (metadataEntry.data.i32[0] == ANDROID_CONTROL_AWB_MODE_AUTO) ? 0 : 1; appendEntryU16(exifData.get(), allocator.get(), EXIF_IFD_EXIF, EXIF_TAG_WHITE_BALANCE, v); } if (!find_camera_metadata_ro_entry(rawMetadata, ANDROID_JPEG_GPS_COORDINATES, &metadataEntry)) { { const auto [ideg, minutes, secondsM] = convertDegToDegMmSs( fabs(metadataEntry.data.d[0])); ExifRational degmmss[3] = {{ideg, 1}, {minutes, 1}, {secondsM, 1000000}}; appendEntryR32(exifData.get(), allocator.get(), EXIF_IFD_GPS, static_cast(EXIF_TAG_GPS_LATITUDE), degmmss, 3); const char* latRef = (metadataEntry.data.d[0] < 0.0) ? "S" : "N"; appendEntryS(exifData.get(), allocator.get(), EXIF_IFD_GPS, static_cast(EXIF_TAG_GPS_LATITUDE_REF), latRef, 2, EXIF_FORMAT_ASCII); } { const auto [ideg, minutes, secondsM] = convertDegToDegMmSs( fabs(metadataEntry.data.d[1])); ExifRational degmmss[3] = {{ideg, 1}, {minutes, 1}, {secondsM, 1000000}}; appendEntryR32(exifData.get(), allocator.get(), EXIF_IFD_GPS, static_cast(EXIF_TAG_GPS_LONGITUDE), degmmss, 3); const char* latRef = (metadataEntry.data.d[1] < 0.0) ? "W" : "E"; appendEntryS(exifData.get(), allocator.get(), EXIF_IFD_GPS, static_cast(EXIF_TAG_GPS_LONGITUDE_REF), latRef, 2, EXIF_FORMAT_ASCII); } { appendEntryR32(exifData.get(), allocator.get(), EXIF_IFD_GPS, static_cast(EXIF_TAG_GPS_ALTITUDE), static_cast(fabs(metadataEntry.data.d[2]) * 1000.0), 1000); appendEntryU8(exifData.get(), allocator.get(), EXIF_IFD_GPS, static_cast(EXIF_TAG_GPS_ALTITUDE_REF), (metadataEntry.data.d[2] < 0.0) ? 1 : 0); } } if (!find_camera_metadata_ro_entry(rawMetadata, ANDROID_JPEG_GPS_TIMESTAMP, &metadataEntry)) { struct tm gpsTime = convertT64ToTm(metadataEntry.data.i64[0]); { char yyyymmdd[12]; const int len = snprintf(yyyymmdd, sizeof(yyyymmdd), "%04d:%02d:%02d", gpsTime.tm_year + 1900, gpsTime.tm_mon + 1, gpsTime.tm_mday) + 1; appendEntryS(exifData.get(), allocator.get(), EXIF_IFD_GPS, static_cast(EXIF_TAG_GPS_DATE_STAMP), yyyymmdd, len, EXIF_FORMAT_ASCII); } { ExifRational hhmmss[3] = {{static_cast(gpsTime.tm_hour), 1}, {static_cast(gpsTime.tm_min), 1}, {static_cast(gpsTime.tm_sec), 1}}; appendEntryR32(exifData.get(), allocator.get(), EXIF_IFD_GPS, static_cast(EXIF_TAG_GPS_TIME_STAMP), hhmmss, 3); } } if (!find_camera_metadata_ro_entry(rawMetadata, ANDROID_JPEG_GPS_PROCESSING_METHOD, &metadataEntry)) { // EXIF_FORMAT_UNDEFINED requires this prefix std::vector value = {0x41, 0x53, 0x43, 0x49, 0x49, 0x00, 0x00, 0x00}; value.insert(value.end(), reinterpret_cast(metadataEntry.data.u8), reinterpret_cast(metadataEntry.data.u8) + metadataEntry.count); appendEntryS(exifData.get(), allocator.get(), EXIF_IFD_GPS, static_cast(EXIF_TAG_GPS_PROCESSING_METHOD), value.data(), value.size(), EXIF_FORMAT_UNDEFINED); } return exifData; } void* exifDataAllocThumbnail(ExifData* const edata, const size_t size) { // WARNING: maloc and free must match the functions that are used in // exif_mem_new_default (see above) to manage memory. They will be used in // exif_data_free to deallocate memory allocated here. void* mem = malloc(size); if (mem) { if (edata->data) { free(edata->data); } edata->size = size; edata->data = static_cast(mem); } return mem; } void ExifDataDeleter::operator()(ExifData* p) const { exif_data_free(p); } } // namespace exif } // namespace implementation } // namespace provider } // namespace camera } // namespace hardware } // namespace android