android_hardware_camera2_DngCreator.cpp revision b8df8e07d6fc530c82d21ca3199411e2e60975b1
1/*
2 * Copyright 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "DngCreator_JNI"
19
20#include <system/camera_metadata.h>
21#include <camera/CameraMetadata.h>
22#include <img_utils/DngUtils.h>
23#include <img_utils/TagDefinitions.h>
24#include <img_utils/TiffIfd.h>
25#include <img_utils/TiffWriter.h>
26#include <img_utils/Output.h>
27
28#include <utils/Log.h>
29#include <utils/Errors.h>
30#include <utils/StrongPointer.h>
31#include <utils/RefBase.h>
32#include <cutils/properties.h>
33
34#include <string.h>
35
36#include "android_runtime/AndroidRuntime.h"
37#include "android_runtime/android_hardware_camera2_CameraMetadata.h"
38
39#include <jni.h>
40#include <JNIHelp.h>
41
42using namespace android;
43using namespace img_utils;
44
45#define BAIL_IF_INVALID(expr, jnienv, tagId) \
46    if ((expr) != OK) { \
47        jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
48                "Invalid metadata for tag %x", tagId); \
49        return; \
50    }
51
52#define BAIL_IF_EMPTY(entry, jnienv, tagId) \
53    if (entry.count == 0) { \
54        jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
55                "Missing metadata fields for tag %x", tagId); \
56        return; \
57    }
58
59#define ANDROID_DNGCREATOR_CTX_JNI_ID     "mNativeContext"
60
61static struct {
62    jfieldID mNativeContext;
63} gDngCreatorClassInfo;
64
65static struct {
66    jmethodID mWriteMethod;
67} gOutputStreamClassInfo;
68
69enum {
70    BITS_PER_SAMPLE = 16,
71    BYTES_PER_SAMPLE = 2,
72    TIFF_IFD_0 = 0
73};
74
75// ----------------------------------------------------------------------------
76
77// This class is not intended to be used across JNI calls.
78class JniOutputStream : public Output, public LightRefBase<JniOutputStream> {
79public:
80    JniOutputStream(JNIEnv* env, jobject outStream);
81
82    virtual ~JniOutputStream();
83
84    status_t open();
85    status_t write(const uint8_t* buf, size_t offset, size_t count);
86    status_t close();
87private:
88    enum {
89        BYTE_ARRAY_LENGTH = 1024
90    };
91    jobject mOutputStream;
92    JNIEnv* mEnv;
93    jbyteArray mByteArray;
94};
95
96JniOutputStream::JniOutputStream(JNIEnv* env, jobject outStream) : mOutputStream(outStream),
97        mEnv(env) {
98    mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH);
99    if (mByteArray == NULL) {
100        jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array.");
101    }
102}
103
104JniOutputStream::~JniOutputStream() {
105    mEnv->DeleteLocalRef(mByteArray);
106}
107
108status_t JniOutputStream::open() {
109    // Do nothing
110    return OK;
111}
112
113status_t JniOutputStream::write(const uint8_t* buf, size_t offset, size_t count) {
114    while(count > 0) {
115        size_t len = BYTE_ARRAY_LENGTH;
116        len = (count > len) ? len : count;
117        mEnv->SetByteArrayRegion(mByteArray, 0, len, reinterpret_cast<const jbyte*>(buf + offset));
118
119        if (mEnv->ExceptionCheck()) {
120            return BAD_VALUE;
121        }
122
123        mEnv->CallVoidMethod(mOutputStream, gOutputStreamClassInfo.mWriteMethod, mByteArray,
124                0, len);
125
126        if (mEnv->ExceptionCheck()) {
127            return BAD_VALUE;
128        }
129
130        count -= len;
131        offset += len;
132    }
133    return OK;
134}
135
136status_t JniOutputStream::close() {
137    // Do nothing
138    return OK;
139}
140
141// ----------------------------------------------------------------------------
142
143extern "C" {
144
145static TiffWriter* DngCreator_getCreator(JNIEnv* env, jobject thiz) {
146    ALOGV("%s:", __FUNCTION__);
147    return reinterpret_cast<TiffWriter*>(env->GetLongField(thiz,
148            gDngCreatorClassInfo.mNativeContext));
149}
150
151static void DngCreator_setCreator(JNIEnv* env, jobject thiz, sp<TiffWriter> writer) {
152    ALOGV("%s:", __FUNCTION__);
153    TiffWriter* current = DngCreator_getCreator(env, thiz);
154    if (writer != NULL) {
155        writer->incStrong((void*) DngCreator_setCreator);
156    }
157    if (current) {
158        current->decStrong((void*) DngCreator_setCreator);
159    }
160    env->SetLongField(thiz, gDngCreatorClassInfo.mNativeContext,
161            reinterpret_cast<jlong>(writer.get()));
162}
163
164static void DngCreator_nativeClassInit(JNIEnv* env, jclass clazz) {
165    ALOGV("%s:", __FUNCTION__);
166
167    gDngCreatorClassInfo.mNativeContext = env->GetFieldID(clazz,
168            ANDROID_DNGCREATOR_CTX_JNI_ID, "J");
169    LOG_ALWAYS_FATAL_IF(gDngCreatorClassInfo.mNativeContext == NULL,
170            "can't find android/hardware/camera2/DngCreator.%s",
171            ANDROID_DNGCREATOR_CTX_JNI_ID);
172
173    jclass outputStreamClazz = env->FindClass("java/io/OutputStream");
174    LOG_ALWAYS_FATAL_IF(outputStreamClazz == NULL, "Can't find java/io/OutputStream class");
175    gOutputStreamClassInfo.mWriteMethod = env->GetMethodID(outputStreamClazz, "write", "([BII)V");
176    LOG_ALWAYS_FATAL_IF(gOutputStreamClassInfo.mWriteMethod == NULL, "Can't find write method");
177}
178
179static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPtr,
180        jobject resultsPtr, jstring formattedCaptureTime) {
181    ALOGV("%s:", __FUNCTION__);
182    CameraMetadata characteristics;
183    CameraMetadata results;
184    if (CameraMetadata_getNativeMetadata(env, characteristicsPtr, &characteristics) != OK) {
185         jniThrowException(env, "java/lang/AssertionError",
186                "No native metadata defined for camera characteristics.");
187         return;
188    }
189    if (CameraMetadata_getNativeMetadata(env, resultsPtr, &results) != OK) {
190        jniThrowException(env, "java/lang/AssertionError",
191                "No native metadata defined for capture results.");
192        return;
193    }
194
195    sp<TiffWriter> writer = new TiffWriter();
196
197    writer->addIfd(TIFF_IFD_0);
198
199    status_t err = OK;
200
201    const uint32_t samplesPerPixel = 1;
202    const uint32_t bitsPerSample = BITS_PER_SAMPLE;
203    const uint32_t bitsPerByte = BITS_PER_SAMPLE / BYTES_PER_SAMPLE;
204    uint32_t imageWidth = 0;
205    uint32_t imageHeight = 0;
206
207    OpcodeListBuilder::CfaLayout opcodeCfaLayout = OpcodeListBuilder::CFA_RGGB;
208
209    // TODO: Greensplit.
210    // TODO: Add remaining non-essential tags
211    {
212        // Set orientation
213        uint16_t orientation = 1; // Normal
214        BAIL_IF_INVALID(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0), env,
215                TAG_ORIENTATION);
216    }
217
218    {
219        // Set subfiletype
220        uint32_t subfileType = 0; // Main image
221        BAIL_IF_INVALID(writer->addEntry(TAG_NEWSUBFILETYPE, 1, &subfileType, TIFF_IFD_0), env,
222                TAG_NEWSUBFILETYPE);
223    }
224
225    {
226        // Set bits per sample
227        uint16_t bits = static_cast<uint16_t>(bitsPerSample);
228        BAIL_IF_INVALID(writer->addEntry(TAG_BITSPERSAMPLE, 1, &bits, TIFF_IFD_0), env,
229                TAG_BITSPERSAMPLE);
230    }
231
232    {
233        // Set compression
234        uint16_t compression = 1; // None
235        BAIL_IF_INVALID(writer->addEntry(TAG_COMPRESSION, 1, &compression, TIFF_IFD_0), env,
236                TAG_COMPRESSION);
237    }
238
239    {
240        // Set dimensions
241        camera_metadata_entry entry =
242                characteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
243        BAIL_IF_EMPTY(entry, env, TAG_IMAGEWIDTH);
244        uint32_t width = static_cast<uint32_t>(entry.data.i32[2]);
245        uint32_t height = static_cast<uint32_t>(entry.data.i32[3]);
246        BAIL_IF_INVALID(writer->addEntry(TAG_IMAGEWIDTH, 1, &width, TIFF_IFD_0), env,
247                TAG_IMAGEWIDTH);
248        BAIL_IF_INVALID(writer->addEntry(TAG_IMAGELENGTH, 1, &height, TIFF_IFD_0), env,
249                TAG_IMAGELENGTH);
250        imageWidth = width;
251        imageHeight = height;
252    }
253
254    {
255        // Set photometric interpretation
256        uint16_t interpretation = 32803;
257        BAIL_IF_INVALID(writer->addEntry(TAG_PHOTOMETRICINTERPRETATION, 1, &interpretation,
258                TIFF_IFD_0), env, TAG_PHOTOMETRICINTERPRETATION);
259    }
260
261    {
262        // Set blacklevel tags
263        camera_metadata_entry entry =
264                characteristics.find(ANDROID_SENSOR_BLACK_LEVEL_PATTERN);
265        BAIL_IF_EMPTY(entry, env, TAG_BLACKLEVEL);
266        const uint32_t* blackLevel = reinterpret_cast<const uint32_t*>(entry.data.i32);
267        BAIL_IF_INVALID(writer->addEntry(TAG_BLACKLEVEL, entry.count, blackLevel, TIFF_IFD_0), env,
268                TAG_BLACKLEVEL);
269
270        uint16_t repeatDim[2] = {2, 2};
271        BAIL_IF_INVALID(writer->addEntry(TAG_BLACKLEVELREPEATDIM, 2, repeatDim, TIFF_IFD_0), env,
272                TAG_BLACKLEVELREPEATDIM);
273    }
274
275    {
276        // Set samples per pixel
277        uint16_t samples = static_cast<uint16_t>(samplesPerPixel);
278        BAIL_IF_INVALID(writer->addEntry(TAG_SAMPLESPERPIXEL, 1, &samples, TIFF_IFD_0),
279                env, TAG_SAMPLESPERPIXEL);
280    }
281
282    {
283        // Set planar configuration
284        uint16_t config = 1; // Chunky
285        BAIL_IF_INVALID(writer->addEntry(TAG_PLANARCONFIGURATION, 1, &config, TIFF_IFD_0),
286                env, TAG_PLANARCONFIGURATION);
287    }
288
289    {
290        // Set CFA pattern dimensions
291        uint16_t repeatDim[2] = {2, 2};
292        BAIL_IF_INVALID(writer->addEntry(TAG_CFAREPEATPATTERNDIM, 2, repeatDim, TIFF_IFD_0),
293                env, TAG_CFAREPEATPATTERNDIM);
294    }
295
296    {
297        // Set CFA pattern
298        camera_metadata_entry entry =
299                        characteristics.find(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT);
300        BAIL_IF_EMPTY(entry, env, TAG_CFAPATTERN);
301        camera_metadata_enum_android_sensor_info_color_filter_arrangement_t cfa =
302                static_cast<camera_metadata_enum_android_sensor_info_color_filter_arrangement_t>(
303                entry.data.u8[0]);
304        switch(cfa) {
305            case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB: {
306                uint8_t cfa[4] = {0, 1, 1, 2};
307                BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0),
308                                                env, TAG_CFAPATTERN);
309                opcodeCfaLayout = OpcodeListBuilder::CFA_RGGB;
310                break;
311            }
312            case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG: {
313                uint8_t cfa[4] = {1, 0, 2, 1};
314                BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0),
315                                                env, TAG_CFAPATTERN);
316                opcodeCfaLayout = OpcodeListBuilder::CFA_GRBG;
317                break;
318            }
319            case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG: {
320                uint8_t cfa[4] = {1, 2, 0, 1};
321                BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0),
322                                                env, TAG_CFAPATTERN);
323                opcodeCfaLayout = OpcodeListBuilder::CFA_GBRG;
324                break;
325            }
326            case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR: {
327                uint8_t cfa[4] = {2, 1, 1, 0};
328                BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0),
329                                env, TAG_CFAPATTERN);
330                opcodeCfaLayout = OpcodeListBuilder::CFA_BGGR;
331                break;
332            }
333            default: {
334                jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
335                            "Invalid metadata for tag %d", TAG_CFAPATTERN);
336                return;
337            }
338        }
339    }
340
341    {
342        // Set CFA plane color
343        uint8_t cfaPlaneColor[3] = {0, 1, 2};
344        BAIL_IF_INVALID(writer->addEntry(TAG_CFAPLANECOLOR, 3, cfaPlaneColor, TIFF_IFD_0),
345                env, TAG_CFAPLANECOLOR);
346    }
347
348    {
349        // Set CFA layout
350        uint16_t cfaLayout = 1;
351        BAIL_IF_INVALID(writer->addEntry(TAG_CFALAYOUT, 1, &cfaLayout, TIFF_IFD_0),
352                env, TAG_CFALAYOUT);
353    }
354
355    {
356        // image description
357        uint8_t imageDescription = '\0'; // empty
358        BAIL_IF_INVALID(writer->addEntry(TAG_IMAGEDESCRIPTION, 1, &imageDescription, TIFF_IFD_0),
359                env, TAG_IMAGEDESCRIPTION);
360    }
361
362    {
363        // make
364        char manufacturer[PROPERTY_VALUE_MAX];
365
366        // Use "" to represent unknown make as suggested in TIFF/EP spec.
367        property_get("ro.product.manufacturer", manufacturer, "");
368        uint32_t count = static_cast<uint32_t>(strlen(manufacturer)) + 1;
369
370        BAIL_IF_INVALID(writer->addEntry(TAG_MAKE, count, reinterpret_cast<uint8_t*>(manufacturer),
371                TIFF_IFD_0), env, TAG_MAKE);
372    }
373
374    {
375        // model
376        char model[PROPERTY_VALUE_MAX];
377
378        // Use "" to represent unknown model as suggested in TIFF/EP spec.
379        property_get("ro.product.model", model, "");
380        uint32_t count = static_cast<uint32_t>(strlen(model)) + 1;
381
382        BAIL_IF_INVALID(writer->addEntry(TAG_MODEL, count, reinterpret_cast<uint8_t*>(model),
383                TIFF_IFD_0), env, TAG_MODEL);
384    }
385
386    {
387        // x resolution
388        uint32_t xres[] = { 72, 1 }; // default 72 ppi
389        BAIL_IF_INVALID(writer->addEntry(TAG_XRESOLUTION, 1, xres, TIFF_IFD_0),
390                env, TAG_XRESOLUTION);
391
392        // y resolution
393        uint32_t yres[] = { 72, 1 }; // default 72 ppi
394        BAIL_IF_INVALID(writer->addEntry(TAG_YRESOLUTION, 1, yres, TIFF_IFD_0),
395                env, TAG_YRESOLUTION);
396
397        uint16_t unit = 2; // inches
398        BAIL_IF_INVALID(writer->addEntry(TAG_RESOLUTIONUNIT, 1, &unit, TIFF_IFD_0),
399                env, TAG_RESOLUTIONUNIT);
400    }
401
402    {
403        // software
404        char software[PROPERTY_VALUE_MAX];
405        property_get("ro.build.fingerprint", software, "");
406        uint32_t count = static_cast<uint32_t>(strlen(software)) + 1;
407        BAIL_IF_INVALID(writer->addEntry(TAG_SOFTWARE, count, reinterpret_cast<uint8_t*>(software),
408                TIFF_IFD_0), env, TAG_SOFTWARE);
409    }
410
411    {
412        // datetime
413        const size_t DATETIME_COUNT = 20;
414        const char* captureTime = env->GetStringUTFChars(formattedCaptureTime, NULL);
415
416        size_t len = strlen(captureTime) + 1;
417        if (len != DATETIME_COUNT) {
418            jniThrowException(env, "java/lang/IllegalArgumentException",
419                    "Timestamp string length is not required 20 characters");
420            return;
421        }
422
423        BAIL_IF_INVALID(writer->addEntry(TAG_DATETIME, DATETIME_COUNT,
424                reinterpret_cast<const uint8_t*>(captureTime), TIFF_IFD_0), env, TAG_DATETIMEORIGINAL);
425
426        // datetime original
427        BAIL_IF_INVALID(writer->addEntry(TAG_DATETIMEORIGINAL, DATETIME_COUNT,
428                reinterpret_cast<const uint8_t*>(captureTime), TIFF_IFD_0), env, TAG_DATETIMEORIGINAL);
429        env->ReleaseStringUTFChars(formattedCaptureTime, captureTime);
430    }
431
432    {
433        // TIFF/EP standard id
434        uint8_t standardId[] = { 1, 0, 0, 0 };
435        BAIL_IF_INVALID(writer->addEntry(TAG_TIFFEPSTANDARDID, 4, standardId,
436                TIFF_IFD_0), env, TAG_TIFFEPSTANDARDID);
437    }
438
439    {
440        // copyright
441        uint8_t copyright = '\0'; // empty
442        BAIL_IF_INVALID(writer->addEntry(TAG_COPYRIGHT, 1, &copyright,
443                TIFF_IFD_0), env, TAG_COPYRIGHT);
444    }
445
446    {
447        // exposure time
448        camera_metadata_entry entry =
449            results.find(ANDROID_SENSOR_EXPOSURE_TIME);
450        BAIL_IF_EMPTY(entry, env, TAG_EXPOSURETIME);
451
452        int64_t exposureTime = *(entry.data.i64);
453
454        if (exposureTime < 0) {
455            // Should be unreachable
456            jniThrowException(env, "java/lang/IllegalArgumentException",
457                    "Negative exposure time in metadata");
458            return;
459        }
460
461        // Ensure exposure time doesn't overflow (for exposures > 4s)
462        uint32_t denominator = 1000000000;
463        while (exposureTime > UINT32_MAX) {
464            exposureTime >>= 1;
465            denominator >>= 1;
466            if (denominator == 0) {
467                // Should be unreachable
468                jniThrowException(env, "java/lang/IllegalArgumentException",
469                        "Exposure time too long");
470                return;
471            }
472        }
473
474        uint32_t exposure[] = { static_cast<uint32_t>(exposureTime), denominator };
475        BAIL_IF_INVALID(writer->addEntry(TAG_EXPOSURETIME, 1, exposure,
476                TIFF_IFD_0), env, TAG_EXPOSURETIME);
477
478    }
479
480    {
481        // ISO speed ratings
482        camera_metadata_entry entry =
483            results.find(ANDROID_SENSOR_SENSITIVITY);
484        BAIL_IF_EMPTY(entry, env, TAG_ISOSPEEDRATINGS);
485
486        int32_t tempIso = *(entry.data.i32);
487        if (tempIso < 0) {
488            jniThrowException(env, "java/lang/IllegalArgumentException",
489                                    "Negative ISO value");
490            return;
491        }
492
493        if (tempIso > UINT16_MAX) {
494            ALOGW("%s: ISO value overflows UINT16_MAX, clamping to max", __FUNCTION__);
495            tempIso = UINT16_MAX;
496        }
497
498        uint16_t iso = static_cast<uint16_t>(tempIso);
499        BAIL_IF_INVALID(writer->addEntry(TAG_ISOSPEEDRATINGS, 1, &iso,
500                TIFF_IFD_0), env, TAG_ISOSPEEDRATINGS);
501    }
502
503    {
504        // focal length
505        camera_metadata_entry entry =
506            results.find(ANDROID_LENS_FOCAL_LENGTH);
507        BAIL_IF_EMPTY(entry, env, TAG_FOCALLENGTH);
508
509        uint32_t focalLength[] = { static_cast<uint32_t>(*(entry.data.f) * 100), 100 };
510        BAIL_IF_INVALID(writer->addEntry(TAG_FOCALLENGTH, 1, focalLength,
511                TIFF_IFD_0), env, TAG_FOCALLENGTH);
512    }
513
514    {
515        // f number
516        camera_metadata_entry entry =
517            results.find(ANDROID_LENS_APERTURE);
518        BAIL_IF_EMPTY(entry, env, TAG_FNUMBER);
519
520        uint32_t fnum[] = { static_cast<uint32_t>(*(entry.data.f) * 100), 100 };
521        BAIL_IF_INVALID(writer->addEntry(TAG_FNUMBER, 1, fnum,
522                TIFF_IFD_0), env, TAG_FNUMBER);
523    }
524
525    {
526        // Set DNG version information
527        uint8_t version[4] = {1, 4, 0, 0};
528        BAIL_IF_INVALID(writer->addEntry(TAG_DNGVERSION, 4, version, TIFF_IFD_0),
529                env, TAG_DNGVERSION);
530
531        uint8_t backwardVersion[4] = {1, 1, 0, 0};
532        BAIL_IF_INVALID(writer->addEntry(TAG_DNGBACKWARDVERSION, 4, backwardVersion, TIFF_IFD_0),
533                env, TAG_DNGBACKWARDVERSION);
534    }
535
536    {
537        // Set whitelevel
538        camera_metadata_entry entry =
539                characteristics.find(ANDROID_SENSOR_INFO_WHITE_LEVEL);
540        BAIL_IF_EMPTY(entry, env, TAG_WHITELEVEL);
541        uint32_t whiteLevel = static_cast<uint32_t>(entry.data.i32[0]);
542        BAIL_IF_INVALID(writer->addEntry(TAG_WHITELEVEL, 1, &whiteLevel, TIFF_IFD_0), env,
543                TAG_WHITELEVEL);
544    }
545
546    {
547        // Set default scale
548        uint32_t defaultScale[4] = {1, 1, 1, 1};
549        BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTSCALE, 2, defaultScale, TIFF_IFD_0),
550                env, TAG_DEFAULTSCALE);
551    }
552
553    bool singleIlluminant = false;
554    {
555        // Set calibration illuminants
556        camera_metadata_entry entry1 =
557            characteristics.find(ANDROID_SENSOR_REFERENCE_ILLUMINANT1);
558        BAIL_IF_EMPTY(entry1, env, TAG_CALIBRATIONILLUMINANT1);
559        camera_metadata_entry entry2 =
560            characteristics.find(ANDROID_SENSOR_REFERENCE_ILLUMINANT2);
561        if (entry2.count == 0) {
562            singleIlluminant = true;
563        }
564        uint16_t ref1 = entry1.data.u8[0];
565
566        BAIL_IF_INVALID(writer->addEntry(TAG_CALIBRATIONILLUMINANT1, 1, &ref1,
567                TIFF_IFD_0), env, TAG_CALIBRATIONILLUMINANT1);
568
569        if (!singleIlluminant) {
570            uint16_t ref2 = entry2.data.u8[0];
571            BAIL_IF_INVALID(writer->addEntry(TAG_CALIBRATIONILLUMINANT2, 1, &ref2,
572                    TIFF_IFD_0), env, TAG_CALIBRATIONILLUMINANT2);
573        }
574    }
575
576    {
577        // Set color transforms
578        camera_metadata_entry entry1 =
579            characteristics.find(ANDROID_SENSOR_COLOR_TRANSFORM1);
580        BAIL_IF_EMPTY(entry1, env, TAG_COLORMATRIX1);
581
582        int32_t colorTransform1[entry1.count * 2];
583
584        size_t ctr = 0;
585        for(size_t i = 0; i < entry1.count; ++i) {
586            colorTransform1[ctr++] = entry1.data.r[i].numerator;
587            colorTransform1[ctr++] = entry1.data.r[i].denominator;
588        }
589
590        BAIL_IF_INVALID(writer->addEntry(TAG_COLORMATRIX1, entry1.count, colorTransform1, TIFF_IFD_0),
591                env, TAG_COLORMATRIX1);
592
593        if (!singleIlluminant) {
594            camera_metadata_entry entry2 = characteristics.find(ANDROID_SENSOR_COLOR_TRANSFORM2);
595            BAIL_IF_EMPTY(entry2, env, TAG_COLORMATRIX2);
596            int32_t colorTransform2[entry2.count * 2];
597
598            ctr = 0;
599            for(size_t i = 0; i < entry2.count; ++i) {
600                colorTransform2[ctr++] = entry2.data.r[i].numerator;
601                colorTransform2[ctr++] = entry2.data.r[i].denominator;
602            }
603
604            BAIL_IF_INVALID(writer->addEntry(TAG_COLORMATRIX2, entry2.count, colorTransform2, TIFF_IFD_0),
605                    env, TAG_COLORMATRIX2);
606        }
607    }
608
609    {
610        // Set calibration transforms
611        camera_metadata_entry entry1 =
612            characteristics.find(ANDROID_SENSOR_CALIBRATION_TRANSFORM1);
613        BAIL_IF_EMPTY(entry1, env, TAG_CAMERACALIBRATION1);
614
615        int32_t calibrationTransform1[entry1.count * 2];
616
617        size_t ctr = 0;
618        for(size_t i = 0; i < entry1.count; ++i) {
619            calibrationTransform1[ctr++] = entry1.data.r[i].numerator;
620            calibrationTransform1[ctr++] = entry1.data.r[i].denominator;
621        }
622
623        BAIL_IF_INVALID(writer->addEntry(TAG_CAMERACALIBRATION1, entry1.count, calibrationTransform1,
624                TIFF_IFD_0), env, TAG_CAMERACALIBRATION1);
625
626        if (!singleIlluminant) {
627            camera_metadata_entry entry2 =
628                characteristics.find(ANDROID_SENSOR_CALIBRATION_TRANSFORM2);
629            BAIL_IF_EMPTY(entry2, env, TAG_CAMERACALIBRATION2);
630            int32_t calibrationTransform2[entry2.count * 2];
631
632            ctr = 0;
633            for(size_t i = 0; i < entry2.count; ++i) {
634                calibrationTransform2[ctr++] = entry2.data.r[i].numerator;
635                calibrationTransform2[ctr++] = entry2.data.r[i].denominator;
636            }
637
638            BAIL_IF_INVALID(writer->addEntry(TAG_CAMERACALIBRATION2, entry2.count, calibrationTransform1,
639                    TIFF_IFD_0),  env, TAG_CAMERACALIBRATION2);
640        }
641    }
642
643    {
644        // Set forward transforms
645        camera_metadata_entry entry1 =
646            characteristics.find(ANDROID_SENSOR_FORWARD_MATRIX1);
647        BAIL_IF_EMPTY(entry1, env, TAG_FORWARDMATRIX1);
648
649        int32_t forwardTransform1[entry1.count * 2];
650
651        size_t ctr = 0;
652        for(size_t i = 0; i < entry1.count; ++i) {
653            forwardTransform1[ctr++] = entry1.data.r[i].numerator;
654            forwardTransform1[ctr++] = entry1.data.r[i].denominator;
655        }
656
657        BAIL_IF_INVALID(writer->addEntry(TAG_FORWARDMATRIX1, entry1.count, forwardTransform1,
658                TIFF_IFD_0), env, TAG_FORWARDMATRIX1);
659
660        if (!singleIlluminant) {
661            camera_metadata_entry entry2 =
662                characteristics.find(ANDROID_SENSOR_FORWARD_MATRIX2);
663            BAIL_IF_EMPTY(entry2, env, TAG_FORWARDMATRIX2);
664            int32_t forwardTransform2[entry2.count * 2];
665
666            ctr = 0;
667            for(size_t i = 0; i < entry2.count; ++i) {
668                forwardTransform2[ctr++] = entry2.data.r[i].numerator;
669                forwardTransform2[ctr++] = entry2.data.r[i].denominator;
670            }
671
672            BAIL_IF_INVALID(writer->addEntry(TAG_FORWARDMATRIX2, entry2.count, forwardTransform2,
673                    TIFF_IFD_0),  env, TAG_FORWARDMATRIX2);
674        }
675    }
676
677    {
678        // Set camera neutral
679        camera_metadata_entry entry =
680            results.find(ANDROID_SENSOR_NEUTRAL_COLOR_POINT);
681        BAIL_IF_EMPTY(entry, env, TAG_ASSHOTNEUTRAL);
682        uint32_t cameraNeutral[entry.count * 2];
683
684        size_t ctr = 0;
685        for(size_t i = 0; i < entry.count; ++i) {
686            cameraNeutral[ctr++] =
687                    static_cast<uint32_t>(entry.data.r[i].numerator);
688            cameraNeutral[ctr++] =
689                    static_cast<uint32_t>(entry.data.r[i].denominator);
690        }
691
692        BAIL_IF_INVALID(writer->addEntry(TAG_ASSHOTNEUTRAL, entry.count, cameraNeutral,
693                TIFF_IFD_0), env, TAG_ASSHOTNEUTRAL);
694    }
695
696    {
697        // Setup data strips
698        // TODO: Switch to tiled implementation.
699        uint32_t offset = 0;
700        BAIL_IF_INVALID(writer->addEntry(TAG_STRIPOFFSETS, 1, &offset, TIFF_IFD_0), env,
701                TAG_STRIPOFFSETS);
702
703        BAIL_IF_INVALID(writer->addEntry(TAG_ROWSPERSTRIP, 1, &imageHeight, TIFF_IFD_0), env,
704                TAG_ROWSPERSTRIP);
705
706        uint32_t byteCount = imageWidth * imageHeight * bitsPerSample * samplesPerPixel /
707                bitsPerByte;
708        BAIL_IF_INVALID(writer->addEntry(TAG_STRIPBYTECOUNTS, 1, &byteCount, TIFF_IFD_0), env,
709                TAG_STRIPBYTECOUNTS);
710    }
711
712    {
713        // Setup default crop + crop origin tags
714        uint32_t margin = 8; // Default margin recommended by Adobe for interpolation.
715        uint32_t dimensionLimit = 128; // Smallest image dimension crop margin from.
716        if (imageWidth >= dimensionLimit && imageHeight >= dimensionLimit) {
717            uint32_t defaultCropOrigin[] = {margin, margin};
718            uint32_t defaultCropSize[] = {imageWidth - margin, imageHeight - margin};
719            BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTCROPORIGIN, 2, defaultCropOrigin,
720                    TIFF_IFD_0), env, TAG_DEFAULTCROPORIGIN);
721            BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTCROPSIZE, 2, defaultCropSize,
722                    TIFF_IFD_0), env, TAG_DEFAULTCROPSIZE);
723        }
724    }
725
726    {
727        // Setup unique camera model tag
728        char model[PROPERTY_VALUE_MAX];
729        property_get("ro.product.model", model, "");
730
731        char manufacturer[PROPERTY_VALUE_MAX];
732        property_get("ro.product.manufacturer", manufacturer, "");
733
734        char brand[PROPERTY_VALUE_MAX];
735        property_get("ro.product.brand", brand, "");
736
737        String8 cameraModel(model);
738        cameraModel += "-";
739        cameraModel += manufacturer;
740        cameraModel += "-";
741        cameraModel += brand;
742
743        BAIL_IF_INVALID(writer->addEntry(TAG_UNIQUECAMERAMODEL, cameraModel.size() + 1,
744                reinterpret_cast<const uint8_t*>(cameraModel.string()), TIFF_IFD_0), env,
745                TAG_UNIQUECAMERAMODEL);
746    }
747
748    {
749        // Setup opcode List 2
750        camera_metadata_entry entry1 =
751                characteristics.find(ANDROID_LENS_INFO_SHADING_MAP_SIZE);
752        BAIL_IF_EMPTY(entry1, env, TAG_OPCODELIST2);
753        uint32_t lsmWidth = static_cast<uint32_t>(entry1.data.i32[0]);
754        uint32_t lsmHeight = static_cast<uint32_t>(entry1.data.i32[1]);
755
756        camera_metadata_entry entry2 =
757                results.find(ANDROID_STATISTICS_LENS_SHADING_MAP);
758        BAIL_IF_EMPTY(entry2, env, TAG_OPCODELIST2);
759        if (entry2.count == lsmWidth * lsmHeight * 4) {
760
761            OpcodeListBuilder builder;
762            status_t err = builder.addGainMapsForMetadata(lsmWidth,
763                                                          lsmHeight,
764                                                          0,
765                                                          0,
766                                                          imageHeight,
767                                                          imageWidth,
768                                                          opcodeCfaLayout,
769                                                          entry2.data.f);
770            if (err == OK) {
771                size_t listSize = builder.getSize();
772                uint8_t opcodeListBuf[listSize];
773                err = builder.buildOpList(opcodeListBuf);
774                if (err == OK) {
775                    BAIL_IF_INVALID(writer->addEntry(TAG_OPCODELIST2, listSize, opcodeListBuf,
776                            TIFF_IFD_0), env, TAG_OPCODELIST2);
777                } else {
778                    ALOGE("%s: Could not build Lens shading map opcode.", __FUNCTION__);
779                    jniThrowRuntimeException(env, "failed to construct lens shading map opcode.");
780                }
781            } else {
782                ALOGE("%s: Could not add Lens shading map.", __FUNCTION__);
783                jniThrowRuntimeException(env, "failed to add lens shading map.");
784            }
785        } else {
786            ALOGW("%s: Lens shading map not present in results, skipping...", __FUNCTION__);
787        }
788    }
789
790    DngCreator_setCreator(env, thiz, writer);
791}
792
793static void DngCreator_destroy(JNIEnv* env, jobject thiz) {
794    ALOGV("%s:", __FUNCTION__);
795    DngCreator_setCreator(env, thiz, NULL);
796}
797
798static void DngCreator_nativeSetOrientation(JNIEnv* env, jobject thiz) {
799    ALOGV("%s:", __FUNCTION__);
800    jniThrowRuntimeException(env, "nativeSetOrientation is not implemented");
801}
802
803static void DngCreator_nativeSetThumbnailBitmap(JNIEnv* env, jobject thiz, jobject bitmap) {
804    ALOGV("%s:", __FUNCTION__);
805    jniThrowRuntimeException(env, "nativeSetThumbnailBitmap is not implemented");
806}
807
808static void DngCreator_nativeSetThumbnailImage(JNIEnv* env, jobject thiz, jint width, jint height,
809        jobject yBuffer, jint yRowStride, jint yPixStride, jobject uBuffer, jint uRowStride,
810        jint uPixStride, jobject vBuffer, jint vRowStride, jint vPixStride) {
811    ALOGV("%s:", __FUNCTION__);
812    jniThrowRuntimeException(env, "nativeSetThumbnailImage is not implemented");
813}
814
815static void DngCreator_nativeWriteImage(JNIEnv* env, jobject thiz, jobject outStream, jint width,
816        jint height, jobject inBuffer, jint rowStride, jint pixStride) {
817    ALOGV("%s:", __FUNCTION__);
818
819    sp<JniOutputStream> out = new JniOutputStream(env, outStream);
820    if(env->ExceptionCheck()) {
821        ALOGE("%s: Could not allocate buffers for output stream", __FUNCTION__);
822        return;
823    }
824
825    uint8_t* pixelBytes = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(inBuffer));
826    if (pixelBytes == NULL) {
827        ALOGE("%s: Could not get native byte buffer", __FUNCTION__);
828        jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid bytebuffer");
829        return;
830    }
831
832    TiffWriter* writer = DngCreator_getCreator(env, thiz);
833    if (writer == NULL) {
834        ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
835        jniThrowException(env, "java/lang/AssertionError",
836                "Write called with uninitialized DngCreator");
837        return;
838    }
839    // TODO: handle lens shading map, etc. conversions for other raw buffer sizes.
840    uint32_t metadataWidth = *(writer->getEntry(TAG_IMAGEWIDTH, TIFF_IFD_0)->getData<uint32_t>());
841    uint32_t metadataHeight = *(writer->getEntry(TAG_IMAGELENGTH, TIFF_IFD_0)->getData<uint32_t>());
842    if (metadataWidth != width) {
843        jniThrowExceptionFmt(env, "java/lang/IllegalStateException", \
844                        "Metadata width %d doesn't match image width %d", metadataWidth, width);
845        return;
846    }
847
848    if (metadataHeight != height) {
849        jniThrowExceptionFmt(env, "java/lang/IllegalStateException", \
850                        "Metadata height %d doesn't match image height %d", metadataHeight, height);
851        return;
852    }
853
854    uint32_t stripOffset = writer->getTotalSize();
855
856    BAIL_IF_INVALID(writer->addEntry(TAG_STRIPOFFSETS, 1, &stripOffset, TIFF_IFD_0), env,
857                    TAG_STRIPOFFSETS);
858
859    if (writer->write(out.get()) != OK) {
860        if (!env->ExceptionCheck()) {
861            jniThrowException(env, "java/io/IOException", "Failed to write metadata");
862        }
863        return;
864    }
865
866    size_t fullSize = rowStride * height;
867    jlong capacity = env->GetDirectBufferCapacity(inBuffer);
868    if (capacity < 0 || fullSize > capacity) {
869        jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
870                "Invalid size %d for Image, size given in metadata is %d at current stride",
871                capacity, fullSize);
872        return;
873    }
874
875    if (pixStride == BYTES_PER_SAMPLE && rowStride == width * BYTES_PER_SAMPLE) {
876        if (out->write(pixelBytes, 0, fullSize) != OK || env->ExceptionCheck()) {
877            if (!env->ExceptionCheck()) {
878                jniThrowException(env, "java/io/IOException", "Failed to write pixel data");
879            }
880            return;
881        }
882    } else if (pixStride == BYTES_PER_SAMPLE) {
883        for (size_t i = 0; i < height; ++i) {
884            if (out->write(pixelBytes, i * rowStride, pixStride * width) != OK ||
885                        env->ExceptionCheck()) {
886                if (!env->ExceptionCheck()) {
887                    jniThrowException(env, "java/io/IOException", "Failed to write pixel data");
888                }
889                return;
890            }
891        }
892    } else {
893        for (size_t i = 0; i < height; ++i) {
894            for (size_t j = 0; j < width; ++j) {
895                if (out->write(pixelBytes, i * rowStride + j * pixStride,
896                        BYTES_PER_SAMPLE) != OK || !env->ExceptionCheck()) {
897                    if (env->ExceptionCheck()) {
898                        jniThrowException(env, "java/io/IOException", "Failed to write pixel data");
899                    }
900                    return;
901                }
902            }
903        }
904    }
905
906}
907
908static void DngCreator_nativeWriteByteBuffer(JNIEnv* env, jobject thiz, jobject outStream,
909        jobject rawBuffer, jlong offset) {
910    ALOGV("%s:", __FUNCTION__);
911    jniThrowRuntimeException(env, "nativeWriteByteBuffer is not implemented.");
912}
913
914static void DngCreator_nativeWriteInputStream(JNIEnv* env, jobject thiz, jobject outStream,
915        jobject inStream, jlong offset) {
916    ALOGV("%s:", __FUNCTION__);
917    jniThrowRuntimeException(env, "nativeWriteInputStream is not implemented.");
918}
919
920} /*extern "C" */
921
922static JNINativeMethod gDngCreatorMethods[] = {
923    {"nativeClassInit",        "()V", (void*) DngCreator_nativeClassInit},
924    {"nativeInit", "(Landroid/hardware/camera2/impl/CameraMetadataNative;"
925            "Landroid/hardware/camera2/impl/CameraMetadataNative;Ljava/lang/String;)V",
926            (void*) DngCreator_init},
927    {"nativeDestroy",           "()V",      (void*) DngCreator_destroy},
928    {"nativeSetOrientation",    "(I)V",     (void*) DngCreator_nativeSetOrientation},
929    {"nativeSetThumbnailBitmap","(Landroid/graphics/Bitmap;)V",
930            (void*) DngCreator_nativeSetThumbnailBitmap},
931    {"nativeSetThumbnailImage",
932            "(IILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;II)V",
933            (void*) DngCreator_nativeSetThumbnailImage},
934    {"nativeWriteImage",        "(Ljava/io/OutputStream;IILjava/nio/ByteBuffer;II)V",
935            (void*) DngCreator_nativeWriteImage},
936    {"nativeWriteByteBuffer",    "(Ljava/io/OutputStream;Ljava/nio/ByteBuffer;J)V",
937            (void*) DngCreator_nativeWriteByteBuffer},
938    {"nativeWriteInputStream",    "(Ljava/io/OutputStream;Ljava/io/InputStream;J)V",
939            (void*) DngCreator_nativeWriteInputStream},
940};
941
942int register_android_hardware_camera2_DngCreator(JNIEnv *env) {
943    return AndroidRuntime::registerNativeMethods(env,
944                   "android/hardware/camera2/DngCreator", gDngCreatorMethods,
945                   NELEM(gDngCreatorMethods));
946}
947