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, ©right, 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