android_hardware_camera2_DngCreator.cpp revision 9ce22a095685a581823316457217a318fb40c754
1f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk/* 2f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk * Copyright 2014 The Android Open Source Project 3f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk * 4f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk * Licensed under the Apache License, Version 2.0 (the "License"); 5f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk * you may not use this file except in compliance with the License. 6f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk * You may obtain a copy of the License at 7f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk * 8f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk * http://www.apache.org/licenses/LICENSE-2.0 9f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk * 10f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk * Unless required by applicable law or agreed to in writing, software 11f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk * distributed under the License is distributed on an "AS IS" BASIS, 12f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk * See the License for the specific language governing permissions and 14f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk * limitations under the License. 15f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk */ 16f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 172079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk#define LOG_NDEBUG 0 18f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#define LOG_TAG "DngCreator_JNI" 1946d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <inttypes.h> 2046d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <string.h> 21b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk#include <algorithm> 22b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk#include <memory> 239ce22a095685a581823316457217a318fb40c754Ruben Brunk#include <vector> 2446d8444631b4b1253a76bfcc78a29d26014d022fDan Albert 2546d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <utils/Log.h> 2646d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <utils/Errors.h> 2746d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <utils/StrongPointer.h> 2846d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <utils/RefBase.h> 2946d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <utils/Vector.h> 302079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk#include <utils/String8.h> 3146d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <cutils/properties.h> 32f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <system/camera_metadata.h> 33f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <camera/CameraMetadata.h> 34f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <img_utils/DngUtils.h> 35f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <img_utils/TagDefinitions.h> 36f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <img_utils/TiffIfd.h> 37f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <img_utils/TiffWriter.h> 38f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <img_utils/Output.h> 3947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk#include <img_utils/Input.h> 4047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk#include <img_utils/StripSource.h> 41f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 42ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe#include "core_jni_helpers.h" 43b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 44f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include "android_runtime/AndroidRuntime.h" 45f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include "android_runtime/android_hardware_camera2_CameraMetadata.h" 46f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 47f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <jni.h> 48f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <JNIHelp.h> 49f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 50f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkusing namespace android; 51f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkusing namespace img_utils; 52f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 532079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk#define BAIL_IF_INVALID_RET_BOOL(expr, jnienv, tagId, writer) \ 54f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if ((expr) != OK) { \ 55f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \ 5647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Invalid metadata for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \ 572079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return false; \ 58f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 59f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 602079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 612079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk#define BAIL_IF_INVALID_RET_NULL_SP(expr, jnienv, tagId, writer) \ 622079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if ((expr) != OK) { \ 632079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \ 642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk "Invalid metadata for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \ 652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; \ 662079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 672079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 69b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk#define BAIL_IF_INVALID_R(expr, jnienv, tagId, writer) \ 70b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk if ((expr) != OK) { \ 71b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \ 72b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk "Invalid metadata for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \ 73b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk return -1; \ 74b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk } 75b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk#define BAIL_IF_EMPTY_RET_NULL_SP(entry, jnienv, tagId, writer) \ 77f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (entry.count == 0) { \ 78f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \ 7947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Missing metadata fields for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \ 802079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; \ 81f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 82f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 832079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 84b6079005ed0631c3972ff427f56e12523ec214a7Ruben Brunk#define ANDROID_DNGCREATOR_CTX_JNI_ID "mNativeContext" 85f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 86f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic struct { 87f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jfieldID mNativeContext; 88f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} gDngCreatorClassInfo; 89f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 90f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic struct { 91f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jmethodID mWriteMethod; 92f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} gOutputStreamClassInfo; 93f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 9447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic struct { 9547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jmethodID mReadMethod; 9647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jmethodID mSkipMethod; 9747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} gInputStreamClassInfo; 9847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 9947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic struct { 10047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jmethodID mGetMethod; 10147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} gInputByteBufferClassInfo; 10247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 103f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkenum { 104f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk BITS_PER_SAMPLE = 16, 105f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk BYTES_PER_SAMPLE = 2, 10647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk BYTES_PER_RGB_PIXEL = 3, 10747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk BITS_PER_RGB_SAMPLE = 8, 10847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk BYTES_PER_RGB_SAMPLE = 1, 10947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk SAMPLES_PER_RGB_PIXEL = 3, 11047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk SAMPLES_PER_RAW_PIXEL = 1, 11147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0 = 0, 11247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_SUB1 = 1, 11347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_GPSINFO = 2, 114f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}; 115f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1162079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 1172079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk/** 1182079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk * POD container class for GPS tag data. 1192079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk */ 1202079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkclass GpsData { 1212079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkpublic: 1222079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk enum { 1232079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GPS_VALUE_LENGTH = 6, 1242079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GPS_REF_LENGTH = 2, 1252079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GPS_DATE_LENGTH = 11, 1262079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk }; 1272079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 1282079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t mLatitude[GPS_VALUE_LENGTH]; 1292079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t mLongitude[GPS_VALUE_LENGTH]; 1302079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t mTimestamp[GPS_VALUE_LENGTH]; 1312079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint8_t mLatitudeRef[GPS_REF_LENGTH]; 1322079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint8_t mLongitudeRef[GPS_REF_LENGTH]; 1332079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint8_t mDate[GPS_DATE_LENGTH]; 1342079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk}; 1352079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 136f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk// ---------------------------------------------------------------------------- 137f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 13847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/** 13947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * Container class for the persistent native context. 14047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */ 14147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 14247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkclass NativeContext : public LightRefBase<NativeContext> { 14347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkpublic: 1442079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk enum { 1452079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk DATETIME_COUNT = 20, 1462079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk }; 1472079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 148b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk NativeContext(const CameraMetadata& characteristics, const CameraMetadata& result); 14947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual ~NativeContext(); 15047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 15147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TiffWriter* getWriter(); 15247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 153b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk std::shared_ptr<const CameraMetadata> getCharacteristics() const; 154b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk std::shared_ptr<const CameraMetadata> getResult() const; 155b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 1562079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t getThumbnailWidth() const; 1572079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t getThumbnailHeight() const; 1582079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk const uint8_t* getThumbnail() const; 1592079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk bool hasThumbnail() const; 16047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 16147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk bool setThumbnail(const uint8_t* buffer, uint32_t width, uint32_t height); 16247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 1632079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk void setOrientation(uint16_t orientation); 1642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint16_t getOrientation() const; 1652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 1662079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk void setDescription(const String8& desc); 1672079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk String8 getDescription() const; 1682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk bool hasDescription() const; 1692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 1702079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk void setGpsData(const GpsData& data); 1712079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GpsData getGpsData() const; 1722079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk bool hasGpsData() const; 1732079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 1742079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk void setCaptureTime(const String8& formattedCaptureTime); 1752079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk String8 getCaptureTime() const; 1762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk bool hasCaptureTime() const; 1772079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 17847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkprivate: 17947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk Vector<uint8_t> mCurrentThumbnail; 18047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TiffWriter mWriter; 181b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk std::shared_ptr<CameraMetadata> mCharacteristics; 182b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk std::shared_ptr<CameraMetadata> mResult; 18347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mThumbnailWidth; 18447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mThumbnailHeight; 1852079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint16_t mOrientation; 1862079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk bool mThumbnailSet; 1872079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk bool mGpsSet; 1882079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk bool mDescriptionSet; 1892079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk bool mCaptureTimeSet; 1902079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk String8 mDescription; 1912079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GpsData mGpsData; 1922079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk String8 mFormattedCaptureTime; 19347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}; 19447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 195b8f4c6ab1e99a44a51af26dc522819bb833825abRuben BrunkNativeContext::NativeContext(const CameraMetadata& characteristics, const CameraMetadata& result) : 196b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk mCharacteristics(std::make_shared<CameraMetadata>(characteristics)), 197b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk mResult(std::make_shared<CameraMetadata>(result)), mThumbnailWidth(0), 1982079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mThumbnailHeight(0), mOrientation(0), mThumbnailSet(false), mGpsSet(false), 1992079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mDescriptionSet(false), mCaptureTimeSet(false) {} 20047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 20147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkNativeContext::~NativeContext() {} 20247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 20347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkTiffWriter* NativeContext::getWriter() { 20447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return &mWriter; 20547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 20647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 207b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunkstd::shared_ptr<const CameraMetadata> NativeContext::getCharacteristics() const { 208b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk return mCharacteristics; 209b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk} 210b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 211b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunkstd::shared_ptr<const CameraMetadata> NativeContext::getResult() const { 212b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk return mResult; 213b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk} 214b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 2152079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkuint32_t NativeContext::getThumbnailWidth() const { 21647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return mThumbnailWidth; 21747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 21847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 2192079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkuint32_t NativeContext::getThumbnailHeight() const { 22047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return mThumbnailHeight; 22147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 22247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 2232079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkconst uint8_t* NativeContext::getThumbnail() const { 22447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return mCurrentThumbnail.array(); 22547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 22647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 2272079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkbool NativeContext::hasThumbnail() const { 2282079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return mThumbnailSet; 2292079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2302079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 23147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkbool NativeContext::setThumbnail(const uint8_t* buffer, uint32_t width, uint32_t height) { 23247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mThumbnailWidth = width; 23347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mThumbnailHeight = height; 23447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 23547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk size_t size = BYTES_PER_RGB_PIXEL * width * height; 23647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (mCurrentThumbnail.resize(size) < 0) { 23747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Could not resize thumbnail buffer.", __FUNCTION__); 23847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return false; 23947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 24047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 24147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint8_t* thumb = mCurrentThumbnail.editArray(); 24247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk memcpy(thumb, buffer, size); 2432079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mThumbnailSet = true; 24447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return true; 24547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 24647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 2472079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkvoid NativeContext::setOrientation(uint16_t orientation) { 2482079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mOrientation = orientation; 2492079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2502079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2512079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkuint16_t NativeContext::getOrientation() const { 2522079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return mOrientation; 2532079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2542079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2552079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkvoid NativeContext::setDescription(const String8& desc) { 2562079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mDescription = desc; 2572079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mDescriptionSet = true; 2582079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2592079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2602079612e5851d73f4672ae3729c883a58adc4dddRuben BrunkString8 NativeContext::getDescription() const { 2612079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return mDescription; 2622079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2632079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkbool NativeContext::hasDescription() const { 2652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return mDescriptionSet; 2662079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2672079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkvoid NativeContext::setGpsData(const GpsData& data) { 2692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mGpsData = data; 2702079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mGpsSet = true; 2712079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2722079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2732079612e5851d73f4672ae3729c883a58adc4dddRuben BrunkGpsData NativeContext::getGpsData() const { 2742079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return mGpsData; 2752079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2772079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkbool NativeContext::hasGpsData() const { 2782079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return mGpsSet; 2792079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2802079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2812079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkvoid NativeContext::setCaptureTime(const String8& formattedCaptureTime) { 2822079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mFormattedCaptureTime = formattedCaptureTime; 2832079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mCaptureTimeSet = true; 2842079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2852079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2862079612e5851d73f4672ae3729c883a58adc4dddRuben BrunkString8 NativeContext::getCaptureTime() const { 2872079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return mFormattedCaptureTime; 2882079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2892079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2902079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkbool NativeContext::hasCaptureTime() const { 2912079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return mCaptureTimeSet; 2922079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2932079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 29447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of NativeContext 29547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ---------------------------------------------------------------------------- 29647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 29747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/** 29847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * Wrapper class for a Java OutputStream. 29947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * 30047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * This class is not intended to be used across JNI calls. 30147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */ 302f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkclass JniOutputStream : public Output, public LightRefBase<JniOutputStream> { 303f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkpublic: 304f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk JniOutputStream(JNIEnv* env, jobject outStream); 305f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 306f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk virtual ~JniOutputStream(); 307f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 308f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk status_t open(); 30947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 310f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk status_t write(const uint8_t* buf, size_t offset, size_t count); 31147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 312f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk status_t close(); 313f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkprivate: 314f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk enum { 31547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk BYTE_ARRAY_LENGTH = 4096 316f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk }; 317f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jobject mOutputStream; 318f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk JNIEnv* mEnv; 319f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jbyteArray mByteArray; 320f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}; 321f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 322f967a5486a78db244624fde4c105aa5e6fa914b9Ruben BrunkJniOutputStream::JniOutputStream(JNIEnv* env, jobject outStream) : mOutputStream(outStream), 323f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk mEnv(env) { 324f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH); 3252079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (mByteArray == nullptr) { 326f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array."); 327f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 328f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 329f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 330f967a5486a78db244624fde4c105aa5e6fa914b9Ruben BrunkJniOutputStream::~JniOutputStream() { 331f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk mEnv->DeleteLocalRef(mByteArray); 332f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 333f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 334f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatus_t JniOutputStream::open() { 335f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Do nothing 336f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return OK; 337f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 338f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 339f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatus_t JniOutputStream::write(const uint8_t* buf, size_t offset, size_t count) { 340f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk while(count > 0) { 341f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk size_t len = BYTE_ARRAY_LENGTH; 342f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk len = (count > len) ? len : count; 343f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk mEnv->SetByteArrayRegion(mByteArray, 0, len, reinterpret_cast<const jbyte*>(buf + offset)); 344f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 345f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (mEnv->ExceptionCheck()) { 346f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return BAD_VALUE; 347f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 348f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 349f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk mEnv->CallVoidMethod(mOutputStream, gOutputStreamClassInfo.mWriteMethod, mByteArray, 350f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 0, len); 351f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 352f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (mEnv->ExceptionCheck()) { 353f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return BAD_VALUE; 354f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 355f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 356f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk count -= len; 357f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk offset += len; 358f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 359f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return OK; 360f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 361f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 362f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatus_t JniOutputStream::close() { 363f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Do nothing 364f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return OK; 365f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 366f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 36747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of JniOutputStream 368f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk// ---------------------------------------------------------------------------- 369f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 37047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/** 37147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * Wrapper class for a Java InputStream. 37247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * 37347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * This class is not intended to be used across JNI calls. 37447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */ 37547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkclass JniInputStream : public Input, public LightRefBase<JniInputStream> { 37647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkpublic: 37747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk JniInputStream(JNIEnv* env, jobject inStream); 37847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 37947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk status_t open(); 38047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 38147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk status_t close(); 38247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 38347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ssize_t read(uint8_t* buf, size_t offset, size_t count); 38447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 38547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ssize_t skip(size_t count); 38647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 38747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual ~JniInputStream(); 38847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkprivate: 38947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk enum { 39047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk BYTE_ARRAY_LENGTH = 4096 39147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk }; 39247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jobject mInStream; 39347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk JNIEnv* mEnv; 39447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jbyteArray mByteArray; 39547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 39647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}; 39747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 39847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkJniInputStream::JniInputStream(JNIEnv* env, jobject inStream) : mInStream(inStream), mEnv(env) { 39947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH); 4002079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (mByteArray == nullptr) { 40147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array."); 40247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 40347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 40447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 40547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkJniInputStream::~JniInputStream() { 40647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mEnv->DeleteLocalRef(mByteArray); 40747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 40847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 40947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkssize_t JniInputStream::read(uint8_t* buf, size_t offset, size_t count) { 41047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 41147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jint realCount = BYTE_ARRAY_LENGTH; 41247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (count < BYTE_ARRAY_LENGTH) { 41347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk realCount = count; 41447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 41547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jint actual = mEnv->CallIntMethod(mInStream, gInputStreamClassInfo.mReadMethod, mByteArray, 0, 41647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk realCount); 41747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 41847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (actual < 0) { 41947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return NOT_ENOUGH_DATA; 42047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 42147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 42247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (mEnv->ExceptionCheck()) { 42347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 42447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 42547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 42647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mEnv->GetByteArrayRegion(mByteArray, 0, actual, reinterpret_cast<jbyte*>(buf + offset)); 42747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (mEnv->ExceptionCheck()) { 42847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 42947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 43047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return actual; 43147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 43247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 43347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkssize_t JniInputStream::skip(size_t count) { 43447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jlong actual = mEnv->CallLongMethod(mInStream, gInputStreamClassInfo.mSkipMethod, 43547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk static_cast<jlong>(count)); 43647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 43747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (mEnv->ExceptionCheck()) { 43847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 43947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 44047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (actual < 0) { 44147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return NOT_ENOUGH_DATA; 44247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 44347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return actual; 44447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 44547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 44647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t JniInputStream::open() { 44747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk // Do nothing 44847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return OK; 44947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 45047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 45147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t JniInputStream::close() { 45247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk // Do nothing 45347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return OK; 45447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 45547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 45647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of JniInputStream 45747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ---------------------------------------------------------------------------- 45847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 45947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/** 46047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * Wrapper class for a non-direct Java ByteBuffer. 46147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * 46247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * This class is not intended to be used across JNI calls. 46347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */ 46447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkclass JniInputByteBuffer : public Input, public LightRefBase<JniInputByteBuffer> { 46547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkpublic: 46647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk JniInputByteBuffer(JNIEnv* env, jobject inBuf); 46747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 46847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk status_t open(); 46947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 47047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk status_t close(); 47147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 47247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ssize_t read(uint8_t* buf, size_t offset, size_t count); 47347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 47447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual ~JniInputByteBuffer(); 47547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkprivate: 47647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk enum { 47747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk BYTE_ARRAY_LENGTH = 4096 47847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk }; 47947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jobject mInBuf; 48047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk JNIEnv* mEnv; 48147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jbyteArray mByteArray; 48247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}; 48347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 48447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkJniInputByteBuffer::JniInputByteBuffer(JNIEnv* env, jobject inBuf) : mInBuf(inBuf), mEnv(env) { 48547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH); 4862079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (mByteArray == nullptr) { 48747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array."); 48847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 48947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 49047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 49147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkJniInputByteBuffer::~JniInputByteBuffer() { 49247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mEnv->DeleteLocalRef(mByteArray); 49347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 49447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 49547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkssize_t JniInputByteBuffer::read(uint8_t* buf, size_t offset, size_t count) { 49647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jint realCount = BYTE_ARRAY_LENGTH; 49747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (count < BYTE_ARRAY_LENGTH) { 49847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk realCount = count; 49947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 50047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 5015f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk jobject chainingBuf = mEnv->CallObjectMethod(mInBuf, gInputByteBufferClassInfo.mGetMethod, 5025f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk mByteArray, 0, realCount); 503a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk mEnv->DeleteLocalRef(chainingBuf); 50447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 50547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (mEnv->ExceptionCheck()) { 506a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk ALOGE("%s: Exception while reading from input into byte buffer.", __FUNCTION__); 50747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 50847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 50947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 51047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mEnv->GetByteArrayRegion(mByteArray, 0, realCount, reinterpret_cast<jbyte*>(buf + offset)); 51147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (mEnv->ExceptionCheck()) { 512a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk ALOGE("%s: Exception while reading from byte buffer.", __FUNCTION__); 51347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 51447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 51547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return realCount; 51647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 51747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 51847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t JniInputByteBuffer::open() { 51947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk // Do nothing 52047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return OK; 52147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 52247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 52347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t JniInputByteBuffer::close() { 52447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk // Do nothing 52547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return OK; 52647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 52747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 52847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of JniInputByteBuffer 52947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ---------------------------------------------------------------------------- 53047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 53147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/** 53247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * StripSource subclass for Input types. 53347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * 53447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * This class is not intended to be used across JNI calls. 53547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */ 53647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 53747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkclass InputStripSource : public StripSource, public LightRefBase<InputStripSource> { 53847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkpublic: 53947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk InputStripSource(JNIEnv* env, Input& input, uint32_t ifd, uint32_t width, uint32_t height, 54047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t pixStride, uint32_t rowStride, uint64_t offset, uint32_t bytesPerSample, 54147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t samplesPerPixel); 54247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 54347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual ~InputStripSource(); 54447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 54547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual status_t writeToStream(Output& stream, uint32_t count); 54647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 54747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual uint32_t getIfd() const; 54847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkprotected: 54947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mIfd; 55047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk Input* mInput; 55147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mWidth; 55247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mHeight; 55347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mPixStride; 55447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mRowStride; 55547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint64_t mOffset; 55647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk JNIEnv* mEnv; 55747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mBytesPerSample; 55847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mSamplesPerPixel; 55947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}; 56047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 56147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkInputStripSource::InputStripSource(JNIEnv* env, Input& input, uint32_t ifd, uint32_t width, 56247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t height, uint32_t pixStride, uint32_t rowStride, uint64_t offset, 56347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t bytesPerSample, uint32_t samplesPerPixel) : mIfd(ifd), mInput(&input), 56447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mWidth(width), mHeight(height), mPixStride(pixStride), mRowStride(rowStride), 56547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mOffset(offset), mEnv(env), mBytesPerSample(bytesPerSample), 56647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mSamplesPerPixel(samplesPerPixel) {} 56747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 56847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkInputStripSource::~InputStripSource() {} 56947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 57047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t InputStripSource::writeToStream(Output& stream, uint32_t count) { 5713e1902504979b9b456a14dffa6507ee2d9ea3d6aRuben Brunk uint32_t fullSize = mWidth * mHeight * mBytesPerSample * mSamplesPerPixel; 57247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jlong offset = mOffset; 57347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 57447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (fullSize != count) { 57547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Amount to write %u doesn't match image size %u", __FUNCTION__, count, 57647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk fullSize); 57747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/lang/IllegalStateException", "Not enough data to write"); 57847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 57947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 58047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 58147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk // Skip offset 58247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk while (offset > 0) { 58347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ssize_t skipped = mInput->skip(offset); 58447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (skipped <= 0) { 58547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (skipped == NOT_ENOUGH_DATA || skipped == 0) { 58647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(mEnv, "java/io/IOException", 58747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Early EOF encountered in skip, not enough pixel data for image of size %u", 58847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk fullSize); 58947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk skipped = NOT_ENOUGH_DATA; 59047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } else { 59147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!mEnv->ExceptionCheck()) { 59247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/io/IOException", 59347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Error encountered while skip bytes in input stream."); 59447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 59547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 59647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 59747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return skipped; 59847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 59947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk offset -= skipped; 60047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 60147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 60247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk Vector<uint8_t> row; 60347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (row.resize(mRowStride) < 0) { 60447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/lang/OutOfMemoryError", "Could not allocate row vector."); 60547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 60647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 60747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 60847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint8_t* rowBytes = row.editArray(); 60947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 61047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk for (uint32_t i = 0; i < mHeight; ++i) { 61147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk size_t rowFillAmt = 0; 612a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk size_t rowSize = mRowStride; 61347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 61447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk while (rowFillAmt < mRowStride) { 61547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ssize_t bytesRead = mInput->read(rowBytes, rowFillAmt, rowSize); 61647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (bytesRead <= 0) { 61747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (bytesRead == NOT_ENOUGH_DATA || bytesRead == 0) { 618a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk ALOGE("%s: Early EOF on row %" PRIu32 ", received bytesRead %zd", 619a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk __FUNCTION__, i, bytesRead); 62047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(mEnv, "java/io/IOException", 621a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk "Early EOF encountered, not enough pixel data for image of size %" 622a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk PRIu32, fullSize); 62347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk bytesRead = NOT_ENOUGH_DATA; 62447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } else { 62547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!mEnv->ExceptionCheck()) { 62647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/io/IOException", 62747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Error encountered while reading"); 62847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 62947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 63047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return bytesRead; 63147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 63247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk rowFillAmt += bytesRead; 63347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk rowSize -= bytesRead; 63447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 63547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 63647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (mPixStride == mBytesPerSample * mSamplesPerPixel) { 63747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Using stream per-row write for strip.", __FUNCTION__); 63847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 63947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (stream.write(rowBytes, 0, mBytesPerSample * mSamplesPerPixel * mWidth) != OK || 64047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mEnv->ExceptionCheck()) { 64147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!mEnv->ExceptionCheck()) { 64247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/io/IOException", "Failed to write pixel data"); 64347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 64447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 64547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 64647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } else { 64747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Using stream per-pixel write for strip.", __FUNCTION__); 64847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/lang/IllegalStateException", 64947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Per-pixel strides are not supported for RAW16 -- pixels must be contiguous"); 65047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 65147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 65247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk // TODO: Add support for non-contiguous pixels if needed. 65347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 65447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 65547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return OK; 65647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 65747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 65847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkuint32_t InputStripSource::getIfd() const { 65947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return mIfd; 66047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 66147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 66247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of InputStripSource 66347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ---------------------------------------------------------------------------- 66447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 66547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/** 66647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * StripSource subclass for direct buffer types. 66747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * 66847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * This class is not intended to be used across JNI calls. 66947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */ 67047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 67147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkclass DirectStripSource : public StripSource, public LightRefBase<DirectStripSource> { 67247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkpublic: 67347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk DirectStripSource(JNIEnv* env, const uint8_t* pixelBytes, uint32_t ifd, uint32_t width, 67447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t height, uint32_t pixStride, uint32_t rowStride, uint64_t offset, 67547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t bytesPerSample, uint32_t samplesPerPixel); 67647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 67747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual ~DirectStripSource(); 67847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 67947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual status_t writeToStream(Output& stream, uint32_t count); 68047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 68147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual uint32_t getIfd() const; 68247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkprotected: 68347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mIfd; 68447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk const uint8_t* mPixelBytes; 68547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mWidth; 68647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mHeight; 68747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mPixStride; 68847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mRowStride; 68947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint16_t mOffset; 69047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk JNIEnv* mEnv; 69147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mBytesPerSample; 69247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mSamplesPerPixel; 69347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}; 69447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 69547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkDirectStripSource::DirectStripSource(JNIEnv* env, const uint8_t* pixelBytes, uint32_t ifd, 69647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t width, uint32_t height, uint32_t pixStride, uint32_t rowStride, 69747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint64_t offset, uint32_t bytesPerSample, uint32_t samplesPerPixel) : mIfd(ifd), 69847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mPixelBytes(pixelBytes), mWidth(width), mHeight(height), mPixStride(pixStride), 69947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mRowStride(rowStride), mOffset(offset), mEnv(env), mBytesPerSample(bytesPerSample), 70047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mSamplesPerPixel(samplesPerPixel) {} 70147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 70247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkDirectStripSource::~DirectStripSource() {} 70347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 70447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t DirectStripSource::writeToStream(Output& stream, uint32_t count) { 7053e1902504979b9b456a14dffa6507ee2d9ea3d6aRuben Brunk uint32_t fullSize = mWidth * mHeight * mBytesPerSample * mSamplesPerPixel; 70647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 70747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (fullSize != count) { 70847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Amount to write %u doesn't match image size %u", __FUNCTION__, count, 70947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk fullSize); 71047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/lang/IllegalStateException", "Not enough data to write"); 71147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 71247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 71347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 7142079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 71547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (mPixStride == mBytesPerSample * mSamplesPerPixel 71647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk && mRowStride == mWidth * mBytesPerSample * mSamplesPerPixel) { 71747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Using direct single-pass write for strip.", __FUNCTION__); 71847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 71947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (stream.write(mPixelBytes, mOffset, fullSize) != OK || mEnv->ExceptionCheck()) { 72047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!mEnv->ExceptionCheck()) { 72147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/io/IOException", "Failed to write pixel data"); 72247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 72347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 72447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 72547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } else if (mPixStride == mBytesPerSample * mSamplesPerPixel) { 72647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Using direct per-row write for strip.", __FUNCTION__); 72747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 72847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk for (size_t i = 0; i < mHeight; ++i) { 72947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (stream.write(mPixelBytes, mOffset + i * mRowStride, mPixStride * mWidth) != OK || 73047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mEnv->ExceptionCheck()) { 73147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!mEnv->ExceptionCheck()) { 73247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/io/IOException", "Failed to write pixel data"); 73347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 73447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 73547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 73647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 73747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } else { 73847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Using direct per-pixel write for strip.", __FUNCTION__); 73947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 74047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/lang/IllegalStateException", 74147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Per-pixel strides are not supported for RAW16 -- pixels must be contiguous"); 74247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 74347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 74447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk // TODO: Add support for non-contiguous pixels if needed. 74547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 74647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return OK; 74747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 74847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 74947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 75047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkuint32_t DirectStripSource::getIfd() const { 75147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return mIfd; 75247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 75347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 75447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of DirectStripSource 75547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ---------------------------------------------------------------------------- 75647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 757b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk/** 7582079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk * Given a buffer crop rectangle relative to the pixel array size, and the pre-correction active 7592079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk * array crop rectangle for the camera characteristics, set the default crop rectangle in the 7602079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk * TiffWriter relative to the buffer crop rectangle origin. 761b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk */ 762b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunkstatic status_t calculateAndSetCrop(JNIEnv* env, const CameraMetadata& characteristics, 7632079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t bufWidth, uint32_t bufHeight, sp<TiffWriter> writer) { 764b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 765b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk camera_metadata_ro_entry entry = 7662079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); 767b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk uint32_t xmin = static_cast<uint32_t>(entry.data.i32[0]); 768b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk uint32_t ymin = static_cast<uint32_t>(entry.data.i32[1]); 769b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk uint32_t width = static_cast<uint32_t>(entry.data.i32[2]); 770b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk uint32_t height = static_cast<uint32_t>(entry.data.i32[3]); 771b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 7722079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk const uint32_t margin = 8; // Default margin recommended by Adobe for interpolation. 7732079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 7742079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Crop based on pre-correction array for pixel array 775b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk uint32_t aLeft = xmin; 776b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk uint32_t aTop = ymin; 777b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk uint32_t aRight = xmin + width; 778b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk uint32_t aBottom = ymin + height; 779b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 7802079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // 8 pixel border crop for pixel array dimens 7812079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t bLeft = margin; 7822079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t bTop = margin; 7832079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t bRight = bufWidth - margin; 7842079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t bBottom = bufHeight - margin; 785b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 7862079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set the crop to be the intersection of the two rectangles 787b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk uint32_t defaultCropOrigin[] = {std::max(aLeft, bLeft), std::max(aTop, bTop)}; 788b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk uint32_t defaultCropSize[] = {std::min(aRight, bRight) - defaultCropOrigin[0], 789b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk std::min(aBottom, bBottom) - defaultCropOrigin[1]}; 790b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 7912079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // If using buffers with pre-correction array dimens, switch to 8 pixel border crop 7922079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // relative to the pixel array dimens 7932079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (bufWidth == width && bufHeight == height) { 7942079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk defaultCropOrigin[0] = xmin + margin; 7952079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk defaultCropOrigin[1] = ymin + margin; 7962079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk defaultCropSize[0] = width - margin; 7972079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk defaultCropSize[1] = height - margin; 7982079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 7992079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 800b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk BAIL_IF_INVALID_R(writer->addEntry(TAG_DEFAULTCROPORIGIN, 2, defaultCropOrigin, 801b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk TIFF_IFD_0), env, TAG_DEFAULTCROPORIGIN, writer); 802b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk BAIL_IF_INVALID_R(writer->addEntry(TAG_DEFAULTCROPSIZE, 2, defaultCropSize, 803b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk TIFF_IFD_0), env, TAG_DEFAULTCROPSIZE, writer); 804b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 805b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk return OK; 806b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk} 80747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 8082079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkstatic bool validateDngHeader(JNIEnv* env, sp<TiffWriter> writer, 809b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk const CameraMetadata& characteristics, jint width, jint height) { 810b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk if (width <= 0) { 811b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \ 812b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk "Image width %d is invalid", width); 813b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk return false; 814b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk } 81547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 816b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk if (height <= 0) { 81747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \ 818b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk "Image height %d is invalid", height); 81947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return false; 82047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 82147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 822b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk camera_metadata_ro_entry preCorrectionEntry = 823b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); 824b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk camera_metadata_ro_entry pixelArrayEntry = 825b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk characteristics.find(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE); 826b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 827b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk int pWidth = static_cast<int>(pixelArrayEntry.data.i32[0]); 828b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk int pHeight = static_cast<int>(pixelArrayEntry.data.i32[1]); 829b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk int cWidth = static_cast<int>(preCorrectionEntry.data.i32[2]); 830b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk int cHeight = static_cast<int>(preCorrectionEntry.data.i32[3]); 831b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 832b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk bool matchesPixelArray = (pWidth == width && pHeight == height); 833b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk bool matchesPreCorrectionArray = (cWidth == width && cHeight == height); 834b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 8352079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (!(matchesPixelArray || matchesPreCorrectionArray)) { 83647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \ 837b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk "Image dimensions (w=%d,h=%d) are invalid, must match either the pixel " 838b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk "array size (w=%d, h=%d) or the pre-correction array size (w=%d, h=%d)", 839b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk width, height, pWidth, pHeight, cWidth, cHeight); 84047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return false; 84147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 84247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 84347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return true; 84447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 84547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 8462079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkstatic status_t moveEntries(sp<TiffWriter> writer, uint32_t ifdFrom, uint32_t ifdTo, 84747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk const Vector<uint16_t>& entries) { 84847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk for (size_t i = 0; i < entries.size(); ++i) { 84947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint16_t tagId = entries[i]; 85047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sp<TiffEntry> entry = writer->getEntry(tagId, ifdFrom); 8512079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (entry.get() == nullptr) { 85247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: moveEntries failed, entry %u not found in IFD %u", __FUNCTION__, tagId, 85347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ifdFrom); 85447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 85547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 85647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (writer->addEntry(entry, ifdTo) != OK) { 85747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: moveEntries failed, could not add entry %u to IFD %u", __FUNCTION__, tagId, 85847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ifdFrom); 85947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 86047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 86147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk writer->removeEntry(tagId, ifdFrom); 86247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 86347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return OK; 86447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 86547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 866d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk/** 867d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * Write CFA pattern for given CFA enum into cfaOut. cfaOut must have length >= 4. 868d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * Returns OK on success, or a negative error code if the CFA enum was invalid. 869d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk */ 870d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunkstatic status_t convertCFA(uint8_t cfaEnum, /*out*/uint8_t* cfaOut) { 871d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk camera_metadata_enum_android_sensor_info_color_filter_arrangement_t cfa = 872d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk static_cast<camera_metadata_enum_android_sensor_info_color_filter_arrangement_t>( 873d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaEnum); 874d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk switch(cfa) { 875d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB: { 876d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[0] = 0; 877d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[1] = 1; 878d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[2] = 1; 879d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[3] = 2; 880d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk break; 881d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 882d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG: { 883d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[0] = 1; 884d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[1] = 0; 885d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[2] = 2; 886d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[3] = 1; 887d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk break; 888d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 889d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG: { 890d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[0] = 1; 891d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[1] = 2; 892d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[2] = 0; 893d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[3] = 1; 894d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk break; 895d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 896d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR: { 897d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[0] = 2; 898d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[1] = 1; 899d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[2] = 1; 900d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[3] = 0; 901d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk break; 902d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 903d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk default: { 904d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return BAD_VALUE; 905d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 906d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 907d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return OK; 908d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk} 909d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 910d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk/** 911d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * Convert the CFA layout enum to an OpcodeListBuilder::CfaLayout enum, defaults to 912d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * RGGB for an unknown enum. 913d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk */ 914d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunkstatic OpcodeListBuilder::CfaLayout convertCFAEnumToOpcodeLayout(uint8_t cfaEnum) { 915d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk camera_metadata_enum_android_sensor_info_color_filter_arrangement_t cfa = 916d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk static_cast<camera_metadata_enum_android_sensor_info_color_filter_arrangement_t>( 917d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaEnum); 918d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk switch(cfa) { 919d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB: { 920d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return OpcodeListBuilder::CFA_RGGB; 921d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 922d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG: { 923d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return OpcodeListBuilder::CFA_GRBG; 924d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 925d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG: { 926d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return OpcodeListBuilder::CFA_GBRG; 927d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 928d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR: { 929d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return OpcodeListBuilder::CFA_BGGR; 930d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 931d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk default: { 932d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return OpcodeListBuilder::CFA_RGGB; 933d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 934d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 935d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk} 936d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 937d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk/** 938d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * For each color plane, find the corresponding noise profile coefficients given in the 939d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * per-channel noise profile. If multiple channels in the CFA correspond to a color in the color 940d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * plane, this method takes the pair of noise profile coefficients with the higher S coefficient. 941d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * 942d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * perChannelNoiseProfile - numChannels * 2 noise profile coefficients. 943d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * cfa - numChannels color channels corresponding to each of the per-channel noise profile 944d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * coefficients. 945d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * numChannels - the number of noise profile coefficient pairs and color channels given in 946d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * the perChannelNoiseProfile and cfa arguments, respectively. 947d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * planeColors - the color planes in the noise profile output. 948d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * numPlanes - the number of planes in planeColors and pairs of coefficients in noiseProfile. 949d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * noiseProfile - 2 * numPlanes doubles containing numPlanes pairs of noise profile coefficients. 950d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * 951d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * returns OK, or a negative error code on failure. 952d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk */ 953d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunkstatic status_t generateNoiseProfile(const double* perChannelNoiseProfile, uint8_t* cfa, 954d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk size_t numChannels, const uint8_t* planeColors, size_t numPlanes, 955d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk /*out*/double* noiseProfile) { 956d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 957d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk for (size_t p = 0; p < numPlanes; ++p) { 958d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk size_t S = p * 2; 959d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk size_t O = p * 2 + 1; 960d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 961d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk noiseProfile[S] = 0; 962d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk noiseProfile[O] = 0; 963d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk bool uninitialized = true; 964d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk for (size_t c = 0; c < numChannels; ++c) { 965d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk if (cfa[c] == planeColors[p] && perChannelNoiseProfile[c * 2] > noiseProfile[S]) { 966d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk noiseProfile[S] = perChannelNoiseProfile[c * 2]; 967d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk noiseProfile[O] = perChannelNoiseProfile[c * 2 + 1]; 968d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk uninitialized = false; 969d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 970d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 971d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk if (uninitialized) { 97246d8444631b4b1253a76bfcc78a29d26014d022fDan Albert ALOGE("%s: No valid NoiseProfile coefficients for color plane %zu", 97346d8444631b4b1253a76bfcc78a29d26014d022fDan Albert __FUNCTION__, p); 974d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return BAD_VALUE; 975d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 976d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 977d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return OK; 978d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk} 979d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 98047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ---------------------------------------------------------------------------- 981f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkextern "C" { 982f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 98347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic NativeContext* DngCreator_getNativeContext(JNIEnv* env, jobject thiz) { 984f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 98547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return reinterpret_cast<NativeContext*>(env->GetLongField(thiz, 986f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk gDngCreatorClassInfo.mNativeContext)); 987f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 988f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 98947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic void DngCreator_setNativeContext(JNIEnv* env, jobject thiz, sp<NativeContext> context) { 990f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 99147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk NativeContext* current = DngCreator_getNativeContext(env, thiz); 99247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 9932079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (context != nullptr) { 99447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk context->incStrong((void*) DngCreator_setNativeContext); 995f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 99647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 997f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (current) { 99847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk current->decStrong((void*) DngCreator_setNativeContext); 999f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 100047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 1001f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk env->SetLongField(thiz, gDngCreatorClassInfo.mNativeContext, 100247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk reinterpret_cast<jlong>(context.get())); 100347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 100447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 1005f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic void DngCreator_nativeClassInit(JNIEnv* env, jclass clazz) { 1006f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 1007f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1008ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gDngCreatorClassInfo.mNativeContext = GetFieldIDOrDie(env, 1009ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe clazz, ANDROID_DNGCREATOR_CTX_JNI_ID, "J"); 1010ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe 1011ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe jclass outputStreamClazz = FindClassOrDie(env, "java/io/OutputStream"); 1012ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gOutputStreamClassInfo.mWriteMethod = GetMethodIDOrDie(env, 1013ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe outputStreamClazz, "write", "([BII)V"); 1014ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe 1015ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe jclass inputStreamClazz = FindClassOrDie(env, "java/io/InputStream"); 1016ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gInputStreamClassInfo.mReadMethod = GetMethodIDOrDie(env, inputStreamClazz, "read", "([BII)I"); 1017ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gInputStreamClassInfo.mSkipMethod = GetMethodIDOrDie(env, inputStreamClazz, "skip", "(J)J"); 1018ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe 1019ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe jclass inputBufferClazz = FindClassOrDie(env, "java/nio/ByteBuffer"); 1020ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gInputByteBufferClassInfo.mGetMethod = GetMethodIDOrDie(env, 1021ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe inputBufferClazz, "get", "([BII)Ljava/nio/ByteBuffer;"); 1022f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 1023f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1024f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPtr, 1025b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk jobject resultsPtr, jstring formattedCaptureTime) { 1026f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 1027f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk CameraMetadata characteristics; 1028f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk CameraMetadata results; 1029f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (CameraMetadata_getNativeMetadata(env, characteristicsPtr, &characteristics) != OK) { 1030f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jniThrowException(env, "java/lang/AssertionError", 1031f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk "No native metadata defined for camera characteristics."); 1032f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 1033f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1034f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (CameraMetadata_getNativeMetadata(env, resultsPtr, &results) != OK) { 1035f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jniThrowException(env, "java/lang/AssertionError", 1036f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk "No native metadata defined for capture results."); 1037f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 1038f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1039f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1040b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk sp<NativeContext> nativeContext = new NativeContext(characteristics, results); 10412079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10422079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk const char* captureTime = env->GetStringUTFChars(formattedCaptureTime, nullptr); 10432079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10442079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk size_t len = strlen(captureTime) + 1; 10452079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (len != NativeContext::DATETIME_COUNT) { 10462079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", 10472079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk "Formatted capture time string length is not required 20 characters"); 10482079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return; 10492079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 10502079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10512079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk nativeContext->setCaptureTime(String8(captureTime)); 10522079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10532079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk DngCreator_setNativeContext(env, thiz, nativeContext); 10542079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 10552079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10562079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkstatic sp<TiffWriter> DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t imageWidth, 10572079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t imageHeight) { 10582079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10592079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk NativeContext* nativeContext = DngCreator_getNativeContext(env, thiz); 10602079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10612079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (nativeContext == nullptr) { 10622079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowException(env, "java/lang/AssertionError", 10632079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk "No native context, must call init before other operations."); 10642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 10652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 10662079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10672079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk CameraMetadata characteristics = *(nativeContext->getCharacteristics()); 10682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk CameraMetadata results = *(nativeContext->getResult()); 10692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10702079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk sp<TiffWriter> writer = new TiffWriter(); 10712079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10722079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t preWidth = 0; 10732079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t preHeight = 0; 10742079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 10752079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Check dimensions 10762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk camera_metadata_entry entry = 10772079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); 10782079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_IMAGEWIDTH, writer); 10792079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk preWidth = static_cast<uint32_t>(entry.data.i32[2]); 10802079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk preHeight = static_cast<uint32_t>(entry.data.i32[3]); 10812079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10822079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk camera_metadata_entry pixelArrayEntry = 10832079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk characteristics.find(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE); 10842079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t pixWidth = static_cast<uint32_t>(pixelArrayEntry.data.i32[0]); 10852079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t pixHeight = static_cast<uint32_t>(pixelArrayEntry.data.i32[1]); 10862079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10872079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (!((imageWidth == preWidth && imageHeight == preHeight) || 10882079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk (imageWidth == pixWidth && imageHeight == pixHeight))) { 10892079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowException(env, "java/lang/AssertionError", 10902079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk "Height and width of imate buffer did not match height and width of" 10912079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk "either the preCorrectionActiveArraySize or the pixelArraySize."); 10922079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 10932079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 10942079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 10952079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10962079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 1097f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1098f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk writer->addIfd(TIFF_IFD_0); 1099f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1100f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk status_t err = OK; 1101f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1102f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk const uint32_t samplesPerPixel = 1; 1103f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk const uint32_t bitsPerSample = BITS_PER_SAMPLE; 1104f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1105f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk OpcodeListBuilder::CfaLayout opcodeCfaLayout = OpcodeListBuilder::CFA_RGGB; 1106d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk uint8_t cfaPlaneColor[3] = {0, 1, 2}; 1107d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk uint8_t cfaEnum = -1; 1108f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1109f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // TODO: Greensplit. 1110f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // TODO: Add remaining non-essential tags 111147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 111247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk // Setup main image tags 111347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 1114f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1115f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set orientation 1116f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t orientation = 1; // Normal 11172079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0), 11182079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_ORIENTATION, writer); 1119f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1120f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1121f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1122f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set subfiletype 1123f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint32_t subfileType = 0; // Main image 11242079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_NEWSUBFILETYPE, 1, &subfileType, 11252079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_NEWSUBFILETYPE, writer); 1126f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1127f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1128f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1129f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set bits per sample 1130f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t bits = static_cast<uint16_t>(bitsPerSample); 11312079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BITSPERSAMPLE, 1, &bits, TIFF_IFD_0), env, 113247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TAG_BITSPERSAMPLE, writer); 1133f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1134f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1135f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1136f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set compression 1137f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t compression = 1; // None 11382079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_COMPRESSION, 1, &compression, 11392079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_COMPRESSION, writer); 1140f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1141f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1142f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1143f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set dimensions 11442079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGEWIDTH, 1, &imageWidth, TIFF_IFD_0), 11452079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_IMAGEWIDTH, writer); 11462079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGELENGTH, 1, &imageHeight, TIFF_IFD_0), 11472079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_IMAGELENGTH, writer); 1148f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1149f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1150f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1151f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set photometric interpretation 115247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint16_t interpretation = 32803; // CFA 11532079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_PHOTOMETRICINTERPRETATION, 1, 11542079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk &interpretation, TIFF_IFD_0), env, TAG_PHOTOMETRICINTERPRETATION, writer); 1155f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1156f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1157f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1158f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set blacklevel tags 1159f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry = 1160f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_BLACK_LEVEL_PATTERN); 11612079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_BLACKLEVEL, writer); 1162f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk const uint32_t* blackLevel = reinterpret_cast<const uint32_t*>(entry.data.i32); 11632079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BLACKLEVEL, entry.count, blackLevel, 11642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_BLACKLEVEL, writer); 1165f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1166f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t repeatDim[2] = {2, 2}; 11672079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BLACKLEVELREPEATDIM, 2, repeatDim, 11682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_BLACKLEVELREPEATDIM, writer); 1169f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1170f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1171f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1172f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set samples per pixel 1173f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t samples = static_cast<uint16_t>(samplesPerPixel); 11742079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_SAMPLESPERPIXEL, 1, &samples, TIFF_IFD_0), 117547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk env, TAG_SAMPLESPERPIXEL, writer); 1176f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1177f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1178f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1179f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set planar configuration 1180f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t config = 1; // Chunky 11812079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_PLANARCONFIGURATION, 1, &config, 11822079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_PLANARCONFIGURATION, writer); 1183f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1184f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1185f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1186f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set CFA pattern dimensions 1187f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t repeatDim[2] = {2, 2}; 11882079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CFAREPEATPATTERNDIM, 2, repeatDim, 11892079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_CFAREPEATPATTERNDIM, writer); 1190f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1191f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1192f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1193f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set CFA pattern 1194f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry = 1195f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT); 11962079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_CFAPATTERN, writer); 1197d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 1198d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk const int cfaLength = 4; 1199d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaEnum = entry.data.u8[0]; 1200d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk uint8_t cfa[cfaLength]; 1201d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk if ((err = convertCFA(cfaEnum, /*out*/cfa)) != OK) { 1202d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 1203d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk "Invalid metadata for tag %d", TAG_CFAPATTERN); 1204f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1205d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 12062079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CFAPATTERN, cfaLength, cfa, TIFF_IFD_0), 12072079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_CFAPATTERN, writer); 1208d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 1209d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk opcodeCfaLayout = convertCFAEnumToOpcodeLayout(cfaEnum); 1210f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1211f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1212f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1213f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set CFA plane color 12142079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CFAPLANECOLOR, 3, cfaPlaneColor, 12152079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_CFAPLANECOLOR, writer); 1216f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1217f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1218f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1219f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set CFA layout 1220f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t cfaLayout = 1; 12212079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CFALAYOUT, 1, &cfaLayout, TIFF_IFD_0), 122247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk env, TAG_CFALAYOUT, writer); 1223f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1224f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1225f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1226b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // image description 1227b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint8_t imageDescription = '\0'; // empty 12282079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGEDESCRIPTION, 1, &imageDescription, 12292079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_IMAGEDESCRIPTION, writer); 1230b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1231b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1232b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1233b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // make 1234b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk char manufacturer[PROPERTY_VALUE_MAX]; 1235b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1236b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // Use "" to represent unknown make as suggested in TIFF/EP spec. 1237b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk property_get("ro.product.manufacturer", manufacturer, ""); 1238b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t count = static_cast<uint32_t>(strlen(manufacturer)) + 1; 1239b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 12402079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_MAKE, count, 12412079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<uint8_t*>(manufacturer), TIFF_IFD_0), env, TAG_MAKE, writer); 1242b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1243b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1244b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1245b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // model 1246b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk char model[PROPERTY_VALUE_MAX]; 1247b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1248b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // Use "" to represent unknown model as suggested in TIFF/EP spec. 1249b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk property_get("ro.product.model", model, ""); 1250b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t count = static_cast<uint32_t>(strlen(model)) + 1; 1251b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 12522079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_MODEL, count, 12532079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<uint8_t*>(model), TIFF_IFD_0), env, TAG_MODEL, writer); 1254b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1255b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1256b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1257b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // x resolution 1258b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t xres[] = { 72, 1 }; // default 72 ppi 12592079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_XRESOLUTION, 1, xres, TIFF_IFD_0), 126047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk env, TAG_XRESOLUTION, writer); 1261b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1262b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // y resolution 1263b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t yres[] = { 72, 1 }; // default 72 ppi 12642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_YRESOLUTION, 1, yres, TIFF_IFD_0), 126547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk env, TAG_YRESOLUTION, writer); 1266b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1267b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint16_t unit = 2; // inches 12682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_RESOLUTIONUNIT, 1, &unit, TIFF_IFD_0), 126947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk env, TAG_RESOLUTIONUNIT, writer); 1270b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1271b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1272b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1273b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // software 1274b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk char software[PROPERTY_VALUE_MAX]; 1275b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk property_get("ro.build.fingerprint", software, ""); 1276b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t count = static_cast<uint32_t>(strlen(software)) + 1; 12772079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_SOFTWARE, count, 12782079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<uint8_t*>(software), TIFF_IFD_0), env, TAG_SOFTWARE, writer); 1279b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1280b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 12812079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (nativeContext->hasCaptureTime()) { 1282b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // datetime 12832079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk String8 captureTime = nativeContext->getCaptureTime(); 1284b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 12852079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer->addEntry(TAG_DATETIME, NativeContext::DATETIME_COUNT, 12862079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<const uint8_t*>(captureTime.string()), TIFF_IFD_0) != OK) { 128747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 128847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Invalid metadata for tag %x", TAG_DATETIME); 12892079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 129047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 1291b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1292b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // datetime original 12932079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer->addEntry(TAG_DATETIMEORIGINAL, NativeContext::DATETIME_COUNT, 12942079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<const uint8_t*>(captureTime.string()), TIFF_IFD_0) != OK) { 129547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 129647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Invalid metadata for tag %x", TAG_DATETIMEORIGINAL); 12972079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 129847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 1299b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1300b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1301b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1302b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // TIFF/EP standard id 1303b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint8_t standardId[] = { 1, 0, 0, 0 }; 13042079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_TIFFEPSTANDARDID, 4, standardId, 130547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_TIFFEPSTANDARDID, writer); 1306b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1307b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1308b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1309b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // copyright 1310b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint8_t copyright = '\0'; // empty 13112079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_COPYRIGHT, 1, ©right, 131247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_COPYRIGHT, writer); 1313b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1314b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1315b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1316b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // exposure time 1317b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk camera_metadata_entry entry = 1318b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk results.find(ANDROID_SENSOR_EXPOSURE_TIME); 13192079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_EXPOSURETIME, writer); 1320b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1321b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk int64_t exposureTime = *(entry.data.i64); 1322b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1323b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk if (exposureTime < 0) { 1324b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // Should be unreachable 1325b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", 1326b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk "Negative exposure time in metadata"); 13272079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 1328b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1329b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1330b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // Ensure exposure time doesn't overflow (for exposures > 4s) 1331b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t denominator = 1000000000; 1332b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk while (exposureTime > UINT32_MAX) { 1333b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk exposureTime >>= 1; 1334b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk denominator >>= 1; 1335b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk if (denominator == 0) { 1336b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // Should be unreachable 1337b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", 1338b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk "Exposure time too long"); 13392079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 1340b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1341b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1342b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1343b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t exposure[] = { static_cast<uint32_t>(exposureTime), denominator }; 13442079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_EXPOSURETIME, 1, exposure, 134547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_EXPOSURETIME, writer); 1346b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1347b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1348b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1349b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1350b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // ISO speed ratings 1351b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk camera_metadata_entry entry = 1352b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk results.find(ANDROID_SENSOR_SENSITIVITY); 13532079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_ISOSPEEDRATINGS, writer); 1354b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1355b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk int32_t tempIso = *(entry.data.i32); 1356b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk if (tempIso < 0) { 1357b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", 1358b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk "Negative ISO value"); 13592079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 1360b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1361b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1362b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk if (tempIso > UINT16_MAX) { 1363b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk ALOGW("%s: ISO value overflows UINT16_MAX, clamping to max", __FUNCTION__); 1364b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk tempIso = UINT16_MAX; 1365b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1366b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1367b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint16_t iso = static_cast<uint16_t>(tempIso); 13682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ISOSPEEDRATINGS, 1, &iso, 136947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_ISOSPEEDRATINGS, writer); 1370b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1371b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1372b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1373b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // focal length 1374b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk camera_metadata_entry entry = 1375b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk results.find(ANDROID_LENS_FOCAL_LENGTH); 13762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_FOCALLENGTH, writer); 1377b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1378b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t focalLength[] = { static_cast<uint32_t>(*(entry.data.f) * 100), 100 }; 13792079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_FOCALLENGTH, 1, focalLength, 138047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_FOCALLENGTH, writer); 1381b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1382b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1383b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1384b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // f number 1385b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk camera_metadata_entry entry = 1386b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk results.find(ANDROID_LENS_APERTURE); 13872079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_FNUMBER, writer); 1388b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1389b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t fnum[] = { static_cast<uint32_t>(*(entry.data.f) * 100), 100 }; 13902079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_FNUMBER, 1, fnum, 139147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_FNUMBER, writer); 1392b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1393b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1394b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1395f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set DNG version information 1396f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint8_t version[4] = {1, 4, 0, 0}; 13972079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_DNGVERSION, 4, version, TIFF_IFD_0), 139847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk env, TAG_DNGVERSION, writer); 1399f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1400f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint8_t backwardVersion[4] = {1, 1, 0, 0}; 14012079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_DNGBACKWARDVERSION, 4, backwardVersion, 14022079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_DNGBACKWARDVERSION, writer); 1403f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1404f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1405f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1406f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set whitelevel 1407f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry = 1408f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_INFO_WHITE_LEVEL); 14092079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_WHITELEVEL, writer); 1410f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint32_t whiteLevel = static_cast<uint32_t>(entry.data.i32[0]); 14112079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_WHITELEVEL, 1, &whiteLevel, TIFF_IFD_0), 14122079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_WHITELEVEL, writer); 1413f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1414f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1415f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1416f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set default scale 1417f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint32_t defaultScale[4] = {1, 1, 1, 1}; 14182079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_DEFAULTSCALE, 2, defaultScale, 14192079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_DEFAULTSCALE, writer); 1420f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1421f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1422f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk bool singleIlluminant = false; 1423f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1424f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set calibration illuminants 1425f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry1 = 1426f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_REFERENCE_ILLUMINANT1); 14272079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry1, env, TAG_CALIBRATIONILLUMINANT1, writer); 1428f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry2 = 1429f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_REFERENCE_ILLUMINANT2); 1430f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (entry2.count == 0) { 1431f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk singleIlluminant = true; 1432f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1433f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t ref1 = entry1.data.u8[0]; 1434f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 14352079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CALIBRATIONILLUMINANT1, 1, &ref1, 143647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_CALIBRATIONILLUMINANT1, writer); 1437f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1438f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (!singleIlluminant) { 1439f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t ref2 = entry2.data.u8[0]; 14402079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CALIBRATIONILLUMINANT2, 1, &ref2, 144147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_CALIBRATIONILLUMINANT2, writer); 1442f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1443f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1444f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1445f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1446f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set color transforms 1447f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry1 = 1448f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_COLOR_TRANSFORM1); 14492079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry1, env, TAG_COLORMATRIX1, writer); 1450f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1451f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk int32_t colorTransform1[entry1.count * 2]; 1452f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1453f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk size_t ctr = 0; 1454f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk for(size_t i = 0; i < entry1.count; ++i) { 1455f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk colorTransform1[ctr++] = entry1.data.r[i].numerator; 1456f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk colorTransform1[ctr++] = entry1.data.r[i].denominator; 1457f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1458f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 14592079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_COLORMATRIX1, entry1.count, 14602079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk colorTransform1, TIFF_IFD_0), env, TAG_COLORMATRIX1, writer); 1461f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1462f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (!singleIlluminant) { 1463f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry2 = characteristics.find(ANDROID_SENSOR_COLOR_TRANSFORM2); 14642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry2, env, TAG_COLORMATRIX2, writer); 1465f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk int32_t colorTransform2[entry2.count * 2]; 1466f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1467f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ctr = 0; 1468f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk for(size_t i = 0; i < entry2.count; ++i) { 1469f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk colorTransform2[ctr++] = entry2.data.r[i].numerator; 1470f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk colorTransform2[ctr++] = entry2.data.r[i].denominator; 1471f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1472f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 14732079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_COLORMATRIX2, entry2.count, 14742079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk colorTransform2, TIFF_IFD_0), env, TAG_COLORMATRIX2, writer); 1475f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1476f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1477f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1478f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1479f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set calibration transforms 1480f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry1 = 1481f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_CALIBRATION_TRANSFORM1); 14822079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry1, env, TAG_CAMERACALIBRATION1, writer); 1483f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1484f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk int32_t calibrationTransform1[entry1.count * 2]; 1485f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1486f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk size_t ctr = 0; 1487f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk for(size_t i = 0; i < entry1.count; ++i) { 1488f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk calibrationTransform1[ctr++] = entry1.data.r[i].numerator; 1489f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk calibrationTransform1[ctr++] = entry1.data.r[i].denominator; 1490f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1491f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 14922079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CAMERACALIBRATION1, entry1.count, 1493b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk calibrationTransform1, TIFF_IFD_0), env, TAG_CAMERACALIBRATION1, writer); 1494f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1495f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (!singleIlluminant) { 1496f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry2 = 1497f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_CALIBRATION_TRANSFORM2); 14982079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry2, env, TAG_CAMERACALIBRATION2, writer); 1499f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk int32_t calibrationTransform2[entry2.count * 2]; 1500f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1501f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ctr = 0; 1502f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk for(size_t i = 0; i < entry2.count; ++i) { 1503f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk calibrationTransform2[ctr++] = entry2.data.r[i].numerator; 1504f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk calibrationTransform2[ctr++] = entry2.data.r[i].denominator; 1505f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1506f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 15072079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CAMERACALIBRATION2, entry2.count, 15082377cd319f8a77f147f3d70a7ddc75fa9e9fe87cAndreas Gampe calibrationTransform2, TIFF_IFD_0), env, TAG_CAMERACALIBRATION2, writer); 1509f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1510f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1511f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1512f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1513f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set forward transforms 1514f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry1 = 1515f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_FORWARD_MATRIX1); 15162079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry1, env, TAG_FORWARDMATRIX1, writer); 1517f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1518f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk int32_t forwardTransform1[entry1.count * 2]; 1519f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1520f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk size_t ctr = 0; 1521f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk for(size_t i = 0; i < entry1.count; ++i) { 1522f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk forwardTransform1[ctr++] = entry1.data.r[i].numerator; 1523f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk forwardTransform1[ctr++] = entry1.data.r[i].denominator; 1524f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1525f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 15262079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_FORWARDMATRIX1, entry1.count, 15272079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk forwardTransform1, TIFF_IFD_0), env, TAG_FORWARDMATRIX1, writer); 1528f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1529f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (!singleIlluminant) { 1530f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry2 = 1531f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_FORWARD_MATRIX2); 15322079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry2, env, TAG_FORWARDMATRIX2, writer); 1533f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk int32_t forwardTransform2[entry2.count * 2]; 1534f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1535f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ctr = 0; 1536f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk for(size_t i = 0; i < entry2.count; ++i) { 1537f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk forwardTransform2[ctr++] = entry2.data.r[i].numerator; 1538f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk forwardTransform2[ctr++] = entry2.data.r[i].denominator; 1539f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1540f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 15412079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_FORWARDMATRIX2, entry2.count, 15422079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk forwardTransform2, TIFF_IFD_0), env, TAG_FORWARDMATRIX2, writer); 1543f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1544f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1545f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1546f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1547f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set camera neutral 1548f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry = 1549f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk results.find(ANDROID_SENSOR_NEUTRAL_COLOR_POINT); 15502079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_ASSHOTNEUTRAL, writer); 1551f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint32_t cameraNeutral[entry.count * 2]; 1552f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1553f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk size_t ctr = 0; 1554f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk for(size_t i = 0; i < entry.count; ++i) { 1555f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk cameraNeutral[ctr++] = 1556f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk static_cast<uint32_t>(entry.data.r[i].numerator); 1557f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk cameraNeutral[ctr++] = 1558f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk static_cast<uint32_t>(entry.data.r[i].denominator); 1559f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1560f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 15612079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ASSHOTNEUTRAL, entry.count, cameraNeutral, 156247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_ASSHOTNEUTRAL, writer); 1563f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1564f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1565f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1566f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1567b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk // Set dimensions 15682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (calculateAndSetCrop(env, characteristics, imageWidth, imageHeight, writer) != OK) { 15692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 15702079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 1571b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk camera_metadata_entry entry = 1572b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); 15732079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_DEFAULTCROPSIZE, writer); 1574b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk uint32_t xmin = static_cast<uint32_t>(entry.data.i32[0]); 1575b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk uint32_t ymin = static_cast<uint32_t>(entry.data.i32[1]); 1576b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk uint32_t width = static_cast<uint32_t>(entry.data.i32[2]); 1577b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk uint32_t height = static_cast<uint32_t>(entry.data.i32[3]); 15782079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 15792079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t activeArea[] = {ymin, xmin, ymin + height, xmin + width}; 15802079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ACTIVEAREA, 4, activeArea, TIFF_IFD_0), 15812079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_ACTIVEAREA, writer); 1582f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1583f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1584f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1585f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Setup unique camera model tag 1586f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk char model[PROPERTY_VALUE_MAX]; 1587f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk property_get("ro.product.model", model, ""); 1588f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1589f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk char manufacturer[PROPERTY_VALUE_MAX]; 1590f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk property_get("ro.product.manufacturer", manufacturer, ""); 1591f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1592f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk char brand[PROPERTY_VALUE_MAX]; 1593f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk property_get("ro.product.brand", brand, ""); 1594f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1595f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk String8 cameraModel(model); 1596f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk cameraModel += "-"; 1597f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk cameraModel += manufacturer; 1598f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk cameraModel += "-"; 1599f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk cameraModel += brand; 1600f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 16012079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_UNIQUECAMERAMODEL, cameraModel.size() + 1, 1602f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk reinterpret_cast<const uint8_t*>(cameraModel.string()), TIFF_IFD_0), env, 160347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TAG_UNIQUECAMERAMODEL, writer); 1604f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1605f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1606f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1607b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk // Setup sensor noise model 1608b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk camera_metadata_entry entry = 1609b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk results.find(ANDROID_SENSOR_NOISE_PROFILE); 1610b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk 1611d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk const status_t numPlaneColors = 3; 1612d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk const status_t numCfaChannels = 4; 1613d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 1614d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk uint8_t cfaOut[numCfaChannels]; 1615d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk if ((err = convertCFA(cfaEnum, /*out*/cfaOut)) != OK) { 1616d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", 1617d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk "Invalid CFA from camera characteristics"); 16182079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 1619d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 1620d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 1621d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk double noiseProfile[numPlaneColors * 2]; 1622d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 1623b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk if (entry.count > 0) { 1624d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk if (entry.count != numCfaChannels * 2) { 162546d8444631b4b1253a76bfcc78a29d26014d022fDan Albert ALOGW("%s: Invalid entry count %zu for noise profile returned " 162646d8444631b4b1253a76bfcc78a29d26014d022fDan Albert "in characteristics, no noise profile tag written...", 162746d8444631b4b1253a76bfcc78a29d26014d022fDan Albert __FUNCTION__, entry.count); 1628d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } else { 1629d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk if ((err = generateNoiseProfile(entry.data.d, cfaOut, numCfaChannels, 1630d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaPlaneColor, numPlaneColors, /*out*/ noiseProfile)) == OK) { 1631d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 16322079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_NOISEPROFILE, 16332079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk numPlaneColors * 2, noiseProfile, TIFF_IFD_0), env, TAG_NOISEPROFILE, 16342079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk writer); 1635d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } else { 1636d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk ALOGW("%s: Error converting coefficients for noise profile, no noise profile" 1637d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk " tag written...", __FUNCTION__); 1638d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 1639d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 1640b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk } else { 1641b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk ALOGW("%s: No noise profile found in result metadata. Image quality may be reduced.", 1642b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk __FUNCTION__); 1643b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk } 1644b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk } 1645b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk 1646b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk { 16475f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk // Set up opcode List 2 16485f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk OpcodeListBuilder builder; 16495f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk status_t err = OK; 16505f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk 16515f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk // Set up lens shading map 1652f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry1 = 1653f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_LENS_INFO_SHADING_MAP_SIZE); 165447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 165547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t lsmWidth = 0; 165647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t lsmHeight = 0; 165747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 165847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (entry1.count != 0) { 165947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk lsmWidth = static_cast<uint32_t>(entry1.data.i32[0]); 166047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk lsmHeight = static_cast<uint32_t>(entry1.data.i32[1]); 166147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 1662f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 16639ce22a095685a581823316457217a318fb40c754Ruben Brunk camera_metadata_entry entry2 = results.find(ANDROID_STATISTICS_LENS_SHADING_MAP); 166447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 16652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk camera_metadata_entry entry = 16662079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); 16672079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_IMAGEWIDTH, writer); 16682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t xmin = static_cast<uint32_t>(entry.data.i32[0]); 16692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t ymin = static_cast<uint32_t>(entry.data.i32[1]); 16702079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t width = static_cast<uint32_t>(entry.data.i32[2]); 16712079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t height = static_cast<uint32_t>(entry.data.i32[3]); 167247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (entry2.count > 0 && entry2.count == lsmWidth * lsmHeight * 4) { 16735f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk err = builder.addGainMapsForMetadata(lsmWidth, 16745f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk lsmHeight, 16752079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk ymin, 16762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk xmin, 16772079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk height, 16782079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk width, 16795f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk opcodeCfaLayout, 16805f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk entry2.data.f); 16815f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk if (err != OK) { 1682f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGE("%s: Could not add Lens shading map.", __FUNCTION__); 1683f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jniThrowRuntimeException(env, "failed to add lens shading map."); 16842079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 16855f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk } 16865f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk } 16875f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk 16889ce22a095685a581823316457217a318fb40c754Ruben Brunk 16899ce22a095685a581823316457217a318fb40c754Ruben Brunk // Set up bad pixel correction list 16909ce22a095685a581823316457217a318fb40c754Ruben Brunk camera_metadata_entry entry3 = characteristics.find(ANDROID_STATISTICS_HOT_PIXEL_MAP); 16919ce22a095685a581823316457217a318fb40c754Ruben Brunk 16929ce22a095685a581823316457217a318fb40c754Ruben Brunk if ((entry3.count % 2) != 0) { 16939ce22a095685a581823316457217a318fb40c754Ruben Brunk ALOGE("%s: Hot pixel map contains odd number of values, cannot map to pairs!", 16949ce22a095685a581823316457217a318fb40c754Ruben Brunk __FUNCTION__); 16959ce22a095685a581823316457217a318fb40c754Ruben Brunk jniThrowRuntimeException(env, "failed to add hotpixel map."); 16969ce22a095685a581823316457217a318fb40c754Ruben Brunk return nullptr; 16979ce22a095685a581823316457217a318fb40c754Ruben Brunk } 16989ce22a095685a581823316457217a318fb40c754Ruben Brunk 16999ce22a095685a581823316457217a318fb40c754Ruben Brunk // Adjust the bad pixel coordinates to be relative to the origin of the active area DNG tag 17009ce22a095685a581823316457217a318fb40c754Ruben Brunk std::vector<uint32_t> v; 17019ce22a095685a581823316457217a318fb40c754Ruben Brunk for (size_t i = 0; i < entry3.count; i+=2) { 17029ce22a095685a581823316457217a318fb40c754Ruben Brunk int32_t x = entry3.data.i32[i]; 17039ce22a095685a581823316457217a318fb40c754Ruben Brunk int32_t y = entry3.data.i32[i + 1]; 17049ce22a095685a581823316457217a318fb40c754Ruben Brunk x -= static_cast<int32_t>(xmin); 17059ce22a095685a581823316457217a318fb40c754Ruben Brunk y -= static_cast<int32_t>(ymin); 17069ce22a095685a581823316457217a318fb40c754Ruben Brunk if (x < 0 || y < 0 || static_cast<uint32_t>(x) >= width || 17079ce22a095685a581823316457217a318fb40c754Ruben Brunk static_cast<uint32_t>(y) >= width) { 17089ce22a095685a581823316457217a318fb40c754Ruben Brunk continue; 17099ce22a095685a581823316457217a318fb40c754Ruben Brunk } 17109ce22a095685a581823316457217a318fb40c754Ruben Brunk v.push_back(x); 17119ce22a095685a581823316457217a318fb40c754Ruben Brunk v.push_back(y); 17129ce22a095685a581823316457217a318fb40c754Ruben Brunk } 17139ce22a095685a581823316457217a318fb40c754Ruben Brunk const uint32_t* badPixels = &v[0]; 17149ce22a095685a581823316457217a318fb40c754Ruben Brunk uint32_t badPixelCount = v.size(); 17159ce22a095685a581823316457217a318fb40c754Ruben Brunk 17169ce22a095685a581823316457217a318fb40c754Ruben Brunk if (badPixelCount > 0) { 17179ce22a095685a581823316457217a318fb40c754Ruben Brunk err = builder.addBadPixelListForMetadata(badPixels, badPixelCount, opcodeCfaLayout); 17189ce22a095685a581823316457217a318fb40c754Ruben Brunk 17199ce22a095685a581823316457217a318fb40c754Ruben Brunk if (err != OK) { 17209ce22a095685a581823316457217a318fb40c754Ruben Brunk ALOGE("%s: Could not add hotpixel map.", __FUNCTION__); 17219ce22a095685a581823316457217a318fb40c754Ruben Brunk jniThrowRuntimeException(env, "failed to add hotpixel map."); 17229ce22a095685a581823316457217a318fb40c754Ruben Brunk return nullptr; 17239ce22a095685a581823316457217a318fb40c754Ruben Brunk } 17249ce22a095685a581823316457217a318fb40c754Ruben Brunk } 17259ce22a095685a581823316457217a318fb40c754Ruben Brunk 17269ce22a095685a581823316457217a318fb40c754Ruben Brunk 1727fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk size_t listSize = builder.getSize(); 1728fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk uint8_t opcodeListBuf[listSize]; 1729fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk err = builder.buildOpList(opcodeListBuf); 1730fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk if (err == OK) { 17312079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_OPCODELIST2, listSize, opcodeListBuf, 1732fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk TIFF_IFD_0), env, TAG_OPCODELIST2, writer); 1733fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk } else { 1734fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk ALOGE("%s: Could not build list of opcodes for distortion correction and lens shading" 1735fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk "map.", __FUNCTION__); 1736fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk jniThrowRuntimeException(env, "failed to construct opcode list for distortion" 1737fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk " correction and lens shading map"); 17382079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 1739fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk } 1740fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk } 1741fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk 1742fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk { 1743fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk // Set up opcode List 3 1744fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk OpcodeListBuilder builder; 1745fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk status_t err = OK; 1746fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk 17475f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk // Set up rectilinear distortion correction 17485f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk camera_metadata_entry entry3 = 17495f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk results.find(ANDROID_LENS_RADIAL_DISTORTION); 17505f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk camera_metadata_entry entry4 = 17515f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk results.find(ANDROID_LENS_INTRINSIC_CALIBRATION); 17525f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk 17535f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk if (entry3.count == 6 && entry4.count == 5) { 17545f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk float cx = entry4.data.f[/*c_x*/2]; 17555f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk float cy = entry4.data.f[/*c_y*/3]; 17562079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk err = builder.addWarpRectilinearForMetadata(entry3.data.f, preWidth, preHeight, cx, 17575f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk cy); 17585f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk if (err != OK) { 17595f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk ALOGE("%s: Could not add distortion correction.", __FUNCTION__); 17605f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk jniThrowRuntimeException(env, "failed to add distortion correction."); 17612079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 1762f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 17635f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk } 17645f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk 17655f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk size_t listSize = builder.getSize(); 17665f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk uint8_t opcodeListBuf[listSize]; 17675f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk err = builder.buildOpList(opcodeListBuf); 17685f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk if (err == OK) { 17692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_OPCODELIST3, listSize, opcodeListBuf, 1770fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk TIFF_IFD_0), env, TAG_OPCODELIST3, writer); 1771f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } else { 17725f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk ALOGE("%s: Could not build list of opcodes for distortion correction and lens shading" 17735f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk "map.", __FUNCTION__); 17745f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk jniThrowRuntimeException(env, "failed to construct opcode list for distortion" 17755f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk " correction and lens shading map"); 17762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 1777f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1778f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1779f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 17802079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 17812079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set up orientation tags. 17822079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint16_t orientation = nativeContext->getOrientation(); 17832079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0), 17842079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_ORIENTATION, writer); 17852079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 17862079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 17872079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 17882079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (nativeContext->hasDescription()){ 17892079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set Description 17902079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk String8 description = nativeContext->getDescription(); 17912079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk size_t len = description.bytes() + 1; 17922079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer->addEntry(TAG_IMAGEDESCRIPTION, len, 17932079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<const uint8_t*>(description.string()), TIFF_IFD_0) != OK) { 17942079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 17952079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk "Invalid metadata for tag %x", TAG_IMAGEDESCRIPTION); 17962079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 17972079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 17982079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 17992079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (nativeContext->hasGpsData()) { 18002079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set GPS tags 18012079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GpsData gpsData = nativeContext->getGpsData(); 18022079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (!writer->hasIfd(TIFF_IFD_GPSINFO)) { 18032079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer->addSubIfd(TIFF_IFD_0, TIFF_IFD_GPSINFO, TiffWriter::GPSINFO) != OK) { 18042079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk ALOGE("%s: Failed to add GpsInfo IFD %u to IFD %u", __FUNCTION__, TIFF_IFD_GPSINFO, 18052079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0); 18062079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowException(env, "java/lang/IllegalStateException", "Failed to add GPSINFO"); 18072079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 18082079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18092079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18102079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18112079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 18122079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint8_t version[] = {2, 3, 0, 0}; 18132079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSVERSIONID, 4, version, 18142079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_GPSINFO), env, TAG_GPSVERSIONID, writer); 18152079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18162079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18172079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 18182079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSLATITUDEREF, 18192079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GpsData::GPS_REF_LENGTH, gpsData.mLatitudeRef, TIFF_IFD_GPSINFO), env, 18202079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TAG_GPSLATITUDEREF, writer); 18212079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18222079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18232079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 18242079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSLONGITUDEREF, 18252079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GpsData::GPS_REF_LENGTH, gpsData.mLongitudeRef, TIFF_IFD_GPSINFO), env, 18262079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TAG_GPSLONGITUDEREF, writer); 18272079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18282079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18292079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 18302079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSLATITUDE, 3, gpsData.mLatitude, 18312079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_GPSINFO), env, TAG_GPSLATITUDE, writer); 18322079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18332079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18342079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 18352079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSLONGITUDE, 3, gpsData.mLongitude, 18362079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_GPSINFO), env, TAG_GPSLONGITUDE, writer); 18372079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18382079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18392079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 18402079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSTIMESTAMP, 3, gpsData.mTimestamp, 18412079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_GPSINFO), env, TAG_GPSTIMESTAMP, writer); 18422079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18432079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18442079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 18452079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSDATESTAMP, 18462079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GpsData::GPS_DATE_LENGTH, gpsData.mDate, TIFF_IFD_GPSINFO), env, 18472079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TAG_GPSDATESTAMP, writer); 18482079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18492079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18502079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18512079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18522079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (nativeContext->hasThumbnail()) { 18532079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (!writer->hasIfd(TIFF_IFD_SUB1)) { 18542079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer->addSubIfd(TIFF_IFD_0, TIFF_IFD_SUB1) != OK) { 18552079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk ALOGE("%s: Failed to add SubIFD %u to IFD %u", __FUNCTION__, TIFF_IFD_SUB1, 18562079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0); 18572079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowException(env, "java/lang/IllegalStateException", "Failed to add SubIFD"); 18582079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 18592079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18602079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18612079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18622079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk Vector<uint16_t> tagsToMove; 18632079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_ORIENTATION); 18642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_NEWSUBFILETYPE); 18652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_ACTIVEAREA); 18662079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_BITSPERSAMPLE); 18672079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_COMPRESSION); 18682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_IMAGEWIDTH); 18692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_IMAGELENGTH); 18702079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_PHOTOMETRICINTERPRETATION); 18712079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_BLACKLEVEL); 18722079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_BLACKLEVELREPEATDIM); 18732079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_SAMPLESPERPIXEL); 18742079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_PLANARCONFIGURATION); 18752079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_CFAREPEATPATTERNDIM); 18762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_CFAPATTERN); 18772079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_CFAPLANECOLOR); 18782079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_CFALAYOUT); 18792079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_XRESOLUTION); 18802079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_YRESOLUTION); 18812079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_RESOLUTIONUNIT); 18822079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_WHITELEVEL); 18832079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_DEFAULTSCALE); 18842079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_DEFAULTCROPORIGIN); 18852079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_DEFAULTCROPSIZE); 18862079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_OPCODELIST2); 18872079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_OPCODELIST3); 18882079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18892079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (moveEntries(writer, TIFF_IFD_0, TIFF_IFD_SUB1, tagsToMove) != OK) { 18902079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowException(env, "java/lang/IllegalStateException", "Failed to move entries"); 18912079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 18922079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18932079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18942079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Make sure both IFDs get the same orientation tag 18952079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk sp<TiffEntry> orientEntry = writer->getEntry(TAG_ORIENTATION, TIFF_IFD_SUB1); 18962079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (orientEntry.get() != nullptr) { 18972079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk writer->addEntry(orientEntry, TIFF_IFD_0); 18982079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18992079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19002079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Setup thumbnail tags 19012079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19022079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 19032079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set photometric interpretation 19042079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint16_t interpretation = 2; // RGB 19052079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_PHOTOMETRICINTERPRETATION, 1, 19062079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk &interpretation, TIFF_IFD_0), env, TAG_PHOTOMETRICINTERPRETATION, writer); 19072079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19082079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19092079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 19102079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set planar configuration 19112079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint16_t config = 1; // Chunky 19122079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_PLANARCONFIGURATION, 1, &config, 19132079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_PLANARCONFIGURATION, writer); 19142079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19152079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19162079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 19172079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set samples per pixel 19182079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint16_t samples = SAMPLES_PER_RGB_PIXEL; 19192079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_SAMPLESPERPIXEL, 1, &samples, 19202079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_SAMPLESPERPIXEL, writer); 19212079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19222079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19232079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 19242079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set bits per sample 19252079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint16_t bits = BITS_PER_RGB_SAMPLE; 19262079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BITSPERSAMPLE, 1, &bits, TIFF_IFD_0), 19272079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_BITSPERSAMPLE, writer); 19282079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19292079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19302079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 19312079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set subfiletype 19322079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t subfileType = 1; // Thumbnail image 19332079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_NEWSUBFILETYPE, 1, &subfileType, 19342079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_NEWSUBFILETYPE, writer); 19352079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19362079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19372079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 19382079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set compression 19392079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint16_t compression = 1; // None 19402079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_COMPRESSION, 1, &compression, 19412079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_COMPRESSION, writer); 19422079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19432079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19442079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 19452079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set dimensions 19462079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t uWidth = nativeContext->getThumbnailWidth(); 19472079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t uHeight = nativeContext->getThumbnailHeight(); 19482079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGEWIDTH, 1, &uWidth, TIFF_IFD_0), 19492079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_IMAGEWIDTH, writer); 19502079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGELENGTH, 1, &uHeight, TIFF_IFD_0), 19512079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_IMAGELENGTH, writer); 19522079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19532079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19542079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 19552079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // x resolution 19562079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t xres[] = { 72, 1 }; // default 72 ppi 19572079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_XRESOLUTION, 1, xres, TIFF_IFD_0), 19582079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_XRESOLUTION, writer); 19592079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19602079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // y resolution 19612079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t yres[] = { 72, 1 }; // default 72 ppi 19622079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_YRESOLUTION, 1, yres, TIFF_IFD_0), 19632079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_YRESOLUTION, writer); 19642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint16_t unit = 2; // inches 19662079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_RESOLUTIONUNIT, 1, &unit, TIFF_IFD_0), 19672079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_RESOLUTIONUNIT, writer); 19682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19702079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19712079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer->addStrip(TIFF_IFD_0) != OK) { 19722079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk ALOGE("%s: Could not setup thumbnail strip tags.", __FUNCTION__); 19732079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowException(env, "java/lang/IllegalStateException", 19742079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk "Failed to setup thumbnail strip tags."); 19752079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 19762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19772079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19782079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer->hasIfd(TIFF_IFD_SUB1)) { 19792079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer->addStrip(TIFF_IFD_SUB1) != OK) { 19802079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk ALOGE("%s: Could not main image strip tags.", __FUNCTION__); 19812079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowException(env, "java/lang/IllegalStateException", 19822079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk "Failed to setup main image strip tags."); 19832079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 19842079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19852079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19862079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return writer; 1987f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 1988f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1989f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic void DngCreator_destroy(JNIEnv* env, jobject thiz) { 1990f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 19912079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk DngCreator_setNativeContext(env, thiz, nullptr); 1992f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 1993f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 199447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic void DngCreator_nativeSetOrientation(JNIEnv* env, jobject thiz, jint orient) { 1995f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 1996f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 19972079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk NativeContext* context = DngCreator_getNativeContext(env, thiz); 19982079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (context == nullptr) { 199947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__); 200047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/AssertionError", 200147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "setOrientation called with uninitialized DngCreator"); 200247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 200347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 200447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 200547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint16_t orientation = static_cast<uint16_t>(orient); 20062079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk context->setOrientation(orientation); 2007f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 2008f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 200947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic void DngCreator_nativeSetDescription(JNIEnv* env, jobject thiz, jstring description) { 2010f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 201147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 20122079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk NativeContext* context = DngCreator_getNativeContext(env, thiz); 20132079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (context == nullptr) { 201447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__); 201547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/AssertionError", 201647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "setDescription called with uninitialized DngCreator"); 201747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 201847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 201947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 20202079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk const char* desc = env->GetStringUTFChars(description, nullptr); 20212079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk context->setDescription(String8(desc)); 202247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk env->ReleaseStringUTFChars(description, desc); 2023f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 2024f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 20252079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkstatic void DngCreator_nativeSetGpsTags(JNIEnv* env, jobject thiz, jintArray latTag, 20262079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jstring latRef, jintArray longTag, jstring longRef, jstring dateTag, jintArray timeTag) { 2027f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 2028f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 20292079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk NativeContext* context = DngCreator_getNativeContext(env, thiz); 20302079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (context == nullptr) { 203147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__); 203247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/AssertionError", 203347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "setGpsTags called with uninitialized DngCreator"); 2034f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 2035f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 2036f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 20372079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GpsData data; 203847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 203947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jsize latLen = env->GetArrayLength(latTag); 204047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jsize longLen = env->GetArrayLength(longTag); 204147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jsize timeLen = env->GetArrayLength(timeTag); 20422079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (latLen != GpsData::GPS_VALUE_LENGTH) { 204347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", 204447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "invalid latitude tag length"); 204547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 20462079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } else if (longLen != GpsData::GPS_VALUE_LENGTH) { 204747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", 204847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "invalid longitude tag length"); 2049f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 20502079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } else if (timeLen != GpsData::GPS_VALUE_LENGTH) { 205147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", 205247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "invalid time tag length"); 205347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 205447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 205547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 20562079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env->GetIntArrayRegion(latTag, 0, static_cast<jsize>(GpsData::GPS_VALUE_LENGTH), 20572079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<jint*>(&data.mLatitude)); 20582079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env->GetIntArrayRegion(longTag, 0, static_cast<jsize>(GpsData::GPS_VALUE_LENGTH), 20592079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<jint*>(&data.mLongitude)); 20602079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env->GetIntArrayRegion(timeTag, 0, static_cast<jsize>(GpsData::GPS_VALUE_LENGTH), 20612079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<jint*>(&data.mTimestamp)); 206247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 206347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 20642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env->GetStringUTFRegion(latRef, 0, 1, reinterpret_cast<char*>(&data.mLatitudeRef)); 20652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk data.mLatitudeRef[GpsData::GPS_REF_LENGTH - 1] = '\0'; 20662079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env->GetStringUTFRegion(longRef, 0, 1, reinterpret_cast<char*>(&data.mLongitudeRef)); 20672079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk data.mLongitudeRef[GpsData::GPS_REF_LENGTH - 1] = '\0'; 20682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env->GetStringUTFRegion(dateTag, 0, GpsData::GPS_DATE_LENGTH - 1, 20692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<char*>(&data.mDate)); 20702079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk data.mDate[GpsData::GPS_DATE_LENGTH - 1] = '\0'; 207147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 20722079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk context->setGpsData(data); 207347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 207447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 207547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic void DngCreator_nativeSetThumbnail(JNIEnv* env, jobject thiz, jobject buffer, jint width, 207647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jint height) { 207747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s:", __FUNCTION__); 207847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 207947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk NativeContext* context = DngCreator_getNativeContext(env, thiz); 20802079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (context == nullptr) { 2081f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__); 2082f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jniThrowException(env, "java/lang/AssertionError", 208347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "setThumbnail called with uninitialized DngCreator"); 2084f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 2085f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 208647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 208747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk size_t fullSize = width * height * BYTES_PER_RGB_PIXEL; 208847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jlong capacity = env->GetDirectBufferCapacity(buffer); 20890f0b4919667f418b249c497f5ad3e83fdf4437e5Andreas Gampe if (static_cast<uint64_t>(capacity) != static_cast<uint64_t>(fullSize)) { 209047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/lang/AssertionError", 209147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Invalid size %d for thumbnail, expected size was %d", 209247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk capacity, fullSize); 2093f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 2094f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 2095f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 209647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint8_t* pixelBytes = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(buffer)); 20972079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (pixelBytes == nullptr) { 209847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Could not get native ByteBuffer", __FUNCTION__); 209947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid ByteBuffer"); 2100f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 2101f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 2102f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 210347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!context->setThumbnail(pixelBytes, width, height)) { 210447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/IllegalStateException", 210547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Failed to set thumbnail."); 2106f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 2107f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 210847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 2109f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 211047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// TODO: Refactor out common preamble for the two nativeWrite methods. 211147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic void DngCreator_nativeWriteImage(JNIEnv* env, jobject thiz, jobject outStream, jint width, 211247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jint height, jobject inBuffer, jint rowStride, jint pixStride, jlong offset, 211347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jboolean isDirect) { 211447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s:", __FUNCTION__); 211546d8444631b4b1253a76bfcc78a29d26014d022fDan Albert ALOGV("%s: nativeWriteImage called with: width=%d, height=%d, " 211646d8444631b4b1253a76bfcc78a29d26014d022fDan Albert "rowStride=%d, pixStride=%d, offset=%" PRId64, __FUNCTION__, width, 211746d8444631b4b1253a76bfcc78a29d26014d022fDan Albert height, rowStride, pixStride, offset); 211847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t rStride = static_cast<uint32_t>(rowStride); 211947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t pStride = static_cast<uint32_t>(pixStride); 212047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t uWidth = static_cast<uint32_t>(width); 212147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t uHeight = static_cast<uint32_t>(height); 212247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint64_t uOffset = static_cast<uint64_t>(offset); 212347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 212447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sp<JniOutputStream> out = new JniOutputStream(env, outStream); 212547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if(env->ExceptionCheck()) { 212647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Could not allocate buffers for output stream", __FUNCTION__); 2127f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 2128f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 2129f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 213047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk NativeContext* context = DngCreator_getNativeContext(env, thiz); 21312079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (context == nullptr) { 213247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__); 213347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/AssertionError", 213447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Write called with uninitialized DngCreator"); 213547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 213647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 21372079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk sp<TiffWriter> writer = DngCreator_setup(env, thiz, uWidth, uHeight); 213847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 21392079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer.get() == nullptr) { 21402079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return; 21412079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 21422079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 21432079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Validate DNG size 2144b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk if (!validateDngHeader(env, writer, *(context->getCharacteristics()), width, height)) { 214547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 214647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 214747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 214847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sp<JniInputByteBuffer> inBuf; 214947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk Vector<StripSource*> sources; 215047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sp<DirectStripSource> thumbnailSource; 215147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t targetIfd = TIFF_IFD_0; 215247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 215347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk bool hasThumbnail = writer->hasIfd(TIFF_IFD_SUB1); 215447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 215547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (hasThumbnail) { 215647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Adding thumbnail strip sources.", __FUNCTION__); 215747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t bytesPerPixel = SAMPLES_PER_RGB_PIXEL * BYTES_PER_RGB_SAMPLE; 215847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t thumbWidth = context->getThumbnailWidth(); 215947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk thumbnailSource = new DirectStripSource(env, context->getThumbnail(), TIFF_IFD_0, 216047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk thumbWidth, context->getThumbnailHeight(), bytesPerPixel, 216147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk bytesPerPixel * thumbWidth, /*offset*/0, BYTES_PER_RGB_SAMPLE, 216247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk SAMPLES_PER_RGB_PIXEL); 216347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sources.add(thumbnailSource.get()); 216447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk targetIfd = TIFF_IFD_SUB1; 216547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 216647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 216747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (isDirect) { 216847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk size_t fullSize = rStride * uHeight; 216947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jlong capacity = env->GetDirectBufferCapacity(inBuffer); 217047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (capacity < 0 || fullSize + uOffset > static_cast<uint64_t>(capacity)) { 217147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 217247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Invalid size %d for Image, size given in metadata is %d at current stride", 217347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk capacity, fullSize); 2174f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 2175f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 217647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 217747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint8_t* pixelBytes = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(inBuffer)); 21782079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (pixelBytes == nullptr) { 217947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Could not get native ByteBuffer", __FUNCTION__); 218047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid ByteBuffer"); 218147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 218247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 218347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 218447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Using direct-type strip source.", __FUNCTION__); 218547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk DirectStripSource stripSource(env, pixelBytes, targetIfd, uWidth, uHeight, pStride, 218647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk rStride, uOffset, BYTES_PER_SAMPLE, SAMPLES_PER_RAW_PIXEL); 218747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sources.add(&stripSource); 218847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 218947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk status_t ret = OK; 219047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if ((ret = writer->write(out.get(), sources.editArray(), sources.size())) != OK) { 219147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: write failed with error %d.", __FUNCTION__, ret); 219247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!env->ExceptionCheck()) { 219347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/io/IOException", 219447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Encountered error %d while writing file.", ret); 2195f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 219647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 2197f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 2198f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } else { 219947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk inBuf = new JniInputByteBuffer(env, inBuffer); 220047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 220147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Using input-type strip source.", __FUNCTION__); 220247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk InputStripSource stripSource(env, *inBuf, targetIfd, uWidth, uHeight, pStride, 220347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk rStride, uOffset, BYTES_PER_SAMPLE, SAMPLES_PER_RAW_PIXEL); 220447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sources.add(&stripSource); 220547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 220647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk status_t ret = OK; 220747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if ((ret = writer->write(out.get(), sources.editArray(), sources.size())) != OK) { 220847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: write failed with error %d.", __FUNCTION__, ret); 220947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!env->ExceptionCheck()) { 221047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/io/IOException", 221147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Encountered error %d while writing file.", ret); 2212f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 221347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 2214f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 2215f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 2216f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 2217f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 2218f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic void DngCreator_nativeWriteInputStream(JNIEnv* env, jobject thiz, jobject outStream, 221947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jobject inStream, jint width, jint height, jlong offset) { 2220f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 222147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 222247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t rowStride = width * BYTES_PER_SAMPLE; 222347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t pixStride = BYTES_PER_SAMPLE; 222447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t uWidth = static_cast<uint32_t>(width); 222547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t uHeight = static_cast<uint32_t>(height); 222647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint64_t uOffset = static_cast<uint32_t>(offset); 222747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 222846d8444631b4b1253a76bfcc78a29d26014d022fDan Albert ALOGV("%s: nativeWriteInputStream called with: width=%d, height=%d, " 222946d8444631b4b1253a76bfcc78a29d26014d022fDan Albert "rowStride=%d, pixStride=%d, offset=%" PRId64, __FUNCTION__, width, 223046d8444631b4b1253a76bfcc78a29d26014d022fDan Albert height, rowStride, pixStride, offset); 223147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 223247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sp<JniOutputStream> out = new JniOutputStream(env, outStream); 223346d8444631b4b1253a76bfcc78a29d26014d022fDan Albert if (env->ExceptionCheck()) { 223447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Could not allocate buffers for output stream", __FUNCTION__); 223547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 223647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 223747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 223847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk NativeContext* context = DngCreator_getNativeContext(env, thiz); 22392079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (context == nullptr) { 224047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__); 224147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/AssertionError", 224247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Write called with uninitialized DngCreator"); 224347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 224447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 22452079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk sp<TiffWriter> writer = DngCreator_setup(env, thiz, uWidth, uHeight); 22462079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 22472079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer.get() == nullptr) { 22482079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return; 22492079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 225047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 22512079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Validate DNG size 2252b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk if (!validateDngHeader(env, writer, *(context->getCharacteristics()), width, height)) { 225347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 225447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 225547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 225647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sp<DirectStripSource> thumbnailSource; 225747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t targetIfd = TIFF_IFD_0; 225847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk bool hasThumbnail = writer->hasIfd(TIFF_IFD_SUB1); 225947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk Vector<StripSource*> sources; 226047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 226147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (hasThumbnail) { 226247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Adding thumbnail strip sources.", __FUNCTION__); 226347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t bytesPerPixel = SAMPLES_PER_RGB_PIXEL * BYTES_PER_RGB_SAMPLE; 226447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t width = context->getThumbnailWidth(); 226547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk thumbnailSource = new DirectStripSource(env, context->getThumbnail(), TIFF_IFD_0, 226647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk width, context->getThumbnailHeight(), bytesPerPixel, 226747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk bytesPerPixel * width, /*offset*/0, BYTES_PER_RGB_SAMPLE, 226847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk SAMPLES_PER_RGB_PIXEL); 226947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sources.add(thumbnailSource.get()); 227047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk targetIfd = TIFF_IFD_SUB1; 227147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 227247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 227347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sp<JniInputStream> in = new JniInputStream(env, inStream); 227447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 227547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Using input-type strip source.", __FUNCTION__); 227647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk InputStripSource stripSource(env, *in, targetIfd, uWidth, uHeight, pixStride, 227747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk rowStride, uOffset, BYTES_PER_SAMPLE, SAMPLES_PER_RAW_PIXEL); 227847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sources.add(&stripSource); 227947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 228047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk status_t ret = OK; 228147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if ((ret = writer->write(out.get(), sources.editArray(), sources.size())) != OK) { 228247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: write failed with error %d.", __FUNCTION__, ret); 228347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!env->ExceptionCheck()) { 228447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/io/IOException", 228547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Encountered error %d while writing file.", ret); 228647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 228747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 228847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 2289f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 2290f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 2291f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} /*extern "C" */ 2292f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 2293f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic JNINativeMethod gDngCreatorMethods[] = { 2294f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk {"nativeClassInit", "()V", (void*) DngCreator_nativeClassInit}, 2295f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk {"nativeInit", "(Landroid/hardware/camera2/impl/CameraMetadataNative;" 2296b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk "Landroid/hardware/camera2/impl/CameraMetadataNative;Ljava/lang/String;)V", 2297b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk (void*) DngCreator_init}, 2298f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk {"nativeDestroy", "()V", (void*) DngCreator_destroy}, 2299f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk {"nativeSetOrientation", "(I)V", (void*) DngCreator_nativeSetOrientation}, 230047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk {"nativeSetDescription", "(Ljava/lang/String;)V", (void*) DngCreator_nativeSetDescription}, 230147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk {"nativeSetGpsTags", "([ILjava/lang/String;[ILjava/lang/String;Ljava/lang/String;[I)V", 230247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk (void*) DngCreator_nativeSetGpsTags}, 230347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk {"nativeSetThumbnail","(Ljava/nio/ByteBuffer;II)V", (void*) DngCreator_nativeSetThumbnail}, 230447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk {"nativeWriteImage", "(Ljava/io/OutputStream;IILjava/nio/ByteBuffer;IIJZ)V", 2305f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk (void*) DngCreator_nativeWriteImage}, 230647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk {"nativeWriteInputStream", "(Ljava/io/OutputStream;Ljava/io/InputStream;IIJ)V", 2307f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk (void*) DngCreator_nativeWriteInputStream}, 2308f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}; 2309f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 2310b6079005ed0631c3972ff427f56e12523ec214a7Ruben Brunkint register_android_hardware_camera2_DngCreator(JNIEnv *env) { 2311ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe return RegisterMethodsOrDie(env, 2312ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe "android/hardware/camera2/DngCreator", gDngCreatorMethods, NELEM(gDngCreatorMethods)); 2313f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 2314