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 178c35d5be63ab1811679875f12b19b050ac163b18Eino-Ville Talvala//#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> 247ca1371987736e8b3c51818afcbd245ca6286bc0Emilian Peev#include <cmath> 2546d8444631b4b1253a76bfcc78a29d26014d022fDan Albert 2646d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <utils/Log.h> 2746d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <utils/Errors.h> 2846d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <utils/StrongPointer.h> 2946d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <utils/RefBase.h> 3046d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <utils/Vector.h> 312079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk#include <utils/String8.h> 3246d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <cutils/properties.h> 33f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <system/camera_metadata.h> 34f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <camera/CameraMetadata.h> 35f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <img_utils/DngUtils.h> 36f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <img_utils/TagDefinitions.h> 37f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <img_utils/TiffIfd.h> 38f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <img_utils/TiffWriter.h> 39f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <img_utils/Output.h> 4047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk#include <img_utils/Input.h> 4147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk#include <img_utils/StripSource.h> 42f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 43ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe#include "core_jni_helpers.h" 44b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 45f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include "android_runtime/AndroidRuntime.h" 46f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include "android_runtime/android_hardware_camera2_CameraMetadata.h" 47f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 48f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <jni.h> 492279b2534272282a5b5152723235da397e49195cSteven Moreland#include <nativehelper/JNIHelp.h> 50f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 51f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkusing namespace android; 52f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkusing namespace img_utils; 53f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 542079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk#define BAIL_IF_INVALID_RET_BOOL(expr, jnienv, tagId, writer) \ 55f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if ((expr) != OK) { \ 56f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \ 5747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Invalid metadata for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \ 582079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return false; \ 59f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 60f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 612079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 622079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk#define BAIL_IF_INVALID_RET_NULL_SP(expr, jnienv, tagId, writer) \ 632079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if ((expr) != OK) { \ 642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \ 652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk "Invalid metadata for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \ 662079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; \ 672079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 70b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk#define BAIL_IF_INVALID_R(expr, jnienv, tagId, writer) \ 71b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk if ((expr) != OK) { \ 72b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \ 73b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk "Invalid metadata for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \ 74b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk return -1; \ 75b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk } 76b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 772079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk#define BAIL_IF_EMPTY_RET_NULL_SP(entry, jnienv, tagId, writer) \ 783c22e00fb9e1574bee2ce96c57cca3a62d8aaa05Chih-Hung Hsieh if ((entry).count == 0) { \ 79f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \ 8047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Missing metadata fields for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \ 812079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; \ 82f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 83f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 848069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala#define BAIL_IF_EXPR_RET_NULL_SP(expr, jnienv, tagId, writer) \ 858069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala if (expr) { \ 868069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \ 878069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala "Invalid metadata for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \ 888069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala return nullptr; \ 898069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala } 908069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala 912079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 92b6079005ed0631c3972ff427f56e12523ec214a7Ruben Brunk#define ANDROID_DNGCREATOR_CTX_JNI_ID "mNativeContext" 93f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 94f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic struct { 95f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jfieldID mNativeContext; 96f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} gDngCreatorClassInfo; 97f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 98f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic struct { 99f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jmethodID mWriteMethod; 100f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} gOutputStreamClassInfo; 101f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 10247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic struct { 10347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jmethodID mReadMethod; 10447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jmethodID mSkipMethod; 10547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} gInputStreamClassInfo; 10647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 10747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic struct { 10847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jmethodID mGetMethod; 10947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} gInputByteBufferClassInfo; 11047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 111f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkenum { 112f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk BITS_PER_SAMPLE = 16, 113f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk BYTES_PER_SAMPLE = 2, 11447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk BYTES_PER_RGB_PIXEL = 3, 11547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk BITS_PER_RGB_SAMPLE = 8, 11647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk BYTES_PER_RGB_SAMPLE = 1, 11747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk SAMPLES_PER_RGB_PIXEL = 3, 11847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk SAMPLES_PER_RAW_PIXEL = 1, 11947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0 = 0, 12047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_SUB1 = 1, 12147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_GPSINFO = 2, 122f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}; 123f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1242079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 1252079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk/** 1262079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk * POD container class for GPS tag data. 1272079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk */ 1282079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkclass GpsData { 1292079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkpublic: 1302079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk enum { 1312079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GPS_VALUE_LENGTH = 6, 1322079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GPS_REF_LENGTH = 2, 1332079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GPS_DATE_LENGTH = 11, 1342079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk }; 1352079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 1362079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t mLatitude[GPS_VALUE_LENGTH]; 1372079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t mLongitude[GPS_VALUE_LENGTH]; 1382079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t mTimestamp[GPS_VALUE_LENGTH]; 1392079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint8_t mLatitudeRef[GPS_REF_LENGTH]; 1402079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint8_t mLongitudeRef[GPS_REF_LENGTH]; 1412079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint8_t mDate[GPS_DATE_LENGTH]; 1422079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk}; 1432079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 144f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk// ---------------------------------------------------------------------------- 145f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 14647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/** 14747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * Container class for the persistent native context. 14847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */ 14947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 15047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkclass NativeContext : public LightRefBase<NativeContext> { 15147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkpublic: 1522079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk enum { 1532079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk DATETIME_COUNT = 20, 1542079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk }; 1552079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 156b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk NativeContext(const CameraMetadata& characteristics, const CameraMetadata& result); 15747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual ~NativeContext(); 15847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 15947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TiffWriter* getWriter(); 16047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 161b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk std::shared_ptr<const CameraMetadata> getCharacteristics() const; 162b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk std::shared_ptr<const CameraMetadata> getResult() const; 163b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 1642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t getThumbnailWidth() const; 1652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t getThumbnailHeight() const; 1662079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk const uint8_t* getThumbnail() const; 1672079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk bool hasThumbnail() const; 16847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 16947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk bool setThumbnail(const uint8_t* buffer, uint32_t width, uint32_t height); 17047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 1712079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk void setOrientation(uint16_t orientation); 1722079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint16_t getOrientation() const; 1732079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 1742079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk void setDescription(const String8& desc); 1752079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk String8 getDescription() const; 1762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk bool hasDescription() const; 1772079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 1782079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk void setGpsData(const GpsData& data); 1792079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GpsData getGpsData() const; 1802079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk bool hasGpsData() const; 1812079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 1822079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk void setCaptureTime(const String8& formattedCaptureTime); 1832079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk String8 getCaptureTime() const; 1842079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk bool hasCaptureTime() const; 1852079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkprivate: 18747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk Vector<uint8_t> mCurrentThumbnail; 18847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TiffWriter mWriter; 189b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk std::shared_ptr<CameraMetadata> mCharacteristics; 190b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk std::shared_ptr<CameraMetadata> mResult; 19147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mThumbnailWidth; 19247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mThumbnailHeight; 1932079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint16_t mOrientation; 1942079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk bool mThumbnailSet; 1952079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk bool mGpsSet; 1962079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk bool mDescriptionSet; 1972079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk bool mCaptureTimeSet; 1982079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk String8 mDescription; 1992079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GpsData mGpsData; 2002079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk String8 mFormattedCaptureTime; 20147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}; 20247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 203b8f4c6ab1e99a44a51af26dc522819bb833825abRuben BrunkNativeContext::NativeContext(const CameraMetadata& characteristics, const CameraMetadata& result) : 204b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk mCharacteristics(std::make_shared<CameraMetadata>(characteristics)), 205b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk mResult(std::make_shared<CameraMetadata>(result)), mThumbnailWidth(0), 2068069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala mThumbnailHeight(0), mOrientation(TAG_ORIENTATION_UNKNOWN), mThumbnailSet(false), 2078069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala mGpsSet(false), mDescriptionSet(false), mCaptureTimeSet(false) {} 20847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 20947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkNativeContext::~NativeContext() {} 21047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 21147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkTiffWriter* NativeContext::getWriter() { 21247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return &mWriter; 21347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 21447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 215b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunkstd::shared_ptr<const CameraMetadata> NativeContext::getCharacteristics() const { 216b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk return mCharacteristics; 217b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk} 218b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 219b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunkstd::shared_ptr<const CameraMetadata> NativeContext::getResult() const { 220b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk return mResult; 221b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk} 222b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 2232079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkuint32_t NativeContext::getThumbnailWidth() const { 22447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return mThumbnailWidth; 22547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 22647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 2272079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkuint32_t NativeContext::getThumbnailHeight() const { 22847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return mThumbnailHeight; 22947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 23047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 2312079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkconst uint8_t* NativeContext::getThumbnail() const { 23247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return mCurrentThumbnail.array(); 23347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 23447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 2352079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkbool NativeContext::hasThumbnail() const { 2362079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return mThumbnailSet; 2372079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2382079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 23947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkbool NativeContext::setThumbnail(const uint8_t* buffer, uint32_t width, uint32_t height) { 24047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mThumbnailWidth = width; 24147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mThumbnailHeight = height; 24247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 24347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk size_t size = BYTES_PER_RGB_PIXEL * width * height; 24447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (mCurrentThumbnail.resize(size) < 0) { 24547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Could not resize thumbnail buffer.", __FUNCTION__); 24647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return false; 24747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 24847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 24947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint8_t* thumb = mCurrentThumbnail.editArray(); 25047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk memcpy(thumb, buffer, size); 2512079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mThumbnailSet = true; 25247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return true; 25347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 25447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 2552079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkvoid NativeContext::setOrientation(uint16_t orientation) { 2562079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mOrientation = orientation; 2572079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2582079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2592079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkuint16_t NativeContext::getOrientation() const { 2602079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return mOrientation; 2612079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2622079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2632079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkvoid NativeContext::setDescription(const String8& desc) { 2642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mDescription = desc; 2652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mDescriptionSet = true; 2662079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2672079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2682079612e5851d73f4672ae3729c883a58adc4dddRuben BrunkString8 NativeContext::getDescription() const { 2692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return mDescription; 2702079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2712079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2722079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkbool NativeContext::hasDescription() const { 2732079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return mDescriptionSet; 2742079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2752079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkvoid NativeContext::setGpsData(const GpsData& data) { 2772079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mGpsData = data; 2782079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mGpsSet = true; 2792079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2802079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2812079612e5851d73f4672ae3729c883a58adc4dddRuben BrunkGpsData NativeContext::getGpsData() const { 2822079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return mGpsData; 2832079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2842079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2852079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkbool NativeContext::hasGpsData() const { 2862079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return mGpsSet; 2872079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2882079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2892079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkvoid NativeContext::setCaptureTime(const String8& formattedCaptureTime) { 2902079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mFormattedCaptureTime = formattedCaptureTime; 2912079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mCaptureTimeSet = true; 2922079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2932079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2942079612e5851d73f4672ae3729c883a58adc4dddRuben BrunkString8 NativeContext::getCaptureTime() const { 2952079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return mFormattedCaptureTime; 2962079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2972079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2982079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkbool NativeContext::hasCaptureTime() const { 2992079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return mCaptureTimeSet; 3002079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 3012079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 30247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of NativeContext 30347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ---------------------------------------------------------------------------- 30447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 30547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/** 30647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * Wrapper class for a Java OutputStream. 30747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * 30847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * This class is not intended to be used across JNI calls. 30947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */ 310f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkclass JniOutputStream : public Output, public LightRefBase<JniOutputStream> { 311f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkpublic: 312f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk JniOutputStream(JNIEnv* env, jobject outStream); 313f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 314f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk virtual ~JniOutputStream(); 315f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 316f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk status_t open(); 31747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 318f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk status_t write(const uint8_t* buf, size_t offset, size_t count); 31947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 320f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk status_t close(); 321f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkprivate: 322f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk enum { 32347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk BYTE_ARRAY_LENGTH = 4096 324f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk }; 325f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jobject mOutputStream; 326f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk JNIEnv* mEnv; 327f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jbyteArray mByteArray; 328f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}; 329f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 330f967a5486a78db244624fde4c105aa5e6fa914b9Ruben BrunkJniOutputStream::JniOutputStream(JNIEnv* env, jobject outStream) : mOutputStream(outStream), 331f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk mEnv(env) { 332f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH); 3332079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (mByteArray == nullptr) { 334f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array."); 335f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 336f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 337f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 338f967a5486a78db244624fde4c105aa5e6fa914b9Ruben BrunkJniOutputStream::~JniOutputStream() { 339f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk mEnv->DeleteLocalRef(mByteArray); 340f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 341f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 342f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatus_t JniOutputStream::open() { 343f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Do nothing 344f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return OK; 345f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 346f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 347f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatus_t JniOutputStream::write(const uint8_t* buf, size_t offset, size_t count) { 348f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk while(count > 0) { 349f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk size_t len = BYTE_ARRAY_LENGTH; 350f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk len = (count > len) ? len : count; 351f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk mEnv->SetByteArrayRegion(mByteArray, 0, len, reinterpret_cast<const jbyte*>(buf + offset)); 352f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 353f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (mEnv->ExceptionCheck()) { 354f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return BAD_VALUE; 355f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 356f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 357f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk mEnv->CallVoidMethod(mOutputStream, gOutputStreamClassInfo.mWriteMethod, mByteArray, 358f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 0, len); 359f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 360f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (mEnv->ExceptionCheck()) { 361f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return BAD_VALUE; 362f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 363f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 364f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk count -= len; 365f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk offset += len; 366f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 367f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return OK; 368f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 369f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 370f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatus_t JniOutputStream::close() { 371f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Do nothing 372f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return OK; 373f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 374f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 37547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of JniOutputStream 376f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk// ---------------------------------------------------------------------------- 377f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 37847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/** 37947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * Wrapper class for a Java InputStream. 38047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * 38147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * This class is not intended to be used across JNI calls. 38247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */ 38347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkclass JniInputStream : public Input, public LightRefBase<JniInputStream> { 38447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkpublic: 38547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk JniInputStream(JNIEnv* env, jobject inStream); 38647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 38747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk status_t open(); 38847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 38947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk status_t close(); 39047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 39147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ssize_t read(uint8_t* buf, size_t offset, size_t count); 39247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 39347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ssize_t skip(size_t count); 39447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 39547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual ~JniInputStream(); 39647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkprivate: 39747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk enum { 39847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk BYTE_ARRAY_LENGTH = 4096 39947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk }; 40047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jobject mInStream; 40147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk JNIEnv* mEnv; 40247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jbyteArray mByteArray; 40347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 40447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}; 40547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 40647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkJniInputStream::JniInputStream(JNIEnv* env, jobject inStream) : mInStream(inStream), mEnv(env) { 40747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH); 4082079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (mByteArray == nullptr) { 40947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array."); 41047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 41147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 41247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 41347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkJniInputStream::~JniInputStream() { 41447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mEnv->DeleteLocalRef(mByteArray); 41547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 41647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 41747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkssize_t JniInputStream::read(uint8_t* buf, size_t offset, size_t count) { 41847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 41947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jint realCount = BYTE_ARRAY_LENGTH; 42047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (count < BYTE_ARRAY_LENGTH) { 42147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk realCount = count; 42247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 42347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jint actual = mEnv->CallIntMethod(mInStream, gInputStreamClassInfo.mReadMethod, mByteArray, 0, 42447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk realCount); 42547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 42647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (actual < 0) { 42747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return NOT_ENOUGH_DATA; 42847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 42947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 43047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (mEnv->ExceptionCheck()) { 43147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 43247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 43347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 43447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mEnv->GetByteArrayRegion(mByteArray, 0, actual, reinterpret_cast<jbyte*>(buf + offset)); 43547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (mEnv->ExceptionCheck()) { 43647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 43747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 43847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return actual; 43947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 44047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 44147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkssize_t JniInputStream::skip(size_t count) { 44247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jlong actual = mEnv->CallLongMethod(mInStream, gInputStreamClassInfo.mSkipMethod, 44347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk static_cast<jlong>(count)); 44447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 44547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (mEnv->ExceptionCheck()) { 44647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 44747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 44847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (actual < 0) { 44947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return NOT_ENOUGH_DATA; 45047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 45147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return actual; 45247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 45347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 45447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t JniInputStream::open() { 45547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk // Do nothing 45647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return OK; 45747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 45847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 45947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t JniInputStream::close() { 46047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk // Do nothing 46147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return OK; 46247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 46347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 46447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of JniInputStream 46547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ---------------------------------------------------------------------------- 46647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 46747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/** 46847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * Wrapper class for a non-direct Java ByteBuffer. 46947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * 47047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * This class is not intended to be used across JNI calls. 47147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */ 47247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkclass JniInputByteBuffer : public Input, public LightRefBase<JniInputByteBuffer> { 47347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkpublic: 47447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk JniInputByteBuffer(JNIEnv* env, jobject inBuf); 47547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 47647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk status_t open(); 47747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 47847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk status_t close(); 47947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 48047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ssize_t read(uint8_t* buf, size_t offset, size_t count); 48147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 48247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual ~JniInputByteBuffer(); 48347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkprivate: 48447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk enum { 48547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk BYTE_ARRAY_LENGTH = 4096 48647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk }; 48747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jobject mInBuf; 48847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk JNIEnv* mEnv; 48947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jbyteArray mByteArray; 49047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}; 49147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 49247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkJniInputByteBuffer::JniInputByteBuffer(JNIEnv* env, jobject inBuf) : mInBuf(inBuf), mEnv(env) { 49347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH); 4942079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (mByteArray == nullptr) { 49547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array."); 49647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 49747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 49847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 49947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkJniInputByteBuffer::~JniInputByteBuffer() { 50047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mEnv->DeleteLocalRef(mByteArray); 50147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 50247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 50347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkssize_t JniInputByteBuffer::read(uint8_t* buf, size_t offset, size_t count) { 50447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jint realCount = BYTE_ARRAY_LENGTH; 50547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (count < BYTE_ARRAY_LENGTH) { 50647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk realCount = count; 50747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 50847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 5095f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk jobject chainingBuf = mEnv->CallObjectMethod(mInBuf, gInputByteBufferClassInfo.mGetMethod, 5105f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk mByteArray, 0, realCount); 511a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk mEnv->DeleteLocalRef(chainingBuf); 51247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 51347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (mEnv->ExceptionCheck()) { 514a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk ALOGE("%s: Exception while reading from input into byte buffer.", __FUNCTION__); 51547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 51647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 51747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 51847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mEnv->GetByteArrayRegion(mByteArray, 0, realCount, reinterpret_cast<jbyte*>(buf + offset)); 51947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (mEnv->ExceptionCheck()) { 520a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk ALOGE("%s: Exception while reading from byte buffer.", __FUNCTION__); 52147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 52247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 52347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return realCount; 52447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 52547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 52647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t JniInputByteBuffer::open() { 52747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk // Do nothing 52847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return OK; 52947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 53047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 53147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t JniInputByteBuffer::close() { 53247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk // Do nothing 53347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return OK; 53447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 53547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 53647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of JniInputByteBuffer 53747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ---------------------------------------------------------------------------- 53847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 53947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/** 54047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * StripSource subclass for Input types. 54147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * 54247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * This class is not intended to be used across JNI calls. 54347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */ 54447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 54547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkclass InputStripSource : public StripSource, public LightRefBase<InputStripSource> { 54647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkpublic: 54747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk InputStripSource(JNIEnv* env, Input& input, uint32_t ifd, uint32_t width, uint32_t height, 54847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t pixStride, uint32_t rowStride, uint64_t offset, uint32_t bytesPerSample, 54947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t samplesPerPixel); 55047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 55147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual ~InputStripSource(); 55247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 55347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual status_t writeToStream(Output& stream, uint32_t count); 55447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 55547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual uint32_t getIfd() const; 55647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkprotected: 55747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mIfd; 55847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk Input* mInput; 55947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mWidth; 56047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mHeight; 56147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mPixStride; 56247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mRowStride; 56347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint64_t mOffset; 56447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk JNIEnv* mEnv; 56547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mBytesPerSample; 56647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mSamplesPerPixel; 56747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}; 56847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 56947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkInputStripSource::InputStripSource(JNIEnv* env, Input& input, uint32_t ifd, uint32_t width, 57047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t height, uint32_t pixStride, uint32_t rowStride, uint64_t offset, 57147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t bytesPerSample, uint32_t samplesPerPixel) : mIfd(ifd), mInput(&input), 57247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mWidth(width), mHeight(height), mPixStride(pixStride), mRowStride(rowStride), 57347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mOffset(offset), mEnv(env), mBytesPerSample(bytesPerSample), 57447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mSamplesPerPixel(samplesPerPixel) {} 57547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 57647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkInputStripSource::~InputStripSource() {} 57747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 57847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t InputStripSource::writeToStream(Output& stream, uint32_t count) { 5793e1902504979b9b456a14dffa6507ee2d9ea3d6aRuben Brunk uint32_t fullSize = mWidth * mHeight * mBytesPerSample * mSamplesPerPixel; 58047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jlong offset = mOffset; 58147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 58247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (fullSize != count) { 58347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Amount to write %u doesn't match image size %u", __FUNCTION__, count, 58447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk fullSize); 58547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/lang/IllegalStateException", "Not enough data to write"); 58647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 58747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 58847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 58947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk // Skip offset 59047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk while (offset > 0) { 59147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ssize_t skipped = mInput->skip(offset); 59247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (skipped <= 0) { 59347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (skipped == NOT_ENOUGH_DATA || skipped == 0) { 59447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(mEnv, "java/io/IOException", 59547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Early EOF encountered in skip, not enough pixel data for image of size %u", 59647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk fullSize); 59747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk skipped = NOT_ENOUGH_DATA; 59847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } else { 59947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!mEnv->ExceptionCheck()) { 60047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/io/IOException", 60147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Error encountered while skip bytes in input stream."); 60247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 60347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 60447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 60547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return skipped; 60647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 60747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk offset -= skipped; 60847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 60947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 61047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk Vector<uint8_t> row; 61147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (row.resize(mRowStride) < 0) { 61247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/lang/OutOfMemoryError", "Could not allocate row vector."); 61347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 61447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 61547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 61647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint8_t* rowBytes = row.editArray(); 61747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 61847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk for (uint32_t i = 0; i < mHeight; ++i) { 61947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk size_t rowFillAmt = 0; 620a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk size_t rowSize = mRowStride; 62147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 62247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk while (rowFillAmt < mRowStride) { 62347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ssize_t bytesRead = mInput->read(rowBytes, rowFillAmt, rowSize); 62447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (bytesRead <= 0) { 62547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (bytesRead == NOT_ENOUGH_DATA || bytesRead == 0) { 626a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk ALOGE("%s: Early EOF on row %" PRIu32 ", received bytesRead %zd", 627a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk __FUNCTION__, i, bytesRead); 62847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(mEnv, "java/io/IOException", 629a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk "Early EOF encountered, not enough pixel data for image of size %" 630a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk PRIu32, fullSize); 63147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk bytesRead = NOT_ENOUGH_DATA; 63247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } else { 63347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!mEnv->ExceptionCheck()) { 63447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/io/IOException", 63547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Error encountered while reading"); 63647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 63747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 63847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return bytesRead; 63947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 64047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk rowFillAmt += bytesRead; 64147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk rowSize -= bytesRead; 64247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 64347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 64447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (mPixStride == mBytesPerSample * mSamplesPerPixel) { 64547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Using stream per-row write for strip.", __FUNCTION__); 64647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 64747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (stream.write(rowBytes, 0, mBytesPerSample * mSamplesPerPixel * mWidth) != OK || 64847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mEnv->ExceptionCheck()) { 64947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!mEnv->ExceptionCheck()) { 65047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/io/IOException", "Failed to write pixel data"); 65147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 65247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 65347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 65447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } else { 65547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Using stream per-pixel write for strip.", __FUNCTION__); 65647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/lang/IllegalStateException", 65747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Per-pixel strides are not supported for RAW16 -- pixels must be contiguous"); 65847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 65947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 66047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk // TODO: Add support for non-contiguous pixels if needed. 66147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 66247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 66347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return OK; 66447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 66547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 66647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkuint32_t InputStripSource::getIfd() const { 66747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return mIfd; 66847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 66947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 67047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of InputStripSource 67147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ---------------------------------------------------------------------------- 67247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 67347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/** 67447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * StripSource subclass for direct buffer types. 67547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * 67647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * This class is not intended to be used across JNI calls. 67747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */ 67847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 67947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkclass DirectStripSource : public StripSource, public LightRefBase<DirectStripSource> { 68047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkpublic: 68147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk DirectStripSource(JNIEnv* env, const uint8_t* pixelBytes, uint32_t ifd, uint32_t width, 68247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t height, uint32_t pixStride, uint32_t rowStride, uint64_t offset, 68347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t bytesPerSample, uint32_t samplesPerPixel); 68447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 68547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual ~DirectStripSource(); 68647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 68747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual status_t writeToStream(Output& stream, uint32_t count); 68847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 68947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual uint32_t getIfd() const; 69047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkprotected: 69147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mIfd; 69247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk const uint8_t* mPixelBytes; 69347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mWidth; 69447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mHeight; 69547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mPixStride; 69647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mRowStride; 69747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint16_t mOffset; 69847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk JNIEnv* mEnv; 69947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mBytesPerSample; 70047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mSamplesPerPixel; 70147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}; 70247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 70347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkDirectStripSource::DirectStripSource(JNIEnv* env, const uint8_t* pixelBytes, uint32_t ifd, 70447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t width, uint32_t height, uint32_t pixStride, uint32_t rowStride, 70547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint64_t offset, uint32_t bytesPerSample, uint32_t samplesPerPixel) : mIfd(ifd), 70647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mPixelBytes(pixelBytes), mWidth(width), mHeight(height), mPixStride(pixStride), 70747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mRowStride(rowStride), mOffset(offset), mEnv(env), mBytesPerSample(bytesPerSample), 70847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mSamplesPerPixel(samplesPerPixel) {} 70947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 71047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkDirectStripSource::~DirectStripSource() {} 71147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 71247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t DirectStripSource::writeToStream(Output& stream, uint32_t count) { 7133e1902504979b9b456a14dffa6507ee2d9ea3d6aRuben Brunk uint32_t fullSize = mWidth * mHeight * mBytesPerSample * mSamplesPerPixel; 71447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 71547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (fullSize != count) { 71647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Amount to write %u doesn't match image size %u", __FUNCTION__, count, 71747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk fullSize); 71847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/lang/IllegalStateException", "Not enough data to write"); 71947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 72047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 72147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 7222079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 72347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (mPixStride == mBytesPerSample * mSamplesPerPixel 72447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk && mRowStride == mWidth * mBytesPerSample * mSamplesPerPixel) { 72547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Using direct single-pass write for strip.", __FUNCTION__); 72647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 72747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (stream.write(mPixelBytes, mOffset, fullSize) != OK || mEnv->ExceptionCheck()) { 72847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!mEnv->ExceptionCheck()) { 72947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/io/IOException", "Failed to write pixel data"); 73047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 73147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 73247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 73347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } else if (mPixStride == mBytesPerSample * mSamplesPerPixel) { 73447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Using direct per-row write for strip.", __FUNCTION__); 73547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 73647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk for (size_t i = 0; i < mHeight; ++i) { 73747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (stream.write(mPixelBytes, mOffset + i * mRowStride, mPixStride * mWidth) != OK || 73847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mEnv->ExceptionCheck()) { 73947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!mEnv->ExceptionCheck()) { 74047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/io/IOException", "Failed to write pixel data"); 74147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 74247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 74347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 74447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 74547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } else { 74647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Using direct per-pixel write for strip.", __FUNCTION__); 74747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 74847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/lang/IllegalStateException", 74947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Per-pixel strides are not supported for RAW16 -- pixels must be contiguous"); 75047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 75147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 75247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk // TODO: Add support for non-contiguous pixels if needed. 75347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 75447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return OK; 75547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 75647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 75747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 75847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkuint32_t DirectStripSource::getIfd() const { 75947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return mIfd; 76047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 76147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 76247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of DirectStripSource 76347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ---------------------------------------------------------------------------- 76447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 765b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk/** 766a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk * Calculate the default crop relative to the "active area" of the image sensor (this active area 767a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk * will always be the pre-correction active area rectangle), and set this. 768b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk */ 769b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunkstatic status_t calculateAndSetCrop(JNIEnv* env, const CameraMetadata& characteristics, 770a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk sp<TiffWriter> writer) { 771b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 772b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk camera_metadata_ro_entry entry = 7732079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); 774b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk uint32_t width = static_cast<uint32_t>(entry.data.i32[2]); 775b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk uint32_t height = static_cast<uint32_t>(entry.data.i32[3]); 776b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 7772079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk const uint32_t margin = 8; // Default margin recommended by Adobe for interpolation. 7782079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 779a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk if (width < margin * 2 || height < margin * 2) { 780a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk ALOGE("%s: Cannot calculate default crop for image, pre-correction active area is too" 781a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk "small: h=%" PRIu32 ", w=%" PRIu32, __FUNCTION__, height, width); 782a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk jniThrowException(env, "java/lang/IllegalStateException", 783a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk "Pre-correction active area is too small."); 784a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk return BAD_VALUE; 7852079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 7862079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 787a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk uint32_t defaultCropOrigin[] = {margin, margin}; 788a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk uint32_t defaultCropSize[] = {width - defaultCropOrigin[0] - margin, 789a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk height - defaultCropOrigin[1] - margin}; 790a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk 791b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk BAIL_IF_INVALID_R(writer->addEntry(TAG_DEFAULTCROPORIGIN, 2, defaultCropOrigin, 792b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk TIFF_IFD_0), env, TAG_DEFAULTCROPORIGIN, writer); 793b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk BAIL_IF_INVALID_R(writer->addEntry(TAG_DEFAULTCROPSIZE, 2, defaultCropSize, 794b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk TIFF_IFD_0), env, TAG_DEFAULTCROPSIZE, writer); 795b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 796b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk return OK; 797b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk} 79847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 7992079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkstatic bool validateDngHeader(JNIEnv* env, sp<TiffWriter> writer, 800b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk const CameraMetadata& characteristics, jint width, jint height) { 801b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk if (width <= 0) { 802b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \ 803b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk "Image width %d is invalid", width); 804b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk return false; 805b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk } 80647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 807b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk if (height <= 0) { 80847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \ 809b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk "Image height %d is invalid", height); 81047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return false; 81147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 81247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 813b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk camera_metadata_ro_entry preCorrectionEntry = 814b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); 815b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk camera_metadata_ro_entry pixelArrayEntry = 816b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk characteristics.find(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE); 817b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 818b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk int pWidth = static_cast<int>(pixelArrayEntry.data.i32[0]); 819b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk int pHeight = static_cast<int>(pixelArrayEntry.data.i32[1]); 820b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk int cWidth = static_cast<int>(preCorrectionEntry.data.i32[2]); 821b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk int cHeight = static_cast<int>(preCorrectionEntry.data.i32[3]); 822b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 823b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk bool matchesPixelArray = (pWidth == width && pHeight == height); 824b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk bool matchesPreCorrectionArray = (cWidth == width && cHeight == height); 825b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 8262079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (!(matchesPixelArray || matchesPreCorrectionArray)) { 82747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \ 828b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk "Image dimensions (w=%d,h=%d) are invalid, must match either the pixel " 829b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk "array size (w=%d, h=%d) or the pre-correction array size (w=%d, h=%d)", 830b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk width, height, pWidth, pHeight, cWidth, cHeight); 83147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return false; 83247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 83347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 83447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return true; 83547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 83647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 8372079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkstatic status_t moveEntries(sp<TiffWriter> writer, uint32_t ifdFrom, uint32_t ifdTo, 83847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk const Vector<uint16_t>& entries) { 83947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk for (size_t i = 0; i < entries.size(); ++i) { 84047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint16_t tagId = entries[i]; 84147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sp<TiffEntry> entry = writer->getEntry(tagId, ifdFrom); 8422079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (entry.get() == nullptr) { 84347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: moveEntries failed, entry %u not found in IFD %u", __FUNCTION__, tagId, 84447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ifdFrom); 84547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 84647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 84747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (writer->addEntry(entry, ifdTo) != OK) { 84847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: moveEntries failed, could not add entry %u to IFD %u", __FUNCTION__, tagId, 84947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ifdFrom); 85047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 85147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 85247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk writer->removeEntry(tagId, ifdFrom); 85347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 85447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return OK; 85547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 85647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 857d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk/** 858d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * Write CFA pattern for given CFA enum into cfaOut. cfaOut must have length >= 4. 859d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * Returns OK on success, or a negative error code if the CFA enum was invalid. 860d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk */ 861d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunkstatic status_t convertCFA(uint8_t cfaEnum, /*out*/uint8_t* cfaOut) { 862d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk camera_metadata_enum_android_sensor_info_color_filter_arrangement_t cfa = 863d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk static_cast<camera_metadata_enum_android_sensor_info_color_filter_arrangement_t>( 864d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaEnum); 865d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk switch(cfa) { 866d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB: { 867d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[0] = 0; 868d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[1] = 1; 869d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[2] = 1; 870d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[3] = 2; 871d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk break; 872d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 873d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG: { 874d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[0] = 1; 875d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[1] = 0; 876d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[2] = 2; 877d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[3] = 1; 878d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk break; 879d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 880d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG: { 881d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[0] = 1; 882d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[1] = 2; 883d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[2] = 0; 884d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[3] = 1; 885d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk break; 886d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 887d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR: { 888d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[0] = 2; 889d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[1] = 1; 890d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[2] = 1; 891d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[3] = 0; 892d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk break; 893d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 894d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk default: { 895d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return BAD_VALUE; 896d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 897d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 898d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return OK; 899d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk} 900d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 901d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk/** 902d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * Convert the CFA layout enum to an OpcodeListBuilder::CfaLayout enum, defaults to 903d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * RGGB for an unknown enum. 904d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk */ 905d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunkstatic OpcodeListBuilder::CfaLayout convertCFAEnumToOpcodeLayout(uint8_t cfaEnum) { 906d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk camera_metadata_enum_android_sensor_info_color_filter_arrangement_t cfa = 907d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk static_cast<camera_metadata_enum_android_sensor_info_color_filter_arrangement_t>( 908d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaEnum); 909d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk switch(cfa) { 910d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB: { 911d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return OpcodeListBuilder::CFA_RGGB; 912d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 913d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG: { 914d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return OpcodeListBuilder::CFA_GRBG; 915d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 916d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG: { 917d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return OpcodeListBuilder::CFA_GBRG; 918d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 919d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR: { 920d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return OpcodeListBuilder::CFA_BGGR; 921d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 922d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk default: { 923d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return OpcodeListBuilder::CFA_RGGB; 924d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 925d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 926d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk} 927d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 928d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk/** 929d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * For each color plane, find the corresponding noise profile coefficients given in the 930d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * per-channel noise profile. If multiple channels in the CFA correspond to a color in the color 931d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * plane, this method takes the pair of noise profile coefficients with the higher S coefficient. 932d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * 933d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * perChannelNoiseProfile - numChannels * 2 noise profile coefficients. 934d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * cfa - numChannels color channels corresponding to each of the per-channel noise profile 935d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * coefficients. 936d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * numChannels - the number of noise profile coefficient pairs and color channels given in 937d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * the perChannelNoiseProfile and cfa arguments, respectively. 938d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * planeColors - the color planes in the noise profile output. 939d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * numPlanes - the number of planes in planeColors and pairs of coefficients in noiseProfile. 940d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * noiseProfile - 2 * numPlanes doubles containing numPlanes pairs of noise profile coefficients. 941d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * 942d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * returns OK, or a negative error code on failure. 943d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk */ 944d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunkstatic status_t generateNoiseProfile(const double* perChannelNoiseProfile, uint8_t* cfa, 945d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk size_t numChannels, const uint8_t* planeColors, size_t numPlanes, 946d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk /*out*/double* noiseProfile) { 947d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 948d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk for (size_t p = 0; p < numPlanes; ++p) { 949d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk size_t S = p * 2; 950d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk size_t O = p * 2 + 1; 951d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 952d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk noiseProfile[S] = 0; 953d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk noiseProfile[O] = 0; 954d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk bool uninitialized = true; 955d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk for (size_t c = 0; c < numChannels; ++c) { 956d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk if (cfa[c] == planeColors[p] && perChannelNoiseProfile[c * 2] > noiseProfile[S]) { 957d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk noiseProfile[S] = perChannelNoiseProfile[c * 2]; 958d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk noiseProfile[O] = perChannelNoiseProfile[c * 2 + 1]; 959d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk uninitialized = false; 960d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 961d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 962d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk if (uninitialized) { 96346d8444631b4b1253a76bfcc78a29d26014d022fDan Albert ALOGE("%s: No valid NoiseProfile coefficients for color plane %zu", 96446d8444631b4b1253a76bfcc78a29d26014d022fDan Albert __FUNCTION__, p); 965d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return BAD_VALUE; 966d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 967d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 968d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return OK; 969d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk} 970d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 97147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ---------------------------------------------------------------------------- 972f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkextern "C" { 973f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 97447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic NativeContext* DngCreator_getNativeContext(JNIEnv* env, jobject thiz) { 975f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 97647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return reinterpret_cast<NativeContext*>(env->GetLongField(thiz, 977f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk gDngCreatorClassInfo.mNativeContext)); 978f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 979f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 98047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic void DngCreator_setNativeContext(JNIEnv* env, jobject thiz, sp<NativeContext> context) { 981f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 98247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk NativeContext* current = DngCreator_getNativeContext(env, thiz); 98347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 9842079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (context != nullptr) { 98547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk context->incStrong((void*) DngCreator_setNativeContext); 986f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 98747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 988f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (current) { 98947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk current->decStrong((void*) DngCreator_setNativeContext); 990f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 99147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 992f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk env->SetLongField(thiz, gDngCreatorClassInfo.mNativeContext, 99347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk reinterpret_cast<jlong>(context.get())); 99447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 99547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 996f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic void DngCreator_nativeClassInit(JNIEnv* env, jclass clazz) { 997f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 998f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 999ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gDngCreatorClassInfo.mNativeContext = GetFieldIDOrDie(env, 1000ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe clazz, ANDROID_DNGCREATOR_CTX_JNI_ID, "J"); 1001ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe 1002ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe jclass outputStreamClazz = FindClassOrDie(env, "java/io/OutputStream"); 1003ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gOutputStreamClassInfo.mWriteMethod = GetMethodIDOrDie(env, 1004ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe outputStreamClazz, "write", "([BII)V"); 1005ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe 1006ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe jclass inputStreamClazz = FindClassOrDie(env, "java/io/InputStream"); 1007ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gInputStreamClassInfo.mReadMethod = GetMethodIDOrDie(env, inputStreamClazz, "read", "([BII)I"); 1008ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gInputStreamClassInfo.mSkipMethod = GetMethodIDOrDie(env, inputStreamClazz, "skip", "(J)J"); 1009ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe 1010ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe jclass inputBufferClazz = FindClassOrDie(env, "java/nio/ByteBuffer"); 1011ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gInputByteBufferClassInfo.mGetMethod = GetMethodIDOrDie(env, 1012ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe inputBufferClazz, "get", "([BII)Ljava/nio/ByteBuffer;"); 1013f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 1014f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1015f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPtr, 1016b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk jobject resultsPtr, jstring formattedCaptureTime) { 1017f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 1018f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk CameraMetadata characteristics; 1019f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk CameraMetadata results; 1020f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (CameraMetadata_getNativeMetadata(env, characteristicsPtr, &characteristics) != OK) { 1021f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jniThrowException(env, "java/lang/AssertionError", 1022f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk "No native metadata defined for camera characteristics."); 1023f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 1024f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1025f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (CameraMetadata_getNativeMetadata(env, resultsPtr, &results) != OK) { 1026f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jniThrowException(env, "java/lang/AssertionError", 1027f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk "No native metadata defined for capture results."); 1028f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 1029f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1030f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1031b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk sp<NativeContext> nativeContext = new NativeContext(characteristics, results); 10322079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10332079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk const char* captureTime = env->GetStringUTFChars(formattedCaptureTime, nullptr); 10342079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10352079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk size_t len = strlen(captureTime) + 1; 10362079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (len != NativeContext::DATETIME_COUNT) { 10372079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", 10382079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk "Formatted capture time string length is not required 20 characters"); 10392079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return; 10402079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 10412079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10422079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk nativeContext->setCaptureTime(String8(captureTime)); 10432079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10442079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk DngCreator_setNativeContext(env, thiz, nativeContext); 10452079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 10462079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10472079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkstatic sp<TiffWriter> DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t imageWidth, 10482079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t imageHeight) { 10492079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10502079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk NativeContext* nativeContext = DngCreator_getNativeContext(env, thiz); 10512079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10522079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (nativeContext == nullptr) { 10532079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowException(env, "java/lang/AssertionError", 10542079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk "No native context, must call init before other operations."); 10552079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 10562079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 10572079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10582079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk CameraMetadata characteristics = *(nativeContext->getCharacteristics()); 10592079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk CameraMetadata results = *(nativeContext->getResult()); 10602079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10612079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk sp<TiffWriter> writer = new TiffWriter(); 10622079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10632079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t preWidth = 0; 10642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t preHeight = 0; 10652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 10662079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Check dimensions 10672079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk camera_metadata_entry entry = 10682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); 10692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_IMAGEWIDTH, writer); 10702079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk preWidth = static_cast<uint32_t>(entry.data.i32[2]); 10712079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk preHeight = static_cast<uint32_t>(entry.data.i32[3]); 10722079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10732079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk camera_metadata_entry pixelArrayEntry = 10742079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk characteristics.find(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE); 10752079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t pixWidth = static_cast<uint32_t>(pixelArrayEntry.data.i32[0]); 10762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t pixHeight = static_cast<uint32_t>(pixelArrayEntry.data.i32[1]); 10772079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10782079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (!((imageWidth == preWidth && imageHeight == preHeight) || 10792079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk (imageWidth == pixWidth && imageHeight == pixHeight))) { 10802079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowException(env, "java/lang/AssertionError", 10812079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk "Height and width of imate buffer did not match height and width of" 10822079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk "either the preCorrectionActiveArraySize or the pixelArraySize."); 10832079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 10842079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 10852079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 10862079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10872079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 1088f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1089f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk writer->addIfd(TIFF_IFD_0); 1090f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1091f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk status_t err = OK; 1092f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1093f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk const uint32_t samplesPerPixel = 1; 1094f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk const uint32_t bitsPerSample = BITS_PER_SAMPLE; 1095f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1096f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk OpcodeListBuilder::CfaLayout opcodeCfaLayout = OpcodeListBuilder::CFA_RGGB; 1097d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk uint8_t cfaPlaneColor[3] = {0, 1, 2}; 1098d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk uint8_t cfaEnum = -1; 1099f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1100f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // TODO: Greensplit. 1101f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // TODO: Add remaining non-essential tags 110247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 110347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk // Setup main image tags 110447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 1105f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1106f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set orientation 11078069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala uint16_t orientation = TAG_ORIENTATION_NORMAL; 11082079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0), 11092079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_ORIENTATION, writer); 1110f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1111f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1112f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1113f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set subfiletype 1114f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint32_t subfileType = 0; // Main image 11152079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_NEWSUBFILETYPE, 1, &subfileType, 11162079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_NEWSUBFILETYPE, writer); 1117f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1118f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1119f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1120f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set bits per sample 1121f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t bits = static_cast<uint16_t>(bitsPerSample); 11222079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BITSPERSAMPLE, 1, &bits, TIFF_IFD_0), env, 112347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TAG_BITSPERSAMPLE, writer); 1124f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1125f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1126f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1127f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set compression 1128f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t compression = 1; // None 11292079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_COMPRESSION, 1, &compression, 11302079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_COMPRESSION, writer); 1131f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1132f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1133f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1134f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set dimensions 11352079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGEWIDTH, 1, &imageWidth, TIFF_IFD_0), 11362079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_IMAGEWIDTH, writer); 11372079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGELENGTH, 1, &imageHeight, TIFF_IFD_0), 11382079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_IMAGELENGTH, writer); 1139f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1140f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1141f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1142f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set photometric interpretation 114347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint16_t interpretation = 32803; // CFA 11442079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_PHOTOMETRICINTERPRETATION, 1, 11452079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk &interpretation, TIFF_IFD_0), env, TAG_PHOTOMETRICINTERPRETATION, writer); 1146f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1147f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1148f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 11498069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala // Set blacklevel tags, using dynamic black level if available 1150f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry = 11518069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala results.find(ANDROID_SENSOR_DYNAMIC_BLACK_LEVEL); 11528069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala uint32_t blackLevelRational[8] = {0}; 11538069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala if (entry.count != 0) { 11548069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala BAIL_IF_EXPR_RET_NULL_SP(entry.count != 4, env, TAG_BLACKLEVEL, writer); 11558069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala for (size_t i = 0; i < entry.count; i++) { 11568069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala blackLevelRational[i * 2] = static_cast<uint32_t>(entry.data.f[i] * 100); 11578069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala blackLevelRational[i * 2 + 1] = 100; 11588069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala } 11598069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala } else { 11608069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala // Fall back to static black level which is guaranteed 11618069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala entry = characteristics.find(ANDROID_SENSOR_BLACK_LEVEL_PATTERN); 11628069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala BAIL_IF_EXPR_RET_NULL_SP(entry.count != 4, env, TAG_BLACKLEVEL, writer); 11638069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala for (size_t i = 0; i < entry.count; i++) { 11648069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala blackLevelRational[i * 2] = static_cast<uint32_t>(entry.data.i32[i]); 11658069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala blackLevelRational[i * 2 + 1] = 1; 11668069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala } 11678069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala 11688069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala } 11698069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BLACKLEVEL, 4, blackLevelRational, 11702079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_BLACKLEVEL, writer); 1171f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1172f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t repeatDim[2] = {2, 2}; 11732079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BLACKLEVELREPEATDIM, 2, repeatDim, 11742079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_BLACKLEVELREPEATDIM, writer); 1175f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1176f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1177f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1178f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set samples per pixel 1179f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t samples = static_cast<uint16_t>(samplesPerPixel); 11802079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_SAMPLESPERPIXEL, 1, &samples, TIFF_IFD_0), 118147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk env, TAG_SAMPLESPERPIXEL, writer); 1182f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1183f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1184f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1185f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set planar configuration 1186f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t config = 1; // Chunky 11872079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_PLANARCONFIGURATION, 1, &config, 11882079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_PLANARCONFIGURATION, writer); 1189f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1190f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1191f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1192f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set CFA pattern dimensions 1193f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t repeatDim[2] = {2, 2}; 11942079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CFAREPEATPATTERNDIM, 2, repeatDim, 11952079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_CFAREPEATPATTERNDIM, writer); 1196f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1197f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1198f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1199f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set CFA pattern 1200f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry = 1201f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT); 12022079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_CFAPATTERN, writer); 1203d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 1204d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk const int cfaLength = 4; 1205d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaEnum = entry.data.u8[0]; 1206d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk uint8_t cfa[cfaLength]; 1207d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk if ((err = convertCFA(cfaEnum, /*out*/cfa)) != OK) { 1208d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 1209d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk "Invalid metadata for tag %d", TAG_CFAPATTERN); 1210f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1211d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 12122079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CFAPATTERN, cfaLength, cfa, TIFF_IFD_0), 12132079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_CFAPATTERN, writer); 1214d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 1215d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk opcodeCfaLayout = convertCFAEnumToOpcodeLayout(cfaEnum); 1216f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1217f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1218f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1219f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set CFA plane color 12202079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CFAPLANECOLOR, 3, cfaPlaneColor, 12212079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_CFAPLANECOLOR, writer); 1222f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1223f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1224f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1225f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set CFA layout 1226f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t cfaLayout = 1; 12272079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CFALAYOUT, 1, &cfaLayout, TIFF_IFD_0), 122847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk env, TAG_CFALAYOUT, writer); 1229f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1230f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1231f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1232b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // image description 1233b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint8_t imageDescription = '\0'; // empty 12342079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGEDESCRIPTION, 1, &imageDescription, 12352079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_IMAGEDESCRIPTION, writer); 1236b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1237b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1238b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1239b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // make 1240b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk char manufacturer[PROPERTY_VALUE_MAX]; 1241b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1242b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // Use "" to represent unknown make as suggested in TIFF/EP spec. 1243b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk property_get("ro.product.manufacturer", manufacturer, ""); 1244b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t count = static_cast<uint32_t>(strlen(manufacturer)) + 1; 1245b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 12462079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_MAKE, count, 12472079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<uint8_t*>(manufacturer), TIFF_IFD_0), env, TAG_MAKE, writer); 1248b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1249b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1250b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1251b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // model 1252b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk char model[PROPERTY_VALUE_MAX]; 1253b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1254b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // Use "" to represent unknown model as suggested in TIFF/EP spec. 1255b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk property_get("ro.product.model", model, ""); 1256b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t count = static_cast<uint32_t>(strlen(model)) + 1; 1257b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 12582079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_MODEL, count, 12592079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<uint8_t*>(model), TIFF_IFD_0), env, TAG_MODEL, writer); 1260b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1261b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1262b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1263b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // x resolution 1264b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t xres[] = { 72, 1 }; // default 72 ppi 12652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_XRESOLUTION, 1, xres, TIFF_IFD_0), 126647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk env, TAG_XRESOLUTION, writer); 1267b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1268b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // y resolution 1269b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t yres[] = { 72, 1 }; // default 72 ppi 12702079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_YRESOLUTION, 1, yres, TIFF_IFD_0), 127147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk env, TAG_YRESOLUTION, writer); 1272b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1273b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint16_t unit = 2; // inches 12742079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_RESOLUTIONUNIT, 1, &unit, TIFF_IFD_0), 127547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk env, TAG_RESOLUTIONUNIT, writer); 1276b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1277b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1278b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1279b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // software 1280b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk char software[PROPERTY_VALUE_MAX]; 1281b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk property_get("ro.build.fingerprint", software, ""); 1282b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t count = static_cast<uint32_t>(strlen(software)) + 1; 12832079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_SOFTWARE, count, 12842079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<uint8_t*>(software), TIFF_IFD_0), env, TAG_SOFTWARE, writer); 1285b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1286b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 12872079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (nativeContext->hasCaptureTime()) { 1288b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // datetime 12892079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk String8 captureTime = nativeContext->getCaptureTime(); 1290b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 12912079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer->addEntry(TAG_DATETIME, NativeContext::DATETIME_COUNT, 12922079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<const uint8_t*>(captureTime.string()), TIFF_IFD_0) != OK) { 129347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 129447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Invalid metadata for tag %x", TAG_DATETIME); 12952079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 129647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 1297b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1298b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // datetime original 12992079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer->addEntry(TAG_DATETIMEORIGINAL, NativeContext::DATETIME_COUNT, 13002079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<const uint8_t*>(captureTime.string()), TIFF_IFD_0) != OK) { 130147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 130247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Invalid metadata for tag %x", TAG_DATETIMEORIGINAL); 13032079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 130447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 1305b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1306b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1307b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1308b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // TIFF/EP standard id 1309b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint8_t standardId[] = { 1, 0, 0, 0 }; 13102079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_TIFFEPSTANDARDID, 4, standardId, 131147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_TIFFEPSTANDARDID, writer); 1312b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1313b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1314b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1315b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // copyright 1316b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint8_t copyright = '\0'; // empty 13172079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_COPYRIGHT, 1, ©right, 131847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_COPYRIGHT, writer); 1319b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1320b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1321b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1322b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // exposure time 1323b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk camera_metadata_entry entry = 1324b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk results.find(ANDROID_SENSOR_EXPOSURE_TIME); 13252079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_EXPOSURETIME, writer); 1326b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1327b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk int64_t exposureTime = *(entry.data.i64); 1328b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1329b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk if (exposureTime < 0) { 1330b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // Should be unreachable 1331b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", 1332b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk "Negative exposure time in metadata"); 13332079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 1334b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1335b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1336b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // Ensure exposure time doesn't overflow (for exposures > 4s) 1337b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t denominator = 1000000000; 1338b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk while (exposureTime > UINT32_MAX) { 1339b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk exposureTime >>= 1; 1340b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk denominator >>= 1; 1341b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk if (denominator == 0) { 1342b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // Should be unreachable 1343b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", 1344b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk "Exposure time too long"); 13452079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 1346b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1347b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1348b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1349b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t exposure[] = { static_cast<uint32_t>(exposureTime), denominator }; 13502079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_EXPOSURETIME, 1, exposure, 135147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_EXPOSURETIME, writer); 1352b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1353b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1354b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1355b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1356b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // ISO speed ratings 1357b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk camera_metadata_entry entry = 1358b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk results.find(ANDROID_SENSOR_SENSITIVITY); 13592079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_ISOSPEEDRATINGS, writer); 1360b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1361b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk int32_t tempIso = *(entry.data.i32); 1362b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk if (tempIso < 0) { 1363b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", 1364b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk "Negative ISO value"); 13652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 1366b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1367b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1368b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk if (tempIso > UINT16_MAX) { 1369b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk ALOGW("%s: ISO value overflows UINT16_MAX, clamping to max", __FUNCTION__); 1370b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk tempIso = UINT16_MAX; 1371b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1372b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1373b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint16_t iso = static_cast<uint16_t>(tempIso); 13742079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ISOSPEEDRATINGS, 1, &iso, 137547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_ISOSPEEDRATINGS, writer); 1376b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1377b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1378b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 13797ca1371987736e8b3c51818afcbd245ca6286bc0Emilian Peev // Baseline exposure 13807ca1371987736e8b3c51818afcbd245ca6286bc0Emilian Peev camera_metadata_entry entry = 13817ca1371987736e8b3c51818afcbd245ca6286bc0Emilian Peev results.find(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST); 13827ca1371987736e8b3c51818afcbd245ca6286bc0Emilian Peev BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_BASELINEEXPOSURE, writer); 13837ca1371987736e8b3c51818afcbd245ca6286bc0Emilian Peev 13847ca1371987736e8b3c51818afcbd245ca6286bc0Emilian Peev // post RAW gain should be boostValue / 100 13857ca1371987736e8b3c51818afcbd245ca6286bc0Emilian Peev double postRAWGain = static_cast<double> (entry.data.i32[0]) / 100.f; 13867ca1371987736e8b3c51818afcbd245ca6286bc0Emilian Peev // Baseline exposure should be in EV units so log2(gain) = 13877ca1371987736e8b3c51818afcbd245ca6286bc0Emilian Peev // log10(gain)/log10(2) 13887ca1371987736e8b3c51818afcbd245ca6286bc0Emilian Peev double baselineExposure = std::log(postRAWGain) / std::log(2.0f); 13897ca1371987736e8b3c51818afcbd245ca6286bc0Emilian Peev int32_t baseExposureSRat[] = { static_cast<int32_t> (baselineExposure * 100), 13907ca1371987736e8b3c51818afcbd245ca6286bc0Emilian Peev 100 }; 13917ca1371987736e8b3c51818afcbd245ca6286bc0Emilian Peev BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BASELINEEXPOSURE, 1, 13927ca1371987736e8b3c51818afcbd245ca6286bc0Emilian Peev baseExposureSRat, TIFF_IFD_0), env, TAG_BASELINEEXPOSURE, writer); 13937ca1371987736e8b3c51818afcbd245ca6286bc0Emilian Peev } 13947ca1371987736e8b3c51818afcbd245ca6286bc0Emilian Peev 13957ca1371987736e8b3c51818afcbd245ca6286bc0Emilian Peev { 1396b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // focal length 1397b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk camera_metadata_entry entry = 1398b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk results.find(ANDROID_LENS_FOCAL_LENGTH); 13992079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_FOCALLENGTH, writer); 1400b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1401b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t focalLength[] = { static_cast<uint32_t>(*(entry.data.f) * 100), 100 }; 14022079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_FOCALLENGTH, 1, focalLength, 140347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_FOCALLENGTH, writer); 1404b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1405b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1406b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1407b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // f number 1408b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk camera_metadata_entry entry = 1409b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk results.find(ANDROID_LENS_APERTURE); 14102079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_FNUMBER, writer); 1411b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1412b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t fnum[] = { static_cast<uint32_t>(*(entry.data.f) * 100), 100 }; 14132079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_FNUMBER, 1, fnum, 141447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_FNUMBER, writer); 1415b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1416b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1417b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1418f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set DNG version information 1419f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint8_t version[4] = {1, 4, 0, 0}; 14202079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_DNGVERSION, 4, version, TIFF_IFD_0), 142147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk env, TAG_DNGVERSION, writer); 1422f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1423f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint8_t backwardVersion[4] = {1, 1, 0, 0}; 14242079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_DNGBACKWARDVERSION, 4, backwardVersion, 14252079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_DNGBACKWARDVERSION, writer); 1426f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1427f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1428f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1429f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set whitelevel 1430f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry = 1431f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_INFO_WHITE_LEVEL); 14322079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_WHITELEVEL, writer); 1433f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint32_t whiteLevel = static_cast<uint32_t>(entry.data.i32[0]); 14342079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_WHITELEVEL, 1, &whiteLevel, TIFF_IFD_0), 14352079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_WHITELEVEL, writer); 1436f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1437f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1438f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1439f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set default scale 1440f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint32_t defaultScale[4] = {1, 1, 1, 1}; 14412079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_DEFAULTSCALE, 2, defaultScale, 14422079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_DEFAULTSCALE, writer); 1443f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1444f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1445f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk bool singleIlluminant = false; 1446f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1447f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set calibration illuminants 1448f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry1 = 1449f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_REFERENCE_ILLUMINANT1); 14502079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry1, env, TAG_CALIBRATIONILLUMINANT1, writer); 1451f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry2 = 1452f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_REFERENCE_ILLUMINANT2); 1453f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (entry2.count == 0) { 1454f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk singleIlluminant = true; 1455f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1456f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t ref1 = entry1.data.u8[0]; 1457f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 14582079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CALIBRATIONILLUMINANT1, 1, &ref1, 145947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_CALIBRATIONILLUMINANT1, writer); 1460f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1461f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (!singleIlluminant) { 1462f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t ref2 = entry2.data.u8[0]; 14632079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CALIBRATIONILLUMINANT2, 1, &ref2, 146447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_CALIBRATIONILLUMINANT2, writer); 1465f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1466f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1467f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1468f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1469f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set color transforms 1470f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry1 = 1471f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_COLOR_TRANSFORM1); 14722079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry1, env, TAG_COLORMATRIX1, writer); 1473f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1474f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk int32_t colorTransform1[entry1.count * 2]; 1475f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1476f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk size_t ctr = 0; 1477f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk for(size_t i = 0; i < entry1.count; ++i) { 1478f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk colorTransform1[ctr++] = entry1.data.r[i].numerator; 1479f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk colorTransform1[ctr++] = entry1.data.r[i].denominator; 1480f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1481f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 14822079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_COLORMATRIX1, entry1.count, 14832079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk colorTransform1, TIFF_IFD_0), env, TAG_COLORMATRIX1, writer); 1484f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1485f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (!singleIlluminant) { 1486f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry2 = characteristics.find(ANDROID_SENSOR_COLOR_TRANSFORM2); 14872079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry2, env, TAG_COLORMATRIX2, writer); 1488f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk int32_t colorTransform2[entry2.count * 2]; 1489f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1490f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ctr = 0; 1491f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk for(size_t i = 0; i < entry2.count; ++i) { 1492f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk colorTransform2[ctr++] = entry2.data.r[i].numerator; 1493f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk colorTransform2[ctr++] = entry2.data.r[i].denominator; 1494f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1495f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 14962079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_COLORMATRIX2, entry2.count, 14972079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk colorTransform2, TIFF_IFD_0), env, TAG_COLORMATRIX2, writer); 1498f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1499f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1500f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1501f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1502f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set calibration transforms 1503f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry1 = 1504f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_CALIBRATION_TRANSFORM1); 15052079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry1, env, TAG_CAMERACALIBRATION1, writer); 1506f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1507f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk int32_t calibrationTransform1[entry1.count * 2]; 1508f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1509f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk size_t ctr = 0; 1510f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk for(size_t i = 0; i < entry1.count; ++i) { 1511f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk calibrationTransform1[ctr++] = entry1.data.r[i].numerator; 1512f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk calibrationTransform1[ctr++] = entry1.data.r[i].denominator; 1513f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1514f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 15152079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CAMERACALIBRATION1, entry1.count, 1516b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk calibrationTransform1, TIFF_IFD_0), env, TAG_CAMERACALIBRATION1, writer); 1517f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1518f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (!singleIlluminant) { 1519f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry2 = 1520f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_CALIBRATION_TRANSFORM2); 15212079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry2, env, TAG_CAMERACALIBRATION2, writer); 1522f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk int32_t calibrationTransform2[entry2.count * 2]; 1523f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1524f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ctr = 0; 1525f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk for(size_t i = 0; i < entry2.count; ++i) { 1526f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk calibrationTransform2[ctr++] = entry2.data.r[i].numerator; 1527f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk calibrationTransform2[ctr++] = entry2.data.r[i].denominator; 1528f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1529f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 15302079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CAMERACALIBRATION2, entry2.count, 15312377cd319f8a77f147f3d70a7ddc75fa9e9fe87cAndreas Gampe calibrationTransform2, TIFF_IFD_0), env, TAG_CAMERACALIBRATION2, writer); 1532f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1533f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1534f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1535f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1536f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set forward transforms 1537f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry1 = 1538f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_FORWARD_MATRIX1); 15392079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry1, env, TAG_FORWARDMATRIX1, writer); 1540f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1541f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk int32_t forwardTransform1[entry1.count * 2]; 1542f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1543f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk size_t ctr = 0; 1544f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk for(size_t i = 0; i < entry1.count; ++i) { 1545f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk forwardTransform1[ctr++] = entry1.data.r[i].numerator; 1546f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk forwardTransform1[ctr++] = entry1.data.r[i].denominator; 1547f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1548f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 15492079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_FORWARDMATRIX1, entry1.count, 15502079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk forwardTransform1, TIFF_IFD_0), env, TAG_FORWARDMATRIX1, writer); 1551f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1552f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (!singleIlluminant) { 1553f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry2 = 1554f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_FORWARD_MATRIX2); 15552079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry2, env, TAG_FORWARDMATRIX2, writer); 1556f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk int32_t forwardTransform2[entry2.count * 2]; 1557f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1558f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ctr = 0; 1559f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk for(size_t i = 0; i < entry2.count; ++i) { 1560f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk forwardTransform2[ctr++] = entry2.data.r[i].numerator; 1561f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk forwardTransform2[ctr++] = entry2.data.r[i].denominator; 1562f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1563f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 15642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_FORWARDMATRIX2, entry2.count, 15652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk forwardTransform2, TIFF_IFD_0), env, TAG_FORWARDMATRIX2, writer); 1566f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1567f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1568f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1569f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1570f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set camera neutral 1571f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry = 1572f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk results.find(ANDROID_SENSOR_NEUTRAL_COLOR_POINT); 15732079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_ASSHOTNEUTRAL, writer); 1574f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint32_t cameraNeutral[entry.count * 2]; 1575f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1576f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk size_t ctr = 0; 1577f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk for(size_t i = 0; i < entry.count; ++i) { 1578f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk cameraNeutral[ctr++] = 1579f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk static_cast<uint32_t>(entry.data.r[i].numerator); 1580f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk cameraNeutral[ctr++] = 1581f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk static_cast<uint32_t>(entry.data.r[i].denominator); 1582f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1583f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 15842079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ASSHOTNEUTRAL, entry.count, cameraNeutral, 158547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_ASSHOTNEUTRAL, writer); 1586f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1587f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1588f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1589f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1590b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk // Set dimensions 1591a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk if (calculateAndSetCrop(env, characteristics, writer) != OK) { 15922079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 15932079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 1594b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk camera_metadata_entry entry = 1595b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); 1596a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_ACTIVEAREA, writer); 1597b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk uint32_t xmin = static_cast<uint32_t>(entry.data.i32[0]); 1598b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk uint32_t ymin = static_cast<uint32_t>(entry.data.i32[1]); 1599b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk uint32_t width = static_cast<uint32_t>(entry.data.i32[2]); 1600b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk uint32_t height = static_cast<uint32_t>(entry.data.i32[3]); 16012079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 1602a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk // If we only have a buffer containing the pre-correction rectangle, ignore the offset 1603a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk // relative to the pixel array. 1604a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk if (imageWidth == width && imageHeight == height) { 1605a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk xmin = 0; 1606a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk ymin = 0; 1607a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk } 1608a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk 16092079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t activeArea[] = {ymin, xmin, ymin + height, xmin + width}; 16102079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ACTIVEAREA, 4, activeArea, TIFF_IFD_0), 16112079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_ACTIVEAREA, writer); 1612f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1613f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1614f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1615f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Setup unique camera model tag 1616f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk char model[PROPERTY_VALUE_MAX]; 1617f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk property_get("ro.product.model", model, ""); 1618f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1619f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk char manufacturer[PROPERTY_VALUE_MAX]; 1620f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk property_get("ro.product.manufacturer", manufacturer, ""); 1621f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1622f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk char brand[PROPERTY_VALUE_MAX]; 1623f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk property_get("ro.product.brand", brand, ""); 1624f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1625f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk String8 cameraModel(model); 1626f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk cameraModel += "-"; 1627f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk cameraModel += manufacturer; 1628f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk cameraModel += "-"; 1629f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk cameraModel += brand; 1630f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 16312079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_UNIQUECAMERAMODEL, cameraModel.size() + 1, 1632f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk reinterpret_cast<const uint8_t*>(cameraModel.string()), TIFF_IFD_0), env, 163347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TAG_UNIQUECAMERAMODEL, writer); 1634f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1635f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1636f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1637b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk // Setup sensor noise model 1638b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk camera_metadata_entry entry = 1639b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk results.find(ANDROID_SENSOR_NOISE_PROFILE); 1640b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk 1641d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk const status_t numPlaneColors = 3; 1642d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk const status_t numCfaChannels = 4; 1643d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 1644d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk uint8_t cfaOut[numCfaChannels]; 1645d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk if ((err = convertCFA(cfaEnum, /*out*/cfaOut)) != OK) { 1646d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", 1647d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk "Invalid CFA from camera characteristics"); 16482079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 1649d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 1650d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 1651d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk double noiseProfile[numPlaneColors * 2]; 1652d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 1653b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk if (entry.count > 0) { 1654d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk if (entry.count != numCfaChannels * 2) { 165546d8444631b4b1253a76bfcc78a29d26014d022fDan Albert ALOGW("%s: Invalid entry count %zu for noise profile returned " 165646d8444631b4b1253a76bfcc78a29d26014d022fDan Albert "in characteristics, no noise profile tag written...", 165746d8444631b4b1253a76bfcc78a29d26014d022fDan Albert __FUNCTION__, entry.count); 1658d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } else { 1659d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk if ((err = generateNoiseProfile(entry.data.d, cfaOut, numCfaChannels, 1660d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaPlaneColor, numPlaneColors, /*out*/ noiseProfile)) == OK) { 1661d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 16622079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_NOISEPROFILE, 16632079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk numPlaneColors * 2, noiseProfile, TIFF_IFD_0), env, TAG_NOISEPROFILE, 16642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk writer); 1665d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } else { 1666d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk ALOGW("%s: Error converting coefficients for noise profile, no noise profile" 1667d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk " tag written...", __FUNCTION__); 1668d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 1669d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 1670b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk } else { 1671b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk ALOGW("%s: No noise profile found in result metadata. Image quality may be reduced.", 1672b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk __FUNCTION__); 1673b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk } 1674b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk } 1675b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk 1676b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk { 16775f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk // Set up opcode List 2 16785f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk OpcodeListBuilder builder; 16795f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk status_t err = OK; 16805f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk 16815f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk // Set up lens shading map 1682f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry1 = 1683f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_LENS_INFO_SHADING_MAP_SIZE); 168447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 168547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t lsmWidth = 0; 168647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t lsmHeight = 0; 168747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 168847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (entry1.count != 0) { 168947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk lsmWidth = static_cast<uint32_t>(entry1.data.i32[0]); 169047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk lsmHeight = static_cast<uint32_t>(entry1.data.i32[1]); 169147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 1692f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 16939ce22a095685a581823316457217a318fb40c754Ruben Brunk camera_metadata_entry entry2 = results.find(ANDROID_STATISTICS_LENS_SHADING_MAP); 169447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 16952079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk camera_metadata_entry entry = 16962079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); 16972079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_IMAGEWIDTH, writer); 16982079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t xmin = static_cast<uint32_t>(entry.data.i32[0]); 16992079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t ymin = static_cast<uint32_t>(entry.data.i32[1]); 17002079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t width = static_cast<uint32_t>(entry.data.i32[2]); 17012079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t height = static_cast<uint32_t>(entry.data.i32[3]); 170247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (entry2.count > 0 && entry2.count == lsmWidth * lsmHeight * 4) { 1703c03443b23de0b474080168d892cd685283c3285bRuben Brunk // GainMap rectangle is relative to the active area origin. 17045f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk err = builder.addGainMapsForMetadata(lsmWidth, 17055f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk lsmHeight, 1706c03443b23de0b474080168d892cd685283c3285bRuben Brunk 0, 1707c03443b23de0b474080168d892cd685283c3285bRuben Brunk 0, 17082079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk height, 17092079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk width, 17105f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk opcodeCfaLayout, 17115f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk entry2.data.f); 17125f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk if (err != OK) { 1713f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGE("%s: Could not add Lens shading map.", __FUNCTION__); 1714f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jniThrowRuntimeException(env, "failed to add lens shading map."); 17152079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 17165f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk } 17175f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk } 17185f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk 17199ce22a095685a581823316457217a318fb40c754Ruben Brunk 17209ce22a095685a581823316457217a318fb40c754Ruben Brunk // Set up bad pixel correction list 17219ce22a095685a581823316457217a318fb40c754Ruben Brunk camera_metadata_entry entry3 = characteristics.find(ANDROID_STATISTICS_HOT_PIXEL_MAP); 17229ce22a095685a581823316457217a318fb40c754Ruben Brunk 17239ce22a095685a581823316457217a318fb40c754Ruben Brunk if ((entry3.count % 2) != 0) { 17249ce22a095685a581823316457217a318fb40c754Ruben Brunk ALOGE("%s: Hot pixel map contains odd number of values, cannot map to pairs!", 17259ce22a095685a581823316457217a318fb40c754Ruben Brunk __FUNCTION__); 17269ce22a095685a581823316457217a318fb40c754Ruben Brunk jniThrowRuntimeException(env, "failed to add hotpixel map."); 17279ce22a095685a581823316457217a318fb40c754Ruben Brunk return nullptr; 17289ce22a095685a581823316457217a318fb40c754Ruben Brunk } 17299ce22a095685a581823316457217a318fb40c754Ruben Brunk 17309ce22a095685a581823316457217a318fb40c754Ruben Brunk // Adjust the bad pixel coordinates to be relative to the origin of the active area DNG tag 17319ce22a095685a581823316457217a318fb40c754Ruben Brunk std::vector<uint32_t> v; 17329ce22a095685a581823316457217a318fb40c754Ruben Brunk for (size_t i = 0; i < entry3.count; i+=2) { 17339ce22a095685a581823316457217a318fb40c754Ruben Brunk int32_t x = entry3.data.i32[i]; 17349ce22a095685a581823316457217a318fb40c754Ruben Brunk int32_t y = entry3.data.i32[i + 1]; 17359ce22a095685a581823316457217a318fb40c754Ruben Brunk x -= static_cast<int32_t>(xmin); 17369ce22a095685a581823316457217a318fb40c754Ruben Brunk y -= static_cast<int32_t>(ymin); 17379ce22a095685a581823316457217a318fb40c754Ruben Brunk if (x < 0 || y < 0 || static_cast<uint32_t>(x) >= width || 17389ce22a095685a581823316457217a318fb40c754Ruben Brunk static_cast<uint32_t>(y) >= width) { 17399ce22a095685a581823316457217a318fb40c754Ruben Brunk continue; 17409ce22a095685a581823316457217a318fb40c754Ruben Brunk } 17419ce22a095685a581823316457217a318fb40c754Ruben Brunk v.push_back(x); 17429ce22a095685a581823316457217a318fb40c754Ruben Brunk v.push_back(y); 17439ce22a095685a581823316457217a318fb40c754Ruben Brunk } 17449ce22a095685a581823316457217a318fb40c754Ruben Brunk const uint32_t* badPixels = &v[0]; 17459ce22a095685a581823316457217a318fb40c754Ruben Brunk uint32_t badPixelCount = v.size(); 17469ce22a095685a581823316457217a318fb40c754Ruben Brunk 17479ce22a095685a581823316457217a318fb40c754Ruben Brunk if (badPixelCount > 0) { 17489ce22a095685a581823316457217a318fb40c754Ruben Brunk err = builder.addBadPixelListForMetadata(badPixels, badPixelCount, opcodeCfaLayout); 17499ce22a095685a581823316457217a318fb40c754Ruben Brunk 17509ce22a095685a581823316457217a318fb40c754Ruben Brunk if (err != OK) { 17519ce22a095685a581823316457217a318fb40c754Ruben Brunk ALOGE("%s: Could not add hotpixel map.", __FUNCTION__); 17529ce22a095685a581823316457217a318fb40c754Ruben Brunk jniThrowRuntimeException(env, "failed to add hotpixel map."); 17539ce22a095685a581823316457217a318fb40c754Ruben Brunk return nullptr; 17549ce22a095685a581823316457217a318fb40c754Ruben Brunk } 17559ce22a095685a581823316457217a318fb40c754Ruben Brunk } 17569ce22a095685a581823316457217a318fb40c754Ruben Brunk 17579ce22a095685a581823316457217a318fb40c754Ruben Brunk 1758fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk size_t listSize = builder.getSize(); 1759fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk uint8_t opcodeListBuf[listSize]; 1760fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk err = builder.buildOpList(opcodeListBuf); 1761fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk if (err == OK) { 17622079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_OPCODELIST2, listSize, opcodeListBuf, 1763fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk TIFF_IFD_0), env, TAG_OPCODELIST2, writer); 1764fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk } else { 1765fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk ALOGE("%s: Could not build list of opcodes for distortion correction and lens shading" 1766fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk "map.", __FUNCTION__); 1767fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk jniThrowRuntimeException(env, "failed to construct opcode list for distortion" 1768fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk " correction and lens shading map"); 17692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 1770fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk } 1771fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk } 1772fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk 1773fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk { 1774fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk // Set up opcode List 3 1775fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk OpcodeListBuilder builder; 1776fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk status_t err = OK; 1777fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk 17785f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk // Set up rectilinear distortion correction 17795f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk camera_metadata_entry entry3 = 17805f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk results.find(ANDROID_LENS_RADIAL_DISTORTION); 17815f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk camera_metadata_entry entry4 = 17825f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk results.find(ANDROID_LENS_INTRINSIC_CALIBRATION); 17835f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk 17845f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk if (entry3.count == 6 && entry4.count == 5) { 17855f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk float cx = entry4.data.f[/*c_x*/2]; 17865f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk float cy = entry4.data.f[/*c_y*/3]; 17872079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk err = builder.addWarpRectilinearForMetadata(entry3.data.f, preWidth, preHeight, cx, 17885f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk cy); 17895f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk if (err != OK) { 17905f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk ALOGE("%s: Could not add distortion correction.", __FUNCTION__); 17915f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk jniThrowRuntimeException(env, "failed to add distortion correction."); 17922079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 1793f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 17945f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk } 17955f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk 17965f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk size_t listSize = builder.getSize(); 17975f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk uint8_t opcodeListBuf[listSize]; 17985f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk err = builder.buildOpList(opcodeListBuf); 17995f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk if (err == OK) { 18002079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_OPCODELIST3, listSize, opcodeListBuf, 1801fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk TIFF_IFD_0), env, TAG_OPCODELIST3, writer); 1802f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } else { 18035f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk ALOGE("%s: Could not build list of opcodes for distortion correction and lens shading" 18045f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk "map.", __FUNCTION__); 18055f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk jniThrowRuntimeException(env, "failed to construct opcode list for distortion" 18065f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk " correction and lens shading map"); 18072079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 1808f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1809f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1810f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 18112079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 18122079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set up orientation tags. 18138c35d5be63ab1811679875f12b19b050ac163b18Eino-Ville Talvala // Note: There's only one orientation field for the whole file, in IFD0 18148c35d5be63ab1811679875f12b19b050ac163b18Eino-Ville Talvala // The main image and any thumbnails therefore have the same orientation. 18152079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint16_t orientation = nativeContext->getOrientation(); 18162079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0), 18172079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_ORIENTATION, writer); 18182079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18192079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18202079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18212079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (nativeContext->hasDescription()){ 18222079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set Description 18232079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk String8 description = nativeContext->getDescription(); 18242079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk size_t len = description.bytes() + 1; 18252079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer->addEntry(TAG_IMAGEDESCRIPTION, len, 18262079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<const uint8_t*>(description.string()), TIFF_IFD_0) != OK) { 18272079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 18282079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk "Invalid metadata for tag %x", TAG_IMAGEDESCRIPTION); 18292079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18302079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18312079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18322079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (nativeContext->hasGpsData()) { 18332079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set GPS tags 18342079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GpsData gpsData = nativeContext->getGpsData(); 18352079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (!writer->hasIfd(TIFF_IFD_GPSINFO)) { 18362079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer->addSubIfd(TIFF_IFD_0, TIFF_IFD_GPSINFO, TiffWriter::GPSINFO) != OK) { 18372079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk ALOGE("%s: Failed to add GpsInfo IFD %u to IFD %u", __FUNCTION__, TIFF_IFD_GPSINFO, 18382079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0); 18392079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowException(env, "java/lang/IllegalStateException", "Failed to add GPSINFO"); 18402079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 18412079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18422079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18432079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18442079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 18452079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint8_t version[] = {2, 3, 0, 0}; 18462079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSVERSIONID, 4, version, 18472079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_GPSINFO), env, TAG_GPSVERSIONID, writer); 18482079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18492079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18502079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 18512079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSLATITUDEREF, 18522079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GpsData::GPS_REF_LENGTH, gpsData.mLatitudeRef, TIFF_IFD_GPSINFO), env, 18532079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TAG_GPSLATITUDEREF, writer); 18542079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18552079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18562079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 18572079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSLONGITUDEREF, 18582079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GpsData::GPS_REF_LENGTH, gpsData.mLongitudeRef, TIFF_IFD_GPSINFO), env, 18592079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TAG_GPSLONGITUDEREF, writer); 18602079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18612079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18622079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 18632079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSLATITUDE, 3, gpsData.mLatitude, 18642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_GPSINFO), env, TAG_GPSLATITUDE, writer); 18652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18662079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18672079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 18682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSLONGITUDE, 3, gpsData.mLongitude, 18692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_GPSINFO), env, TAG_GPSLONGITUDE, writer); 18702079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18712079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18722079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 18732079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSTIMESTAMP, 3, gpsData.mTimestamp, 18742079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_GPSINFO), env, TAG_GPSTIMESTAMP, writer); 18752079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18772079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 18782079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSDATESTAMP, 18792079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GpsData::GPS_DATE_LENGTH, gpsData.mDate, TIFF_IFD_GPSINFO), env, 18802079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TAG_GPSDATESTAMP, writer); 18812079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18822079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18832079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18842079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18852079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (nativeContext->hasThumbnail()) { 18862079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (!writer->hasIfd(TIFF_IFD_SUB1)) { 18872079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer->addSubIfd(TIFF_IFD_0, TIFF_IFD_SUB1) != OK) { 18882079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk ALOGE("%s: Failed to add SubIFD %u to IFD %u", __FUNCTION__, TIFF_IFD_SUB1, 18892079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0); 18902079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowException(env, "java/lang/IllegalStateException", "Failed to add SubIFD"); 18912079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 18922079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18932079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18942079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18952079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk Vector<uint16_t> tagsToMove; 18962079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_NEWSUBFILETYPE); 18972079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_ACTIVEAREA); 18982079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_BITSPERSAMPLE); 18992079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_COMPRESSION); 19002079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_IMAGEWIDTH); 19012079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_IMAGELENGTH); 19022079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_PHOTOMETRICINTERPRETATION); 19032079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_BLACKLEVEL); 19042079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_BLACKLEVELREPEATDIM); 19052079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_SAMPLESPERPIXEL); 19062079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_PLANARCONFIGURATION); 19072079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_CFAREPEATPATTERNDIM); 19082079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_CFAPATTERN); 19092079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_CFAPLANECOLOR); 19102079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_CFALAYOUT); 19112079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_XRESOLUTION); 19122079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_YRESOLUTION); 19132079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_RESOLUTIONUNIT); 19142079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_WHITELEVEL); 19152079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_DEFAULTSCALE); 19162079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_DEFAULTCROPORIGIN); 19172079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_DEFAULTCROPSIZE); 19182079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_OPCODELIST2); 19192079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_OPCODELIST3); 19202079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19212079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (moveEntries(writer, TIFF_IFD_0, TIFF_IFD_SUB1, tagsToMove) != OK) { 19222079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowException(env, "java/lang/IllegalStateException", "Failed to move entries"); 19232079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 19242079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19252079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19262079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Setup thumbnail tags 19272079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19282079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 19292079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set photometric interpretation 19302079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint16_t interpretation = 2; // RGB 19312079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_PHOTOMETRICINTERPRETATION, 1, 19322079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk &interpretation, TIFF_IFD_0), env, TAG_PHOTOMETRICINTERPRETATION, writer); 19332079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19342079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19352079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 19362079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set planar configuration 19372079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint16_t config = 1; // Chunky 19382079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_PLANARCONFIGURATION, 1, &config, 19392079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_PLANARCONFIGURATION, writer); 19402079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19412079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19422079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 19432079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set samples per pixel 19442079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint16_t samples = SAMPLES_PER_RGB_PIXEL; 19452079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_SAMPLESPERPIXEL, 1, &samples, 19462079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_SAMPLESPERPIXEL, writer); 19472079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19482079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19492079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 19502079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set bits per sample 19518069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala uint16_t bits[SAMPLES_PER_RGB_PIXEL]; 19528069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala for (int i = 0; i < SAMPLES_PER_RGB_PIXEL; i++) bits[i] = BITS_PER_RGB_SAMPLE; 19538069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala BAIL_IF_INVALID_RET_NULL_SP( 19548069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala writer->addEntry(TAG_BITSPERSAMPLE, SAMPLES_PER_RGB_PIXEL, bits, TIFF_IFD_0), 19552079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_BITSPERSAMPLE, writer); 19562079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19572079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19582079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 19592079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set subfiletype 19602079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t subfileType = 1; // Thumbnail image 19612079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_NEWSUBFILETYPE, 1, &subfileType, 19622079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_NEWSUBFILETYPE, writer); 19632079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 19662079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set compression 19672079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint16_t compression = 1; // None 19682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_COMPRESSION, 1, &compression, 19692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_COMPRESSION, writer); 19702079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19712079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19722079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 19732079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set dimensions 19742079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t uWidth = nativeContext->getThumbnailWidth(); 19752079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t uHeight = nativeContext->getThumbnailHeight(); 19762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGEWIDTH, 1, &uWidth, TIFF_IFD_0), 19772079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_IMAGEWIDTH, writer); 19782079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGELENGTH, 1, &uHeight, TIFF_IFD_0), 19792079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_IMAGELENGTH, writer); 19802079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19812079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19822079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 19832079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // x resolution 19842079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t xres[] = { 72, 1 }; // default 72 ppi 19852079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_XRESOLUTION, 1, xres, TIFF_IFD_0), 19862079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_XRESOLUTION, writer); 19872079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19882079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // y resolution 19892079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t yres[] = { 72, 1 }; // default 72 ppi 19902079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_YRESOLUTION, 1, yres, TIFF_IFD_0), 19912079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_YRESOLUTION, writer); 19922079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19932079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint16_t unit = 2; // inches 19942079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_RESOLUTIONUNIT, 1, &unit, TIFF_IFD_0), 19952079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_RESOLUTIONUNIT, writer); 19962079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19972079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19982079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19992079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer->addStrip(TIFF_IFD_0) != OK) { 20002079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk ALOGE("%s: Could not setup thumbnail strip tags.", __FUNCTION__); 20012079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowException(env, "java/lang/IllegalStateException", 20022079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk "Failed to setup thumbnail strip tags."); 20032079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 20042079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 20052079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 20062079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer->hasIfd(TIFF_IFD_SUB1)) { 20072079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer->addStrip(TIFF_IFD_SUB1) != OK) { 20082079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk ALOGE("%s: Could not main image strip tags.", __FUNCTION__); 20092079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowException(env, "java/lang/IllegalStateException", 20102079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk "Failed to setup main image strip tags."); 20112079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 20122079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 20132079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 20142079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return writer; 2015f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 2016f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 2017f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic void DngCreator_destroy(JNIEnv* env, jobject thiz) { 2018f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 20192079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk DngCreator_setNativeContext(env, thiz, nullptr); 2020f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 2021f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 202247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic void DngCreator_nativeSetOrientation(JNIEnv* env, jobject thiz, jint orient) { 2023f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 2024f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 20252079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk NativeContext* context = DngCreator_getNativeContext(env, thiz); 20262079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (context == nullptr) { 202747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__); 202847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/AssertionError", 202947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "setOrientation called with uninitialized DngCreator"); 203047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 203147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 203247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 203347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint16_t orientation = static_cast<uint16_t>(orient); 20342079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk context->setOrientation(orientation); 2035f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 2036f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 203747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic void DngCreator_nativeSetDescription(JNIEnv* env, jobject thiz, jstring description) { 2038f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 203947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 20402079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk NativeContext* context = DngCreator_getNativeContext(env, thiz); 20412079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (context == nullptr) { 204247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__); 204347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/AssertionError", 204447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "setDescription called with uninitialized DngCreator"); 204547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 204647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 204747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 20482079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk const char* desc = env->GetStringUTFChars(description, nullptr); 20492079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk context->setDescription(String8(desc)); 205047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk env->ReleaseStringUTFChars(description, desc); 2051f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 2052f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 20532079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkstatic void DngCreator_nativeSetGpsTags(JNIEnv* env, jobject thiz, jintArray latTag, 20542079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jstring latRef, jintArray longTag, jstring longRef, jstring dateTag, jintArray timeTag) { 2055f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 2056f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 20572079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk NativeContext* context = DngCreator_getNativeContext(env, thiz); 20582079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (context == nullptr) { 205947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__); 206047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/AssertionError", 206147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "setGpsTags called with uninitialized DngCreator"); 2062f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 2063f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 2064f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 20652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GpsData data; 206647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 206747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jsize latLen = env->GetArrayLength(latTag); 206847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jsize longLen = env->GetArrayLength(longTag); 206947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jsize timeLen = env->GetArrayLength(timeTag); 20702079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (latLen != GpsData::GPS_VALUE_LENGTH) { 207147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", 207247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "invalid latitude tag length"); 207347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 20742079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } else if (longLen != GpsData::GPS_VALUE_LENGTH) { 207547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", 207647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "invalid longitude tag length"); 2077f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 20782079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } else if (timeLen != GpsData::GPS_VALUE_LENGTH) { 207947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", 208047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "invalid time tag length"); 208147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 208247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 208347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 20842079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env->GetIntArrayRegion(latTag, 0, static_cast<jsize>(GpsData::GPS_VALUE_LENGTH), 20852079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<jint*>(&data.mLatitude)); 20862079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env->GetIntArrayRegion(longTag, 0, static_cast<jsize>(GpsData::GPS_VALUE_LENGTH), 20872079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<jint*>(&data.mLongitude)); 20882079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env->GetIntArrayRegion(timeTag, 0, static_cast<jsize>(GpsData::GPS_VALUE_LENGTH), 20892079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<jint*>(&data.mTimestamp)); 209047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 209147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 20922079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env->GetStringUTFRegion(latRef, 0, 1, reinterpret_cast<char*>(&data.mLatitudeRef)); 20932079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk data.mLatitudeRef[GpsData::GPS_REF_LENGTH - 1] = '\0'; 20942079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env->GetStringUTFRegion(longRef, 0, 1, reinterpret_cast<char*>(&data.mLongitudeRef)); 20952079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk data.mLongitudeRef[GpsData::GPS_REF_LENGTH - 1] = '\0'; 20962079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env->GetStringUTFRegion(dateTag, 0, GpsData::GPS_DATE_LENGTH - 1, 20972079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<char*>(&data.mDate)); 20982079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk data.mDate[GpsData::GPS_DATE_LENGTH - 1] = '\0'; 209947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 21002079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk context->setGpsData(data); 210147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 210247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 210347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic void DngCreator_nativeSetThumbnail(JNIEnv* env, jobject thiz, jobject buffer, jint width, 210447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jint height) { 210547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s:", __FUNCTION__); 210647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 210747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk NativeContext* context = DngCreator_getNativeContext(env, thiz); 21082079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (context == nullptr) { 2109f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__); 2110f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jniThrowException(env, "java/lang/AssertionError", 211147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "setThumbnail called with uninitialized DngCreator"); 2112f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 2113f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 211447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 211547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk size_t fullSize = width * height * BYTES_PER_RGB_PIXEL; 211647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jlong capacity = env->GetDirectBufferCapacity(buffer); 21170f0b4919667f418b249c497f5ad3e83fdf4437e5Andreas Gampe if (static_cast<uint64_t>(capacity) != static_cast<uint64_t>(fullSize)) { 211847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/lang/AssertionError", 211947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Invalid size %d for thumbnail, expected size was %d", 212047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk capacity, fullSize); 2121f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 2122f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 2123f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 212447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint8_t* pixelBytes = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(buffer)); 21252079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (pixelBytes == nullptr) { 212647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Could not get native ByteBuffer", __FUNCTION__); 212747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid ByteBuffer"); 2128f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 2129f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 2130f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 213147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!context->setThumbnail(pixelBytes, width, height)) { 213247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/IllegalStateException", 213347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Failed to set thumbnail."); 2134f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 2135f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 213647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 2137f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 213847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// TODO: Refactor out common preamble for the two nativeWrite methods. 213947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic void DngCreator_nativeWriteImage(JNIEnv* env, jobject thiz, jobject outStream, jint width, 214047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jint height, jobject inBuffer, jint rowStride, jint pixStride, jlong offset, 214147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jboolean isDirect) { 214247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s:", __FUNCTION__); 214346d8444631b4b1253a76bfcc78a29d26014d022fDan Albert ALOGV("%s: nativeWriteImage called with: width=%d, height=%d, " 214446d8444631b4b1253a76bfcc78a29d26014d022fDan Albert "rowStride=%d, pixStride=%d, offset=%" PRId64, __FUNCTION__, width, 214546d8444631b4b1253a76bfcc78a29d26014d022fDan Albert height, rowStride, pixStride, offset); 214647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t rStride = static_cast<uint32_t>(rowStride); 214747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t pStride = static_cast<uint32_t>(pixStride); 214847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t uWidth = static_cast<uint32_t>(width); 214947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t uHeight = static_cast<uint32_t>(height); 215047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint64_t uOffset = static_cast<uint64_t>(offset); 215147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 215247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sp<JniOutputStream> out = new JniOutputStream(env, outStream); 215347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if(env->ExceptionCheck()) { 215447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Could not allocate buffers for output stream", __FUNCTION__); 2155f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 2156f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 2157f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 215847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk NativeContext* context = DngCreator_getNativeContext(env, thiz); 21592079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (context == nullptr) { 216047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__); 216147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/AssertionError", 216247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Write called with uninitialized DngCreator"); 216347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 216447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 21652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk sp<TiffWriter> writer = DngCreator_setup(env, thiz, uWidth, uHeight); 216647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 21672079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer.get() == nullptr) { 21682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return; 21692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 21702079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 21712079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Validate DNG size 2172b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk if (!validateDngHeader(env, writer, *(context->getCharacteristics()), width, height)) { 217347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 217447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 217547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 217647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sp<JniInputByteBuffer> inBuf; 217747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk Vector<StripSource*> sources; 217847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sp<DirectStripSource> thumbnailSource; 217947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t targetIfd = TIFF_IFD_0; 218047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 218147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk bool hasThumbnail = writer->hasIfd(TIFF_IFD_SUB1); 218247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 218347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (hasThumbnail) { 218447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Adding thumbnail strip sources.", __FUNCTION__); 218547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t bytesPerPixel = SAMPLES_PER_RGB_PIXEL * BYTES_PER_RGB_SAMPLE; 218647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t thumbWidth = context->getThumbnailWidth(); 218747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk thumbnailSource = new DirectStripSource(env, context->getThumbnail(), TIFF_IFD_0, 218847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk thumbWidth, context->getThumbnailHeight(), bytesPerPixel, 218947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk bytesPerPixel * thumbWidth, /*offset*/0, BYTES_PER_RGB_SAMPLE, 219047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk SAMPLES_PER_RGB_PIXEL); 219147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sources.add(thumbnailSource.get()); 219247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk targetIfd = TIFF_IFD_SUB1; 219347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 219447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 219547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (isDirect) { 219647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk size_t fullSize = rStride * uHeight; 219747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jlong capacity = env->GetDirectBufferCapacity(inBuffer); 219847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (capacity < 0 || fullSize + uOffset > static_cast<uint64_t>(capacity)) { 219947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 220047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Invalid size %d for Image, size given in metadata is %d at current stride", 220147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk capacity, fullSize); 2202f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 2203f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 220447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 220547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint8_t* pixelBytes = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(inBuffer)); 22062079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (pixelBytes == nullptr) { 220747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Could not get native ByteBuffer", __FUNCTION__); 220847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid ByteBuffer"); 220947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 221047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 221147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 221247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Using direct-type strip source.", __FUNCTION__); 221347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk DirectStripSource stripSource(env, pixelBytes, targetIfd, uWidth, uHeight, pStride, 221447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk rStride, uOffset, BYTES_PER_SAMPLE, SAMPLES_PER_RAW_PIXEL); 221547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sources.add(&stripSource); 221647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 221747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk status_t ret = OK; 221847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if ((ret = writer->write(out.get(), sources.editArray(), sources.size())) != OK) { 221947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: write failed with error %d.", __FUNCTION__, ret); 222047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!env->ExceptionCheck()) { 222147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/io/IOException", 222247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Encountered error %d while writing file.", ret); 2223f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 222447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 2225f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 2226f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } else { 222747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk inBuf = new JniInputByteBuffer(env, inBuffer); 222847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 222947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Using input-type strip source.", __FUNCTION__); 223047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk InputStripSource stripSource(env, *inBuf, targetIfd, uWidth, uHeight, pStride, 223147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk rStride, uOffset, BYTES_PER_SAMPLE, SAMPLES_PER_RAW_PIXEL); 223247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sources.add(&stripSource); 223347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 223447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk status_t ret = OK; 223547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if ((ret = writer->write(out.get(), sources.editArray(), sources.size())) != OK) { 223647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: write failed with error %d.", __FUNCTION__, ret); 223747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!env->ExceptionCheck()) { 223847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/io/IOException", 223947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Encountered error %d while writing file.", ret); 2240f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 224147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 2242f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 2243f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 2244f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 2245f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 2246f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic void DngCreator_nativeWriteInputStream(JNIEnv* env, jobject thiz, jobject outStream, 224747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jobject inStream, jint width, jint height, jlong offset) { 2248f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 224947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 225047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t rowStride = width * BYTES_PER_SAMPLE; 225147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t pixStride = BYTES_PER_SAMPLE; 225247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t uWidth = static_cast<uint32_t>(width); 225347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t uHeight = static_cast<uint32_t>(height); 225447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint64_t uOffset = static_cast<uint32_t>(offset); 225547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 225646d8444631b4b1253a76bfcc78a29d26014d022fDan Albert ALOGV("%s: nativeWriteInputStream called with: width=%d, height=%d, " 225746d8444631b4b1253a76bfcc78a29d26014d022fDan Albert "rowStride=%d, pixStride=%d, offset=%" PRId64, __FUNCTION__, width, 225846d8444631b4b1253a76bfcc78a29d26014d022fDan Albert height, rowStride, pixStride, offset); 225947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 226047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sp<JniOutputStream> out = new JniOutputStream(env, outStream); 226146d8444631b4b1253a76bfcc78a29d26014d022fDan Albert if (env->ExceptionCheck()) { 226247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Could not allocate buffers for output stream", __FUNCTION__); 226347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 226447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 226547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 226647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk NativeContext* context = DngCreator_getNativeContext(env, thiz); 22672079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (context == nullptr) { 226847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__); 226947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/AssertionError", 227047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Write called with uninitialized DngCreator"); 227147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 227247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 22732079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk sp<TiffWriter> writer = DngCreator_setup(env, thiz, uWidth, uHeight); 22742079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 22752079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer.get() == nullptr) { 22762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return; 22772079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 227847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 22792079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Validate DNG size 2280b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk if (!validateDngHeader(env, writer, *(context->getCharacteristics()), width, height)) { 228147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 228247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 228347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 228447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sp<DirectStripSource> thumbnailSource; 228547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t targetIfd = TIFF_IFD_0; 228647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk bool hasThumbnail = writer->hasIfd(TIFF_IFD_SUB1); 228747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk Vector<StripSource*> sources; 228847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 228947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (hasThumbnail) { 229047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Adding thumbnail strip sources.", __FUNCTION__); 229147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t bytesPerPixel = SAMPLES_PER_RGB_PIXEL * BYTES_PER_RGB_SAMPLE; 229247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t width = context->getThumbnailWidth(); 229347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk thumbnailSource = new DirectStripSource(env, context->getThumbnail(), TIFF_IFD_0, 229447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk width, context->getThumbnailHeight(), bytesPerPixel, 229547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk bytesPerPixel * width, /*offset*/0, BYTES_PER_RGB_SAMPLE, 229647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk SAMPLES_PER_RGB_PIXEL); 229747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sources.add(thumbnailSource.get()); 229847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk targetIfd = TIFF_IFD_SUB1; 229947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 230047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 230147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sp<JniInputStream> in = new JniInputStream(env, inStream); 230247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 230347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Using input-type strip source.", __FUNCTION__); 230447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk InputStripSource stripSource(env, *in, targetIfd, uWidth, uHeight, pixStride, 230547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk rowStride, uOffset, BYTES_PER_SAMPLE, SAMPLES_PER_RAW_PIXEL); 230647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sources.add(&stripSource); 230747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 230847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk status_t ret = OK; 230947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if ((ret = writer->write(out.get(), sources.editArray(), sources.size())) != OK) { 231047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: write failed with error %d.", __FUNCTION__, ret); 231147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!env->ExceptionCheck()) { 231247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/io/IOException", 231347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Encountered error %d while writing file.", ret); 231447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 231547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 231647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 2317f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 2318f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 2319f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} /*extern "C" */ 2320f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 232176f6a86de25e1bf74717e047e55fd44b089673f3Daniel Micaystatic const JNINativeMethod gDngCreatorMethods[] = { 2322f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk {"nativeClassInit", "()V", (void*) DngCreator_nativeClassInit}, 2323f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk {"nativeInit", "(Landroid/hardware/camera2/impl/CameraMetadataNative;" 2324b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk "Landroid/hardware/camera2/impl/CameraMetadataNative;Ljava/lang/String;)V", 2325b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk (void*) DngCreator_init}, 2326f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk {"nativeDestroy", "()V", (void*) DngCreator_destroy}, 2327f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk {"nativeSetOrientation", "(I)V", (void*) DngCreator_nativeSetOrientation}, 232847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk {"nativeSetDescription", "(Ljava/lang/String;)V", (void*) DngCreator_nativeSetDescription}, 232947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk {"nativeSetGpsTags", "([ILjava/lang/String;[ILjava/lang/String;Ljava/lang/String;[I)V", 233047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk (void*) DngCreator_nativeSetGpsTags}, 233147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk {"nativeSetThumbnail","(Ljava/nio/ByteBuffer;II)V", (void*) DngCreator_nativeSetThumbnail}, 233247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk {"nativeWriteImage", "(Ljava/io/OutputStream;IILjava/nio/ByteBuffer;IIJZ)V", 2333f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk (void*) DngCreator_nativeWriteImage}, 233447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk {"nativeWriteInputStream", "(Ljava/io/OutputStream;Ljava/io/InputStream;IIJ)V", 2335f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk (void*) DngCreator_nativeWriteInputStream}, 2336f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}; 2337f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 2338b6079005ed0631c3972ff427f56e12523ec214a7Ruben Brunkint register_android_hardware_camera2_DngCreator(JNIEnv *env) { 2339ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe return RegisterMethodsOrDie(env, 2340ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe "android/hardware/camera2/DngCreator", gDngCreatorMethods, NELEM(gDngCreatorMethods)); 2341f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 2342