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>
2446d8444631b4b1253a76bfcc78a29d26014d022fDan Albert
2546d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <utils/Log.h>
2646d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <utils/Errors.h>
2746d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <utils/StrongPointer.h>
2846d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <utils/RefBase.h>
2946d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <utils/Vector.h>
302079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk#include <utils/String8.h>
3146d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <cutils/properties.h>
32f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <system/camera_metadata.h>
33f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <camera/CameraMetadata.h>
34f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <img_utils/DngUtils.h>
35f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <img_utils/TagDefinitions.h>
36f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <img_utils/TiffIfd.h>
37f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <img_utils/TiffWriter.h>
38f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <img_utils/Output.h>
3947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk#include <img_utils/Input.h>
4047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk#include <img_utils/StripSource.h>
41f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
42ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe#include "core_jni_helpers.h"
43b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
44f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include "android_runtime/AndroidRuntime.h"
45f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include "android_runtime/android_hardware_camera2_CameraMetadata.h"
46f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
47f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <jni.h>
48f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <JNIHelp.h>
49f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
50f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkusing namespace android;
51f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkusing namespace img_utils;
52f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
532079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk#define BAIL_IF_INVALID_RET_BOOL(expr, jnienv, tagId, writer) \
54f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    if ((expr) != OK) { \
55f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
5647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                "Invalid metadata for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \
572079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk        return false; \
58f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
59f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
602079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
612079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk#define BAIL_IF_INVALID_RET_NULL_SP(expr, jnienv, tagId, writer) \
622079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    if ((expr) != OK) { \
632079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk        jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk                "Invalid metadata for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \
652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk        return nullptr; \
662079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    }
672079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
69b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk#define BAIL_IF_INVALID_R(expr, jnienv, tagId, writer) \
70b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk    if ((expr) != OK) { \
71b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk        jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
72b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk                "Invalid metadata for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \
73b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk        return -1; \
74b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk    }
75b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk
762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk#define BAIL_IF_EMPTY_RET_NULL_SP(entry, jnienv, tagId, writer) \
77f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    if (entry.count == 0) { \
78f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
7947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                "Missing metadata fields for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \
802079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk        return nullptr; \
81f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
82f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
838069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala#define BAIL_IF_EXPR_RET_NULL_SP(expr, jnienv, tagId, writer) \
848069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala    if (expr) { \
858069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala        jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
868069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala                "Invalid metadata for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \
878069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala        return nullptr; \
888069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala    }
898069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala
902079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
91b6079005ed0631c3972ff427f56e12523ec214a7Ruben Brunk#define ANDROID_DNGCREATOR_CTX_JNI_ID     "mNativeContext"
92f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
93f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic struct {
94f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    jfieldID mNativeContext;
95f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} gDngCreatorClassInfo;
96f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
97f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic struct {
98f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    jmethodID mWriteMethod;
99f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} gOutputStreamClassInfo;
100f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
10147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic struct {
10247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jmethodID mReadMethod;
10347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jmethodID mSkipMethod;
10447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} gInputStreamClassInfo;
10547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
10647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic struct {
10747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jmethodID mGetMethod;
10847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} gInputByteBufferClassInfo;
10947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
110f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkenum {
111f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    BITS_PER_SAMPLE = 16,
112f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    BYTES_PER_SAMPLE = 2,
11347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    BYTES_PER_RGB_PIXEL = 3,
11447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    BITS_PER_RGB_SAMPLE = 8,
11547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    BYTES_PER_RGB_SAMPLE = 1,
11647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    SAMPLES_PER_RGB_PIXEL = 3,
11747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    SAMPLES_PER_RAW_PIXEL = 1,
11847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    TIFF_IFD_0 = 0,
11947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    TIFF_IFD_SUB1 = 1,
12047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    TIFF_IFD_GPSINFO = 2,
121f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk};
122f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1232079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
1242079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk/**
1252079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk * POD container class for GPS tag data.
1262079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk */
1272079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkclass GpsData {
1282079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkpublic:
1292079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    enum {
1302079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk        GPS_VALUE_LENGTH = 6,
1312079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk        GPS_REF_LENGTH = 2,
1322079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk        GPS_DATE_LENGTH = 11,
1332079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    };
1342079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
1352079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    uint32_t mLatitude[GPS_VALUE_LENGTH];
1362079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    uint32_t mLongitude[GPS_VALUE_LENGTH];
1372079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    uint32_t mTimestamp[GPS_VALUE_LENGTH];
1382079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    uint8_t mLatitudeRef[GPS_REF_LENGTH];
1392079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    uint8_t mLongitudeRef[GPS_REF_LENGTH];
1402079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    uint8_t mDate[GPS_DATE_LENGTH];
1412079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk};
1422079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
143f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk// ----------------------------------------------------------------------------
144f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
14547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/**
14647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * Container class for the persistent native context.
14747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */
14847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
14947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkclass NativeContext : public LightRefBase<NativeContext> {
15047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkpublic:
1512079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    enum {
1522079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk        DATETIME_COUNT = 20,
1532079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    };
1542079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
155b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk    NativeContext(const CameraMetadata& characteristics, const CameraMetadata& result);
15647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    virtual ~NativeContext();
15747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
15847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    TiffWriter* getWriter();
15947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
160b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk    std::shared_ptr<const CameraMetadata> getCharacteristics() const;
161b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk    std::shared_ptr<const CameraMetadata> getResult() const;
162b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk
1632079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    uint32_t getThumbnailWidth() const;
1642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    uint32_t getThumbnailHeight() const;
1652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    const uint8_t* getThumbnail() const;
1662079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    bool hasThumbnail() const;
16747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
16847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    bool setThumbnail(const uint8_t* buffer, uint32_t width, uint32_t height);
16947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
1702079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    void setOrientation(uint16_t orientation);
1712079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    uint16_t getOrientation() const;
1722079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
1732079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    void setDescription(const String8& desc);
1742079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    String8 getDescription() const;
1752079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    bool hasDescription() const;
1762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
1772079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    void setGpsData(const GpsData& data);
1782079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    GpsData getGpsData() const;
1792079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    bool hasGpsData() const;
1802079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
1812079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    void setCaptureTime(const String8& formattedCaptureTime);
1822079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    String8 getCaptureTime() const;
1832079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    bool hasCaptureTime() const;
1842079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
18547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkprivate:
18647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    Vector<uint8_t> mCurrentThumbnail;
18747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    TiffWriter mWriter;
188b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk    std::shared_ptr<CameraMetadata> mCharacteristics;
189b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk    std::shared_ptr<CameraMetadata> mResult;
19047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mThumbnailWidth;
19147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mThumbnailHeight;
1922079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    uint16_t mOrientation;
1932079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    bool mThumbnailSet;
1942079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    bool mGpsSet;
1952079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    bool mDescriptionSet;
1962079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    bool mCaptureTimeSet;
1972079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    String8 mDescription;
1982079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    GpsData mGpsData;
1992079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    String8 mFormattedCaptureTime;
20047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk};
20147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
202b8f4c6ab1e99a44a51af26dc522819bb833825abRuben BrunkNativeContext::NativeContext(const CameraMetadata& characteristics, const CameraMetadata& result) :
203b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk        mCharacteristics(std::make_shared<CameraMetadata>(characteristics)),
204b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk        mResult(std::make_shared<CameraMetadata>(result)), mThumbnailWidth(0),
2058069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala        mThumbnailHeight(0), mOrientation(TAG_ORIENTATION_UNKNOWN), mThumbnailSet(false),
2068069b1f252d6a1e1c469dfc733bdd0db5d69574fEino-Ville Talvala        mGpsSet(false), mDescriptionSet(false), mCaptureTimeSet(false) {}
20747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
20847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkNativeContext::~NativeContext() {}
20947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
21047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkTiffWriter* NativeContext::getWriter() {
21147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return &mWriter;
21247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
21347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
214b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunkstd::shared_ptr<const CameraMetadata> NativeContext::getCharacteristics() const {
215b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk    return mCharacteristics;
216b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk}
217b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk
218b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunkstd::shared_ptr<const CameraMetadata> NativeContext::getResult() const {
219b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk    return mResult;
220b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk}
221b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk
2222079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkuint32_t NativeContext::getThumbnailWidth() const {
22347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return mThumbnailWidth;
22447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
22547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
2262079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkuint32_t NativeContext::getThumbnailHeight() const {
22747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return mThumbnailHeight;
22847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
22947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
2302079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkconst uint8_t* NativeContext::getThumbnail() const {
23147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return mCurrentThumbnail.array();
23247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
23347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
2342079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkbool NativeContext::hasThumbnail() const {
2352079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    return mThumbnailSet;
2362079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk}
2372079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
23847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkbool NativeContext::setThumbnail(const uint8_t* buffer, uint32_t width, uint32_t height) {
23947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    mThumbnailWidth = width;
24047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    mThumbnailHeight = height;
24147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
24247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    size_t size = BYTES_PER_RGB_PIXEL * width * height;
24347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (mCurrentThumbnail.resize(size) < 0) {
24447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ALOGE("%s: Could not resize thumbnail buffer.", __FUNCTION__);
24547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return false;
24647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
24747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
24847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint8_t* thumb = mCurrentThumbnail.editArray();
24947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    memcpy(thumb, buffer, size);
2502079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    mThumbnailSet = true;
25147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return true;
25247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
25347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
2542079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkvoid NativeContext::setOrientation(uint16_t orientation) {
2552079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    mOrientation = orientation;
2562079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk}
2572079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
2582079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkuint16_t NativeContext::getOrientation() const {
2592079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    return mOrientation;
2602079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk}
2612079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
2622079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkvoid NativeContext::setDescription(const String8& desc) {
2632079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    mDescription = desc;
2642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    mDescriptionSet = true;
2652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk}
2662079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
2672079612e5851d73f4672ae3729c883a58adc4dddRuben BrunkString8 NativeContext::getDescription() const {
2682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    return mDescription;
2692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk}
2702079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
2712079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkbool NativeContext::hasDescription() const {
2722079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    return mDescriptionSet;
2732079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk}
2742079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
2752079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkvoid NativeContext::setGpsData(const GpsData& data) {
2762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    mGpsData = data;
2772079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    mGpsSet = true;
2782079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk}
2792079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
2802079612e5851d73f4672ae3729c883a58adc4dddRuben BrunkGpsData NativeContext::getGpsData() const {
2812079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    return mGpsData;
2822079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk}
2832079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
2842079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkbool NativeContext::hasGpsData() const {
2852079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    return mGpsSet;
2862079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk}
2872079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
2882079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkvoid NativeContext::setCaptureTime(const String8& formattedCaptureTime) {
2892079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    mFormattedCaptureTime = formattedCaptureTime;
2902079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    mCaptureTimeSet = true;
2912079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk}
2922079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
2932079612e5851d73f4672ae3729c883a58adc4dddRuben BrunkString8 NativeContext::getCaptureTime() const {
2942079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    return mFormattedCaptureTime;
2952079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk}
2962079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
2972079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkbool NativeContext::hasCaptureTime() const {
2982079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    return mCaptureTimeSet;
2992079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk}
3002079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
30147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of NativeContext
30247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ----------------------------------------------------------------------------
30347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
30447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/**
30547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * Wrapper class for a Java OutputStream.
30647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk *
30747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * This class is not intended to be used across JNI calls.
30847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */
309f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkclass JniOutputStream : public Output, public LightRefBase<JniOutputStream> {
310f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkpublic:
311f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    JniOutputStream(JNIEnv* env, jobject outStream);
312f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
313f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    virtual ~JniOutputStream();
314f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
315f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    status_t open();
31647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
317f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    status_t write(const uint8_t* buf, size_t offset, size_t count);
31847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
319f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    status_t close();
320f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkprivate:
321f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    enum {
32247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BYTE_ARRAY_LENGTH = 4096
323f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    };
324f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    jobject mOutputStream;
325f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    JNIEnv* mEnv;
326f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    jbyteArray mByteArray;
327f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk};
328f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
329f967a5486a78db244624fde4c105aa5e6fa914b9Ruben BrunkJniOutputStream::JniOutputStream(JNIEnv* env, jobject outStream) : mOutputStream(outStream),
330f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        mEnv(env) {
331f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH);
3322079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    if (mByteArray == nullptr) {
333f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array.");
334f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
335f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}
336f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
337f967a5486a78db244624fde4c105aa5e6fa914b9Ruben BrunkJniOutputStream::~JniOutputStream() {
338f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    mEnv->DeleteLocalRef(mByteArray);
339f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}
340f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
341f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatus_t JniOutputStream::open() {
342f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    // Do nothing
343f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    return OK;
344f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}
345f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
346f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatus_t JniOutputStream::write(const uint8_t* buf, size_t offset, size_t count) {
347f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    while(count > 0) {
348f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        size_t len = BYTE_ARRAY_LENGTH;
349f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        len = (count > len) ? len : count;
350f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        mEnv->SetByteArrayRegion(mByteArray, 0, len, reinterpret_cast<const jbyte*>(buf + offset));
351f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
352f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        if (mEnv->ExceptionCheck()) {
353f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            return BAD_VALUE;
354f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        }
355f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
356f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        mEnv->CallVoidMethod(mOutputStream, gOutputStreamClassInfo.mWriteMethod, mByteArray,
357f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                0, len);
358f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
359f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        if (mEnv->ExceptionCheck()) {
360f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            return BAD_VALUE;
361f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        }
362f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
363f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        count -= len;
364f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        offset += len;
365f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
366f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    return OK;
367f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}
368f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
369f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatus_t JniOutputStream::close() {
370f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    // Do nothing
371f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    return OK;
372f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}
373f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
37447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of JniOutputStream
375f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk// ----------------------------------------------------------------------------
376f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
37747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/**
37847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * Wrapper class for a Java InputStream.
37947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk *
38047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * This class is not intended to be used across JNI calls.
38147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */
38247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkclass JniInputStream : public Input, public LightRefBase<JniInputStream> {
38347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkpublic:
38447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    JniInputStream(JNIEnv* env, jobject inStream);
38547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
38647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    status_t open();
38747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
38847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    status_t close();
38947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
39047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    ssize_t read(uint8_t* buf, size_t offset, size_t count);
39147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
39247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    ssize_t skip(size_t count);
39347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
39447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    virtual ~JniInputStream();
39547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkprivate:
39647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    enum {
39747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BYTE_ARRAY_LENGTH = 4096
39847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    };
39947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jobject mInStream;
40047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    JNIEnv* mEnv;
40147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jbyteArray mByteArray;
40247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
40347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk};
40447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
40547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkJniInputStream::JniInputStream(JNIEnv* env, jobject inStream) : mInStream(inStream), mEnv(env) {
40647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH);
4072079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    if (mByteArray == nullptr) {
40847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array.");
40947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
41047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
41147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
41247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkJniInputStream::~JniInputStream() {
41347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    mEnv->DeleteLocalRef(mByteArray);
41447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
41547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
41647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkssize_t JniInputStream::read(uint8_t* buf, size_t offset, size_t count) {
41747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
41847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jint realCount = BYTE_ARRAY_LENGTH;
41947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (count < BYTE_ARRAY_LENGTH) {
42047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        realCount = count;
42147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
42247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jint actual = mEnv->CallIntMethod(mInStream, gInputStreamClassInfo.mReadMethod, mByteArray, 0,
42347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            realCount);
42447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
42547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (actual < 0) {
42647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return NOT_ENOUGH_DATA;
42747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
42847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
42947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (mEnv->ExceptionCheck()) {
43047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return BAD_VALUE;
43147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
43247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
43347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    mEnv->GetByteArrayRegion(mByteArray, 0, actual, reinterpret_cast<jbyte*>(buf + offset));
43447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (mEnv->ExceptionCheck()) {
43547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return BAD_VALUE;
43647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
43747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return actual;
43847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
43947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
44047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkssize_t JniInputStream::skip(size_t count) {
44147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jlong actual = mEnv->CallLongMethod(mInStream, gInputStreamClassInfo.mSkipMethod,
44247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            static_cast<jlong>(count));
44347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
44447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (mEnv->ExceptionCheck()) {
44547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return BAD_VALUE;
44647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
44747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (actual < 0) {
44847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return NOT_ENOUGH_DATA;
44947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
45047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return actual;
45147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
45247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
45347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t JniInputStream::open() {
45447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    // Do nothing
45547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return OK;
45647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
45747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
45847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t JniInputStream::close() {
45947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    // Do nothing
46047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return OK;
46147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
46247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
46347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of JniInputStream
46447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ----------------------------------------------------------------------------
46547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
46647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/**
46747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * Wrapper class for a non-direct Java ByteBuffer.
46847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk *
46947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * This class is not intended to be used across JNI calls.
47047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */
47147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkclass JniInputByteBuffer : public Input, public LightRefBase<JniInputByteBuffer> {
47247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkpublic:
47347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    JniInputByteBuffer(JNIEnv* env, jobject inBuf);
47447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
47547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    status_t open();
47647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
47747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    status_t close();
47847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
47947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    ssize_t read(uint8_t* buf, size_t offset, size_t count);
48047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
48147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    virtual ~JniInputByteBuffer();
48247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkprivate:
48347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    enum {
48447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BYTE_ARRAY_LENGTH = 4096
48547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    };
48647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jobject mInBuf;
48747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    JNIEnv* mEnv;
48847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jbyteArray mByteArray;
48947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk};
49047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
49147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkJniInputByteBuffer::JniInputByteBuffer(JNIEnv* env, jobject inBuf) : mInBuf(inBuf), mEnv(env) {
49247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH);
4932079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    if (mByteArray == nullptr) {
49447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array.");
49547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
49647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
49747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
49847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkJniInputByteBuffer::~JniInputByteBuffer() {
49947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    mEnv->DeleteLocalRef(mByteArray);
50047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
50147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
50247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkssize_t JniInputByteBuffer::read(uint8_t* buf, size_t offset, size_t count) {
50347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jint realCount = BYTE_ARRAY_LENGTH;
50447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (count < BYTE_ARRAY_LENGTH) {
50547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        realCount = count;
50647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
50747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
5085f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk    jobject chainingBuf = mEnv->CallObjectMethod(mInBuf, gInputByteBufferClassInfo.mGetMethod,
5095f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk            mByteArray, 0, realCount);
510a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk    mEnv->DeleteLocalRef(chainingBuf);
51147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
51247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (mEnv->ExceptionCheck()) {
513a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk        ALOGE("%s: Exception while reading from input into byte buffer.", __FUNCTION__);
51447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return BAD_VALUE;
51547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
51647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
51747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    mEnv->GetByteArrayRegion(mByteArray, 0, realCount, reinterpret_cast<jbyte*>(buf + offset));
51847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (mEnv->ExceptionCheck()) {
519a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk        ALOGE("%s: Exception while reading from byte buffer.", __FUNCTION__);
52047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return BAD_VALUE;
52147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
52247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return realCount;
52347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
52447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
52547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t JniInputByteBuffer::open() {
52647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    // Do nothing
52747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return OK;
52847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
52947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
53047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t JniInputByteBuffer::close() {
53147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    // Do nothing
53247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return OK;
53347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
53447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
53547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of JniInputByteBuffer
53647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ----------------------------------------------------------------------------
53747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
53847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/**
53947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * StripSource subclass for Input types.
54047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk *
54147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * This class is not intended to be used across JNI calls.
54247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */
54347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
54447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkclass InputStripSource : public StripSource, public LightRefBase<InputStripSource> {
54547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkpublic:
54647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    InputStripSource(JNIEnv* env, Input& input, uint32_t ifd, uint32_t width, uint32_t height,
54747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            uint32_t pixStride, uint32_t rowStride, uint64_t offset, uint32_t bytesPerSample,
54847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            uint32_t samplesPerPixel);
54947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
55047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    virtual ~InputStripSource();
55147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
55247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    virtual status_t writeToStream(Output& stream, uint32_t count);
55347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
55447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    virtual uint32_t getIfd() const;
55547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkprotected:
55647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mIfd;
55747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    Input* mInput;
55847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mWidth;
55947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mHeight;
56047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mPixStride;
56147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mRowStride;
56247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint64_t mOffset;
56347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    JNIEnv* mEnv;
56447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mBytesPerSample;
56547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mSamplesPerPixel;
56647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk};
56747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
56847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkInputStripSource::InputStripSource(JNIEnv* env, Input& input, uint32_t ifd, uint32_t width,
56947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        uint32_t height, uint32_t pixStride, uint32_t rowStride, uint64_t offset,
57047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        uint32_t bytesPerSample, uint32_t samplesPerPixel) : mIfd(ifd), mInput(&input),
57147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        mWidth(width), mHeight(height), mPixStride(pixStride), mRowStride(rowStride),
57247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        mOffset(offset), mEnv(env), mBytesPerSample(bytesPerSample),
57347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        mSamplesPerPixel(samplesPerPixel) {}
57447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
57547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkInputStripSource::~InputStripSource() {}
57647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
57747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t InputStripSource::writeToStream(Output& stream, uint32_t count) {
5783e1902504979b9b456a14dffa6507ee2d9ea3d6aRuben Brunk    uint32_t fullSize = mWidth * mHeight * mBytesPerSample * mSamplesPerPixel;
57947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jlong offset = mOffset;
58047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
58147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (fullSize != count) {
58247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ALOGE("%s: Amount to write %u doesn't match image size %u", __FUNCTION__, count,
58347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                fullSize);
58447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowException(mEnv, "java/lang/IllegalStateException", "Not enough data to write");
58547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return BAD_VALUE;
58647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
58747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
58847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    // Skip offset
58947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    while (offset > 0) {
59047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ssize_t skipped = mInput->skip(offset);
59147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        if (skipped <= 0) {
59247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            if (skipped == NOT_ENOUGH_DATA || skipped == 0) {
59347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                jniThrowExceptionFmt(mEnv, "java/io/IOException",
59447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                        "Early EOF encountered in skip, not enough pixel data for image of size %u",
59547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                        fullSize);
59647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                skipped = NOT_ENOUGH_DATA;
59747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            } else {
59847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                if (!mEnv->ExceptionCheck()) {
59947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    jniThrowException(mEnv, "java/io/IOException",
60047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                            "Error encountered while skip bytes in input stream.");
60147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                }
60247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            }
60347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
60447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            return skipped;
60547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        }
60647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        offset -= skipped;
60747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
60847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
60947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    Vector<uint8_t> row;
61047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (row.resize(mRowStride) < 0) {
61147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowException(mEnv, "java/lang/OutOfMemoryError", "Could not allocate row vector.");
61247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return BAD_VALUE;
61347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
61447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
61547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint8_t* rowBytes = row.editArray();
61647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
61747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    for (uint32_t i = 0; i < mHeight; ++i) {
61847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        size_t rowFillAmt = 0;
619a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk        size_t rowSize = mRowStride;
62047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
62147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        while (rowFillAmt < mRowStride) {
62247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            ssize_t bytesRead = mInput->read(rowBytes, rowFillAmt, rowSize);
62347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            if (bytesRead <= 0) {
62447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                if (bytesRead == NOT_ENOUGH_DATA || bytesRead == 0) {
625a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk                    ALOGE("%s: Early EOF on row %" PRIu32 ", received bytesRead %zd",
626a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk                            __FUNCTION__, i, bytesRead);
62747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    jniThrowExceptionFmt(mEnv, "java/io/IOException",
628a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk                            "Early EOF encountered, not enough pixel data for image of size %"
629a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk                            PRIu32, fullSize);
63047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    bytesRead = NOT_ENOUGH_DATA;
63147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                } else {
63247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    if (!mEnv->ExceptionCheck()) {
63347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                        jniThrowException(mEnv, "java/io/IOException",
63447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                                "Error encountered while reading");
63547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    }
63647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                }
63747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                return bytesRead;
63847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            }
63947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            rowFillAmt += bytesRead;
64047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            rowSize -= bytesRead;
64147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        }
64247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
64347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        if (mPixStride == mBytesPerSample * mSamplesPerPixel) {
64447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            ALOGV("%s: Using stream per-row write for strip.", __FUNCTION__);
64547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
64647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            if (stream.write(rowBytes, 0, mBytesPerSample * mSamplesPerPixel * mWidth) != OK ||
64747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    mEnv->ExceptionCheck()) {
64847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                if (!mEnv->ExceptionCheck()) {
64947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    jniThrowException(mEnv, "java/io/IOException", "Failed to write pixel data");
65047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                }
65147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                return BAD_VALUE;
65247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            }
65347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        } else {
65447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            ALOGV("%s: Using stream per-pixel write for strip.", __FUNCTION__);
65547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            jniThrowException(mEnv, "java/lang/IllegalStateException",
65647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    "Per-pixel strides are not supported for RAW16 -- pixels must be contiguous");
65747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            return BAD_VALUE;
65847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
65947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            // TODO: Add support for non-contiguous pixels if needed.
66047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        }
66147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
66247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return OK;
66347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
66447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
66547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkuint32_t InputStripSource::getIfd() const {
66647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return mIfd;
66747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
66847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
66947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of InputStripSource
67047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ----------------------------------------------------------------------------
67147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
67247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/**
67347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * StripSource subclass for direct buffer types.
67447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk *
67547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * This class is not intended to be used across JNI calls.
67647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */
67747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
67847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkclass DirectStripSource : public StripSource, public LightRefBase<DirectStripSource> {
67947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkpublic:
68047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    DirectStripSource(JNIEnv* env, const uint8_t* pixelBytes, uint32_t ifd, uint32_t width,
68147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            uint32_t height, uint32_t pixStride, uint32_t rowStride, uint64_t offset,
68247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            uint32_t bytesPerSample, uint32_t samplesPerPixel);
68347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
68447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    virtual ~DirectStripSource();
68547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
68647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    virtual status_t writeToStream(Output& stream, uint32_t count);
68747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
68847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    virtual uint32_t getIfd() const;
68947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkprotected:
69047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mIfd;
69147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    const uint8_t* mPixelBytes;
69247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mWidth;
69347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mHeight;
69447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mPixStride;
69547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mRowStride;
69647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint16_t mOffset;
69747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    JNIEnv* mEnv;
69847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mBytesPerSample;
69947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mSamplesPerPixel;
70047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk};
70147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
70247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkDirectStripSource::DirectStripSource(JNIEnv* env, const uint8_t* pixelBytes, uint32_t ifd,
70347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            uint32_t width, uint32_t height, uint32_t pixStride, uint32_t rowStride,
70447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            uint64_t offset, uint32_t bytesPerSample, uint32_t samplesPerPixel) : mIfd(ifd),
70547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            mPixelBytes(pixelBytes), mWidth(width), mHeight(height), mPixStride(pixStride),
70647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            mRowStride(rowStride), mOffset(offset), mEnv(env), mBytesPerSample(bytesPerSample),
70747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            mSamplesPerPixel(samplesPerPixel) {}
70847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
70947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkDirectStripSource::~DirectStripSource() {}
71047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
71147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t DirectStripSource::writeToStream(Output& stream, uint32_t count) {
7123e1902504979b9b456a14dffa6507ee2d9ea3d6aRuben Brunk    uint32_t fullSize = mWidth * mHeight * mBytesPerSample * mSamplesPerPixel;
71347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
71447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (fullSize != count) {
71547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ALOGE("%s: Amount to write %u doesn't match image size %u", __FUNCTION__, count,
71647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                fullSize);
71747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowException(mEnv, "java/lang/IllegalStateException", "Not enough data to write");
71847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return BAD_VALUE;
71947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
72047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
7212079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
72247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (mPixStride == mBytesPerSample * mSamplesPerPixel
72347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            && mRowStride == mWidth * mBytesPerSample * mSamplesPerPixel) {
72447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ALOGV("%s: Using direct single-pass write for strip.", __FUNCTION__);
72547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
72647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        if (stream.write(mPixelBytes, mOffset, fullSize) != OK || mEnv->ExceptionCheck()) {
72747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            if (!mEnv->ExceptionCheck()) {
72847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                jniThrowException(mEnv, "java/io/IOException", "Failed to write pixel data");
72947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            }
73047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            return BAD_VALUE;
73147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        }
73247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    } else if (mPixStride == mBytesPerSample * mSamplesPerPixel) {
73347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ALOGV("%s: Using direct per-row write for strip.", __FUNCTION__);
73447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
73547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        for (size_t i = 0; i < mHeight; ++i) {
73647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            if (stream.write(mPixelBytes, mOffset + i * mRowStride, mPixStride * mWidth) != OK ||
73747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                        mEnv->ExceptionCheck()) {
73847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                if (!mEnv->ExceptionCheck()) {
73947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    jniThrowException(mEnv, "java/io/IOException", "Failed to write pixel data");
74047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                }
74147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                return BAD_VALUE;
74247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            }
74347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        }
74447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    } else {
74547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ALOGV("%s: Using direct per-pixel write for strip.", __FUNCTION__);
74647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
74747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowException(mEnv, "java/lang/IllegalStateException",
74847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                "Per-pixel strides are not supported for RAW16 -- pixels must be contiguous");
74947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return BAD_VALUE;
75047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
75147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        // TODO: Add support for non-contiguous pixels if needed.
75247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
75347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return OK;
75447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
75547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
75647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
75747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkuint32_t DirectStripSource::getIfd() const {
75847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return mIfd;
75947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
76047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
76147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of DirectStripSource
76247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ----------------------------------------------------------------------------
76347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
764b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk/**
765a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk * Calculate the default crop relative to the "active area" of the image sensor (this active area
766a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk * will always be the pre-correction active area rectangle), and set this.
767b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk */
768b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunkstatic status_t calculateAndSetCrop(JNIEnv* env, const CameraMetadata& characteristics,
769a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk        sp<TiffWriter> writer) {
770b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk
771b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk    camera_metadata_ro_entry entry =
7722079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk            characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
773b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk    uint32_t width = static_cast<uint32_t>(entry.data.i32[2]);
774b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk    uint32_t height = static_cast<uint32_t>(entry.data.i32[3]);
775b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk
7762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    const uint32_t margin = 8; // Default margin recommended by Adobe for interpolation.
7772079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
778a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk    if (width < margin * 2 || height < margin * 2) {
779a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk        ALOGE("%s: Cannot calculate default crop for image, pre-correction active area is too"
780a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk                "small: h=%" PRIu32 ", w=%" PRIu32, __FUNCTION__, height, width);
781a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk        jniThrowException(env, "java/lang/IllegalStateException",
782a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk                "Pre-correction active area is too small.");
783a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk        return BAD_VALUE;
7842079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    }
7852079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk
786a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk    uint32_t defaultCropOrigin[] = {margin, margin};
787a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk    uint32_t defaultCropSize[] = {width - defaultCropOrigin[0] - margin,
788a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk                                  height - defaultCropOrigin[1] - margin};
789a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk
790b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk    BAIL_IF_INVALID_R(writer->addEntry(TAG_DEFAULTCROPORIGIN, 2, defaultCropOrigin,
791b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk            TIFF_IFD_0), env, TAG_DEFAULTCROPORIGIN, writer);
792b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk    BAIL_IF_INVALID_R(writer->addEntry(TAG_DEFAULTCROPSIZE, 2, defaultCropSize,
793b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk            TIFF_IFD_0), env, TAG_DEFAULTCROPSIZE, writer);
794b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk
795b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk    return OK;
796b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk}
79747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
7982079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkstatic bool validateDngHeader(JNIEnv* env, sp<TiffWriter> writer,
799b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk        const CameraMetadata& characteristics, jint width, jint height) {
800b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk    if (width <= 0) {
801b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \
802b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk                        "Image width %d is invalid", width);
803b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk        return false;
804b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk    }
80547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
806b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk    if (height <= 0) {
80747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \
808b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk                        "Image height %d is invalid", height);
80947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return false;
81047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
81147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
812b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk    camera_metadata_ro_entry preCorrectionEntry =
813b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk            characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
814b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk    camera_metadata_ro_entry pixelArrayEntry =
815b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk            characteristics.find(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE);
816b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk
817b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk    int pWidth = static_cast<int>(pixelArrayEntry.data.i32[0]);
818b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk    int pHeight = static_cast<int>(pixelArrayEntry.data.i32[1]);
819b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk    int cWidth = static_cast<int>(preCorrectionEntry.data.i32[2]);
820b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk    int cHeight = static_cast<int>(preCorrectionEntry.data.i32[3]);
821b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk
822b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk    bool matchesPixelArray = (pWidth == width && pHeight == height);
823b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk    bool matchesPreCorrectionArray = (cWidth == width && cHeight == height);
824b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk
8252079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk    if (!(matchesPixelArray || matchesPreCorrectionArray)) {
82647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \
827b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk                        "Image dimensions (w=%d,h=%d) are invalid, must match either the pixel "
828b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk                        "array size (w=%d, h=%d) or the pre-correction array size (w=%d, h=%d)",
829b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk                        width, height, pWidth, pHeight, cWidth, cHeight);
83047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return false;
83147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
83247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
83347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return true;
83447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
83547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
8362079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkstatic status_t moveEntries(sp<TiffWriter> writer, uint32_t ifdFrom, uint32_t ifdTo,
83747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        const Vector<uint16_t>& entries) {
838